diff --git a/.eslintrc.js b/.eslintrc.js
index 270ced0..766d2114 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -11,6 +11,7 @@
   'rules': {
     // Enabled checks.
     'no-extra-semi': 'error',
+    'no-new-wrappers': 'error',
     'no-restricted-properties': ['error', {
       'object': 'document',
       'property': 'getElementById',
diff --git a/DEPS b/DEPS
index 1667d1b..e0accf5 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '2fdc3d56a250e15445ee073ec49981d2c4f94953',
+  'skia_revision': '3f3075819f242158dcfc1690df5c15ba39c5dbb3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'c092edbb88f4317058ebc952420e366911db6777',
+  'v8_revision': '3692957d2864e013fb324de5d652fe4bdcbd71b9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
diff --git a/android_webview/browser/aw_safe_browsing_ui_manager.cc b/android_webview/browser/aw_safe_browsing_ui_manager.cc
index 562a9066..cf33463 100644
--- a/android_webview/browser/aw_safe_browsing_ui_manager.cc
+++ b/android_webview/browser/aw_safe_browsing_ui_manager.cc
@@ -43,7 +43,8 @@
     const UnsafeResource& resource) const {
   WebContents* web_contents = resource.web_contents_getter.Run();
   UIManagerClient* client = UIManagerClient::FromWebContents(web_contents);
-  return client && client->GetErrorUiType();
+  DCHECK(client);
+  return client->GetErrorUiType();
 }
 
 }  // namespace android_webview
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 5df23998..e397fb0ba 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1188,6 +1188,7 @@
     "shelf/shelf_application_menu_model_unittest.cc",
     "shelf/shelf_background_animator_unittest.cc",
     "shelf/shelf_button_pressed_metric_tracker_unittest.cc",
+    "shelf/shelf_controller_unittest.cc",
     "shelf/shelf_layout_manager_unittest.cc",
     "shelf/shelf_locking_manager_unittest.cc",
     "shelf/shelf_model_unittest.cc",
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc
index 21e54ed..cff2bbf 100644
--- a/ash/accelerators/accelerator_controller.cc
+++ b/ash/accelerators/accelerator_controller.cc
@@ -354,7 +354,8 @@
 void HandleShowSystemTrayBubble() {
   base::RecordAction(UserMetricsAction("Accel_Show_System_Tray_Bubble"));
   aura::Window* target_root = Shell::GetRootWindowForNewWindows();
-  SystemTray* tray = GetRootWindowController(target_root)->GetSystemTray();
+  SystemTray* tray =
+      RootWindowController::ForWindow(target_root)->GetSystemTray();
   if (!tray->HasSystemBubble()) {
     tray->ShowDefaultView(BUBBLE_CREATE_NEW);
     tray->ActivateBubble();
@@ -526,8 +527,7 @@
 
 void HandleShowStylusTools() {
   base::RecordAction(UserMetricsAction("Accel_Show_Stylus_Tools"));
-  GetRootWindowController(Shell::GetRootWindowForNewWindows())
-      ->shelf()
+  Shelf::ForWindow(Shell::GetRootWindowForNewWindows())
       ->GetStatusAreaWidget()
       ->palette_tray()
       ->ShowPalette();
diff --git a/ash/accelerators/exit_warning_handler.cc b/ash/accelerators/exit_warning_handler.cc
index 27989c0..747a413 100644
--- a/ash/accelerators/exit_warning_handler.cc
+++ b/ash/accelerators/exit_warning_handler.cc
@@ -153,7 +153,7 @@
   params.bounds = bounds;
   params.name = "ExitWarningWindow";
   widget_.reset(new views::Widget);
-  GetRootWindowController(root_window)
+  RootWindowController::ForWindow(root_window)
       ->ConfigureWidgetInitParamsForContainer(
           widget_.get(), kShellWindowId_SettingBubbleContainer, &params);
   widget_->Init(params);
diff --git a/ash/app_list/app_list_presenter_delegate.cc b/ash/app_list/app_list_presenter_delegate.cc
index 0bbb1c1..01b2bcc5 100644
--- a/ash/app_list/app_list_presenter_delegate.cc
+++ b/ash/app_list/app_list_presenter_delegate.cc
@@ -89,13 +89,13 @@
                                     int current_apps_page) {
   // App list needs to know the new shelf layout in order to calculate its
   // UI layout when AppListView visibility changes.
-  ash::Shell::GetPrimaryRootWindowController()
+  Shell::GetPrimaryRootWindowController()
       ->GetShelfLayoutManager()
       ->UpdateAutoHideState();
   view_ = view;
   aura::Window* root_window =
       ShellPort::Get()->GetRootWindowForDisplayId(display_id);
-  aura::Window* container = GetRootWindowController(root_window)
+  aura::Window* container = RootWindowController::ForWindow(root_window)
                                 ->GetContainer(kShellWindowId_AppListContainer);
 
   view->Initialize(container, current_apps_page);
@@ -185,7 +185,7 @@
   aura::Window* target = static_cast<aura::Window*>(event->target());
   if (target) {
     RootWindowController* root_controller =
-        GetRootWindowController(target->GetRootWindow());
+        RootWindowController::ForWindow(target);
     if (root_controller) {
       aura::Window* menu_container =
           root_controller->GetContainer(kShellWindowId_MenuContainer);
diff --git a/ash/display/cursor_window_controller.cc b/ash/display/cursor_window_controller.cc
index 06b2c12..477c6d4 100644
--- a/ash/display/cursor_window_controller.cc
+++ b/ash/display/cursor_window_controller.cc
@@ -162,7 +162,7 @@
   if (!root_window)
     return;
 
-  SetContainer(GetRootWindowController(root_window)
+  SetContainer(RootWindowController::ForWindow(root_window)
                    ->GetContainer(kShellWindowId_MouseCursorContainer));
   SetBoundsInScreen(display.bounds());
   // Updates the hot point based on the current display.
diff --git a/ash/display/display_util_unittest.cc b/ash/display/display_util_unittest.cc
index 9ec1d0d..33f0232a 100644
--- a/ash/display/display_util_unittest.cc
+++ b/ash/display/display_util_unittest.cc
@@ -17,9 +17,9 @@
     UpdateDisplay("10+10-500x400,600+10-1000x600/r");
     aura::Window::Windows root_windows = Shell::GetAllRootWindows();
     AshWindowTreeHost* host0 =
-        GetRootWindowController(root_windows[0])->ash_host();
+        RootWindowController::ForWindow(root_windows[0])->ash_host();
     AshWindowTreeHost* host1 =
-        GetRootWindowController(root_windows[1])->ash_host();
+        RootWindowController::ForWindow(root_windows[1])->ash_host();
     gfx::Rect rect0 = GetNativeEdgeBounds(host0, gfx::Rect(499, 10, 1, 300));
     gfx::Rect rect1 = GetNativeEdgeBounds(host1, gfx::Rect(500, 10, 1, 300));
     EXPECT_EQ("509,20 1x300", rect0.ToString());
@@ -29,9 +29,9 @@
     UpdateDisplay("10+10-500x400,600+10-1000x600/l");
     aura::Window::Windows root_windows = Shell::GetAllRootWindows();
     AshWindowTreeHost* host0 =
-        GetRootWindowController(root_windows[0])->ash_host();
+        RootWindowController::ForWindow(root_windows[0])->ash_host();
     AshWindowTreeHost* host1 =
-        GetRootWindowController(root_windows[1])->ash_host();
+        RootWindowController::ForWindow(root_windows[1])->ash_host();
     gfx::Rect rect0 = GetNativeEdgeBounds(host0, gfx::Rect(499, 10, 1, 300));
     gfx::Rect rect1 = GetNativeEdgeBounds(host1, gfx::Rect(500, 10, 1, 300));
     EXPECT_EQ("509,20 1x300", rect0.ToString());
@@ -41,9 +41,9 @@
     UpdateDisplay("10+10-500x400,600+10-1000x600/u");
     aura::Window::Windows root_windows = Shell::GetAllRootWindows();
     AshWindowTreeHost* host0 =
-        GetRootWindowController(root_windows[0])->ash_host();
+        RootWindowController::ForWindow(root_windows[0])->ash_host();
     AshWindowTreeHost* host1 =
-        GetRootWindowController(root_windows[1])->ash_host();
+        RootWindowController::ForWindow(root_windows[1])->ash_host();
     gfx::Rect rect0 = GetNativeEdgeBounds(host0, gfx::Rect(499, 10, 1, 300));
     gfx::Rect rect1 = GetNativeEdgeBounds(host1, gfx::Rect(500, 10, 1, 300));
     EXPECT_EQ("509,20 1x300", rect0.ToString());
@@ -54,9 +54,9 @@
     UpdateDisplay("10+10-500x400/r,600+10-1000x600");
     aura::Window::Windows root_windows = Shell::GetAllRootWindows();
     AshWindowTreeHost* host0 =
-        GetRootWindowController(root_windows[0])->ash_host();
+        RootWindowController::ForWindow(root_windows[0])->ash_host();
     AshWindowTreeHost* host1 =
-        GetRootWindowController(root_windows[1])->ash_host();
+        RootWindowController::ForWindow(root_windows[1])->ash_host();
     gfx::Rect rect0 = GetNativeEdgeBounds(host0, gfx::Rect(399, 10, 1, 300));
     gfx::Rect rect1 = GetNativeEdgeBounds(host1, gfx::Rect(400, 10, 1, 300));
     EXPECT_EQ("199,409 300x1", rect0.ToString());
@@ -66,9 +66,9 @@
     UpdateDisplay("10+10-500x400/l,600+10-1000x600");
     aura::Window::Windows root_windows = Shell::GetAllRootWindows();
     AshWindowTreeHost* host0 =
-        GetRootWindowController(root_windows[0])->ash_host();
+        RootWindowController::ForWindow(root_windows[0])->ash_host();
     AshWindowTreeHost* host1 =
-        GetRootWindowController(root_windows[1])->ash_host();
+        RootWindowController::ForWindow(root_windows[1])->ash_host();
     gfx::Rect rect0 = GetNativeEdgeBounds(host0, gfx::Rect(499, 10, 1, 300));
     gfx::Rect rect1 = GetNativeEdgeBounds(host1, gfx::Rect(500, 10, 1, 300));
     EXPECT_EQ("20,10 300x1", rect0.ToString());
@@ -78,9 +78,9 @@
     UpdateDisplay("10+10-500x400/u,600+10-1000x600");
     aura::Window::Windows root_windows = Shell::GetAllRootWindows();
     AshWindowTreeHost* host0 =
-        GetRootWindowController(root_windows[0])->ash_host();
+        RootWindowController::ForWindow(root_windows[0])->ash_host();
     AshWindowTreeHost* host1 =
-        GetRootWindowController(root_windows[1])->ash_host();
+        RootWindowController::ForWindow(root_windows[1])->ash_host();
     gfx::Rect rect0 = GetNativeEdgeBounds(host0, gfx::Rect(499, 10, 1, 300));
     gfx::Rect rect1 = GetNativeEdgeBounds(host1, gfx::Rect(500, 10, 1, 300));
     EXPECT_EQ("10,99 1x300", rect0.ToString());
diff --git a/ash/display/extended_mouse_warp_controller.cc b/ash/display/extended_mouse_warp_controller.cc
index ac31b33b..7553812e 100644
--- a/ash/display/extended_mouse_warp_controller.cc
+++ b/ash/display/extended_mouse_warp_controller.cc
@@ -77,8 +77,10 @@
   aura::Window* a_window = GetRootWindowForDisplayId(a_display_id);
   aura::Window* b_window = GetRootWindowForDisplayId(b_display_id);
 
-  AshWindowTreeHost* a_ash_host = GetRootWindowController(a_window)->ash_host();
-  AshWindowTreeHost* b_ash_host = GetRootWindowController(b_window)->ash_host();
+  AshWindowTreeHost* a_ash_host =
+      RootWindowController::ForWindow(a_window)->ash_host();
+  AshWindowTreeHost* b_ash_host =
+      RootWindowController::ForWindow(b_window)->ash_host();
 
   a_edge_bounds_in_native_ =
       GetNativeEdgeBounds(a_ash_host, a_indicator_bounds);
@@ -189,7 +191,7 @@
     aura::Window* dst_window = GetRootWindowForDisplayId(
         in_a_edge ? warp->b_display_id_ : warp->a_display_id_);
     AshWindowTreeHost* target_ash_host =
-        GetRootWindowController(dst_window)->ash_host();
+        RootWindowController::ForWindow(dst_window)->ash_host();
 
     MoveCursorTo(target_ash_host, point_in_screen, update_mouse_location_now);
     return true;
diff --git a/ash/display/window_tree_host_manager.cc b/ash/display/window_tree_host_manager.cc
index 85f3b12..e5d787ef 100644
--- a/ash/display/window_tree_host_manager.cc
+++ b/ash/display/window_tree_host_manager.cc
@@ -273,7 +273,7 @@
   RootWindowController* primary_rwc = nullptr;
   for (aura::Window::Windows::iterator iter = root_windows.begin();
        iter != root_windows.end(); ++iter) {
-    RootWindowController* rwc = GetRootWindowController(*iter);
+    RootWindowController* rwc = RootWindowController::ForWindow(*iter);
     if (GetRootWindowSettings(*iter)->display_id == primary_id)
       primary_rwc = rwc;
     else
@@ -350,7 +350,7 @@
   for (WindowTreeHostMap::const_iterator it = window_tree_hosts_.begin();
        it != window_tree_hosts_.end(); ++it) {
     DCHECK(it->second);
-    if (GetRootWindowController(GetWindow(it->second)))
+    if (RootWindowController::ForWindow(GetWindow(it->second)))
       windows.push_back(GetWindow(it->second));
   }
   return windows;
@@ -372,7 +372,7 @@
   for (WindowTreeHostMap::const_iterator it = window_tree_hosts_.begin();
        it != window_tree_hosts_.end(); ++it) {
     RootWindowController* controller =
-        GetRootWindowController(GetWindow(it->second));
+        RootWindowController::ForWindow(GetWindow(it->second));
     if (controller)
       controllers.push_back(controller);
   }
@@ -583,7 +583,7 @@
     // Show the shelf if the original WTH had a visible system
     // tray. It may or may not be visible depending on OOBE state.
     ash::SystemTray* old_tray =
-        GetRootWindowController(to_delete->AsWindowTreeHost()->window())
+        RootWindowController::ForWindow(to_delete->AsWindowTreeHost()->window())
             ->GetSystemTray();
     ash::SystemTray* new_tray = ash::Shell::Get()->GetPrimarySystemTray();
     if (old_tray->GetWidget()->IsVisible()) {
@@ -630,7 +630,7 @@
 void WindowTreeHostManager::DeleteHost(AshWindowTreeHost* host_to_delete) {
   ClearDisplayPropertiesOnHost(host_to_delete);
   RootWindowController* controller =
-      GetRootWindowController(GetWindow(host_to_delete));
+      RootWindowController::ForWindow(GetWindow(host_to_delete));
   DCHECK(controller);
   controller->MoveWindowsTo(GetPrimaryRootWindow());
   // Delete most of root window related objects, but don't delete
diff --git a/ash/extended_desktop_unittest.cc b/ash/extended_desktop_unittest.cc
index 324584e..f8d42b4 100644
--- a/ash/extended_desktop_unittest.cc
+++ b/ash/extended_desktop_unittest.cc
@@ -164,18 +164,15 @@
   }
 };
 
-// Test conditions that root windows in extended desktop mode
-// must satisfy.
+// Test conditions that root windows in extended desktop mode must satisfy.
 TEST_F(ExtendedDesktopTest, Basic) {
   UpdateDisplay("1000x600,600x400");
   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
 
-  // All root windows must have the root window controller.
+  // All root windows must have a root window controller.
   ASSERT_EQ(2U, root_windows.size());
-  for (aura::Window::Windows::const_iterator iter = root_windows.begin();
-       iter != root_windows.end(); ++iter) {
-    EXPECT_TRUE(GetRootWindowController(*iter) != nullptr);
-  }
+  EXPECT_TRUE(RootWindowController::ForWindow(root_windows[0]));
+  EXPECT_TRUE(RootWindowController::ForWindow(root_windows[1]));
   // Make sure root windows share the same controllers.
   EXPECT_EQ(aura::client::GetFocusClient(root_windows[0]),
             aura::client::GetFocusClient(root_windows[1]));
diff --git a/ash/magnifier/magnification_controller.cc b/ash/magnifier/magnification_controller.cc
index 1bcceb3..5e94a9d 100644
--- a/ash/magnifier/magnification_controller.cc
+++ b/ash/magnifier/magnification_controller.cc
@@ -379,7 +379,7 @@
       display::Screen::GetScreen()->GetDisplayNearestWindow(root_window_);
   std::unique_ptr<RootWindowTransformer> transformer(
       CreateRootWindowTransformerForDisplay(root_window_, display));
-  GetRootWindowController(root_window_)
+  RootWindowController::ForWindow(root_window_)
       ->ash_host()
       ->SetRootWindowTransformer(std::move(transformer));
 
diff --git a/ash/mus/top_level_window_factory.cc b/ash/mus/top_level_window_factory.cc
index 639eb60..8e63f527 100644
--- a/ash/mus/top_level_window_factory.cc
+++ b/ash/mus/top_level_window_factory.cc
@@ -72,7 +72,7 @@
       }
     }
   }
-  return GetRootWindowController(Shell::GetRootWindowForNewWindows());
+  return RootWindowController::ForWindow(Shell::GetRootWindowForNewWindows());
 }
 
 // Returns the bounds for the new window.
@@ -226,6 +226,16 @@
     // No need to persist this value.
     properties->erase(focusable_iter);
   }
+
+  auto translucent_iter =
+      properties->find(ui::mojom::WindowManager::kTranslucent_InitProperty);
+  if (translucent_iter != properties->end()) {
+    bool translucent = mojo::ConvertTo<bool>(translucent_iter->second);
+    window->SetTransparent(translucent);
+    // No need to persist this value.
+    properties->erase(translucent_iter);
+  }
+
   return window;
 }
 
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index 78e7144..b8947df 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -13,6 +13,8 @@
     "config.h",
     "mus_property_mirror_ash.cc",
     "mus_property_mirror_ash.h",
+    "remote_shelf_item_delegate.cc",
+    "remote_shelf_item_delegate.h",
     "session_types.h",
     "shelf_item.cc",
     "shelf_item.h",
diff --git a/ash/public/cpp/remote_shelf_item_delegate.cc b/ash/public/cpp/remote_shelf_item_delegate.cc
new file mode 100644
index 0000000..9b6ff1d
--- /dev/null
+++ b/ash/public/cpp/remote_shelf_item_delegate.cc
@@ -0,0 +1,33 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/public/cpp/remote_shelf_item_delegate.h"
+
+namespace ash {
+
+RemoteShelfItemDelegate::RemoteShelfItemDelegate(
+    const ShelfID& shelf_id,
+    mojom::ShelfItemDelegatePtr delegate)
+    : ShelfItemDelegate(shelf_id), delegate_(std::move(delegate)) {}
+
+RemoteShelfItemDelegate::~RemoteShelfItemDelegate() {}
+
+void RemoteShelfItemDelegate::ItemSelected(std::unique_ptr<ui::Event> event,
+                                           int64_t display_id,
+                                           ShelfLaunchSource source,
+                                           ItemSelectedCallback callback) {
+  delegate_->ItemSelected(std::move(event), display_id, source,
+                          std::move(callback));
+}
+
+void RemoteShelfItemDelegate::ExecuteCommand(uint32_t command_id,
+                                             int32_t event_flags) {
+  delegate_->ExecuteCommand(command_id, event_flags);
+}
+
+void RemoteShelfItemDelegate::Close() {
+  delegate_->Close();
+}
+
+}  // namespace ash
diff --git a/ash/public/cpp/remote_shelf_item_delegate.h b/ash/public/cpp/remote_shelf_item_delegate.h
new file mode 100644
index 0000000..f9a9b8f
--- /dev/null
+++ b/ash/public/cpp/remote_shelf_item_delegate.h
@@ -0,0 +1,37 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_PUBLIC_CPP_REMOTE_SHELF_ITEM_DELEGATE_H_
+#define ASH_PUBLIC_CPP_REMOTE_SHELF_ITEM_DELEGATE_H_
+
+#include "ash/public/cpp/shelf_item_delegate.h"
+
+namespace ash {
+
+// A ShelfItemDelegate that forwards calls to a remote ShelfItemDelegatePtr.
+// Used by Ash and Chrome ShelfModels for delegation across service boundaries.
+class ASH_PUBLIC_EXPORT RemoteShelfItemDelegate : public ShelfItemDelegate {
+ public:
+  RemoteShelfItemDelegate(const ShelfID& shelf_id,
+                          mojom::ShelfItemDelegatePtr delegate);
+  ~RemoteShelfItemDelegate() override;
+
+  // mojom::ShelfItemDelegate
+  void ItemSelected(std::unique_ptr<ui::Event> event,
+                    int64_t display_id,
+                    ShelfLaunchSource source,
+                    ItemSelectedCallback callback) override;
+  void ExecuteCommand(uint32_t command_id, int32_t event_flags) override;
+  void Close() override;
+
+ private:
+  // The pointer to the remote delegate.
+  mojom::ShelfItemDelegatePtr delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(RemoteShelfItemDelegate);
+};
+
+}  // namespace ash
+
+#endif  // ASH_PUBLIC_CPP_REMOTE_SHELF_ITEM_DELEGATE_H_
diff --git a/ash/public/cpp/shelf_item_delegate.cc b/ash/public/cpp/shelf_item_delegate.cc
index c1fdab9..471d5f3 100644
--- a/ash/public/cpp/shelf_item_delegate.cc
+++ b/ash/public/cpp/shelf_item_delegate.cc
@@ -7,10 +7,14 @@
 namespace ash {
 
 ShelfItemDelegate::ShelfItemDelegate(const ash::ShelfID& shelf_id)
-    : shelf_id_(shelf_id), image_set_by_controller_(false) {}
+    : shelf_id_(shelf_id), binding_(this), image_set_by_controller_(false) {}
 
 ShelfItemDelegate::~ShelfItemDelegate() {}
 
+mojom::ShelfItemDelegatePtr ShelfItemDelegate::CreateInterfacePtrAndBind() {
+  return binding_.CreateInterfacePtrAndBind();
+}
+
 MenuItemList ShelfItemDelegate::GetAppMenuItems(int event_flags) {
   return MenuItemList();
 }
diff --git a/ash/public/cpp/shelf_item_delegate.h b/ash/public/cpp/shelf_item_delegate.h
index 7b4dce2..10562b1 100644
--- a/ash/public/cpp/shelf_item_delegate.h
+++ b/ash/public/cpp/shelf_item_delegate.h
@@ -12,6 +12,7 @@
 #include "ash/public/interfaces/shelf.mojom.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "mojo/public/cpp/bindings/binding.h"
 #include "ui/events/event.h"
 
 class AppWindowLauncherItemController;
@@ -37,6 +38,9 @@
     image_set_by_controller_ = image_set_by_controller;
   }
 
+  // Returns a pointer to this instance, to be used by remote shelf models, etc.
+  mojom::ShelfItemDelegatePtr CreateInterfacePtrAndBind();
+
   // Returns items for the application menu; used for convenience and testing.
   virtual MenuItemList GetAppMenuItems(int event_flags);
 
@@ -51,6 +55,9 @@
   // identify each shelf item that has the same app_id.
   ShelfID shelf_id_;
 
+  // A binding used by remote shelf item delegate users.
+  mojo::Binding<mojom::ShelfItemDelegate> binding_;
+
   // Set to true if the launcher item image has been set by the controller.
   bool image_set_by_controller_;
 
diff --git a/ash/public/cpp/shelf_types.cc b/ash/public/cpp/shelf_types.cc
index 0448723..b5d1bf9 100644
--- a/ash/public/cpp/shelf_types.cc
+++ b/ash/public/cpp/shelf_types.cc
@@ -68,4 +68,8 @@
   return ShelfID(components[0], components[1]);
 }
 
+std::ostream& operator<<(std::ostream& o, const ShelfID& id) {
+  return o << "app_id:" << id.app_id << ", launch_id:" << id.launch_id;
+}
+
 }  // namespace ash
diff --git a/ash/public/cpp/shelf_types.h b/ash/public/cpp/shelf_types.h
index 1ccd509..3a181207 100644
--- a/ash/public/cpp/shelf_types.h
+++ b/ash/public/cpp/shelf_types.h
@@ -165,6 +165,8 @@
   std::string launch_id;
 };
 
+ASH_PUBLIC_EXPORT std::ostream& operator<<(std::ostream& o, const ShelfID& id);
+
 }  // namespace ash
 
 #endif  // ASH_PUBLIC_CPP_SHELF_TYPES_H_
diff --git a/ash/public/interfaces/shelf.mojom b/ash/public/interfaces/shelf.mojom
index faaeddf..7382716 100644
--- a/ash/public/interfaces/shelf.mojom
+++ b/ash/public/interfaces/shelf.mojom
@@ -61,23 +61,49 @@
   // Observers are immediately notified of the current shelf states when added.
   AddObserver(associated ShelfObserver observer);
 
+  // Note: ShelfObservers are not notified of ShelfModel changes made by the
+  // ShelfItem functions below. Chrome is the solitary ShelfObserver and client
+  // of these functions, so notifications would be cyclical and problematic.
+
+  // Add |item| at |index|, which is clamped to be greater than 0 (AppList's
+  // index) and not exceeding the item count. Use a negative |index| to append.
+  AddShelfItem(int32 index, ShelfItem item);
+  // Remove the item with |id|. Bails if |id| is unknown or for the AppList.
+  RemoveShelfItem(ShelfID id);
+  // Moves item with |id| to |index|, which is in terms of the model after the
+  // item is removed, and is clamped to be greater than 0 (AppList's index) and
+  // not exceeding the item count. Bails if |id| is unknown or for the AppList.
+  MoveShelfItem(ShelfID id, int32 target_index);
+  // Updates |item| via ShelfID. Bails if the id is unknown or for the AppList.
+  UpdateShelfItem(ShelfItem item);
+  // Sets the |delegate| for the item with |id|.
+  SetShelfItemDelegate(ShelfID id, ShelfItemDelegate delegate);
+
   // Set the shelf alignment and auto-hide behavior. See Shelf for details.
+  // TODO(jamescook): Eliminate all these methods and use the ash pref service
+  // to observe and to set prefs. http://crbug.com/723085
   SetAlignment(ShelfAlignment alignment, int64 display_id);
   SetAutoHideBehavior(ShelfAutoHideBehavior auto_hide, int64 display_id);
-
-  // Pin and unpin items on the shelf, or update shelf item images.
-  PinItem(ShelfItem item, associated ShelfItemDelegate delegate);
-  UnpinItem(string app_id);
-  SetItemImage(string app_id, skia.mojom.Bitmap image);
 };
 
-// ShelfObserver is notified on shelf changes; used to persist profile settings.
+// A Shelf observer, used to persist profile settings and cache a ShelfModel.
 interface ShelfObserver {
   // TODO(jamescook): Eliminate all these methods and use the ash pref service
   // to observe and to set prefs. http://crbug.com/723085
   OnShelfInitialized(int64 display_id);
   OnAlignmentChanged(ShelfAlignment alignment, int64 display_id);
   OnAutoHideBehaviorChanged(ShelfAutoHideBehavior auto_hide, int64 display_id);
+
+  // Called when the |item| has been added at |index|.
+  OnShelfItemAdded(int32 index, ShelfItem item);
+  // Called when the item with |id| has been removed.
+  OnShelfItemRemoved(ShelfID id);
+  // Called when the item with |id| has been moved to |index|.
+  OnShelfItemMoved(ShelfID id, int32 index);
+  // Called when the |item| with matching ShelfID has been updated.
+  OnShelfItemUpdated(ShelfItem item);
+  // Called when |delegate| for the item with |id| has been changed.
+  OnShelfItemDelegateChanged(ShelfID id, ShelfItemDelegate delegate);
 };
 
 // ShelfItemDelegate handles shelf item selection, menu command execution, etc.
@@ -129,12 +155,12 @@
 // ShelfItems are used to populate the shelf.
 // This structure matches ash::ShelfItem.
 struct ShelfItem {
-  ShelfItemType type;       // The type of the shelf item.
-  skia.mojom.Bitmap image;  // An icon image Bitmap, shown on the shelf.
-  ShelfItemStatus status;   // The running/closed/etc. status of the item.
-  ShelfID shelf_id;         // The id for the shelf item and its windows.
+  ShelfItemType type;        // The type of the shelf item.
+  skia.mojom.Bitmap? image;  // An icon image Bitmap, shown on the shelf.
+  ShelfItemStatus status;    // The running/closed/etc. status of the item.
+  ShelfID shelf_id;          // The id for the shelf item and its windows.
   mojo.common.mojom.String16 title;  // The title to display for tooltips, etc.
-  bool shows_tooltip;       // Whether the tooltip should be shown on hover.
-  bool pinned_by_policy;    // Whether the item is pinned by policy preferences,
-                            // the user cannot un-pin these items.
+  bool shows_tooltip;        // Whether the tooltip should be shown on hover.
+  bool pinned_by_policy;     // Whether the item is pinned by policy prefs, the
+                             // user cannot un-pin these items.
 };
diff --git a/ash/public/interfaces/shelf.typemap b/ash/public/interfaces/shelf.typemap
index 1e8afb4..e3bd00f 100644
--- a/ash/public/interfaces/shelf.typemap
+++ b/ash/public/interfaces/shelf.typemap
@@ -19,6 +19,7 @@
   "ash.mojom.ShelfAction=ash::ShelfAction",
   "ash.mojom.ShelfAlignment=ash::ShelfAlignment",
   "ash.mojom.ShelfAutoHideBehavior=ash::ShelfAutoHideBehavior",
+  "ash.mojom.ShelfID=ash::ShelfID",
   "ash.mojom.ShelfItem=ash::ShelfItem",
   "ash.mojom.ShelfItemStatus=ash::ShelfItemStatus",
   "ash.mojom.ShelfItemType=ash::ShelfItemType",
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index ec3e336..7910744 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -311,13 +311,13 @@
     const aura::Window* window) {
   DCHECK(window);
   CHECK(Shell::HasInstance());
-  return GetRootWindowController(window->GetRootWindow());
+  return GetRootWindowSettings(window->GetRootWindow())->controller;
 }
 
 // static
 RootWindowController* RootWindowController::ForTargetRootWindow() {
   CHECK(Shell::HasInstance());
-  return GetRootWindowController(Shell::GetRootWindowForNewWindows());
+  return ForWindow(Shell::GetRootWindowForNewWindows());
 }
 
 void RootWindowController::ConfigureWidgetInitParamsForContainer(
@@ -1073,8 +1073,4 @@
     DisableTouchHudProjection();
 }
 
-RootWindowController* GetRootWindowController(const aura::Window* root_window) {
-  return root_window ? GetRootWindowSettings(root_window)->controller : nullptr;
-}
-
 }  // namespace ash
diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h
index f97dce28..497c942 100644
--- a/ash/root_window_controller.h
+++ b/ash/root_window_controller.h
@@ -79,7 +79,7 @@
 // indirectly owned and deleted by |WindowTreeHostManager|.
 // The RootWindowController for particular root window is stored in
 // its property (RootWindowSettings) and can be obtained using
-// |GetRootWindowController(aura::WindowEventDispatcher*)| function.
+// |RootWindowController::ForWindow(aura::Window*)| function.
 class ASH_EXPORT RootWindowController : public ShellObserver {
  public:
   // Enumerates the type of display. If there is only a single display then
@@ -359,12 +359,6 @@
   DISALLOW_COPY_AND_ASSIGN(RootWindowController);
 };
 
-// On classic ash, returns the RootWindowController for the given |root_window|.
-// On mus ash, returns the RootWindowController for the primary display.
-// See RootWindowController class comment above.
-ASH_EXPORT RootWindowController* GetRootWindowController(
-    const aura::Window* root_window);
-
 }  // namespace ash
 
 #endif  // ASH_ROOT_WINDOW_CONTROLLER_H_
diff --git a/ash/root_window_controller_unittest.cc b/ash/root_window_controller_unittest.cc
index 385d8cd..7e1fd70 100644
--- a/ash/root_window_controller_unittest.cc
+++ b/ash/root_window_controller_unittest.cc
@@ -560,32 +560,32 @@
   EXPECT_EQ(NULL, controllers[1]->GetWindowForFullscreenMode());
 }
 
-// Test that GetRootWindowController() works with multiple displays and
-// child widgets.
-TEST_F(RootWindowControllerTest, GetRootWindowController) {
+// Test that ForWindow() works with multiple displays and child widgets.
+TEST_F(RootWindowControllerTest, ForWindow) {
   UpdateDisplay("600x600,600x600");
   Shell::RootWindowControllerList controllers =
       Shell::Get()->GetAllRootWindowControllers();
   ASSERT_EQ(2u, controllers.size());
 
-  // Test null.
-  EXPECT_FALSE(GetRootWindowController(nullptr));
+  // Test a root window.
+  EXPECT_EQ(controllers[0],
+            RootWindowController::ForWindow(Shell::GetPrimaryRootWindow()));
 
   // Test a widget on the first display.
   Widget* w1 = CreateTestWidget(gfx::Rect(0, 0, 100, 100));
   EXPECT_EQ(controllers[0],
-            GetRootWindowController(w1->GetNativeWindow()->GetRootWindow()));
+            RootWindowController::ForWindow(w1->GetNativeWindow()));
 
   // Test a child widget.
   Widget* w2 = Widget::CreateWindowWithParentAndBounds(
       nullptr, w1->GetNativeWindow(), gfx::Rect(0, 0, 100, 100));
   EXPECT_EQ(controllers[0],
-            GetRootWindowController(w2->GetNativeWindow()->GetRootWindow()));
+            RootWindowController::ForWindow(w2->GetNativeWindow()));
 
   // Test a widget on the second display.
   Widget* w3 = CreateTestWidget(gfx::Rect(600, 0, 100, 100));
   EXPECT_EQ(controllers[1],
-            GetRootWindowController(w3->GetNativeWindow()->GetRootWindow()));
+            RootWindowController::ForWindow(w3->GetNativeWindow()));
 }
 
 // Test that user session window can't be focused if user session blocked by
@@ -657,15 +657,15 @@
   window1->set_owned_by_parent(false);
   observer1.SetWindow(window1);
   window1->Init(ui::LAYER_NOT_DRAWN);
-  aura::client::ParentWindowWithContext(
-      window1, Shell::Get()->GetPrimaryRootWindow(), gfx::Rect());
+  aura::client::ParentWindowWithContext(window1, Shell::GetPrimaryRootWindow(),
+                                        gfx::Rect());
 
   DestroyedWindowObserver observer2;
   aura::Window* window2 = new aura::Window(NULL);
   window2->set_owned_by_parent(false);
   observer2.SetWindow(window2);
   window2->Init(ui::LAYER_NOT_DRAWN);
-  Shell::Get()->GetPrimaryRootWindow()->AddChild(window2);
+  Shell::GetPrimaryRootWindow()->AddChild(window2);
 
   Shell::GetPrimaryRootWindowController()->CloseChildWindows();
 
diff --git a/ash/screen_util.cc b/ash/screen_util.cc
index b6cbf603..072ca79a 100644
--- a/ash/screen_util.cc
+++ b/ash/screen_util.cc
@@ -4,7 +4,6 @@
 
 #include "ash/screen_util.h"
 
-#include "ash/root_window_controller.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
 #include "ash/shell_port.h"
@@ -21,8 +20,7 @@
 
 // static
 gfx::Rect ScreenUtil::GetMaximizedWindowBoundsInParent(aura::Window* window) {
-  aura::Window* root_window = window->GetRootWindow();
-  if (GetRootWindowController(root_window)->shelf()->shelf_widget())
+  if (Shelf::ForWindow(window)->shelf_widget())
     return GetDisplayWorkAreaBoundsInParent(window);
   return GetDisplayBoundsInParent(window);
 }
diff --git a/ash/shelf/app_list_shelf_item_delegate.cc b/ash/shelf/app_list_shelf_item_delegate.cc
index 76361cd9..3783580 100644
--- a/ash/shelf/app_list_shelf_item_delegate.cc
+++ b/ash/shelf/app_list_shelf_item_delegate.cc
@@ -8,36 +8,9 @@
 
 #include "ash/shelf/shelf_model.h"
 #include "ash/shell.h"
-#include "ash/strings/grit/ash_strings.h"
-#include "base/memory/ptr_util.h"
-#include "ui/app_list/app_list_switches.h"
-#include "ui/base/l10n/l10n_util.h"
 
 namespace ash {
 
-namespace {
-
-// An app id for the app list, used to identify the shelf item.
-// Generated as crx_file::id_util::GenerateId("org.chromium.applist")
-static constexpr char kAppListId[] = "jlfapfmkapbjlfbpjedlinehodkccjee";
-
-}  // namespace
-
-// static
-void AppListShelfItemDelegate::CreateAppListItemAndDelegate(ShelfModel* model) {
-  // Add the app list item to the shelf model.
-  ShelfItem item;
-  item.type = TYPE_APP_LIST;
-  item.id = ShelfID(kAppListId);
-  item.title = l10n_util::GetStringUTF16(IDS_ASH_SHELF_APP_LIST_LAUNCHER_TITLE);
-  int index = model->Add(item);
-  DCHECK_GE(index, 0);
-
-  // Create an AppListShelfItemDelegate for that item.
-  model->SetShelfItemDelegate(item.id,
-                              base::MakeUnique<AppListShelfItemDelegate>());
-}
-
 AppListShelfItemDelegate::AppListShelfItemDelegate()
     : ShelfItemDelegate(ShelfID(kAppListId)) {}
 
diff --git a/ash/shelf/app_list_shelf_item_delegate.h b/ash/shelf/app_list_shelf_item_delegate.h
index e0ca704..bb985cf 100644
--- a/ash/shelf/app_list_shelf_item_delegate.h
+++ b/ash/shelf/app_list_shelf_item_delegate.h
@@ -9,15 +9,10 @@
 #include "base/macros.h"
 
 namespace ash {
-class ShelfModel;
 
 // ShelfItemDelegate for TYPE_APP_LIST.
 class AppListShelfItemDelegate : public ShelfItemDelegate {
  public:
-  // Initializes the app list item in the shelf data model and creates an
-  // AppListShelfItemDelegate which will be owned by |model|.
-  static void CreateAppListItemAndDelegate(ShelfModel* model);
-
   AppListShelfItemDelegate();
   ~AppListShelfItemDelegate() override;
 
diff --git a/ash/shelf/shelf.cc b/ash/shelf/shelf.cc
index dce85c9..ec1b0bf 100644
--- a/ash/shelf/shelf.cc
+++ b/ash/shelf/shelf.cc
@@ -73,7 +73,7 @@
 
 // static
 Shelf* Shelf::ForWindow(aura::Window* window) {
-  return GetRootWindowController(window->GetRootWindow())->shelf();
+  return RootWindowController::ForWindow(window)->shelf();
 }
 
 // static
diff --git a/ash/shelf/shelf_controller.cc b/ash/shelf/shelf_controller.cc
index fda0675..4b51989 100644
--- a/ash/shelf/shelf_controller.cc
+++ b/ash/shelf/shelf_controller.cc
@@ -4,12 +4,14 @@
 
 #include "ash/shelf/shelf_controller.h"
 
-#include "ash/public/interfaces/shelf.mojom.h"
+#include "ash/public/cpp/config.h"
+#include "ash/public/cpp/remote_shelf_item_delegate.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
 #include "ash/shelf/app_list_shelf_item_delegate.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
+#include "base/auto_reset.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/display/display.h"
@@ -30,11 +32,15 @@
 }  // namespace
 
 ShelfController::ShelfController() {
-  // Create the app list item in the shelf.
-  AppListShelfItemDelegate::CreateAppListItemAndDelegate(&model_);
+  // Create an AppListShelfItemDelegate for the app list item.
+  model_.SetShelfItemDelegate(ShelfID(kAppListId),
+                              base::MakeUnique<AppListShelfItemDelegate>());
+  model_.AddObserver(this);
 }
 
-ShelfController::~ShelfController() {}
+ShelfController::~ShelfController() {
+  model_.RemoveObserver(this);
+}
 
 void ShelfController::BindRequest(mojom::ShelfControllerRequest request) {
   bindings_.AddBinding(this, std::move(request));
@@ -75,6 +81,22 @@
     mojom::ShelfObserverAssociatedPtrInfo observer) {
   mojom::ShelfObserverAssociatedPtr observer_ptr;
   observer_ptr.Bind(std::move(observer));
+
+  if (Shell::GetAshConfig() == Config::MASH) {
+    // Mash synchronizes two ShelfModel instances, owned by Ash and Chrome.
+    // Notify Chrome of existing ShelfModel items created by Ash.
+    for (int i = 0; i < model_.item_count(); ++i) {
+      const ShelfItem& item = model_.items()[i];
+      observer_ptr->OnShelfItemAdded(i, item);
+      ShelfItemDelegate* delegate = model_.GetShelfItemDelegate(item.id);
+      mojom::ShelfItemDelegatePtr delegate_ptr;
+      if (delegate)
+        delegate_ptr = delegate->CreateInterfacePtrAndBind();
+      observer_ptr->OnShelfItemDelegateChanged(item.id,
+                                               std::move(delegate_ptr));
+    }
+  }
+
   observers_.AddPtr(std::move(observer_ptr));
 }
 
@@ -98,19 +120,130 @@
     shelf->SetAutoHideBehavior(auto_hide);
 }
 
-void ShelfController::PinItem(
-    const ShelfItem& item,
-    mojom::ShelfItemDelegateAssociatedPtrInfo delegate) {
-  NOTIMPLEMENTED();
+void ShelfController::AddShelfItem(int32_t index, const ShelfItem& item) {
+  DCHECK_EQ(Shell::GetAshConfig(), Config::MASH) << "Unexpected model sync";
+  DCHECK(!applying_remote_shelf_model_changes_) << "Unexpected model change";
+  index = index < 0 ? model_.item_count() : index;
+  DCHECK_GT(index, 0) << "Items can not preceed the AppList";
+  DCHECK_LE(index, model_.item_count()) << "Index out of bounds";
+  index = std::min(std::max(index, 1), model_.item_count());
+  base::AutoReset<bool> reset(&applying_remote_shelf_model_changes_, true);
+  model_.AddAt(index, item);
 }
 
-void ShelfController::UnpinItem(const std::string& app_id) {
-  NOTIMPLEMENTED();
+void ShelfController::RemoveShelfItem(const ShelfID& id) {
+  DCHECK_EQ(Shell::GetAshConfig(), Config::MASH) << "Unexpected model sync";
+  DCHECK(!applying_remote_shelf_model_changes_) << "Unexpected model change";
+  const int index = model_.ItemIndexByID(id);
+  DCHECK_GE(index, 0) << "Item not found";
+  DCHECK_NE(index, 0) << "The AppList shelf item cannot be removed";
+  if (index <= 0)
+    return;
+  base::AutoReset<bool> reset(&applying_remote_shelf_model_changes_, true);
+  model_.RemoveItemAt(index);
 }
 
-void ShelfController::SetItemImage(const std::string& app_id,
-                                   const SkBitmap& image) {
-  NOTIMPLEMENTED();
+void ShelfController::MoveShelfItem(const ShelfID& id, int32_t index) {
+  DCHECK_EQ(Shell::GetAshConfig(), Config::MASH) << "Unexpected model sync";
+  DCHECK(!applying_remote_shelf_model_changes_) << "Unexpected model change";
+  const int current_index = model_.ItemIndexByID(id);
+  DCHECK_GE(current_index, 0) << "No item found with the given id";
+  DCHECK_NE(current_index, 0) << "The AppList shelf item cannot be moved";
+  if (current_index <= 0)
+    return;
+  DCHECK_GT(index, 0) << "Items can not preceed the AppList";
+  DCHECK_LT(index, model_.item_count()) << "Index out of bounds";
+  index = std::min(std::max(index, 1), model_.item_count() - 1);
+  DCHECK_NE(current_index, index) << "The item is already at the given index";
+  if (current_index == index)
+    return;
+  base::AutoReset<bool> reset(&applying_remote_shelf_model_changes_, true);
+  model_.Move(current_index, index);
+}
+
+void ShelfController::UpdateShelfItem(const ShelfItem& item) {
+  DCHECK_EQ(Shell::GetAshConfig(), Config::MASH) << "Unexpected model sync";
+  DCHECK(!applying_remote_shelf_model_changes_) << "Unexpected model change";
+  const int index = model_.ItemIndexByID(item.id);
+  DCHECK_GE(index, 0) << "No item found with the given id";
+  if (index < 0)
+    return;
+  base::AutoReset<bool> reset(&applying_remote_shelf_model_changes_, true);
+  model_.Set(index, item);
+}
+
+void ShelfController::SetShelfItemDelegate(
+    const ShelfID& id,
+    mojom::ShelfItemDelegatePtr delegate) {
+  DCHECK_EQ(Shell::GetAshConfig(), Config::MASH) << "Unexpected model sync";
+  DCHECK(!applying_remote_shelf_model_changes_) << "Unexpected model change";
+  base::AutoReset<bool> reset(&applying_remote_shelf_model_changes_, true);
+  if (delegate.is_bound())
+    model_.SetShelfItemDelegate(
+        id, base::MakeUnique<RemoteShelfItemDelegate>(id, std::move(delegate)));
+  else
+    model_.SetShelfItemDelegate(id, nullptr);
+}
+
+void ShelfController::ShelfItemAdded(int index) {
+  if (applying_remote_shelf_model_changes_ ||
+      Shell::GetAshConfig() != Config::MASH) {
+    return;
+  }
+
+  const ShelfItem& item = model_.items()[index];
+  observers_.ForAllPtrs([index, item](mojom::ShelfObserver* observer) {
+    observer->OnShelfItemAdded(index, item);
+  });
+}
+
+void ShelfController::ShelfItemRemoved(int index, const ShelfItem& old_item) {
+  if (applying_remote_shelf_model_changes_ ||
+      Shell::GetAshConfig() != Config::MASH) {
+    return;
+  }
+
+  observers_.ForAllPtrs([old_item](mojom::ShelfObserver* observer) {
+    observer->OnShelfItemRemoved(old_item.id);
+  });
+}
+
+void ShelfController::ShelfItemMoved(int start_index, int target_index) {
+  if (applying_remote_shelf_model_changes_ ||
+      Shell::GetAshConfig() != Config::MASH) {
+    return;
+  }
+
+  const ShelfItem& item = model_.items()[target_index];
+  observers_.ForAllPtrs([item, target_index](mojom::ShelfObserver* observer) {
+    observer->OnShelfItemMoved(item.id, target_index);
+  });
+}
+
+void ShelfController::ShelfItemChanged(int index, const ShelfItem& old_item) {
+  if (applying_remote_shelf_model_changes_ ||
+      Shell::GetAshConfig() != Config::MASH) {
+    return;
+  }
+
+  const ShelfItem& item = model_.items()[index];
+  observers_.ForAllPtrs([item](mojom::ShelfObserver* observer) {
+    observer->OnShelfItemUpdated(item);
+  });
+}
+
+void ShelfController::ShelfItemDelegateChanged(const ShelfID& id,
+                                               ShelfItemDelegate* delegate) {
+  if (applying_remote_shelf_model_changes_ ||
+      Shell::GetAshConfig() != Config::MASH) {
+    return;
+  }
+
+  observers_.ForAllPtrs([id, delegate](mojom::ShelfObserver* observer) {
+    observer->OnShelfItemDelegateChanged(
+        id, delegate ? delegate->CreateInterfacePtrAndBind()
+                     : mojom::ShelfItemDelegatePtr());
+  });
 }
 
 }  // namespace ash
diff --git a/ash/shelf/shelf_controller.h b/ash/shelf/shelf_controller.h
index c12ce33..5b73a388 100644
--- a/ash/shelf/shelf_controller.h
+++ b/ash/shelf/shelf_controller.h
@@ -5,13 +5,11 @@
 #ifndef ASH_SHELF_SHELF_CONTROLLER_H_
 #define ASH_SHELF_SHELF_CONTROLLER_H_
 
-#include <map>
-#include <string>
-
 #include "ash/public/cpp/shelf_item.h"
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/public/interfaces/shelf.mojom.h"
 #include "ash/shelf/shelf_model.h"
+#include "ash/shelf/shelf_model_observer.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/interface_ptr_set.h"
 
@@ -19,9 +17,10 @@
 
 class Shelf;
 
-// Ash's implementation of the mojom::ShelfController interface. Chrome connects
-// to this interface to observe and manage the per-display ash shelf instances.
-class ShelfController : public mojom::ShelfController {
+// Ash's ShelfController owns the ShelfModel and implements interface functions
+// that allow Chrome to modify and observe the Shelf and ShelfModel state.
+class ShelfController : public mojom::ShelfController,
+                        public ShelfModelObserver {
  public:
   ShelfController();
   ~ShelfController() override;
@@ -36,15 +35,25 @@
   void NotifyShelfAlignmentChanged(Shelf* shelf);
   void NotifyShelfAutoHideBehaviorChanged(Shelf* shelf);
 
-  // mojom::Shelf:
+  // mojom::ShelfController:
   void AddObserver(mojom::ShelfObserverAssociatedPtrInfo observer) override;
   void SetAlignment(ShelfAlignment alignment, int64_t display_id) override;
   void SetAutoHideBehavior(ShelfAutoHideBehavior auto_hide,
                            int64_t display_id) override;
-  void PinItem(const ShelfItem& item,
-               mojom::ShelfItemDelegateAssociatedPtrInfo delegate) override;
-  void UnpinItem(const std::string& app_id) override;
-  void SetItemImage(const std::string& app_id, const SkBitmap& image) override;
+  void AddShelfItem(int32_t index, const ShelfItem& item) override;
+  void RemoveShelfItem(const ShelfID& id) override;
+  void MoveShelfItem(const ShelfID& id, int32_t index) override;
+  void UpdateShelfItem(const ShelfItem& item) override;
+  void SetShelfItemDelegate(const ShelfID& id,
+                            mojom::ShelfItemDelegatePtr delegate) override;
+
+  // ShelfModelObserver:
+  void ShelfItemAdded(int index) override;
+  void ShelfItemRemoved(int index, const ShelfItem& old_item) override;
+  void ShelfItemMoved(int start_index, int target_index) override;
+  void ShelfItemChanged(int index, const ShelfItem& old_item) override;
+  void ShelfItemDelegateChanged(const ShelfID& id,
+                                ShelfItemDelegate* delegate) override;
 
  private:
   // The shelf model shared by all shelf instances.
@@ -53,7 +62,11 @@
   // Bindings for the ShelfController interface.
   mojo::BindingSet<mojom::ShelfController> bindings_;
 
-  // The set of shelf observers notified about shelf state and settings changes.
+  // True when applying changes from the remote ShelfModel owned by Chrome.
+  // Changes to the local ShelfModel should not be reported during this time.
+  bool applying_remote_shelf_model_changes_ = false;
+
+  // The set of shelf observers notified about state and model changes.
   mojo::AssociatedInterfacePtrSet<mojom::ShelfObserver> observers_;
 
   DISALLOW_COPY_AND_ASSIGN(ShelfController);
diff --git a/ash/shelf/shelf_controller_unittest.cc b/ash/shelf/shelf_controller_unittest.cc
new file mode 100644
index 0000000..4926ab05
--- /dev/null
+++ b/ash/shelf/shelf_controller_unittest.cc
@@ -0,0 +1,192 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/shelf/shelf_controller.h"
+
+#include <set>
+#include <string>
+
+#include "ash/public/cpp/config.h"
+#include "ash/public/interfaces/shelf.mojom.h"
+#include "ash/shelf/shelf.h"
+#include "ash/shelf/shelf_model.h"
+#include "ash/shelf/shelf_model_observer.h"
+#include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "ui/display/types/display_constants.h"
+
+namespace ash {
+namespace {
+
+// A test implementation of the ShelfObserver mojo interface.
+class TestShelfObserver : public mojom::ShelfObserver {
+ public:
+  TestShelfObserver() = default;
+  ~TestShelfObserver() override = default;
+
+  // mojom::ShelfObserver:
+  void OnShelfInitialized(int64_t display_id) override {
+    display_id_ = display_id;
+  }
+  void OnAlignmentChanged(ShelfAlignment alignment,
+                          int64_t display_id) override {
+    alignment_ = alignment;
+    display_id_ = display_id;
+  }
+  void OnAutoHideBehaviorChanged(ShelfAutoHideBehavior auto_hide,
+                                 int64_t display_id) override {
+    auto_hide_ = auto_hide;
+    display_id_ = display_id;
+  }
+  void OnShelfItemAdded(int32_t, const ShelfItem&) override { added_count_++; }
+  void OnShelfItemRemoved(const ShelfID&) override { removed_count_++; }
+  void OnShelfItemMoved(const ShelfID&, int32_t) override {}
+  void OnShelfItemUpdated(const ShelfItem&) override {}
+  void OnShelfItemDelegateChanged(const ShelfID&,
+                                  mojom::ShelfItemDelegatePtr) override {}
+
+  int64_t display_id() const { return display_id_; }
+  ShelfAlignment alignment() const { return alignment_; }
+  ShelfAutoHideBehavior auto_hide() const { return auto_hide_; }
+  size_t added_count() const { return added_count_; }
+  size_t removed_count() const { return removed_count_; }
+
+ private:
+  int64_t display_id_ = display::kInvalidDisplayId;
+  ShelfAlignment alignment_ = SHELF_ALIGNMENT_BOTTOM_LOCKED;
+  ShelfAutoHideBehavior auto_hide_ = SHELF_AUTO_HIDE_ALWAYS_HIDDEN;
+  size_t added_count_ = 0;
+  size_t removed_count_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(TestShelfObserver);
+};
+
+using ShelfControllerTest = test::AshTestBase;
+using NoSessionShelfControllerTest = test::NoSessionAshTestBase;
+
+TEST_F(ShelfControllerTest, IntializesAppListItemDelegate) {
+  ShelfModel* model = Shell::Get()->shelf_controller()->model();
+  EXPECT_EQ(1, model->item_count());
+  EXPECT_EQ(kAppListId, model->items()[0].id.app_id);
+  EXPECT_TRUE(model->GetShelfItemDelegate(ShelfID(kAppListId)));
+}
+
+TEST_F(NoSessionShelfControllerTest, AlignmentAndAutoHide) {
+  ShelfController* controller = Shell::Get()->shelf_controller();
+  TestShelfObserver observer;
+  mojom::ShelfObserverAssociatedPtr observer_ptr;
+  mojo::AssociatedBinding<mojom::ShelfObserver> binding(
+      &observer, mojo::MakeIsolatedRequest(&observer_ptr));
+  controller->AddObserver(observer_ptr.PassInterface());
+
+  // Simulated login should initialize the primary shelf and notify |observer|.
+  EXPECT_EQ(display::kInvalidDisplayId, observer.display_id());
+  EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM_LOCKED, observer.alignment());
+  EXPECT_EQ(SHELF_AUTO_HIDE_ALWAYS_HIDDEN, observer.auto_hide());
+  SetUserLoggedIn(true);
+  SetSessionStarted(true);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(GetPrimaryDisplay().id(), observer.display_id());
+  EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, observer.alignment());
+  EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_NEVER, observer.auto_hide());
+
+  // Changing shelf properties should notify |observer|.
+  GetPrimaryShelf()->SetAlignment(SHELF_ALIGNMENT_LEFT);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(SHELF_ALIGNMENT_LEFT, observer.alignment());
+  GetPrimaryShelf()->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, observer.auto_hide());
+}
+
+TEST_F(ShelfControllerTest, ShelfModelChangesInClassicAsh) {
+  if (Shell::GetAshConfig() == Config::MASH)
+    return;
+
+  ShelfController* controller = Shell::Get()->shelf_controller();
+  TestShelfObserver observer;
+  mojom::ShelfObserverAssociatedPtr observer_ptr;
+  mojo::AssociatedBinding<mojom::ShelfObserver> binding(
+      &observer, mojo::MakeIsolatedRequest(&observer_ptr));
+  controller->AddObserver(observer_ptr.PassInterface());
+
+  // The ShelfModel should be initialized with a single item for the AppList.
+  // In classic ash, the observer should not be notified of ShelfModel changes.
+  EXPECT_EQ(1, controller->model()->item_count());
+  EXPECT_EQ(0u, observer.added_count());
+  EXPECT_EQ(0u, observer.removed_count());
+
+  // Add a ShelfModel item; |observer| should not be notified in classic ash.
+  ShelfItem item;
+  item.type = TYPE_PINNED_APP;
+  item.id = ShelfID("foo");
+  int index = controller->model()->Add(item);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(2, controller->model()->item_count());
+  EXPECT_EQ(0u, observer.added_count());
+  EXPECT_EQ(0u, observer.removed_count());
+
+  // Remove a ShelfModel item; |observer| should not be notified in classic ash.
+  controller->model()->RemoveItemAt(index);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1, controller->model()->item_count());
+  EXPECT_EQ(0u, observer.added_count());
+  EXPECT_EQ(0u, observer.removed_count());
+}
+
+TEST_F(ShelfControllerTest, ShelfModelChangesInMash) {
+  if (Shell::GetAshConfig() != Config::MASH)
+    return;
+
+  ShelfController* controller = Shell::Get()->shelf_controller();
+  TestShelfObserver observer;
+  mojom::ShelfObserverAssociatedPtr observer_ptr;
+  mojo::AssociatedBinding<mojom::ShelfObserver> binding(
+      &observer, mojo::MakeIsolatedRequest(&observer_ptr));
+  controller->AddObserver(observer_ptr.PassInterface());
+  base::RunLoop().RunUntilIdle();
+
+  // The ShelfModel should be initialized with a single item for the AppList.
+  // In mash, the observer is immediately notified of existing shelf items.
+  EXPECT_EQ(1, controller->model()->item_count());
+  EXPECT_EQ(1u, observer.added_count());
+  EXPECT_EQ(0u, observer.removed_count());
+
+  // Add a ShelfModel item; |observer| should be notified in mash.
+  ShelfItem item;
+  item.type = TYPE_PINNED_APP;
+  item.id = ShelfID("foo");
+  int index = controller->model()->Add(item);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(2, controller->model()->item_count());
+  EXPECT_EQ(2u, observer.added_count());
+  EXPECT_EQ(0u, observer.removed_count());
+
+  // Remove a ShelfModel item; |observer| should be notified in mash.
+  controller->model()->RemoveItemAt(index);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1, controller->model()->item_count());
+  EXPECT_EQ(2u, observer.added_count());
+  EXPECT_EQ(1u, observer.removed_count());
+
+  // Simulate adding an item remotely; Ash should apply the change.
+  // |observer| is not notified; see mojom::ShelfController for rationale.
+  controller->AddShelfItem(index, item);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(2, controller->model()->item_count());
+  EXPECT_EQ(2u, observer.added_count());
+  EXPECT_EQ(1u, observer.removed_count());
+
+  // Simulate removing an item remotely; Ash should apply the change.
+  // |observer| is not notified; see mojom::ShelfController for rationale.
+  controller->RemoveShelfItem(item.id);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1, controller->model()->item_count());
+  EXPECT_EQ(2u, observer.added_count());
+  EXPECT_EQ(1u, observer.removed_count());
+}
+
+}  // namespace
+}  // namespace ash
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index 95868ea8..0bfea3d7 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -9,7 +9,6 @@
 #include "ash/focus_cycler.h"
 #include "ash/public/cpp/config.h"
 #include "ash/public/cpp/shell_window_ids.h"
-#include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_constants.h"
@@ -1076,8 +1075,8 @@
   EXPECT_EQ(root_windows.size(), 2U);
 
   // Get the shelves in both displays and set them to be 'AutoHide'.
-  Shelf* shelf_1 = GetRootWindowController(root_windows[0])->shelf();
-  Shelf* shelf_2 = GetRootWindowController(root_windows[1])->shelf();
+  Shelf* shelf_1 = Shelf::ForWindow(root_windows[0]);
+  Shelf* shelf_2 = Shelf::ForWindow(root_windows[1]);
   EXPECT_NE(shelf_1, shelf_2);
   EXPECT_NE(shelf_1->GetWindow()->GetRootWindow(),
             shelf_2->GetWindow()->GetRootWindow());
@@ -1199,8 +1198,8 @@
   EXPECT_EQ(2U, root_windows.size());
 
   // Get the shelves in both displays and set them to be 'AutoHide'.
-  Shelf* shelf_1 = GetRootWindowController(root_windows[0])->shelf();
-  Shelf* shelf_2 = GetRootWindowController(root_windows[1])->shelf();
+  Shelf* shelf_1 = Shelf::ForWindow(root_windows[0]);
+  Shelf* shelf_2 = Shelf::ForWindow(root_windows[1]);
   EXPECT_NE(shelf_1, shelf_2);
   EXPECT_NE(shelf_1->GetWindow()->GetRootWindow(),
             shelf_2->GetWindow()->GetRootWindow());
@@ -1266,8 +1265,6 @@
 TEST_F(ShelfLayoutManagerTest, FullscreenWindowOnSecondDisplay) {
   UpdateDisplay("800x600,800x600");
   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
-  Shell::RootWindowControllerList root_window_controllers =
-      Shell::GetAllRootWindowControllers();
 
   // Create windows on either display.
   aura::Window* window1 = CreateTestWindow();
@@ -1287,10 +1284,10 @@
   wm::GetWindowState(window2)->Activate();
   EXPECT_EQ(
       SHELF_HIDDEN,
-      root_window_controllers[0]->GetShelfLayoutManager()->visibility_state());
+      Shelf::ForWindow(window1)->shelf_layout_manager()->visibility_state());
   EXPECT_EQ(
       SHELF_VISIBLE,
-      root_window_controllers[1]->GetShelfLayoutManager()->visibility_state());
+      Shelf::ForWindow(window2)->shelf_layout_manager()->visibility_state());
 }
 
 // Test for Pinned mode.
diff --git a/ash/shelf/shelf_model.cc b/ash/shelf/shelf_model.cc
index e5ddd25..3aa6ade5 100644
--- a/ash/shelf/shelf_model.cc
+++ b/ash/shelf/shelf_model.cc
@@ -8,6 +8,8 @@
 
 #include "ash/public/cpp/shelf_item_delegate.h"
 #include "ash/shelf/shelf_model_observer.h"
+#include "ash/strings/grit/ash_strings.h"
+#include "ui/base/l10n/l10n_util.h"
 
 namespace ash {
 
@@ -43,7 +45,17 @@
 
 }  // namespace
 
-ShelfModel::ShelfModel() = default;
+const char kAppListId[] = "jlfapfmkapbjlfbpjedlinehodkccjee";
+
+ShelfModel::ShelfModel() {
+  // Add the app list item.
+  ShelfItem item;
+  item.type = TYPE_APP_LIST;
+  item.id = ShelfID(kAppListId);
+  item.title = l10n_util::GetStringUTF16(IDS_ASH_SHELF_APP_LIST_LAUNCHER_TITLE);
+  const int index = Add(item);
+  DCHECK_EQ(0, index);
+}
 
 ShelfModel::~ShelfModel() = default;
 
@@ -106,8 +118,8 @@
 
 int ShelfModel::AddAt(int index, const ShelfItem& item) {
   // Items should have unique non-empty ids to avoid undefined model behavior.
-  DCHECK(!item.id.IsNull());
-  DCHECK_EQ(ItemIndexByID(item.id), -1);
+  DCHECK(!item.id.IsNull()) << " The id is null.";
+  DCHECK_EQ(ItemIndexByID(item.id), -1) << " The id is not unique: " << item.id;
   index = ValidateInsertionIndex(item.type, index);
   items_.insert(items_.begin() + index, item);
   for (auto& observer : observers_)
@@ -210,6 +222,10 @@
     item_delegate->set_shelf_id(shelf_id);
   // This assignment replaces any ShelfItemDelegate already registered for |id|.
   id_to_item_delegate_map_[shelf_id] = std::move(item_delegate);
+  for (auto& observer : observers_) {
+    observer.ShelfItemDelegateChanged(shelf_id,
+                                      id_to_item_delegate_map_[shelf_id].get());
+  }
 }
 
 ShelfItemDelegate* ShelfModel::GetShelfItemDelegate(const ShelfID& shelf_id) {
diff --git a/ash/shelf/shelf_model.h b/ash/shelf/shelf_model.h
index 6e6b665..fca50d8 100644
--- a/ash/shelf/shelf_model.h
+++ b/ash/shelf/shelf_model.h
@@ -19,15 +19,19 @@
 class ShelfItemDelegate;
 class ShelfModelObserver;
 
+// An id for the AppList item, which is added in the ShelfModel constructor.
+// Generated as crx_file::id_util::GenerateId("org.chromium.applist")
+ASH_EXPORT extern const char kAppListId[];
+
 // Model used for shelf items. Owns ShelfItemDelegates but does not create them.
+// TODO(msw): Move this to ash/public/cpp and use ASH_PUBLIC_EXPORT.
 class ASH_EXPORT ShelfModel {
  public:
   ShelfModel();
   ~ShelfModel();
 
   // Pins an app with |app_id| to shelf. A running instance will get pinned.
-  // In case there is no running instance a new shelf item is created and
-  // pinned.
+  // If there is no running instance, a new shelf item is created and pinned.
   void PinAppWithID(const std::string& app_id);
 
   // Check if the app with |app_id_| is pinned to the shelf.
diff --git a/ash/shelf/shelf_model_observer.h b/ash/shelf/shelf_model_observer.h
index fafb45c..ca8f4054 100644
--- a/ash/shelf/shelf_model_observer.h
+++ b/ash/shelf/shelf_model_observer.h
@@ -11,7 +11,9 @@
 namespace ash {
 
 struct ShelfItem;
+class ShelfItemDelegate;
 
+// TODO(msw): Move this to ash/public/cpp and use ASH_PUBLIC_EXPORT.
 class ASH_EXPORT ShelfModelObserver {
  public:
   // Invoked after an item has been added to the model.
@@ -28,6 +30,10 @@
   // Invoked after an item changes. |old_item| is the item before the change.
   virtual void ShelfItemChanged(int index, const ShelfItem& old_item) = 0;
 
+  // Invoked after a delegate changes. |delegate| is the new value.
+  virtual void ShelfItemDelegateChanged(const ShelfID& id,
+                                        ShelfItemDelegate* delegate) = 0;
+
  protected:
   virtual ~ShelfModelObserver() {}
 };
diff --git a/ash/shelf/shelf_model_unittest.cc b/ash/shelf/shelf_model_unittest.cc
index 54024bc..e731c8c 100644
--- a/ash/shelf/shelf_model_unittest.cc
+++ b/ash/shelf/shelf_model_unittest.cc
@@ -15,8 +15,6 @@
 
 namespace {
 
-constexpr char kAppListId[] = "jlfapfmkapbjlfbpjedlinehodkccjee";
-
 // ShelfModelObserver implementation that tracks what message are invoked.
 class TestShelfModelObserver : public ShelfModelObserver {
  public:
@@ -39,6 +37,7 @@
   void ShelfItemRemoved(int, const ShelfItem&) override { removed_count_++; }
   void ShelfItemChanged(int, const ShelfItem&) override { changed_count_++; }
   void ShelfItemMoved(int, int) override { moved_count_++; }
+  void ShelfItemDelegateChanged(const ShelfID&, ShelfItemDelegate*) override {}
 
  private:
   void AddToResult(const std::string& format, int count, std::string* result) {
@@ -67,14 +66,6 @@
   void SetUp() override {
     model_.reset(new ShelfModel);
     observer_.reset(new TestShelfModelObserver);
-    EXPECT_EQ(0, model_->item_count());
-
-    ShelfItem item;
-    item.type = TYPE_APP_LIST;
-    item.id = ShelfID(kAppListId);
-    model_->Add(item);
-    EXPECT_EQ(1, model_->item_count());
-
     model_->AddObserver(observer_.get());
   }
 
@@ -90,6 +81,14 @@
   DISALLOW_COPY_AND_ASSIGN(ShelfModelTest);
 };
 
+TEST_F(ShelfModelTest, IntializesAppListItem) {
+  EXPECT_EQ(1, model_->item_count());
+  EXPECT_EQ(kAppListId, model_->items()[0].id.app_id);
+  // The ShelfModel does not initialize the AppList's ShelfItemDelegate.
+  // ShelfController does that to prevent Chrome from creating its own delegate.
+  EXPECT_FALSE(model_->GetShelfItemDelegate(ShelfID(kAppListId)));
+}
+
 TEST_F(ShelfModelTest, BasicAssertions) {
   // Add an item.
   ShelfItem item1;
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 62a52fa..75efc9b4 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -9,6 +9,7 @@
 
 #include "ash/ash_constants.h"
 #include "ash/drag_drop/drag_image_view.h"
+#include "ash/public/cpp/config.h"
 #include "ash/public/cpp/shelf_item_delegate.h"
 #include "ash/scoped_root_window_for_new_windows.h"
 #include "ash/screen_util.h"
@@ -463,10 +464,22 @@
 
   // Notify the item of its selection; handle the result in AfterItemSelected.
   const ShelfItem& item = model_->items()[last_pressed_index_];
+  // Mash requires conversion of mouse and touch events to pointer events.
+  std::unique_ptr<ui::Event> pointer_event;
+  if (Shell::GetAshConfig() == Config::MASH &&
+      ui::PointerEvent::CanConvertFrom(event)) {
+    if (event.IsMouseEvent())
+      pointer_event = base::MakeUnique<ui::PointerEvent>(*event.AsMouseEvent());
+    else if (event.IsTouchEvent())
+      pointer_event = base::MakeUnique<ui::PointerEvent>(*event.AsTouchEvent());
+    else
+      NOTREACHED() << "Need conversion of event to pointer event.";
+  }
+  const ui::Event* event_to_pass = pointer_event ? pointer_event.get() : &event;
   model_->GetShelfItemDelegate(item.id)->ItemSelected(
-      ui::Event::Clone(event), display_id, LAUNCH_FROM_UNKNOWN,
+      ui::Event::Clone(*event_to_pass), display_id, LAUNCH_FROM_UNKNOWN,
       base::Bind(&ShelfView::AfterItemSelected, weak_factory_.GetWeakPtr(),
-                 item, sender, base::Passed(ui::Event::Clone(event)),
+                 item, sender, base::Passed(ui::Event::Clone(*event_to_pass)),
                  ink_drop));
 }
 
@@ -1594,6 +1607,9 @@
     AnimateToIdealBounds();
 }
 
+void ShelfView::ShelfItemDelegateChanged(const ShelfID& id,
+                                         ShelfItemDelegate* delegate) {}
+
 void ShelfView::AfterItemSelected(
     const ShelfItem& item,
     views::Button* sender,
diff --git a/ash/shelf/shelf_view.h b/ash/shelf/shelf_view.h
index 50656ea..42e45ca 100644
--- a/ash/shelf/shelf_view.h
+++ b/ash/shelf/shelf_view.h
@@ -294,6 +294,8 @@
   void ShelfItemRemoved(int model_index, const ShelfItem& old_item) override;
   void ShelfItemChanged(int model_index, const ShelfItem& old_item) override;
   void ShelfItemMoved(int start_index, int target_index) override;
+  void ShelfItemDelegateChanged(const ShelfID& id,
+                                ShelfItemDelegate* delegate) override;
 
   // Handles the result of an item selection, records the |action| taken and
   // optionally shows an application menu with the given |menu_items|.
diff --git a/ash/shelf/shelf_widget_unittest.cc b/ash/shelf/shelf_widget_unittest.cc
index 0b81b03..98ff8ce 100644
--- a/ash/shelf/shelf_widget_unittest.cc
+++ b/ash/shelf/shelf_widget_unittest.cc
@@ -37,7 +37,7 @@
 void TestLauncherAlignment(aura::Window* root,
                            ShelfAlignment alignment,
                            const gfx::Rect& expected) {
-  GetRootWindowController(root)->shelf()->SetAlignment(alignment);
+  Shelf::ForWindow(root)->SetAlignment(alignment);
   EXPECT_EQ(expected.ToString(), display::Screen::GetScreen()
                                      ->GetDisplayNearestWindow(root)
                                      .work_area()
diff --git a/ash/shelf/shelf_window_watcher.cc b/ash/shelf/shelf_window_watcher.cc
index f5efa167..88e000a 100644
--- a/ash/shelf/shelf_window_watcher.cc
+++ b/ash/shelf/shelf_window_watcher.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include <utility>
 
-#include "ash/public/cpp/config.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/shelf/shelf_constants.h"
@@ -29,35 +28,19 @@
 namespace ash {
 namespace {
 
-// Returns the shelf item type, with special temporary behavior for Mash:
-// Mash provides a default shelf item type (TYPE_APP) for non-ignored windows.
+// Returns the window's shelf item type property value.
 ShelfItemType GetShelfItemType(aura::Window* window) {
-  // TODO(msw): Remove Mash default ShelfItemType assignment. crbug.com/722496
-  if (Shell::GetAshConfig() == Config::MASH &&
-      window->GetProperty(kShelfItemTypeKey) == TYPE_UNDEFINED &&
-      !wm::GetWindowState(window)->ignored_by_shelf()) {
-    return TYPE_APP;
-  }
   return static_cast<ShelfItemType>(window->GetProperty(kShelfItemTypeKey));
 }
 
-// Returns the shelf id, with special temporary behavior for Mash:
-// Mash provides a default shelf ids for non-ignored windows.
+// Returns the window's shelf id property value.
 ShelfID GetShelfID(aura::Window* window) {
-  // TODO(msw): Remove Mash default ShelfID assignment. crbug.com/722496
-  if (Shell::GetAshConfig() == Config::MASH &&
-      !window->GetProperty(kShelfIDKey) &&
-      !wm::GetWindowState(window)->ignored_by_shelf()) {
-    static int id = 0;
-    const ash::ShelfID shelf_id(base::IntToString(id++));
-    window->SetProperty(kShelfIDKey, new std::string(shelf_id.Serialize()));
-    return shelf_id;
-  }
   return ShelfID::Deserialize(window->GetProperty(kShelfIDKey));
 }
 
 // Update the ShelfItem from relevant window properties.
 void UpdateShelfItemForWindow(ShelfItem* item, aura::Window* window) {
+  DCHECK(item->id.IsNull() || item->id == GetShelfID(window));
   item->id = GetShelfID(window);
   item->type = GetShelfItemType(window);
 
@@ -120,19 +103,6 @@
     aura::Window* window,
     const void* key,
     intptr_t old) {
-  // ShelfIDs should never change except when replacing Mash temporary defaults.
-  // TODO(msw): Remove Mash default ShelfID handling. crbug.com/722496
-  if (Shell::GetAshConfig() == Config::MASH && key == kShelfIDKey) {
-    ShelfID old_id = ShelfID::Deserialize(reinterpret_cast<std::string*>(old));
-    ShelfID new_id = ShelfID::Deserialize(window->GetProperty(kShelfIDKey));
-    if (old_id != new_id && !old_id.IsNull() && !new_id.IsNull()) {
-      // Id changing is not supported; remove the item and it will be re-added.
-      window_watcher_->user_windows_with_items_.erase(window);
-      const int index = window_watcher_->model_->ItemIndexByID(old_id);
-      window_watcher_->model_->RemoveItemAt(index);
-    }
-  }
-
   if (key == aura::client::kAppIconKey || key == aura::client::kWindowIconKey ||
       key == aura::client::kDrawAttentionKey || key == kPanelAttachedKey ||
       key == kShelfItemTypeKey || key == kShelfIDKey) {
@@ -186,19 +156,10 @@
   ShelfItem item;
   UpdateShelfItemForWindow(&item, window);
 
-  // ShelfWindowWatcher[ItemDelegate] doesn't support multiple windows per item,
-  // but this can happen in Mash (eg. when multiple browser windows are open).
-  // Assign a unique launch id in this case to avoid crashing on DCHECKs.
-  // TODO(msw): Remove Mash duplicate ShelfID handling. crbug.com/722496
-  if (Shell::GetAshConfig() == Config::MASH &&
-      model_->ItemIndexByID(item.id) > 0) {
-    static int id = 0;
-    item.id.launch_id = base::IntToString(id++);
-  }
-
   model_->SetShelfItemDelegate(
       item.id,
       base::MakeUnique<ShelfWindowWatcherItemDelegate>(item.id, window));
+
   // Panels are inserted on the left so as not to push all existing panels over.
   model_->AddAt(item.type == TYPE_APP_PANEL ? 0 : model_->item_count(), item);
 }
diff --git a/ash/shelf/shelf_window_watcher_unittest.cc b/ash/shelf/shelf_window_watcher_unittest.cc
index 836a06e..ad97f4e0 100644
--- a/ash/shelf/shelf_window_watcher_unittest.cc
+++ b/ash/shelf/shelf_window_watcher_unittest.cc
@@ -17,11 +17,25 @@
 #include "ash/wm/window_resizer.h"
 #include "ash/wm/window_state.h"
 #include "base/strings/string_number_conversions.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 #include "ui/base/hit_test.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/resources/grit/ui_resources.h"
 #include "ui/views/widget/widget.h"
 
 namespace ash {
+namespace {
+
+// Create a test 1x1 icon image with a given |color|.
+gfx::ImageSkia CreateImageSkiaIcon(SkColor color) {
+  SkBitmap bitmap;
+  bitmap.allocN32Pixels(1, 1);
+  bitmap.eraseColor(color);
+  return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
+}
 
 class ShelfWindowWatcherTest : public test::AshTestBase {
  public:
@@ -301,6 +315,37 @@
   EXPECT_EQ(1, model_->item_count());
 }
 
+// Ensure items use the app icon and window icon aura::Window properties.
+TEST_F(ShelfWindowWatcherTest, ItemIcon) {
+  // ShelfModel only has an APP_LIST item.
+  EXPECT_EQ(1, model_->item_count());
+
+  // Create a ShelfItem for a window; it should have a default icon.
+  std::unique_ptr<views::Widget> widget =
+      CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect());
+  aura::Window* window = widget->GetNativeWindow();
+  ShelfID id = CreateShelfItem(window);
+  EXPECT_EQ(2, model_->item_count());
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+  gfx::Image default_image = rb.GetImageNamed(IDR_DEFAULT_FAVICON_32);
+  EXPECT_TRUE(model_->items()[1].image.BackedBySameObjectAs(
+      default_image.AsImageSkia()));
+
+  // Setting a window icon should update the item icon.
+  const gfx::ImageSkia red = CreateImageSkiaIcon(SK_ColorRED);
+  window->SetProperty(aura::client::kWindowIconKey, new gfx::ImageSkia(red));
+  EXPECT_EQ(SK_ColorRED, model_->items()[1].image.bitmap()->getColor(0, 0));
+
+  // Setting an app icon should override the window icon.
+  const gfx::ImageSkia blue = CreateImageSkiaIcon(SK_ColorBLUE);
+  window->SetProperty(aura::client::kAppIconKey, new gfx::ImageSkia(blue));
+  EXPECT_EQ(SK_ColorBLUE, model_->items()[1].image.bitmap()->getColor(0, 0));
+
+  // Clearing the app icon should restore the window icon to the shelf item.
+  window->ClearProperty(aura::client::kAppIconKey);
+  EXPECT_EQ(SK_ColorRED, model_->items()[1].image.bitmap()->getColor(0, 0));
+}
+
 TEST_F(ShelfWindowWatcherTest, DontCreateShelfEntriesForChildWindows) {
   const int initial_item_count = model_->item_count();
 
@@ -350,4 +395,5 @@
   EXPECT_EQ(2, model->item_count());
 }
 
+}  // namespace
 }  // namespace ash
diff --git a/ash/shell.cc b/ash/shell.cc
index 132265c..c5cd6e2b 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -250,18 +250,15 @@
 // static
 RootWindowController* Shell::GetPrimaryRootWindowController() {
   CHECK(HasInstance());
-  return GetRootWindowController(GetPrimaryRootWindow());
+  return RootWindowController::ForWindow(GetPrimaryRootWindow());
 }
 
 // static
 Shell::RootWindowControllerList Shell::GetAllRootWindowControllers() {
   CHECK(HasInstance());
   RootWindowControllerList root_window_controllers;
-  for (aura::Window* root_window :
-       instance_->shell_port_->GetAllRootWindows()) {
-    root_window_controllers.push_back(
-        RootWindowController::ForWindow(root_window));
-  }
+  for (aura::Window* root : GetAllRootWindows())
+    root_window_controllers.push_back(RootWindowController::ForWindow(root));
   return root_window_controllers;
 }
 
@@ -269,9 +266,9 @@
 RootWindowController* Shell::GetRootWindowControllerWithDisplayId(
     int64_t display_id) {
   CHECK(HasInstance());
-  aura::Window* root_window =
+  aura::Window* root =
       instance_->shell_port_->GetRootWindowForDisplayId(display_id);
-  return GetRootWindowController(root_window);
+  return root ? RootWindowController::ForWindow(root) : nullptr;
 }
 
 // static
@@ -385,8 +382,8 @@
 }
 
 void Shell::UpdateShelfVisibility() {
-  for (auto* root_window_controller : GetAllRootWindowControllers())
-    root_window_controller->shelf()->UpdateVisibilityState();
+  for (aura::Window* root : GetAllRootWindows())
+    Shelf::ForWindow(root)->UpdateVisibilityState();
 }
 
 PrefService* Shell::GetActiveUserPrefService() const {
@@ -660,8 +657,8 @@
 
   // Destroy SystemTrayDelegate before destroying the status area(s). Make sure
   // to deinitialize the shelf first, as it is initialized after the delegate.
-  for (auto* root_window_controller : GetAllRootWindowControllers())
-    root_window_controller->shelf()->ShutdownShelfWidget();
+  for (aura::Window* root : GetAllRootWindows())
+    Shelf::ForWindow(root)->ShutdownShelfWidget();
   tray_bluetooth_helper_.reset();
   DeleteSystemTrayDelegate();
 
@@ -718,8 +715,7 @@
 
   // This also deletes all RootWindows. Note that we invoke Shutdown() on
   // WindowTreeHostManager before resetting |window_tree_host_manager_|, since
-  // destruction
-  // of its owned RootWindowControllers relies on the value.
+  // destruction of its owned RootWindowControllers relies on the value.
   ScreenAsh::CreateScreenForShutdown();
   display_configuration_controller_.reset();
 
@@ -1164,13 +1160,13 @@
 }
 
 void Shell::CloseAllRootWindowChildWindows() {
-  for (aura::Window* root_window : shell_port_->GetAllRootWindows()) {
-    RootWindowController* controller = GetRootWindowController(root_window);
+  for (aura::Window* root : GetAllRootWindows()) {
+    RootWindowController* controller = RootWindowController::ForWindow(root);
     if (controller) {
       controller->CloseChildWindows();
     } else {
-      while (!root_window->children().empty()) {
-        aura::Window* child = root_window->children()[0];
+      while (!root->children().empty()) {
+        aura::Window* child = root->children()[0];
         delete child;
       }
     }
diff --git a/ash/system/toast/toast_overlay.cc b/ash/system/toast/toast_overlay.cc
index a653304..d825617 100644
--- a/ash/system/toast/toast_overlay.cc
+++ b/ash/system/toast/toast_overlay.cc
@@ -215,7 +215,7 @@
   params.remove_standard_frame = true;
   params.bounds = CalculateOverlayBounds();
   // Show toasts above the app list and below the lock screen.
-  GetRootWindowController(Shell::GetRootWindowForNewWindows())
+  RootWindowController::ForWindow(Shell::GetRootWindowForNewWindows())
       ->ConfigureWidgetInitParamsForContainer(
           overlay_widget_.get(), kShellWindowId_SystemModalContainer, &params);
   overlay_widget_->Init(params);
diff --git a/ash/touch/touch_hud_debug.cc b/ash/touch/touch_hud_debug.cc
index fa40050..dc63d0b8b 100644
--- a/ash/touch/touch_hud_debug.cc
+++ b/ash/touch/touch_hud_debug.cc
@@ -357,10 +357,8 @@
 std::unique_ptr<base::DictionaryValue> TouchHudDebug::GetAllAsDictionary() {
   std::unique_ptr<base::DictionaryValue> value(new base::DictionaryValue());
   aura::Window::Windows roots = Shell::Get()->GetAllRootWindows();
-  for (aura::Window::Windows::iterator iter = roots.begin();
-       iter != roots.end(); ++iter) {
-    RootWindowController* controller = GetRootWindowController(*iter);
-    TouchHudDebug* hud = controller->touch_hud_debug();
+  for (RootWindowController* root : Shell::GetAllRootWindowControllers()) {
+    TouchHudDebug* hud = root->touch_hud_debug();
     if (hud) {
       std::unique_ptr<base::ListValue> list = hud->GetLogAsList();
       if (!list->empty())
diff --git a/ash/touch/touch_observer_hud.cc b/ash/touch/touch_observer_hud.cc
index 2292576f0..e78481d 100644
--- a/ash/touch/touch_observer_hud.cc
+++ b/ash/touch/touch_observer_hud.cc
@@ -65,7 +65,8 @@
 void TouchObserverHUD::Remove() {
   root_window_->RemovePreTargetHandler(this);
 
-  RootWindowController* controller = GetRootWindowController(root_window_);
+  RootWindowController* controller =
+      RootWindowController::ForWindow(root_window_);
   UnsetHudForRootWindowController(controller);
 
   widget_->CloseNow();
@@ -111,7 +112,8 @@
 
   root_window_->RemovePreTargetHandler(this);
 
-  RootWindowController* controller = GetRootWindowController(root_window_);
+  RootWindowController* controller =
+      RootWindowController::ForWindow(root_window_);
   UnsetHudForRootWindowController(controller);
 
   views::Widget::ReparentNativeView(
@@ -134,7 +136,8 @@
       widget_->GetNativeView(),
       Shell::GetContainer(root_window_, kShellWindowId_OverlayContainer));
 
-  RootWindowController* controller = GetRootWindowController(root_window_);
+  RootWindowController* controller =
+      RootWindowController::ForWindow(root_window_);
   SetHudForRootWindowController(controller);
 
   root_window_->AddPreTargetHandler(this);
diff --git a/ash/touch/touch_observer_hud_unittest.cc b/ash/touch/touch_observer_hud_unittest.cc
index 7e7402f..6223bfe 100644
--- a/ash/touch/touch_observer_hud_unittest.cc
+++ b/ash/touch/touch_observer_hud_unittest.cc
@@ -151,22 +151,22 @@
 
   RootWindowController* GetInternalRootController() {
     aura::Window* root = GetInternalRootWindow();
-    return GetRootWindowController(root);
+    return RootWindowController::ForWindow(root);
   }
 
   RootWindowController* GetExternalRootController() {
     aura::Window* root = GetExternalRootWindow();
-    return GetRootWindowController(root);
+    return RootWindowController::ForWindow(root);
   }
 
   RootWindowController* GetPrimaryRootController() {
     aura::Window* root = GetPrimaryRootWindow();
-    return GetRootWindowController(root);
+    return RootWindowController::ForWindow(root);
   }
 
   RootWindowController* GetSecondaryRootController() {
     aura::Window* root = GetSecondaryRootWindow();
-    return GetRootWindowController(root);
+    return RootWindowController::ForWindow(root);
   }
 
   display::ManagedDisplayInfo CreateDisplayInfo(int64_t id,
diff --git a/ash/wm/drag_window_resizer_unittest.cc b/ash/wm/drag_window_resizer_unittest.cc
index 0f6176c..9a42060c 100644
--- a/ash/wm/drag_window_resizer_unittest.cc
+++ b/ash/wm/drag_window_resizer_unittest.cc
@@ -614,7 +614,7 @@
   {
     // Make sure the window is on the default container first.
     aura::Window* default_container =
-        GetRootWindowController(root_windows[1])
+        RootWindowController::ForWindow(root_windows[1])
             ->GetContainer(kShellWindowId_DefaultContainer);
     default_container->AddChild(window_.get());
     window_->SetBoundsInScreen(
diff --git a/ash/wm/window_cycle_list.cc b/ash/wm/window_cycle_list.cc
index e1f47d17..a2c7c38 100644
--- a/ash/wm/window_cycle_list.cc
+++ b/ash/wm/window_cycle_list.cc
@@ -534,7 +534,7 @@
   // TODO(estade): make sure nothing untoward happens when the lock screen
   // or a system modal dialog is shown.
   aura::Window* root_window = Shell::GetRootWindowForNewWindows();
-  GetRootWindowController(root_window)
+  RootWindowController::ForWindow(root_window)
       ->ConfigureWidgetInitParamsForContainer(
           widget, kShellWindowId_OverlayContainer, &params);
   gfx::Rect widget_rect = display::Screen::GetScreen()
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 858aee6..999efbf 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -669,10 +669,14 @@
   ElementId new_element_id = node ? node->element_id : ElementId();
 
 #if DCHECK_IS_ON()
-  int old_layer_id = old_node ? old_node->owning_layer_id : Layer::INVALID_ID;
-  int new_layer_id = node ? node->owning_layer_id : Layer::INVALID_ID;
-  DCHECK(old_layer_id == LayerIdByElementId(old_element_id));
-  DCHECK(new_layer_id == LayerIdByElementId(new_element_id));
+  // In SPv2 scrolling is driven solely by element id and
+  // layer/element-id maps should not be required.
+  if (!settings().use_layer_lists) {
+    int old_layer_id = old_node ? old_node->owning_layer_id : Layer::INVALID_ID;
+    int new_layer_id = node ? node->owning_layer_id : Layer::INVALID_ID;
+    DCHECK(old_layer_id == LayerIdByElementId(old_element_id));
+    DCHECK(new_layer_id == LayerIdByElementId(new_element_id));
+  }
 #endif
 
   if (old_element_id == new_element_id)
diff --git a/chrome/VERSION b/chrome/VERSION
index e89d9d4..72985c5 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=61
 MINOR=0
-BUILD=3117
+BUILD=3118
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java
index 3d6e3730..1649dc0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java
@@ -25,7 +25,7 @@
 /**
  * Java version of the compact translate infobar.
  */
-class TranslateCompactInfoBar extends InfoBar
+public class TranslateCompactInfoBar extends InfoBar
         implements TabLayout.OnTabSelectedListener, TranslateMenuHelper.TranslateMenuListener {
     public static final int TRANSLATING_INFOBAR = 1;
 
@@ -277,7 +277,7 @@
 
     private void closeInfobar(boolean explicitly) {
         // Check if we should trigger the auto "never translate" if infobar is closed explicitly.
-        if (explicitly
+        if (explicitly && mNativeTranslateInfoBarPtr != 0
                 && nativeShouldAutoNeverTranslate(mNativeTranslateInfoBarPtr, mMenuExpanded)) {
             createAndShowSnackbar(getContext().getString(R.string.translate_snackbar_language_never,
                                           mOptions.sourceLanguageName()),
@@ -373,7 +373,7 @@
     @Override
     public void onTargetMenuItemClicked(String code) {
         // Reset target code in both UI and native.
-        if (mOptions.setTargetLanguage(code)) {
+        if (mNativeTranslateInfoBarPtr != 0 && mOptions.setTargetLanguage(code)) {
             recordInfobarLanguageData(
                     INFOBAR_HISTOGRAM_MORE_LANGUAGES_LANGUAGE, mOptions.targetLanguageCode());
             nativeApplyStringTranslateOption(
@@ -387,7 +387,7 @@
     @Override
     public void onSourceMenuItemClicked(String code) {
         // Reset source code in both UI and native.
-        if (mOptions.setSourceLanguage(code)) {
+        if (mNativeTranslateInfoBarPtr != 0 && mOptions.setSourceLanguage(code)) {
             recordInfobarLanguageData(
                     INFOBAR_HISTOGRAM_PAGE_NOT_IN_LANGUAGE, mOptions.sourceLanguageCode());
             nativeApplyStringTranslateOption(
@@ -412,6 +412,22 @@
         super.onStartedHiding();
     }
 
+    /**
+     * Returns true if overflow menu is showing.  This is only used for automation testing.
+     */
+    public boolean isShowingOverflowMenuForTesting() {
+        if (mOverflowMenuHelper == null) return false;
+        return mOverflowMenuHelper.isShowing();
+    }
+
+    /**
+     * Returns true if language menu is showing.  This is only used for automation testing.
+     */
+    public boolean isShowingLanguageMenuForTesting() {
+        if (mLanguageMenuHelper == null) return false;
+        return mLanguageMenuHelper.isShowing();
+    }
+
     private void createAndShowSnackbar(String title, int umaType, int actionId) {
         if (getSnackbarManager() == null) {
             // Directly apply menu option, if snackbar system is not working.
@@ -447,6 +463,9 @@
     }
 
     private void handleTranslateOptionPostSnackbar(int actionId) {
+        // Quit if native is destroyed.
+        if (mNativeTranslateInfoBarPtr == 0) return;
+
         switch (actionId) {
             case ACTION_OVERFLOW_ALWAYS_TRANSLATE:
                 toggleAlwaysTranslate();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/translate/TranslateMenuHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/translate/TranslateMenuHelper.java
index 222a8ab..0d0065d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/translate/TranslateMenuHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/translate/TranslateMenuHelper.java
@@ -191,9 +191,9 @@
     }
 
     /**
-     * @return Whether the app menu is currently showing.
+     * @return Whether the menu is currently showing.
      */
-    private boolean isShowing() {
+    public boolean isShowing() {
         if (mPopup == null) {
             return false;
         }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 6d89300a..931bb9f 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1641,6 +1641,7 @@
   "javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java",
   "javatests/src/org/chromium/chrome/browser/toolbar/ToolbarModelTest.java",
   "javatests/src/org/chromium/chrome/browser/toolbar/ToolbarTest.java",
+  "javatests/src/org/chromium/chrome/browser/translate/TranslateCompactInfoBarTest.java",
   "javatests/src/org/chromium/chrome/browser/translate/TranslateInfoBarTest.java",
   "javatests/src/org/chromium/chrome/browser/translate/TranslateOptionsTest.java",
   "javatests/src/org/chromium/chrome/browser/util/ChromeFileProviderTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateCompactInfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateCompactInfoBarTest.java
new file mode 100644
index 0000000..6c6e2ca
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateCompactInfoBarTest.java
@@ -0,0 +1,138 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.translate;
+
+import android.content.pm.ActivityInfo;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.Restriction;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.infobar.InfoBar;
+import org.chromium.chrome.browser.infobar.InfoBarContainer;
+import org.chromium.chrome.browser.infobar.TranslateCompactInfoBar;
+import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.util.ChromeRestriction;
+import org.chromium.chrome.test.util.InfoBarTestAnimationListener;
+import org.chromium.chrome.test.util.TranslateUtil;
+import org.chromium.net.test.EmbeddedTestServer;
+
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Tests for the translate infobar, assumes it runs on a system with language
+ * preferences set to English.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
+        ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG})
+public class TranslateCompactInfoBarTest {
+    @Rule
+    public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
+            new ChromeActivityTestRule<>(ChromeActivity.class);
+
+    private static final String TRANSLATE_PAGE = "/chrome/test/data/translate/fr_test.html";
+    private static final String ENABLE_COMPACT_UI_FEATURE = "enable-features=TranslateCompactUI";
+
+    private InfoBarContainer mInfoBarContainer;
+    private InfoBarTestAnimationListener mListener;
+    private EmbeddedTestServer mTestServer;
+
+    @Before
+    public void setUp() throws Exception {
+        mActivityTestRule.startMainActivityOnBlankPage();
+        mInfoBarContainer = mActivityTestRule.getActivity().getActivityTab().getInfoBarContainer();
+        mListener = new InfoBarTestAnimationListener();
+        mInfoBarContainer.addAnimationListener(mListener);
+        mTestServer = EmbeddedTestServer.createAndStartServer(
+                InstrumentationRegistry.getInstrumentation().getContext());
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mTestServer.stopAndDestroyServer();
+    }
+
+    /**
+     * Test that the new translate compact UI appears and has at least 2 tabs.
+     */
+    @Test
+    @MediumTest
+    @Feature({"Browser", "Main"})
+    @Restriction(ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES)
+    @CommandLineFlags.Add(ENABLE_COMPACT_UI_FEATURE)
+    public void testTranslateCompactInfoBarAppears() throws InterruptedException, TimeoutException {
+        mActivityTestRule.loadUrl(mTestServer.getURL(TRANSLATE_PAGE));
+        mListener.addInfoBarAnimationFinished("InfoBar not opened.");
+        InfoBar infoBar = mInfoBarContainer.getInfoBarsForTesting().get(0);
+        TranslateUtil.assertCompactTranslateInfoBar(infoBar);
+        TranslateUtil.assertHasAtLeastTwoLanguageTabs((TranslateCompactInfoBar) infoBar);
+    }
+
+    /**
+     * Test the overflow menus of new translate compact UI.
+     */
+    @Test
+    @MediumTest
+    @Feature({"Browser", "Main"})
+    @Restriction(ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES)
+    @CommandLineFlags.Add(ENABLE_COMPACT_UI_FEATURE)
+    public void testTranslateCompactInfoBarOverflowMenus()
+            throws InterruptedException, TimeoutException {
+        mActivityTestRule.loadUrl(mTestServer.getURL(TRANSLATE_PAGE));
+        mListener.addInfoBarAnimationFinished("InfoBar not opened.");
+        TranslateCompactInfoBar infoBar =
+                (TranslateCompactInfoBar) mInfoBarContainer.getInfoBarsForTesting().get(0);
+        TranslateUtil.hasMenuButton(infoBar);
+
+        // 1. Click on menu button and make sure overflow menu appears
+        TranslateUtil.clickMenuButtonAndAssertMenuShown(infoBar);
+
+        // 2. Click on "More language" in the overflow menu and make sure language menu appears
+        TranslateUtil.clickMoreLanguageButtonAndAssertLanguageMenuShown(
+                InstrumentationRegistry.getInstrumentation(), infoBar);
+    }
+
+    /**
+     * Tests that the overflow menu is dismissed when the orientation changes.
+     */
+    @Test
+    @MediumTest
+    @Feature({"Browser", "Main"})
+    @Restriction(ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES)
+    @CommandLineFlags.Add(ENABLE_COMPACT_UI_FEATURE)
+    public void testTabMenuDismissedOnOrientationChange() throws Exception {
+        mActivityTestRule.loadUrl(mTestServer.getURL(TRANSLATE_PAGE));
+        mListener.addInfoBarAnimationFinished("InfoBar not opened.");
+        TranslateCompactInfoBar infoBar =
+                (TranslateCompactInfoBar) mInfoBarContainer.getInfoBarsForTesting().get(0);
+        TranslateUtil.hasMenuButton(infoBar);
+        TranslateUtil.clickMenuButtonAndAssertMenuShown(infoBar);
+
+        // 1. Set orientation to portrait
+        mActivityTestRule.getActivity().setRequestedOrientation(
+                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        // 2. Check if overflow menu is dismissed
+        Assert.assertFalse(infoBar.isShowingLanguageMenuForTesting());
+
+        // 3. Reset orientation
+        mActivityTestRule.getActivity().setRequestedOrientation(
+                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateInfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateInfoBarTest.java
index 599c190..1ab042d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateInfoBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateInfoBarTest.java
@@ -48,7 +48,6 @@
             new ChromeActivityTestRule<>(ChromeActivity.class);
 
     private static final String TRANSLATE_PAGE = "/chrome/test/data/translate/fr_test.html";
-    private static final String ENABLE_COMPACT_UI_FEATURE = "enable-features=TranslateCompactUI";
     private static final String DISABLE_COMPACT_UI_FEATURE = "disable-features=TranslateCompactUI";
     private static final String NEVER_TRANSLATE_MESSAGE =
             "Would you like Google Chrome to offer to translate French pages from this"
@@ -74,21 +73,6 @@
     }
 
     /**
-     * Test the new translate compact UI.
-     */
-    @Test
-    @MediumTest
-    @Feature({"Browser", "Main"})
-    @Restriction(ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES)
-    @CommandLineFlags.Add(ENABLE_COMPACT_UI_FEATURE)
-    public void testTranslateCompactInfoBarAppears() throws InterruptedException, TimeoutException {
-        mActivityTestRule.loadUrl(mTestServer.getURL(TRANSLATE_PAGE));
-        mListener.addInfoBarAnimationFinished("InfoBar not opened.");
-        InfoBar infoBar = mInfoBarContainer.getInfoBarsForTesting().get(0);
-        TranslateUtil.assertCompactTranslateInfoBar(infoBar);
-    }
-
-    /**
      * Test the translate language panel.
      */
     @Test
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 45d37a4b..a925ac9c 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -1539,18 +1539,6 @@
   <message name="IDS_LANGUAGE_SELECTION_SELECT" desc="Label for language selection dropdown">
     Select your language:
   </message>
-  <message name="IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_SIMPLIFIED" desc="Medium length name for the input method for simplified Chinese which is shown following the text: Your input method has changed to...">
-    Simplified Chinese
-  </message>
-  <message name="IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_TRADITIONAL" desc="Medium length name for the input method for traditional Chinese which is show following the text: Your input method has changed to...">
-   Traditional Chinese
-  </message>
-  <message name="IDS_LANGUAGES_MEDIUM_LEN_NAME_KOREAN" desc="Medium length name for the input method for Korean which is show following the text: Your input method has changed to...">
-    Korean
-  </message>
-  <message name="IDS_LANGUAGES_MEDIUM_LEN_NAME_BRAILLE" desc="Medium length name for the input method for the hardware keyboard on a braille display. Shown after the text: Your input method has changed to...">
-    Braille
-  </message>
   <message name="IDS_KEYBOARD_SELECTION_SELECT" desc="Label for keyboard selection dropdown">
     Select your keyboard:
   </message>
@@ -4858,608 +4846,6 @@
   </message>
   <!-- END GENERATED KEYBOARD OVERLAY STRINGS -->
 
-  <message name="IDS_STATUSBAR_LAYOUT_JAPAN" desc="In the language menu button, this shows the input mode [Japanese keyboard].">
-    Japanese
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_SLOVENIA" desc="In the language menu button, this shows the input mode [Slovenian keyboard].">
-    Slovenian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_GERMANY" desc="In the language menu button, this shows the input mode [German keyboard].">
-    German
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_GERMANY_NEO2" desc="In the language menu button, this shows the input mode [German Neo 2 keyboard].">
-    German Neo 2
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_ITALY" desc="In the language menu button, this shows the input mode [Italian keyboard].">
-    Italian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_ESTONIA" desc="In the language menu button, this shows the input mode [Estonian keyboard].">
-    Estonian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_FAROESE" desc="In the language menu button, this shows the input mode [Faroese keyboard].">
-    Faroese
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_HUNGARY" desc="In the language menu button, this shows the input mode [Hungarian keyboard].">
-    Hungarian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_HUNGARY_QWERTY" desc="In the language menu button, this shows the input mode [Hungarian QWERTY keyboard].">
-    Hungarian QWERTY
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_POLAND" desc="In the language menu button, this shows the input mode [Polish keyboard].">
-    Polish
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_DENMARK" desc="In the language menu button, this shows the input mode [Danish keyboard].">
-    Danish
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_CROATIA" desc="In the language menu button, this shows the input mode [Croatian keyboard].">
-    Croatian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_BRAZIL" desc="In the language menu button, this shows the input mode [Brazilian keyboard].">
-    Brazilian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_SERBIA" desc="In the language menu button, this shows the input mode [Serbian keyboard].">
-    Serbian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_CZECHIA" desc="In the language menu button, this shows the input mode [Czech keyboard].">
-    Czech
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_CZECHIA_QWERTY" desc="In the language menu button, this shows the input mode [Czech QWERTY keyboard].">
-    Czech QWERTY
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_USA_DVORAK" desc="In the language menu button, this shows the input mode [US Dvorak keyboard].">
-    US Dvorak
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_USA_DVP" desc="In the language menu button, this shows the input mode [US Programmer Dvorak keyboard].">
-    US Programmer Dvorak
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_USA_COLEMAK" desc="In the language menu button, this shows the input mode [US Colemak keyboard].">
-    US Colemak
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_ROMANIA" desc="In the language menu button, this shows the input mode [Romanian keyboard].">
-    Romanian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_USA" desc="In the language menu button, this shows the input mode [US keyboard].">
-    US
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_USA_EXTENDED" desc="In the language menu button, this shows the input mode [US extended keyboard].">
-    US extended
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_USA_INTERNATIONAL" desc="In the language menu button, this shows the input mode [US international keyboard].">
-    US international
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_USA_WORKMAN" desc="In the language menu button, this shows the input mode [US Workman keyboard].">
-    US Workman
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_USA_WORKMAN_INTERNATIONAL" desc="In the language menu button, this shows the input mode [US Workman international keyboard].">
-    US Workman international
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_LITHUANIA" desc="In the language menu button, this shows the input mode [Lithuanian keyboard].">
-    Lithuanian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_UNITED_KINGDOM" desc="In the language menu button, this shows the input mode [UK keyboard].">
-    UK
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_UNITED_KINGDOM_DVORAK" desc="In the language menu button, this shows the input mode [UK Dvorak keyboard].">
-    UK Dvorak
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_SLOVAKIA" desc="In the language menu button, this shows the input mode [Slovak keyboard].">
-    Slovak
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_RUSSIA" desc="In the language menu button, this shows the input mode [Russian keyboard].">
-    Russian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_RUSSIA_PHONETIC" desc="In the language menu button, this shows the input mode [Russian phonetic keyboard].">
-    Russian phonetic
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_GREECE" desc="In the language menu button, this shows the input mode [Greek keyboard].">
-    Greek
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_BELGIUM" desc="In the language menu button, this shows the input mode [Belgian keyboard].">
-    Belgian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_BULGARIA" desc="In the language menu button, this shows the input mode [Bulgarian keyboard].">
-    Bulgarian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_BULGARIA_PHONETIC" desc="In the language menu button, this shows the input mode [Bulgarian phonetic keyboard].">
-    Bulgarian phonetic
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_SWITZERLAND" desc="In the language menu button, this shows the input mode [Swiss keyboard].">
-    Swiss
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_SWITZERLAND_FRENCH" desc="In the language menu button, this shows the input mode [Swiss French keyboard].">
-    Swiss French
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_TURKEY" desc="In the language menu button, this shows the input mode [Turkish keyboard].">
-    Turkish
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_TURKEY_F" desc="In the language menu button, this shows the input mode [Turkish-F keyboard].">
-    Turkish-F
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_PORTUGAL" desc="In the language menu button, this shows the input mode [Portuguese keyboard].">
-    Portuguese
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_SPAIN" desc="In the language menu button, this shows the input mode [Spanish keyboard].">
-    Spanish
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_FINLAND" desc="In the language menu button, this shows the input mode [Finnish keyboard].">
-    Finnish
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_UKRAINE" desc="In the language menu button, this shows the input mode [Ukrainian keyboard].">
-    Ukrainian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_SPAIN_CATALAN" desc="In the language menu button, this shows the input mode [Catalan keyboard].">
-    Catalan
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_FRANCE_BEPO" desc="In the language menu button, this shows the input mode [French BÉPO keyboard].">
-    French BÉPO
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_FRANCE" desc="In the language menu button, this shows the input mode [French keyboard].">
-    French
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_NORWAY" desc="In the language menu button, this shows the input mode [Norwegian keyboard].">
-    Norwegian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_SWEDEN" desc="In the language menu button, this shows the input mode [Swedish keyboard].">
-    Swedish
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_NETHERLANDS" desc="In the language menu button, this shows the input mode [Dutch keyboard].">
-    Dutch
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_LATIN_AMERICAN" desc="In the language menu button, this shows the input mode [Latin American keyboard].">
-    Latin American
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_LATVIA" desc="In the language menu button, this shows the input mode [Latvian keyboard].">
-    Latvian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_CANADA" desc="In the language menu button, this shows the input mode [Canadian French keyboard].">
-    Canadian French
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_CANADA_ENGLISH" desc="In the language menu button, this shows the input mode [Canadian English keyboard].">
-    Canadian English
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_ISRAEL" desc="In the language menu button, this shows the input mode [Hebrew keyboard].">
-    Hebrew
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_KOREA_104" desc="In the language menu button, this shows the input mode [Korean keyboard].">
-    Korean
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_ICELANDIC" desc="In the language menu button, this shows the input mode [Icelandic keyboard].">
-    Icelandic
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_CANADIAN_MULTILINGUAL" desc="In the language menu button, this shows the input mode [Canadian Multilingual keyboard].">
-    Canadian Multilingual
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_GEORGIAN" desc="In the language menu button, this shows the input mode [Georgian keyboard].">
-    Georgian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_BELARUSIAN" desc="In the language menu button, this shows the input mode [Belarusian keyboard].">
-    Belarusian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_ARMENIAN_PHONETIC" desc="In the language menu button, this shows the input mode [Armenian Phonetic keyboard].">
-    Armenian Phonetic
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_MONGOLIAN" desc="In the language menu button, this shows the input mode [Mongolian keyboard].">
-    Mongolian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_IRISH" desc="In the language menu button, this shows the input mode [Irish keyboard].">
-    Irish
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_MACEDONIAN" desc="In the language menu button, this shows the input mode [Macedonian keyboard].">
-    Macedonian
-  </message>
-  <message name="IDS_STATUSBAR_LAYOUT_KAZAKH" desc="In the language menu button, this shows the input mode [Kazakh keyboard].">
-    Kazakh
-  </message>
-
-  <message name="IDS_IME_NAME_KEYBOARD_ARMENIAN_PHONETIC" desc="The input method name shows in system tray menu, this shows [Armenian Phonetic keyboard].">
-    Armenian Phonetic keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_BELARUSIAN" desc="The input method name shows in system tray menu, this shows [Belarusian keyboard].">
-    Belarusian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_BELGIAN" desc="The input method name shows in system tray menu, this shows [Belgian keyboard].">
-    Belgian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_BRAZILIAN" desc="The input method name shows in system tray menu, this shows [Brazilian keyboard].">
-    Brazilian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_BULGARIAN" desc="The input method name shows in system tray menu, this shows [Bulgarian keyboard].">
-    Bulgarian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_BULGARIAN_PHONETIC" desc="The input method name shows in system tray menu, this shows [Bulgarian Phonetic keyboard].">
-    Bulgarian Phonetic keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_CANADIAN_ENGLISH" desc="The input method name shows in system tray menu, this shows [Canadian English keyboard].">
-    Canadian English keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_CANADIAN_FRENCH" desc="The input method name shows in system tray menu, this shows [Canadian French keyboard].">
-    Canadian French keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_CANADIAN_MULTILINGUAL" desc="The input method name shows in system tray menu, this shows [Canadian Multilingual keyboard].">
-    Canadian Multilingual keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_CATALAN" desc="The input method name shows in system tray menu, this shows [Catalan keyboard].">
-    Catalan keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_CROATIAN" desc="The input method name shows in system tray menu, this shows [Croatian keyboard].">
-    Croatian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_CZECH" desc="The input method name shows in system tray menu, this shows [Czech keyboard].">
-    Czech keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_CZECH_QWERTY" desc="The input method name shows in system tray menu, this shows [Czech QWERTY keyboard].">
-    Czech QWERTY keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_DANISH" desc="The input method name shows in system tray menu, this shows [Danish keyboard].">
-    Danish keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_ESTONIAN" desc="The input method name shows in system tray menu, this shows [Estonian keyboard].">
-    Estonian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_FAROESE" desc="The input method name shows in system tray menu, this shows [Faroese keyboard].">
-    Faroese keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_FINNISH" desc="The input method name shows in system tray menu, this shows [Finnish keyboard].">
-    Finnish keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_FRENCH_BEPO" desc="The input method name shows in system tray menu, this shows [French BÉPO keyboard].">
-    French BÉPO keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_FRENCH" desc="The input method name shows in system tray menu, this shows [French keyboard].">
-    French keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_GEORGIAN" desc="The input method name shows in system tray menu, this shows [Georgian keyboard].">
-    Georgian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_GERMAN" desc="The input method name shows in system tray menu, this shows [German keyboard].">
-    German keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_GERMAN_NEO_2" desc="The input method name shows in system tray menu, this shows [German NEO 2 keyboard].">
-    German NEO 2 keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_GREEK" desc="The input method name shows in system tray menu, this shows [Greek keyboard].">
-    Greek keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_HEBREW" desc="The input method name shows in system tray menu, this shows [Hebrew keyboard].">
-    Hebrew keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_HUNGARIAN" desc="The input method name shows in system tray menu, this shows [Hungarian keyboard].">
-    Hungarian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_HUNGARIAN_QWERTY" desc="The input method name shows in system tray menu, this shows [Hungarian QWERTY keyboard].">
-    Hungarian QWERTY keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_ICELANDIC" desc="The input method name shows in system tray menu, this shows [Icelandic keyboard].">
-    Icelandic keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_IRISH" desc="The input method name shows in system tray menu, this shows [Irish keyboard].">
-    Irish keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_ITALIAN" desc="The input method name shows in system tray menu, this shows [Italian keyboard].">
-    Italian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_JAPANESE" desc="The input method name shows in system tray menu, this shows [Japanese keyboard].">
-    Japanese keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_KAZAKH" desc="The input method name shows in system tray menu, this shows [Kazakh keyboard].">
-    Kazakh keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_LATIN_AMERICAN" desc="The input method name shows in system tray menu, this shows [Latin American keyboard].">
-    Latin American keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_LATVIAN" desc="The input method name shows in system tray menu, this shows [Latvian keyboard].">
-    Latvian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_LITHUANIAN" desc="The input method name shows in system tray menu, this shows [Lithuanian keyboard].">
-    Lithuanian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_MACEDONIAN" desc="The input method name shows in system tray menu, this shows [Macedonian keyboard].">
-    Macedonian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_MALTESE" desc="The input method name shows in system tray menu, this shows [Maltese keyboard].">
-    Maltese keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_MONGOLIAN" desc="The input method name shows in system tray menu, this shows [Mongolian keyboard].">
-    Mongolian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_NETHERLANDS" desc="The input method name shows in system tray menu, this shows [Netherlands keyboard].">
-    Netherlands keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_NORWEGIAN" desc="The input method name shows in system tray menu, this shows [Norwegian keyboard].">
-    Norwegian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_POLISH" desc="The input method name shows in system tray menu, this shows [Polish keyboard].">
-    Polish keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_PORTUGUESE" desc="The input method name shows in system tray menu, this shows [Portuguese keyboard].">
-    Portuguese keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_ROMANIAN" desc="The input method name shows in system tray menu, this shows [Romanian keyboard].">
-    Romanian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_ROMANIAN_STANDARD" desc="The input method name shows in system tray menu, this shows [Romanian standard keyboard].">
-    Romanian standard keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_RUSSIAN" desc="The input method name shows in system tray menu, this shows [Russian keyboard].">
-    Russian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_RUSSIAN_PHONETIC" desc="The input method name shows in system tray menu, this shows [Russian Phonetic keyboard].">
-    Russian Phonetic keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_RUSSIAN_PHONETIC_AATSEEL" desc="The input method name shows in system tray menu, this shows [Russian Phonetic (AATSEEL) keyboard].">
-    Russian Phonetic (AATSEEL) keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_RUSSIAN_PHONETIC_YAZHERT" desc="The input method name shows in system tray menu, this shows [Russian Phonetic (YaZHert) keyboard].">
-    Russian Phonetic (YaZHert) keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_SERBIAN" desc="The input method name shows in system tray menu, this shows [Serbian keyboard].">
-    Serbian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_SLOVAK" desc="The input method name shows in system tray menu, this shows [Slovak keyboard].">
-    Slovak keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_SLOVENIAN" desc="The input method name shows in system tray menu, this shows [Slovenian keyboard].">
-    Slovenian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_SPANISH" desc="The input method name shows in system tray menu, this shows [Spanish keyboard].">
-    Spanish keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_SWEDISH" desc="The input method name shows in system tray menu, this shows [Swedish keyboard].">
-    Swedish keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_SWISS_FRENCH" desc="The input method name shows in system tray menu, this shows [Swiss French keyboard].">
-    Swiss French keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_SWISS" desc="The input method name shows in system tray menu, this shows [Swiss keyboard].">
-    Swiss keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_TURKISH" desc="The input method name shows in system tray menu, this shows [Turkish keyboard].">
-    Turkish keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_TURKISH_F" desc="The input method name shows in system tray menu, this shows [Turkish-F keyboard].">
-    Turkish-F keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_UK_DVORAK" desc="The input method name shows in system tray menu, this shows [UK Dvorak keyboard].">
-    UK Dvorak keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_UK" desc="The input method name shows in system tray menu, this shows [UK keyboard].">
-    UK keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_UKRAINIAN" desc="The input method name shows in system tray menu, this shows [Ukrainian keyboard].">
-    Ukrainian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_US_COLEMAK" desc="The input method name shows in system tray menu, this shows [US Colemak keyboard].">
-    US Colemak keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_US_DVORAK" desc="The input method name shows in system tray menu, this shows [US Dvorak keyboard].">
-    US Dvorak keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_US_DVP" desc="The input method name shows in system tray menu, this shows [US Programmer Dvorak keyboard].">
-    US Programmer Dvorak keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_US_EXTENDED" desc="The input method name shows in system tray menu, this shows [US Extended keyboard].">
-    US Extended keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_US_INTERNATIONAL" desc="The input method name shows in system tray menu, this shows [US International keyboard].">
-    US International keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_US_WORKMAN" desc="The input method name shows in system tray menu, this shows [US Workman keyboard].">
-    US Workman keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_US_WORKMAN_INTERNATIONAL" desc="The input method name shows in system tray menu, this shows [US Workman international keyboard].">
-    US Workman international keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_US" desc="The input method name shows in system tray menu, this shows [US keyboard].">
-    US keyboard
-  </message>
-
-  <message name="IDS_IME_NAME_INPUTMETHOD_ARRAY" desc="The input method name shows in system tray menu, this is Array (\u884c\u5217) input method for Traditional Chinese.">
-    Array input method
-  </message>
-  <message name="IDS_IME_NAME_INPUTMETHOD_CANGJIE" desc="The input method name shows in system tray menu, this is Cangjie input method for Tradition Chinese.">
-    Cangjie input method
-  </message>
-  <message name="IDS_IME_NAME_INPUTMETHOD_DAYI" desc="The input method name shows in system tray menu, this is Dayi (\u5927\u6613) input method for Traditional Chinese.">
-    Dayi input method
-  </message>
-  <message name="IDS_IME_NAME_INPUTMETHOD_MOZC_JP" desc="The input method name shows in system tray menu, this is Japanese input method for Japanese keyboard.">
-    Google Japanese Input (for Japanese keyboard)
-  </message>
-  <message name="IDS_IME_NAME_INPUTMETHOD_MOZC_US" desc="The input method name shows in system tray menu, this is Japanese input method for US keyboard.">
-    Google Japanese Input (for US keyboard)
-  </message>
-  <message name="IDS_IME_NAME_INPUTMETHOD_PINYIN" desc="The input method name shows in system tray menu, this is Pinyin input method for Simplified Chinese.">
-    Pinyin input method
-  </message>
-  <message name="IDS_IME_NAME_INPUTMETHOD_QUICK" desc="The input method name shows in system tray menu, this is Quick input method for Traditional Chinese.">
-    Quick input method
-  </message>
-  <message name="IDS_IME_NAME_INPUTMETHOD_TRADITIONAL_PINYIN" desc="The input method name shows in system tray menu, this is Pinyin input method for Traditional Chinese.">
-    Traditional Pinyin input method
-  </message>
-  <message name="IDS_IME_NAME_INPUTMETHOD_WUBI" desc="The input method name shows in system tray menu, this is Wubi input method for Simplified Chinese.">
-    Wubi input method
-  </message>
-  <message name="IDS_IME_NAME_INPUTMETHOD_ZHUYIN" desc="The input method name shows in system tray menu, this is Zhuyin input method for Traditional Chinese.">
-    Zhuyin input method
-  </message>
-  <message name="IDS_IME_NAME_INPUTMETHOD_CANTONESE" desc="The input method name shows in system tray menu, this is Cantonese input method for Traditional Chinese.">
-    Cantonese input method
-  </message>
-  <message name="IDS_IME_NAME_INPUTMETHOD_HANGUL" desc="The input method name shows in system tray menu, this is Korean Hangul input method.">
-    Korean input method
-  </message>
-  <message name="IDS_IME_NAME_INPUTMETHOD_HANGUL_2_SET" desc="The input method name shows in system tray menu, this is Korean Hangul input method, 2 Set mode.">
-    Hangul 2 Set
-  </message>
-  <message name="IDS_IME_NAME_INPUTMETHOD_HANGUL_3_SET_390" desc="The input method name shows in system tray menu, this is Korean Hangul input method, 3 Set (390) mode.">
-    Hangul 3 Set (390)
-  </message>
-  <message name="IDS_IME_NAME_INPUTMETHOD_HANGUL_3_SET_FINAL" desc="The input method name shows in system tray menu, this is Korean Hangul input method, 3 Set (Final) mode.">
-    Hangul 3 Set (Final)
-  </message>
-  <message name="IDS_IME_NAME_INPUTMETHOD_HANGUL_3_SET_NO_SHIFT" desc="The input method name shows in system tray menu, this is Korean Hangul input method, 3 Set (No Shift) mode.">
-    Hangul 3 Set (No Shift)
-  </message>
-  <message name="IDS_IME_NAME_INPUTMETHOD_HANGUL_ROMAJA" desc="The input method name shows in system tray menu, this is Korean Hangul input method, Romaja mode.">
-    Hangul Romaja
-  </message>
-  <message name="IDS_IME_NAME_INPUTMETHOD_HANGUL_AHNMATAE" desc="The input method name shows in system tray menu, this is Korean Hangul input method, Ahnmatae mode.">
-    Hangul Ahnmatae
-  </message>
-
-  <message name="IDS_IME_NAME_KEYBOARD_ARABIC" desc="The input method name shows in system tray menu.">
-    Arabic keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_BENGALI_PHONETIC" desc="The input method name shows in system tray menu.">
-    Bengali keyboard (Phonetic)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_DEVANAGARI_PHONETIC" desc="The input method name shows in system tray menu.">
-    Devanagari keyboard (Phonetic)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_ETHIOPIC" desc="The input method name shows in system tray menu.">
-    Ethiopic keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_GUJARATI_PHONETIC" desc="The input method name shows in system tray menu.">
-    Gujarati keyboard (Phonetic)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_KANNADA_PHONETIC" desc="The input method name shows in system tray menu.">
-    Kannada keyboard (Phonetic)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_KHMER" desc="The input method name shows in system tray menu.">
-    Khmer keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_LAO" desc="The input method name shows in system tray menu.">
-    Lao keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_MALAYALAM_PHONETIC" desc="The input method name shows in system tray menu.">
-    Malayalam keyboard (Phonetic)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_MYANMAR" desc="The input method name shows in system tray menu.">
-    Myanmar keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_MYANMAR_MYANSAN" desc="The input method name shows in system tray menu.">
-    Myanmar Myansan keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_NEPALI_INSCRIPT" desc="The input method name shows in system tray menu.">
-    Nepali keyboard (InScript)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_NEPALI_PHONETIC" desc="The input method name shows in system tray menu.">
-    Nepali keyboard (Phonetic)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_PERSIAN" desc="The input method name shows in system tray menu.">
-    Persian keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_SINHALA" desc="The input method name shows in system tray menu.">
-    Sinhala keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_SORANIKURDISH_AR" desc="The input method name shows in system tray menu.">
-    Sorani Kurdish Arabic-based keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_SORANIKURDISH_EN" desc="The input method name shows in system tray menu.">
-    Sorani Kurdish English-based keyboard
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_TAMIL_INSCRIPT" desc="The input method name shows in system tray menu.">
-    Tamil keyboard (InScript)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_TAMIL_ITRANS" desc="The input method name shows in system tray menu.">
-    Tamil keyboard (itrans)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_TAMIL_PHONETIC" desc="The input method name shows in system tray menu.">
-    Tamil keyboard (Phonetic)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_TAMIL_TAMIL99" desc="The input method name shows in system tray menu.">
-    Tamil keyboard (Tamil99)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_TAMIL_TYPEWRITER" desc="The input method name shows in system tray menu.">
-    Tamil keyboard (Typewriter)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_TELUGU_PHONETIC" desc="The input method name shows in system tray menu.">
-    Telugu keyboard (Phonetic)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_THAI_KEDMANEE" desc="The input method name shows in system tray menu.">
-    Thai keyboard (Kedmanee)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_THAI_PATTACHOTE" desc="The input method name shows in system tray menu.">
-    Thai keyboard (Pattachote)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_THAI_TIS" desc="The input method name shows in system tray menu.">
-    Thai keyboard (TIS 820-2531)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_VIETNAMESE_TCVN" desc="The input method name shows in system tray menu.">
-    Vietnamese keyboard (TCVN)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_VIETNAMESE_TELEX" desc="The input method name shows in system tray menu.">
-    Vietnamese keyboard (Telex)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_VIETNAMESE_VIQR" desc="The input method name shows in system tray menu.">
-    Vietnamese keyboard (VIQR)
-  </message>
-  <message name="IDS_IME_NAME_KEYBOARD_VIETNAMESE_VNI" desc="The input method name shows in system tray menu.">
-    Vietnamese keyboard (VNI)
-  </message>
-
-  <message name="IDS_IME_NAME_TRANSLITERATION_AM" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (salam &#x2192; &#x1230;&#x120b;&#x121d;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_AR" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (marhaban &#x2190; &#x0645;&#x0631;&#x062d;&#x0628;&#x0627;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_BN" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (namaskar &#x2192; &#x09a8;&#x09ae;&#x09b8;&#x09cd;&#x0995;&#x09be;&#x09b0;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_EL" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (geia &#x2192; &#x03b3;&#x03b5;&#x03b9;&#x03b1;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_FA" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (salam &#x2190; &#x0633;&#x0644;&#x0627;&#x0645;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_GU" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (namaste &#x2192; &#x0aa8;&#x0aae;&#x0ab8;&#x0acd;&#x0aa4;&#x0ac7;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_HE" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (shalom &#x2190; &#x05e9;&#x05dc;&#x05d5;&#x05dd;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_HI" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (namaste &#x2192; &#x0928;&#x092e;&#x0938;&#x094d;&#x0924;&#x0947;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_KN" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (namaskaram &#x2192; &#x0ca8;&#x0cae;&#x0cb8;&#x0ccd;&#x0c95;&#x0cbe;&#x0cb0;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_ML" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (namaskar &#x2192; &#x0d28;&#x0d2e;&#x0d38;&#x0d4d;&#x0d15;&#x0d3e;&#x0d30;&#x0d02;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_MR" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (namaste &#x2192; &#x0928;&#x092e;&#x0938;&#x094d;&#x0915;&#x093e;&#x0930;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_NE" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (namaste &#x2192; &#x0928;&#x092e;&#x0938;&#x094d;&#x0924;&#x0947;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_OR" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (mausam &#x2192; &#x0b28;&#x0b2e;&#x0b38;&#x0b4d;&#x0b24;&#x0b47;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_PA" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (mausam &#x2192; &#x0a2e;&#x0a4c;&#x0a38;&#x0a2e;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_SA" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (namaste &#x2192; &#x0928;&#x092e;&#x0938;&#x094d;&#x0924;&#x0947;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_SR" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (zdravo &#x2192; &#x0437;&#x0434;&#x0440;&#x0430;&#x0432;&#x043e;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_TA" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (vanakkam &#x2192; &#x0bb5;&#x0ba3;&#x0b95;&#x0bcd;&#x0b95;&#x0bae;&#x0bcd;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_TE" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (emandi &#x2192; &#x0c0f;&#x0c2e;&#x0c02;&#x0c21;&#x0c40;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_TI" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (selam &#x2192; &#x1230;&#x120b;&#x121d;)
-  </message>
-  <message name="IDS_IME_NAME_TRANSLITERATION_UR" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
-    Transliteration (salam &#x2190; &#x0633;&#x0644;&#x0627;&#x0645;)
-  </message>
-
   <message name="IDS_LOGIN_ERROR_WHITELIST" desc="Couldn't sign in because user is not whitelisted by the device owner.">
     You are not authorized to use this device. Please contact the device owner for sign-in permission.
   </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 2159a8a..44bd37a 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1994,6 +1994,7 @@
       "//chrome/common/extensions/api:extensions_features",
       "//components/drive",
       "//components/guest_view/browser",
+      "//device/wake_lock/public/interfaces",
       "//extensions/components/javascript_dialog_extensions_client",
       "//media/cast:net",
     ]
@@ -3475,16 +3476,6 @@
       "media_galleries/win/snapshot_file_details.h",
       "memory/oom_memory_details.cc",
       "memory/oom_memory_details.h",
-      "memory/tab_manager.cc",
-      "memory/tab_manager.h",
-      "memory/tab_manager_delegate_chromeos.cc",
-      "memory/tab_manager_delegate_chromeos.h",
-      "memory/tab_manager_observer.cc",
-      "memory/tab_manager_observer.h",
-      "memory/tab_manager_web_contents_data.cc",
-      "memory/tab_manager_web_contents_data.h",
-      "memory/tab_stats.cc",
-      "memory/tab_stats.h",
       "metrics/first_web_contents_profiler.cc",
       "metrics/first_web_contents_profiler.h",
       "metrics/tab_reactivation_tracker.cc",
@@ -3567,6 +3558,16 @@
       "renderer_context_menu/spelling_menu_observer.h",
       "repost_form_warning_controller.cc",
       "repost_form_warning_controller.h",
+      "resource_coordinator/tab_manager.cc",
+      "resource_coordinator/tab_manager.h",
+      "resource_coordinator/tab_manager_delegate_chromeos.cc",
+      "resource_coordinator/tab_manager_delegate_chromeos.h",
+      "resource_coordinator/tab_manager_observer.cc",
+      "resource_coordinator/tab_manager_observer.h",
+      "resource_coordinator/tab_manager_web_contents_data.cc",
+      "resource_coordinator/tab_manager_web_contents_data.h",
+      "resource_coordinator/tab_stats.cc",
+      "resource_coordinator/tab_stats.h",
       "search/local_ntp_source.cc",
       "search/local_ntp_source.h",
       "search/one_google_bar/one_google_bar_data.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index c505095..765442e2 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2777,12 +2777,6 @@
 #endif  // defined(OS_WIN)
 
 #if defined(OS_CHROMEOS)
-    {"show-arc-files-app", flag_descriptions::kShowArcFilesAppName,
-     flag_descriptions::kShowArcFilesAppDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(arc::kShowArcFilesAppFeature)},
-#endif // defined(OS_CHROMEOS)
-
-#if defined(OS_CHROMEOS)
     {"force-enable-stylus-tools",
      flag_descriptions::kForceEnableStylusToolsName,
      flag_descriptions::kForceEnableStylusToolsDescription, kOsCrOS,
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h
index 96d2674..8b742dc 100644
--- a/chrome/browser/browser_process.h
+++ b/chrome/browser/browser_process.h
@@ -67,10 +67,6 @@
 class GCMDriver;
 }
 
-namespace memory {
-class TabManager;
-}
-
 namespace message_center {
 class MessageCenter;
 }
@@ -114,6 +110,10 @@
 class RapporServiceImpl;
 }
 
+namespace resource_coordinator {
+class TabManager;
+}
+
 namespace safe_browsing {
 class ClientSideDetectionService;
 }
@@ -278,7 +278,7 @@
   virtual gcm::GCMDriver* gcm_driver() = 0;
 
   // Returns the tab manager. On non-supported platforms, this returns null.
-  virtual memory::TabManager* GetTabManager() = 0;
+  virtual resource_coordinator::TabManager* GetTabManager() = 0;
 
   // Returns the default web client state of Chrome (i.e., was it the user's
   // default browser) at the time a previous check was made sometime between
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 7334e710..bfa6f696 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -174,7 +174,7 @@
 #endif
 
 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
-#include "chrome/browser/memory/tab_manager.h"
+#include "chrome/browser/resource_coordinator/tab_manager.h"
 #endif
 
 #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
@@ -808,11 +808,11 @@
   return gcm_driver_.get();
 }
 
-memory::TabManager* BrowserProcessImpl::GetTabManager() {
+resource_coordinator::TabManager* BrowserProcessImpl::GetTabManager() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
   if (!tab_manager_.get())
-    tab_manager_.reset(new memory::TabManager());
+    tab_manager_.reset(new resource_coordinator::TabManager());
   return tab_manager_.get();
 #else
   return nullptr;
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index b3f81e36..33ead42 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -154,7 +154,7 @@
 #endif
   network_time::NetworkTimeTracker* network_time_tracker() override;
   gcm::GCMDriver* gcm_driver() override;
-  memory::TabManager* GetTabManager() override;
+  resource_coordinator::TabManager* GetTabManager() override;
   shell_integration::DefaultWebClientState CachedDefaultWebClientState()
       override;
   physical_web::PhysicalWebDataSource* GetPhysicalWebDataSource() override;
@@ -344,8 +344,8 @@
 
 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
   // Any change to this #ifdef must be reflected as well in
-  // chrome/browser/memory/tab_manager_browsertest.cc
-  std::unique_ptr<memory::TabManager> tab_manager_;
+  // chrome/browser/resource_coordinator/tab_manager_browsertest.cc
+  std::unique_ptr<resource_coordinator::TabManager> tab_manager_;
 #endif
 
   shell_integration::DefaultWebClientState cached_default_web_client_state_;
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 7a1da72..d6f9064 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -69,7 +69,6 @@
 #include "chrome/browser/gpu/gpu_profile_cache.h"
 #include "chrome/browser/gpu/three_d_api_observer.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
-#include "chrome/browser/memory/tab_manager.h"
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
 #include "chrome/browser/metrics/field_trial_synchronizer.h"
 #include "chrome/browser/metrics/renderer_uptime_tracker.h"
@@ -90,6 +89,7 @@
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profiles_state.h"
+#include "chrome/browser/resource_coordinator/tab_manager.h"
 #include "chrome/browser/sessions/chrome_serialized_navigation_driver.h"
 #include "chrome/browser/shell_integration.h"
 #include "chrome/browser/tracing/navigation_tracing.h"
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 10c3cc3..c5ad2e6a 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -696,8 +696,6 @@
     "input_method/input_method_persistence.h",
     "input_method/input_method_syncer.cc",
     "input_method/input_method_syncer.h",
-    "input_method/input_method_util.cc",
-    "input_method/input_method_util.h",
     "input_method/mode_indicator_controller.cc",
     "input_method/mode_indicator_controller.h",
     "language_preferences.cc",
@@ -1678,7 +1676,6 @@
     "input_method/input_method_engine_unittest.cc",
     "input_method/input_method_manager_impl_unittest.cc",
     "input_method/input_method_persistence_unittest.cc",
-    "input_method/input_method_util_unittest.cc",
     "locale_change_guard_unittest.cc",
     "lock_screen_apps/state_controller_unittest.cc",
     "login/auth/cryptohome_authenticator_unittest.cc",
@@ -1828,8 +1825,6 @@
     "//components/drive/sync/entry_update_performer_unittest.cc",
     "//components/drive/sync/remove_performer_unittest.cc",
     "//components/drive/sync_client_unittest.cc",
-    "//ui/base/ime/chromeos/input_method_whitelist.cc",
-    "//ui/base/ime/chromeos/input_method_whitelist.h",
   ]
 
   public_deps = [
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index 9806ffb0..dcad19e4 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -83,6 +83,7 @@
 #include "media/audio/sounds/sounds_manager.h"
 #include "media/base/media_switches.h"
 #include "services/service_manager/public/cpp/connector.h"
+#include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/keyboard/keyboard_controller.h"
@@ -173,7 +174,6 @@
       notify(notify) {}
 
 ///////////////////////////////////////////////////////////////////////////////
-//
 // AccessibilityManager::PrefHandler
 
 AccessibilityManager::PrefHandler::PrefHandler(const char* pref_path)
@@ -1093,14 +1093,14 @@
       preload_engines_str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
   std::vector<base::StringPiece>::iterator it =
       std::find(preload_engines.begin(), preload_engines.end(),
-                extension_misc::kBrailleImeEngineId);
+                extension_ime_util::kBrailleImeEngineId);
   bool is_enabled = (it != preload_engines.end());
   bool should_be_enabled =
       (spoken_feedback_enabled_ && braille_display_connected_);
   if (is_enabled == should_be_enabled)
     return;
   if (should_be_enabled)
-    preload_engines.push_back(extension_misc::kBrailleImeEngineId);
+    preload_engines.push_back(extension_ime_util::kBrailleImeEngineId);
   else
     preload_engines.erase(it);
   pref_service->SetString(prefs::kLanguagePreloadEngines,
@@ -1123,7 +1123,7 @@
   const chromeos::input_method::InputMethodDescriptor descriptor =
       manager->GetActiveIMEState()->GetCurrentInputMethod();
   braille_ime_current_ =
-      (descriptor.id() == extension_misc::kBrailleImeEngineId);
+      (descriptor.id() == extension_ime_util::kBrailleImeEngineId);
 }
 
 void AccessibilityManager::OnSessionStateChanged() {
@@ -1425,7 +1425,7 @@
       !braille_ime_current_) {
     input_method::InputMethodManager::Get()
         ->GetActiveIMEState()
-        ->ChangeInputMethod(extension_misc::kBrailleImeEngineId,
+        ->ChangeInputMethod(extension_ime_util::kBrailleImeEngineId,
                             false /* show_message */);
   }
 }
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager_browsertest.cc b/chrome/browser/chromeos/accessibility/accessibility_manager_browsertest.cc
index c666b52d..817565a5 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager_browsertest.cc
@@ -34,6 +34,7 @@
 #include "content/public/test/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ime/chromeos/component_extension_ime_manager.h"
+#include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
 
 using chromeos::input_method::InputMethodManager;
@@ -227,7 +228,7 @@
   for (InputMethodDescriptors::const_iterator i = descriptors->begin();
        i != descriptors->end();
        ++i) {
-    if (i->id() == extension_misc::kBrailleImeEngineId)
+    if (i->id() == extension_ime_util::kBrailleImeEngineId)
       return true;
   }
   return false;
@@ -236,7 +237,7 @@
 bool IsBrailleImeCurrent() {
   InputMethodManager* imm = InputMethodManager::Get();
   return imm->GetActiveIMEState()->GetCurrentInputMethod().id() ==
-         extension_misc::kBrailleImeEngineId;
+         extension_ime_util::kBrailleImeEngineId;
 }
 }  // anonymous namespace
 
diff --git a/chrome/browser/chromeos/accessibility/chromevox_panel.cc b/chrome/browser/chromeos/accessibility/chromevox_panel.cc
index 76a9333..dc8381b7 100644
--- a/chrome/browser/chromeos/accessibility/chromevox_panel.cc
+++ b/chrome/browser/chromeos/accessibility/chromevox_panel.cc
@@ -190,7 +190,7 @@
 
   // If we're in full-screen mode, give the panel a height of 0 unless
   // it's active.
-  if (ash::GetRootWindowController(GetRootWindow())
+  if (ash::RootWindowController::ForWindow(GetRootWindow())
           ->GetWindowForFullscreenMode() &&
       !widget_->IsActive()) {
     bounds.set_height(0);
diff --git a/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.cc b/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.cc
index 8aa0cae..e7de3ac 100644
--- a/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.cc
+++ b/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.cc
@@ -4,8 +4,6 @@
 
 #include "chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.h"
 
-#include "ash/shelf/shelf_model.h"
-#include "ash/shell.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/logging.h"
@@ -16,6 +14,7 @@
 #include "chrome/browser/prefs/pref_service_syncable_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
 #include "components/arc/arc_util.h"
@@ -82,7 +81,6 @@
 
 void ArcPlayStoreEnabledPreferenceHandler::OnPreferenceChanged() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
   const bool is_play_store_enabled = IsArcPlayStoreEnabledForProfile(profile_);
   if (!IsArcPlayStoreEnabledPreferenceManagedForProfile(profile_)) {
     // Update UMA only for non-Managed cases.
@@ -93,11 +91,9 @@
       // Remove the pinned Play Store icon launcher in Shelf.
       // This is only for non-Managed cases. In managed cases, it is expected
       // to be "disabled" rather than "removed", so keep it here.
-      auto* shelf_model = ash::Shell::HasInstance()
-                              ? ash::Shell::Get()->shelf_model()
-                              : nullptr;
-      if (shelf_model)
-        shelf_model->UnpinAppWithID(kPlayStoreAppId);
+      auto* chrome_launcher_controller = ChromeLauncherController::instance();
+      if (chrome_launcher_controller)
+        chrome_launcher_controller->UnpinAppWithID(kPlayStoreAppId);
     }
   }
 
diff --git a/chrome/browser/chromeos/ash_config.cc b/chrome/browser/chromeos/ash_config.cc
index 4b33bf6..1eca0a0 100644
--- a/chrome/browser/chromeos/ash_config.cc
+++ b/chrome/browser/chromeos/ash_config.cc
@@ -10,14 +10,27 @@
 
 namespace chromeos {
 
-ash::Config GetAshConfig() {
-  if (!service_manager::ServiceManagerIsRemote())
-    return ash::Config::CLASSIC;
+namespace {
 
-  return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-             switches::kMusConfig) == switches::kMash
-             ? ash::Config::MASH
-             : ash::Config::MUS;
+ash::Config ComputeAshConfig() {
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  std::string flag = command_line->GetSwitchValueASCII(switches::kMusConfig);
+  ash::Config config = ash::Config::CLASSIC;
+  if (command_line->HasSwitch("mash") || flag == switches::kMash)
+    config = ash::Config::MASH;
+  else if (command_line->HasSwitch("mus") || flag == switches::kMus)
+    config = ash::Config::MUS;
+  VLOG_IF(1, config != ash::Config::CLASSIC &&
+                 !service_manager::ServiceManagerIsRemote())
+      << " Running with a simulated ash config (likely for testing).";
+  return config;
+}
+
+}  // namespace
+
+ash::Config GetAshConfig() {
+  static const ash::Config config = ComputeAshConfig();
+  return config;
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/base/locale_util.cc b/chrome/browser/chromeos/base/locale_util.cc
index 8e4bf4b..4723210 100644
--- a/chrome/browser/chromeos/base/locale_util.cc
+++ b/chrome/browser/chromeos/base/locale_util.cc
@@ -9,11 +9,11 @@
 
 #include "base/task_scheduler/post_task.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/platform_font_linux.h"
 
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 354d48d1..15af8d2 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -54,7 +54,6 @@
 #include "chrome/browser/chromeos/extensions/extension_volume_observer.h"
 #include "chrome/browser/chromeos/external_metrics.h"
 #include "chrome/browser/chromeos/input_method/input_method_configuration.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/language_preferences.h"
 #include "chrome/browser/chromeos/lock_screen_apps/state_controller.h"
 #include "chrome/browser/chromeos/login/helper.h"
@@ -163,6 +162,7 @@
 #include "third_party/cros_system_api/dbus/service_constants.h"
 #include "ui/base/ime/chromeos/ime_keyboard.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 #include "ui/base/touch/touch_device.h"
 #include "ui/chromeos/events/event_rewriter_chromeos.h"
 #include "ui/chromeos/events/pref_names.h"
diff --git a/chrome/browser/chromeos/extensions/input_method_api.cc b/chrome/browser/chromeos/extensions/input_method_api.cc
index 372286b..f012686 100644
--- a/chrome/browser/chromeos/extensions/input_method_api.cc
+++ b/chrome/browser/chromeos/extensions/input_method_api.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/chromeos/extensions/dictionary_event_router.h"
 #include "chrome/browser/chromeos/extensions/ime_menu_event_router.h"
 #include "chrome/browser/chromeos/extensions/input_method_event_router.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/extensions/api/input_ime/input_ime_api.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/spellchecker/spellcheck_factory.h"
@@ -39,6 +38,7 @@
 #include "ui/base/ime/chromeos/ime_keyboard.h"
 #include "ui/base/ime/chromeos/input_method_descriptor.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 #include "ui/keyboard/keyboard_controller.h"
 #include "ui/keyboard/keyboard_util.h"
 
diff --git a/chrome/browser/chromeos/extensions/input_method_apitest_chromeos.cc b/chrome/browser/chromeos/extensions/input_method_apitest_chromeos.cc
index 3344925..f5cfe23c 100644
--- a/chrome/browser/chromeos/extensions/input_method_apitest_chromeos.cc
+++ b/chrome/browser/chromeos/extensions/input_method_apitest_chromeos.cc
@@ -9,7 +9,6 @@
 #include "base/command_line.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/chromeos/extensions/input_method_event_router.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
@@ -18,13 +17,14 @@
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/common/content_switches.h"
-#include "extensions/common/switches.h"
 #include "extensions/browser/api/test/test_api.h"
 #include "extensions/browser/notification_types.h"
+#include "extensions/common/switches.h"
 #include "extensions/test/extension_test_message_listener.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 #include "ui/base/ime/chromeos/input_method_whitelist.h"
 #include "ui/base/ime/ime_bridge.h"
 
diff --git a/chrome/browser/chromeos/input_method/accessibility.cc b/chrome/browser/chromeos/input_method/accessibility.cc
index 084f720..2df2614 100644
--- a/chrome/browser/chromeos/input_method/accessibility.cc
+++ b/chrome/browser/chromeos/input_method/accessibility.cc
@@ -6,9 +6,9 @@
 
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 
 namespace chromeos {
 namespace input_method {
diff --git a/chrome/browser/chromeos/input_method/browser_state_monitor.cc b/chrome/browser/chromeos/input_method/browser_state_monitor.cc
index a0dbdaee..d4fde58 100644
--- a/chrome/browser/chromeos/input_method/browser_state_monitor.cc
+++ b/chrome/browser/chromeos/input_method/browser_state_monitor.cc
@@ -6,9 +6,9 @@
 
 #include "base/logging.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "content/public/browser/notification_service.h"
 #include "ui/base/ime/chromeos/input_method_delegate.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 
 namespace chromeos {
 namespace input_method {
diff --git a/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc b/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc
index fe160978..ef3dfbc 100644
--- a/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc
@@ -76,7 +76,7 @@
 #endif
     {
         // Braille hardware keyboard IME that works together with ChromeVox.
-        extension_misc::kBrailleImeExtensionId, IDR_BRAILLE_MANIFEST,
+        extension_ime_util::kBrailleImeExtensionId, IDR_BRAILLE_MANIFEST,
     },
 };
 
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.h b/chrome/browser/chromeos/input_method/input_method_manager_impl.h
index cf75325..dfd8fdc4 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl.h
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.h
@@ -16,10 +16,10 @@
 #include "base/observer_list.h"
 #include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/input_method/candidate_window_controller.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
 #include "chrome/browser/profiles/profile.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 #include "ui/base/ime/chromeos/input_method_whitelist.h"
 #include "ui/base/ime/ime_engine_handler_interface.h"
 
diff --git a/chrome/browser/chromeos/input_method/input_method_persistence.cc b/chrome/browser/chromeos/input_method/input_method_persistence.cc
index 3ebd98e7..ed47d67 100644
--- a/chrome/browser/chromeos/input_method/input_method_persistence.cc
+++ b/chrome/browser/chromeos/input_method/input_method_persistence.cc
@@ -7,13 +7,13 @@
 #include "base/logging.h"
 #include "base/sys_info.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/language_preferences.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 
 namespace chromeos {
 namespace input_method {
diff --git a/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.cc
index e155343..1b49fe0e 100644
--- a/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.cc
@@ -6,7 +6,7 @@
 
 #include <utility>
 
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 
 namespace chromeos {
 namespace input_method {
diff --git a/chrome/browser/chromeos/input_method/mode_indicator_browsertest.cc b/chrome/browser/chromeos/input_method/mode_indicator_browsertest.cc
index 396a4b9..d9c843b7 100644
--- a/chrome/browser/chromeos/input_method/mode_indicator_browsertest.cc
+++ b/chrome/browser/chromeos/input_method/mode_indicator_browsertest.cc
@@ -8,7 +8,6 @@
 
 #include "ash/shell.h"
 #include "base/macros.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/input_method/mode_indicator_controller.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/test/browser_test_utils.h"
@@ -18,6 +17,7 @@
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/ime_candidate_window_handler_interface.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 #include "ui/base/ime/chromeos/input_method_whitelist.h"
 #include "ui/base/ime/ime_bridge.h"
 #include "ui/base/ime/input_method_factory.h"
diff --git a/chrome/browser/chromeos/input_method/mode_indicator_controller.cc b/chrome/browser/chromeos/input_method/mode_indicator_controller.cc
index 6eb442eb..44869f0 100644
--- a/chrome/browser/chromeos/input_method/mode_indicator_controller.cc
+++ b/chrome/browser/chromeos/input_method/mode_indicator_controller.cc
@@ -9,7 +9,7 @@
 #include "ash/wm/window_util.h"
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 #include "ui/chromeos/ime/mode_indicator_view.h"
 
 namespace chromeos {
diff --git a/chrome/browser/chromeos/login/oobe_localization_browsertest.cc b/chrome/browser/chromeos/login/oobe_localization_browsertest.cc
index d7444cd8..359f442 100644
--- a/chrome/browser/chromeos/login/oobe_localization_browsertest.cc
+++ b/chrome/browser/chromeos/login/oobe_localization_browsertest.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/customization/customization_document.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
 #include "chrome/browser/chromeos/login/login_wizard.h"
 #include "chrome/browser/chromeos/login/screens/network_screen.h"
@@ -33,6 +32,7 @@
 #include "content/public/test/test_utils.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 #include "ui/base/ime/chromeos/input_method_whitelist.h"
 
 namespace base {
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index 607e9fa..e1820c0 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -37,7 +37,6 @@
 #include "chrome/browser/chromeos/boot_times_recorder.h"
 #include "chrome/browser/chromeos/first_run/first_run.h"
 #include "chrome/browser/chromeos/first_run/goodies_displayer.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/login/auth/chrome_cryptohome_authenticator.h"
 #include "chrome/browser/chromeos/login/chrome_restart_request.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
@@ -120,6 +119,7 @@
 #include "rlz/features/features.h"
 #include "ui/base/ime/chromeos/input_method_descriptor.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 #include "ui/message_center/message_center.h"
 #include "url/gurl.h"
 
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
index 0a5ae56f..bd4afc4a 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
@@ -34,7 +34,6 @@
 #include "chrome/browser/chromeos/boot_times_recorder.h"
 #include "chrome/browser/chromeos/first_run/drive_first_run_controller.h"
 #include "chrome/browser/chromeos/first_run/first_run.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/language_preferences.h"
 #include "chrome/browser/chromeos/login/arc_kiosk_controller.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
@@ -93,6 +92,7 @@
 #include "ui/aura/window.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/compositor/layer.h"
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
index 63fb68e..38a541ba 100644
--- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -43,7 +43,6 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h"
 #include "chrome/browser/chromeos/extensions/external_cache.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
 #include "chrome/browser/chromeos/login/screens/base_screen.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
@@ -144,6 +143,7 @@
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/input_method_descriptor.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/gfx/image/image_skia.h"
diff --git a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
index b2c3ae92..935a058 100644
--- a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
+++ b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
@@ -37,10 +37,10 @@
 #include "ui/base/l10n/l10n_util_collator.h"
 
 #if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "ui/base/ime/chromeos/component_extension_ime_manager.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 #endif
 
 namespace extensions {
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc
index a2765c3c..a3b1691 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -35,9 +35,9 @@
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/extensions/window_controller.h"
 #include "chrome/browser/extensions/window_controller_list.h"
-#include "chrome/browser/memory/tab_manager.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/resource_coordinator/tab_manager.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
 #include "chrome/browser/translate/chrome_translate_client.h"
 #include "chrome/browser/ui/apps/chrome_app_delegate.h"
@@ -883,7 +883,8 @@
     TabStripModel* tab_strip = browser->tab_strip_model();
     for (int i = 0; i < tab_strip->count(); ++i) {
       WebContents* web_contents = tab_strip->GetWebContentsAt(i);
-      memory::TabManager* tab_manager = g_browser_process->GetTabManager();
+      resource_coordinator::TabManager* tab_manager =
+          g_browser_process->GetTabManager();
 
       if (index > -1 && i != index)
         continue;
diff --git a/chrome/browser/extensions/api/tabs/tabs_event_router.cc b/chrome/browser/extensions/api/tabs/tabs_event_router.cc
index 53fa5a61..d113fba 100644
--- a/chrome/browser/extensions/api/tabs/tabs_event_router.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_event_router.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/extensions/api/tabs/tabs_windows_api.h"
 #include "chrome/browser/extensions/api/tabs/windows_event_router.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
-#include "chrome/browser/memory/tab_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
diff --git a/chrome/browser/extensions/api/tabs/tabs_event_router.h b/chrome/browser/extensions/api/tabs/tabs_event_router.h
index 340498b..c100285f6 100644
--- a/chrome/browser/extensions/api/tabs/tabs_event_router.h
+++ b/chrome/browser/extensions/api/tabs/tabs_event_router.h
@@ -12,8 +12,8 @@
 #include "base/macros.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/extensions/api/tabs/tabs_api.h"
-#include "chrome/browser/memory/tab_manager.h"
-#include "chrome/browser/memory/tab_manager_observer.h"
+#include "chrome/browser/resource_coordinator/tab_manager.h"
+#include "chrome/browser/resource_coordinator/tab_manager_observer.h"
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "chrome/browser/ui/browser_tab_strip_tracker.h"
 #include "chrome/browser/ui/browser_tab_strip_tracker_delegate.h"
@@ -42,7 +42,7 @@
                         public chrome::BrowserListObserver,
                         public favicon::FaviconDriverObserver,
                         public zoom::ZoomObserver,
-                        public memory::TabManagerObserver {
+                        public resource_coordinator::TabManagerObserver {
  public:
   explicit TabsEventRouter(Profile* profile);
   ~TabsEventRouter() override;
@@ -93,7 +93,7 @@
                         bool icon_url_changed,
                         const gfx::Image& image) override;
 
-  // memory::TabManagerObserver:
+  // resource_coordinator::TabManagerObserver:
   void OnDiscardedStateChange(content::WebContents* contents,
                               bool is_discarded) override;
   void OnAutoDiscardableStateChange(content::WebContents* contents,
@@ -207,7 +207,7 @@
 
   BrowserTabStripTracker browser_tab_strip_tracker_;
 
-  ScopedObserver<memory::TabManager, TabsEventRouter>
+  ScopedObserver<resource_coordinator::TabManager, TabsEventRouter>
       tab_manager_scoped_observer_;
 
   DISALLOW_COPY_AND_ASSIGN(TabsEventRouter);
diff --git a/chrome/browser/extensions/api/tabs/tabs_test.cc b/chrome/browser/extensions/api/tabs/tabs_test.cc
index f14ef64..55dd8156 100644
--- a/chrome/browser/extensions/api/tabs/tabs_test.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_test.cc
@@ -27,9 +27,9 @@
 #include "chrome/browser/extensions/extension_function_test_utils.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/window_controller.h"
-#include "chrome/browser/memory/tab_manager.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/resource_coordinator/tab_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -1317,7 +1317,8 @@
 // TODO(georgesak): change this browsertest to an unittest.
 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DiscardedProperty) {
   ASSERT_TRUE(g_browser_process && g_browser_process->GetTabManager());
-  memory::TabManager* tab_manager = g_browser_process->GetTabManager();
+  resource_coordinator::TabManager* tab_manager =
+      g_browser_process->GetTabManager();
 
   // Create two aditional tabs.
   content::OpenURLParams params(GURL(url::kAboutBlankURL), content::Referrer(),
@@ -1459,7 +1460,8 @@
           discard.get(), base::StringPrintf("[%u]", tab_id), browser())));
 
   // Confirms that TabManager sees the tab as discarded.
-  memory::TabManager* tab_manager = g_browser_process->GetTabManager();
+  resource_coordinator::TabManager* tab_manager =
+      g_browser_process->GetTabManager();
   web_contents = browser()->tab_strip_model()->GetWebContentsAt(1);
   EXPECT_TRUE(tab_manager->IsTabDiscarded(web_contents));
 
@@ -1526,7 +1528,8 @@
   discard->set_extension(extension.get());
 
   // Disable protection time to discard the tab without passing id.
-  memory::TabManager* tab_manager = g_browser_process->GetTabManager();
+  resource_coordinator::TabManager* tab_manager =
+      g_browser_process->GetTabManager();
   tab_manager->set_minimum_protection_time_for_tests(
       base::TimeDelta::FromSeconds(0));
 
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc
index 2d4a581..1724d3e 100644
--- a/chrome/browser/extensions/extension_tab_util.cc
+++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -17,8 +17,8 @@
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/extensions/window_controller.h"
 #include "chrome/browser/extensions/window_controller_list.h"
-#include "chrome/browser/memory/tab_manager.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/resource_coordinator/tab_manager.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 056ca964..7fe282edf 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2921,12 +2921,6 @@
 const char kNewZipUnpackerDescription[] =
     "New ZIP unpacker flow, based on the File System Provider API.";
 
-const char kShowArcFilesAppName[] = "Show Android Files app";
-
-const char kShowArcFilesAppDescription[] =
-    "Show Android Files app in Chrome OS launcher. This is only effective "
-    "on a device with access to Play Store.";
-
 const char kOfficeEditingComponentAppName[] =
     "Office Editing for Docs, Sheets & Slides";
 
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index d9e11a9..f30e45f 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1344,9 +1344,6 @@
 extern const char kOfficeEditingComponentAppName[];
 extern const char kOfficeEditingComponentAppDescription[];
 
-extern const char kShowArcFilesAppName[];
-extern const char kShowArcFilesAppDescription[];
-
 extern const char kSmartVirtualKeyboardName[];
 extern const char kSmartVirtualKeyboardDescription[];
 
diff --git a/chrome/browser/media/DEPS b/chrome/browser/media/DEPS
index ddf2cca..6267b4e 100644
--- a/chrome/browser/media/DEPS
+++ b/chrome/browser/media/DEPS
@@ -1,8 +1,9 @@
 include_rules = [
-  "+device/power_save_blocker",
+  "+device/wake_lock/public/interfaces",
   "+media/audio",
   "+media/base",
   "+media/cast",
   "+media/media_features.h",
   "+media/mojo/interfaces",
+  "+services/device/public/interfaces",
 ]
diff --git a/chrome/browser/media/cast_transport_host_filter.cc b/chrome/browser/media/cast_transport_host_filter.cc
index 89feefd..df512f74 100644
--- a/chrome/browser/media/cast_transport_host_filter.cc
+++ b/chrome/browser/media/cast_transport_host_filter.cc
@@ -12,8 +12,12 @@
 #include "chrome/common/cast_messages.h"
 #include "components/net_log/chrome_net_log.h"
 #include "content/public/browser/browser_thread.h"
-#include "device/power_save_blocker/power_save_blocker.h"
+#include "content/public/common/service_manager_connection.h"
+#include "device/wake_lock/public/interfaces/wake_lock_provider.mojom.h"
 #include "media/cast/net/cast_transport.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "services/device/public/interfaces/constants.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 namespace {
 
@@ -100,6 +104,16 @@
   DISALLOW_COPY_AND_ASSIGN(RtcpClient);
 };
 
+void BindConnectorRequest(
+    service_manager::mojom::ConnectorRequest connector_request) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK(content::ServiceManagerConnection::GetForProcess());
+
+  content::ServiceManagerConnection::GetForProcess()
+      ->GetConnector()
+      ->BindConnectorRequest(std::move(connector_request));
+}
+
 }  // namespace
 
 namespace cast {
@@ -148,17 +162,10 @@
                                     const net::IPEndPoint& local_end_point,
                                     const net::IPEndPoint& remote_end_point,
                                     const base::DictionaryValue& options) {
-  if (!power_save_blocker_) {
+  if (id_map_.IsEmpty()) {
     DVLOG(1) << ("Preventing the application from being suspended while one or "
                  "more transports are active for Cast Streaming.");
-    power_save_blocker_.reset(new device::PowerSaveBlocker(
-        device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
-        device::PowerSaveBlocker::kReasonOther,
-        "Cast is streaming content to a remote receiver",
-        content::BrowserThread::GetTaskRunnerForThread(
-            content::BrowserThread::UI),
-        content::BrowserThread::GetTaskRunnerForThread(
-            content::BrowserThread::FILE)));
+    GetWakeLockService()->RequestWakeLock();
   }
 
   if (id_map_.Lookup(channel_id)) {
@@ -201,10 +208,10 @@
   stream_id_map_.erase(channel_id);
 
   if (id_map_.IsEmpty()) {
-    DVLOG_IF(1, power_save_blocker_) <<
-        ("Releasing the block on application suspension since no transports "
-         "are active anymore for Cast Streaming.");
-    power_save_blocker_.reset();
+    DVLOG(1)
+        << ("Releasing the block on application suspension since no transports "
+            "are active anymore for Cast Streaming.");
+    GetWakeLockService()->CancelWakeLock();
   }
 }
 
@@ -390,4 +397,32 @@
                              std::vector<media::cast::PacketEvent>(), events));
 }
 
+device::mojom::WakeLockService* CastTransportHostFilter::GetWakeLockService() {
+  // Here is a lazy binding, and will not reconnect after connection error.
+  if (!wake_lock_) {
+    device::mojom::WakeLockServiceRequest request =
+        mojo::MakeRequest(&wake_lock_);
+
+    // Service manager connection might be not initialized in some testing
+    // contexts.
+    if (content::ServiceManagerConnection::GetForProcess()) {
+      service_manager::mojom::ConnectorRequest connector_request;
+      auto connector = service_manager::Connector::Create(&connector_request);
+
+      content::BrowserThread::PostTask(
+          content::BrowserThread::UI, FROM_HERE,
+          base::BindOnce(&BindConnectorRequest, std::move(connector_request)));
+
+      device::mojom::WakeLockProviderPtr wake_lock_provider;
+      connector->BindInterface(device::mojom::kServiceName,
+                               mojo::MakeRequest(&wake_lock_provider));
+      wake_lock_provider->GetWakeLockWithoutContext(
+          device::mojom::WakeLockType::PreventAppSuspension,
+          device::mojom::WakeLockReason::ReasonOther,
+          "Cast is streaming content to a remote receiver", std::move(request));
+    }
+  }
+  return wake_lock_.get();
+}
+
 }  // namespace cast
diff --git a/chrome/browser/media/cast_transport_host_filter.h b/chrome/browser/media/cast_transport_host_filter.h
index 82aac94..56dc3ff2 100644
--- a/chrome/browser/media/cast_transport_host_filter.h
+++ b/chrome/browser/media/cast_transport_host_filter.h
@@ -15,15 +15,12 @@
 #include "base/time/default_tick_clock.h"
 #include "chrome/browser/media/cast_remoting_sender.h"
 #include "content/public/browser/browser_message_filter.h"
+#include "device/wake_lock/public/interfaces/wake_lock_service.mojom.h"
 #include "media/cast/cast_sender.h"
 #include "media/cast/logging/logging_defines.h"
 #include "media/cast/net/cast_transport.h"
 #include "media/cast/net/udp_transport.h"
 
-namespace device {
-class PowerSaveBlocker;
-}  // namespace device
-
 namespace cast {
 
 class CastTransportHostFilter : public content::BrowserMessageFilter {
@@ -93,15 +90,18 @@
       int32_t channel_id,
       const std::vector<media::cast::FrameEvent>& events);
 
+  device::mojom::WakeLockService* GetWakeLockService();
+
   IDMap<std::unique_ptr<media::cast::CastTransport>> id_map_;
 
   // Clock used by Cast transport.
   base::DefaultTickClock clock_;
 
-  // While |id_map_| is non-empty, hold an instance of
-  // device::PowerSaveBlocker.  This prevents Chrome from being suspended while
-  // remoting content.
-  std::unique_ptr<device::PowerSaveBlocker> power_save_blocker_;
+  // While |id_map_| is non-empty, we use |wake_lock_| to request and
+  // hold a wake lock. This prevents Chrome from being suspended while remoting
+  // content. If any wake lock is held upon destruction, it's implicitly
+  // canceled when this object is destroyed.
+  device::mojom::WakeLockServicePtr wake_lock_;
 
   // This map records all active remoting senders. It uses the unique RTP
   // stream ID as the key.
diff --git a/chrome/browser/memory/chrome_memory_coordinator_delegate.cc b/chrome/browser/memory/chrome_memory_coordinator_delegate.cc
index bac13e5c..4e82f57 100644
--- a/chrome/browser/memory/chrome_memory_coordinator_delegate.cc
+++ b/chrome/browser/memory/chrome_memory_coordinator_delegate.cc
@@ -6,7 +6,7 @@
 
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/memory/tab_manager.h"
+#include "chrome/browser/resource_coordinator/tab_manager.h"
 
 namespace memory {
 
diff --git a/chrome/browser/memory/DEPS b/chrome/browser/resource_coordinator/DEPS
similarity index 100%
rename from chrome/browser/memory/DEPS
rename to chrome/browser/resource_coordinator/DEPS
diff --git a/chrome/browser/resource_coordinator/OWNERS b/chrome/browser/resource_coordinator/OWNERS
index ee9a18a..7dba98a 100644
--- a/chrome/browser/resource_coordinator/OWNERS
+++ b/chrome/browser/resource_coordinator/OWNERS
@@ -1 +1,4 @@
-file://services/resource_coordinator/OWNERS
\ No newline at end of file
+file://services/resource_coordinator/OWNERS
+
+# ChromeOS tab manager related implementation.
+per-file *chromeos*=cylee@chromium.org
\ No newline at end of file
diff --git a/chrome/browser/memory/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc
similarity index 98%
rename from chrome/browser/memory/tab_manager.cc
rename to chrome/browser/resource_coordinator/tab_manager.cc
index 0d161da8..c2b5150 100644
--- a/chrome/browser/memory/tab_manager.cc
+++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/memory/tab_manager.h"
+#include "chrome/browser/resource_coordinator/tab_manager.h"
 
 #include <stddef.h>
 
@@ -32,9 +32,9 @@
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h"
 #include "chrome/browser/memory/oom_memory_details.h"
-#include "chrome/browser/memory/tab_manager_observer.h"
-#include "chrome/browser/memory/tab_manager_web_contents_data.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/resource_coordinator/tab_manager_observer.h"
+#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -56,7 +56,7 @@
 #if defined(OS_CHROMEOS)
 #include "ash/multi_profile_uma.h"
 #include "ash/shell_port.h"
-#include "chrome/browser/memory/tab_manager_delegate_chromeos.h"
+#include "chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.h"
 #include "components/user_manager/user_manager.h"
 #endif
 
@@ -65,7 +65,7 @@
 using content::BrowserThread;
 using content::WebContents;
 
-namespace memory {
+namespace resource_coordinator {
 namespace {
 
 // The default interval in seconds after which to adjust the oom_score_adj
@@ -156,8 +156,8 @@
                         this, &TabManager::UpdateTimerCallback);
   }
 
-  // MemoryPressureMonitor is not implemented on Linux so far and tabs are never
-  // discarded.
+// MemoryPressureMonitor is not implemented on Linux so far and tabs are never
+// discarded.
 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
   if (!recent_tab_discard_timer_.IsRunning()) {
     recent_tab_discard_timer_.Start(
@@ -334,7 +334,7 @@
 void TabManager::LogMemory(const std::string& title,
                            const base::Closure& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  OomMemoryDetails::Log(title, callback);
+  memory::OomMemoryDetails::Log(title, callback);
 }
 
 void TabManager::set_test_tick_clock(base::TickClock* test_tick_clock) {
@@ -875,4 +875,4 @@
 #endif
 }
 
-}  // namespace memory
+}  // namespace resource_coordinator
diff --git a/chrome/browser/memory/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h
similarity index 97%
rename from chrome/browser/memory/tab_manager.h
rename to chrome/browser/resource_coordinator/tab_manager.h
index 23c5c5f..72fa655 100644
--- a/chrome/browser/memory/tab_manager.h
+++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_MEMORY_TAB_MANAGER_H_
-#define CHROME_BROWSER_MEMORY_TAB_MANAGER_H_
+#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_H_
+#define CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_H_
 
 #include <stdint.h>
 
@@ -22,8 +22,8 @@
 #include "base/strings/string16.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
-#include "chrome/browser/memory/tab_manager_observer.h"
-#include "chrome/browser/memory/tab_stats.h"
+#include "chrome/browser/resource_coordinator/tab_manager_observer.h"
+#include "chrome/browser/resource_coordinator/tab_stats.h"
 #include "chrome/browser/ui/browser_tab_strip_tracker.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 
@@ -39,7 +39,7 @@
 class WebContents;
 }
 
-namespace memory {
+namespace resource_coordinator {
 
 #if defined(OS_CHROMEOS)
 class TabManagerDelegate;
@@ -371,6 +371,6 @@
   DISALLOW_COPY_AND_ASSIGN(TabManager);
 };
 
-}  // namespace memory
+}  // namespace resource_coordinator
 
-#endif  // CHROME_BROWSER_MEMORY_TAB_MANAGER_H_
+#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_H_
diff --git a/chrome/browser/memory/tab_manager_browsertest.cc b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
similarity index 98%
rename from chrome/browser/memory/tab_manager_browsertest.cc
rename to chrome/browser/resource_coordinator/tab_manager_browsertest.cc
index cfe3b33..331e240 100644
--- a/chrome/browser/memory/tab_manager_browsertest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
@@ -10,8 +10,8 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h"
-#include "chrome/browser/memory/tab_manager.h"
-#include "chrome/browser/memory/tab_manager_web_contents_data.h"
+#include "chrome/browser/resource_coordinator/tab_manager.h"
+#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
@@ -33,10 +33,9 @@
 
 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
 
-namespace memory {
+namespace resource_coordinator {
 
-class TabManagerTest : public InProcessBrowserTest {
-};
+class TabManagerTest : public InProcessBrowserTest {};
 
 bool ObserveNavEntryCommitted(const GURL& expected_url,
                               const content::NotificationSource& source,
@@ -582,6 +581,6 @@
   tsm->CloseAllTabs();
 }
 
-}  // namespace memory
+}  // namespace resource_coordinator
 
 #endif  // OS_WIN || OS_MAXOSX || OS_LINUX
diff --git a/chrome/browser/memory/tab_manager_delegate_chromeos.cc b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc
similarity index 94%
rename from chrome/browser/memory/tab_manager_delegate_chromeos.cc
rename to chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc
index 5a075394..1fbefed6 100644
--- a/chrome/browser/memory/tab_manager_delegate_chromeos.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/memory/tab_manager_delegate_chromeos.h"
+#include "chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.h"
 
 #include <math.h>
 #include <stdint.h>
@@ -28,7 +28,7 @@
 #include "chrome/browser/chromeos/arc/process/arc_process.h"
 #include "chrome/browser/chromeos/arc/process/arc_process_service.h"
 #include "chrome/browser/memory/memory_kills_monitor.h"
-#include "chrome/browser/memory/tab_stats.h"
+#include "chrome/browser/resource_coordinator/tab_stats.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -52,7 +52,7 @@
 using base::TimeTicks;
 using content::BrowserThread;
 
-namespace memory {
+namespace resource_coordinator {
 namespace {
 
 // When switching to a new tab the tab's renderer's OOM score needs to be
@@ -105,8 +105,8 @@
 }
 
 // TabManagerDelegate::Candidate implementation.
-std::ostream& operator<<(
-    std::ostream& out, const TabManagerDelegate::Candidate& candidate) {
+std::ostream& operator<<(std::ostream& out,
+                         const TabManagerDelegate::Candidate& candidate) {
   if (candidate.app()) {
     out << "app " << *candidate.app();
   } else if (candidate.tab()) {
@@ -214,8 +214,8 @@
 // TabManagerDelegate::MemoryStat implementation.
 
 // static
-int TabManagerDelegate::MemoryStat::ReadIntFromFile(
-    const char* file_name, const int default_val) {
+int TabManagerDelegate::MemoryStat::ReadIntFromFile(const char* file_name,
+                                                    const int default_val) {
   std::string file_string;
   if (!base::ReadFileToString(base::FilePath(file_name), &file_string)) {
     LOG(WARNING) << "Unable to read file" << file_name;
@@ -223,8 +223,7 @@
   }
   int val = default_val;
   if (!base::StringToInt(
-          base::TrimWhitespaceASCII(file_string, base::TRIM_TRAILING),
-          &val)) {
+          base::TrimWhitespaceASCII(file_string, base::TRIM_TRAILING), &val)) {
     LOG(WARNING) << "Unable to parse string" << file_string;
     return default_val;
   }
@@ -236,8 +235,8 @@
   static const int kDefaultLowMemoryMarginMb = 50;
   static const char kLowMemoryMarginConfig[] =
       "/sys/kernel/mm/chromeos-low_mem/margin";
-  return ReadIntFromFile(
-      kLowMemoryMarginConfig, kDefaultLowMemoryMarginMb) * 1024;
+  return ReadIntFromFile(kLowMemoryMarginConfig, kDefaultLowMemoryMarginMb) *
+         1024;
 }
 
 // The logic of available memory calculation is copied from
@@ -260,10 +259,9 @@
   // kernel to calculate how much memory should be released. In the future,
   // kernel should try to report the amount of memory to release directly to
   // eliminate the duplication here.
-  const int available_mem_kb = system_mem.free +
-      file_mem_kb - system_mem.dirty - min_filelist_kb +
-      system_mem.swap_free / kRamVsSwapWeight -
-      min_free_kb;
+  const int available_mem_kb =
+      system_mem.free + file_mem_kb - system_mem.dirty - min_filelist_kb +
+      system_mem.swap_free / kRamVsSwapWeight - min_free_kb;
 
   return LowMemoryMarginKB() - available_mem_kb;
 }
@@ -279,8 +277,7 @@
 
 TabManagerDelegate::TabManagerDelegate(
     const base::WeakPtr<TabManager>& tab_manager)
-  : TabManagerDelegate(tab_manager, new MemoryStat()) {
-}
+    : TabManagerDelegate(tab_manager, new MemoryStat()) {}
 
 TabManagerDelegate::TabManagerDelegate(
     const base::WeakPtr<TabManager>& tab_manager,
@@ -340,8 +337,8 @@
     // here.
     focus_process_score_adjust_timer_.Start(
         FROM_HERE,
-        TimeDelta::FromMilliseconds(kFocusedProcessScoreAdjustIntervalMs),
-        this, &TabManagerDelegate::ScheduleEarlyOomPrioritiesAdjustment);
+        TimeDelta::FromMilliseconds(kFocusedProcessScoreAdjustIntervalMs), this,
+        &TabManagerDelegate::ScheduleEarlyOomPrioritiesAdjustment);
   }
   if (arc::IsArcAppWindow(lost_active)) {
     // Do not bother adjusting OOM score if the ARC window is deactivated
@@ -361,8 +358,7 @@
 
 // If able to get the list of ARC procsses, prioritize tabs and apps as a whole.
 // Otherwise try to kill tabs only.
-void TabManagerDelegate::LowMemoryKill(
-    const TabStatsList& tab_list) {
+void TabManagerDelegate::LowMemoryKill(const TabStatsList& tab_list) {
   arc::ArcProcessService* arc_process_service = arc::ArcProcessService::Get();
   if (arc_process_service &&
       arc_process_service->RequestAppProcessList(
@@ -429,8 +425,8 @@
     // would be replaced by a new task.
     focus_process_score_adjust_timer_.Start(
         FROM_HERE,
-        TimeDelta::FromMilliseconds(kFocusedProcessScoreAdjustIntervalMs),
-        this, &TabManagerDelegate::OnFocusTabScoreAdjustmentTimeout);
+        TimeDelta::FromMilliseconds(kFocusedProcessScoreAdjustIntervalMs), this,
+        &TabManagerDelegate::OnFocusTabScoreAdjustmentTimeout);
   }
 }
 
@@ -463,8 +459,8 @@
       if (visible) {
         content::RenderProcessHost* render_host =
             content::Source<content::RenderWidgetHost>(source)
-            .ptr()
-            ->GetProcess();
+                .ptr()
+                ->GetProcess();
         AdjustFocusedTabScore(render_host->GetHandle());
       }
       // Do not handle the "else" case when it changes to invisible because
@@ -557,12 +553,10 @@
 
 bool TabManagerDelegate::KillTab(int64_t tab_id) {
   // Check |tab_manager_| is alive before taking tabs into consideration.
-  return tab_manager_ &&
-      tab_manager_->CanDiscardTab(tab_id) &&
-      tab_manager_->DiscardTabById(tab_id);
+  return tab_manager_ && tab_manager_->CanDiscardTab(tab_id) &&
+         tab_manager_->DiscardTabById(tab_id);
 }
 
-
 chromeos::DebugDaemonClient* TabManagerDelegate::GetDebugDaemonClient() {
   return chromeos::DBusThreadManager::Get()->GetDebugDaemonClient();
 }
@@ -612,7 +606,8 @@
       if (KillArcProcess(it->app()->nspid())) {
         recently_killed_arc_processes_[it->app()->process_name()] = now;
         target_memory_to_free_kb -= estimated_memory_freed_kb;
-        MemoryKillsMonitor::LogLowMemoryKill("APP", estimated_memory_freed_kb);
+        memory::MemoryKillsMonitor::LogLowMemoryKill("APP",
+                                                     estimated_memory_freed_kb);
         MEMORY_LOG(ERROR) << "Killed app " << it->app()->process_name() << " ("
                           << it->app()->pid() << ")"
                           << ", estimated " << estimated_memory_freed_kb
@@ -629,7 +624,8 @@
           mem_stat_->EstimatedMemoryFreedKB(it->tab()->renderer_handle);
       if (KillTab(tab_id)) {
         target_memory_to_free_kb -= estimated_memory_freed_kb;
-        MemoryKillsMonitor::LogLowMemoryKill("TAB", estimated_memory_freed_kb);
+        memory::MemoryKillsMonitor::LogLowMemoryKill("TAB",
+                                                     estimated_memory_freed_kb);
         MEMORY_LOG(ERROR) << "Killed tab " << it->tab()->title << " ("
                           << it->tab()->renderer_handle << "), estimated "
                           << estimated_memory_freed_kb << " KB freed";
@@ -768,9 +764,9 @@
   }
 
   if (oom_scores_to_change.size()) {
-    GetDebugDaemonClient()->SetOomScoreAdj(
-        oom_scores_to_change, base::Bind(&OnSetOomScoreAdj));
+    GetDebugDaemonClient()->SetOomScoreAdj(oom_scores_to_change,
+                                           base::Bind(&OnSetOomScoreAdj));
   }
 }
 
-}  // namespace memory
+}  // namespace resource_coordinator
diff --git a/chrome/browser/memory/tab_manager_delegate_chromeos.h b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.h
similarity index 95%
rename from chrome/browser/memory/tab_manager_delegate_chromeos.h
rename to chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.h
index 808a0dfb..ddd8d5f 100644
--- a/chrome/browser/memory/tab_manager_delegate_chromeos.h
+++ b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_MEMORY_TAB_MANAGER_DELEGATE_CHROMEOS_H_
-#define CHROME_BROWSER_MEMORY_TAB_MANAGER_DELEGATE_CHROMEOS_H_
+#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_DELEGATE_CHROMEOS_H_
+#define CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_DELEGATE_CHROMEOS_H_
 
 #include <memory>
 #include <string>
@@ -18,8 +18,8 @@
 #include "base/process/process.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/chromeos/arc/process/arc_process.h"
-#include "chrome/browser/memory/tab_manager.h"
-#include "chrome/browser/memory/tab_stats.h"
+#include "chrome/browser/resource_coordinator/tab_manager.h"
+#include "chrome/browser/resource_coordinator/tab_stats.h"
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "chromeos/dbus/debug_daemon_client.h"
 #include "components/arc/common/process.mojom.h"
@@ -28,7 +28,7 @@
 #include "content/public/browser/notification_registrar.h"
 #include "ui/wm/public/activation_change_observer.h"
 
-namespace memory {
+namespace resource_coordinator {
 
 // Possible types of Apps/Tabs processes. From most important to least
 // important.
@@ -272,6 +272,6 @@
   static int ReadIntFromFile(const char* file_name, int default_val);
 };
 
-}  // namespace memory
+}  // namespace resource_coordinator
 
-#endif  // CHROME_BROWSER_MEMORY_TAB_MANAGER_DELEGATE_CHROMEOS_H_
+#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_DELEGATE_CHROMEOS_H_
diff --git a/chrome/browser/memory/tab_manager_delegate_chromeos_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos_unittest.cc
similarity index 96%
rename from chrome/browser/memory/tab_manager_delegate_chromeos_unittest.cc
rename to chrome/browser/resource_coordinator/tab_manager_delegate_chromeos_unittest.cc
index f922ef9..6eff1424 100644
--- a/chrome/browser/memory/tab_manager_delegate_chromeos_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_delegate_chromeos_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/memory/tab_manager_delegate_chromeos.h"
+#include "chrome/browser/resource_coordinator/tab_manager_delegate_chromeos.h"
 
 #include <map>
 #include <string>
@@ -13,7 +13,7 @@
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace memory {
+namespace resource_coordinator {
 
 class TabManagerDelegateTest : public testing::Test {
  public:
@@ -56,14 +56,11 @@
 
   tab5.tab_contents_id = 500;
   tab5.is_app = true;
-  TabStatsList tab_list = {
-    tab1, tab2, tab3, tab4, tab5
-  };
+  TabStatsList tab_list = {tab1, tab2, tab3, tab4, tab5};
 
   std::vector<TabManagerDelegate::Candidate> candidates;
 
-  candidates = TabManagerDelegate::GetSortedCandidates(
-          tab_list, arc_processes);
+  candidates = TabManagerDelegate::GetSortedCandidates(tab_list, arc_processes);
   ASSERT_EQ(9U, candidates.size());
 
   // focused app.
@@ -128,14 +125,10 @@
         always_return_true_from_is_recently_killed_(false) {}
 
   // unit test.
-  std::vector<int> GetKilledArcProcesses() {
-    return killed_arc_processes_;
-  }
+  std::vector<int> GetKilledArcProcesses() { return killed_arc_processes_; }
 
   // unit test.
-  std::vector<int64_t> GetKilledTabs() {
-    return killed_tabs_;
-  }
+  std::vector<int64_t> GetKilledTabs() { return killed_tabs_; }
 
   // unit test.
   void Clear() {
@@ -184,9 +177,7 @@
   MockMemoryStat() {}
   ~MockMemoryStat() override {}
 
-  int TargetMemoryToFreeKB() override {
-    return target_memory_to_free_kb_;
-  }
+  int TargetMemoryToFreeKB() override { return target_memory_to_free_kb_; }
 
   int EstimatedMemoryFreedKB(base::ProcessHandle pid) override {
     return process_pss_[pid];
@@ -445,4 +436,4 @@
   EXPECT_EQ(1U, processes_map.count("not-visible"));
 }
 
-}  // namespace memory
+}  // namespace resource_coordinator
diff --git a/chrome/browser/memory/tab_manager_observer.cc b/chrome/browser/resource_coordinator/tab_manager_observer.cc
similarity index 79%
rename from chrome/browser/memory/tab_manager_observer.cc
rename to chrome/browser/resource_coordinator/tab_manager_observer.cc
index 782a158..c931f87 100644
--- a/chrome/browser/memory/tab_manager_observer.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_observer.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/memory/tab_manager_observer.h"
+#include "chrome/browser/resource_coordinator/tab_manager_observer.h"
 
 namespace content {
 class WebContents;
 }
 
-namespace memory {
+namespace resource_coordinator {
 
 void TabManagerObserver::OnDiscardedStateChange(content::WebContents* contents,
                                                 bool is_discarded) {}
@@ -19,4 +19,4 @@
 
 TabManagerObserver::~TabManagerObserver() {}
 
-}  // namespace memory
+}  // namespace resource_coordinator
diff --git a/chrome/browser/memory/tab_manager_observer.h b/chrome/browser/resource_coordinator/tab_manager_observer.h
similarity index 76%
rename from chrome/browser/memory/tab_manager_observer.h
rename to chrome/browser/resource_coordinator/tab_manager_observer.h
index 86dbc13f..e717fc3f 100644
--- a/chrome/browser/memory/tab_manager_observer.h
+++ b/chrome/browser/resource_coordinator/tab_manager_observer.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_MEMORY_TAB_MANAGER_OBSERVER_H_
-#define CHROME_BROWSER_MEMORY_TAB_MANAGER_OBSERVER_H_
+#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_OBSERVER_H_
+#define CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_OBSERVER_H_
 
 namespace content {
 class WebContents;
 }
 
-namespace memory {
+namespace resource_coordinator {
 
 // Interface for objects that wish to be notified of changes in TabManager.
 class TabManagerObserver {
@@ -28,6 +28,6 @@
   virtual ~TabManagerObserver();
 };
 
-}  // namespace memory
+}  // namespace resource_coordinator
 
-#endif  // CHROME_BROWSER_MEMORY_TAB_MANAGER_OBSERVER_H_
+#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_OBSERVER_H_
diff --git a/chrome/browser/memory/tab_manager_observer_browsertest.cc b/chrome/browser/resource_coordinator/tab_manager_observer_browsertest.cc
similarity index 95%
rename from chrome/browser/memory/tab_manager_observer_browsertest.cc
rename to chrome/browser/resource_coordinator/tab_manager_observer_browsertest.cc
index 4a71b0a..39d4673 100644
--- a/chrome/browser/memory/tab_manager_observer_browsertest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_observer_browsertest.cc
@@ -4,9 +4,9 @@
 
 #include "base/macros.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/memory/tab_manager.h"
-#include "chrome/browser/memory/tab_manager_observer.h"
-#include "chrome/browser/memory/tab_manager_web_contents_data.h"
+#include "chrome/browser/resource_coordinator/tab_manager.h"
+#include "chrome/browser/resource_coordinator/tab_manager_observer.h"
+#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/url_constants.h"
@@ -19,7 +19,7 @@
 
 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
 
-namespace memory {
+namespace resource_coordinator {
 
 class TabManagerObserverTest : public InProcessBrowserTest {
  public:
@@ -184,6 +184,6 @@
   EXPECT_EQ(ContentsId(contents), ContentsId(observer.content()));
 }
 
-}  // namespace memory
+}  // namespace resource_coordinator
 
 #endif  // OS_WIN || OS_MAXOSX || OS_LINUX
diff --git a/chrome/browser/memory/tab_manager_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
similarity index 96%
rename from chrome/browser/memory/tab_manager_unittest.cc
rename to chrome/browser/resource_coordinator/tab_manager_unittest.cc
index 6cf646f..60a00d2 100644
--- a/chrome/browser/memory/tab_manager_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/memory/tab_manager.h"
+#include "chrome/browser/resource_coordinator/tab_manager.h"
 
 #include <algorithm>
 #include <map>
@@ -17,9 +17,9 @@
 #include "base/test/simple_test_tick_clock.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "chrome/browser/memory/tab_manager_web_contents_data.h"
-#include "chrome/browser/memory/tab_stats.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
+#include "chrome/browser/resource_coordinator/tab_stats.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
 #include "chrome/common/chrome_features.h"
@@ -37,7 +37,7 @@
 using content::WebContents;
 using content::WebContentsTester;
 
-namespace memory {
+namespace resource_coordinator {
 namespace {
 
 class TabStripDummyDelegate : public TestTabStripModelDelegate {
@@ -374,9 +374,8 @@
   // Setting the variation parameter to true.
   {
     std::unique_ptr<base::FieldTrialList> field_trial_list_;
-    field_trial_list_.reset(
-        new base::FieldTrialList(
-            base::MakeUnique<base::MockEntropyProvider>()));
+    field_trial_list_.reset(new base::FieldTrialList(
+        base::MakeUnique<base::MockEntropyProvider>()));
     variations::testing::ClearAllVariationParams();
 
     std::map<std::string, std::string> params;
@@ -391,9 +390,8 @@
   // Setting the variation parameter to something else.
   {
     std::unique_ptr<base::FieldTrialList> field_trial_list_;
-    field_trial_list_.reset(
-        new base::FieldTrialList(
-            base::MakeUnique<base::MockEntropyProvider>()));
+    field_trial_list_.reset(new base::FieldTrialList(
+        base::MakeUnique<base::MockEntropyProvider>()));
     variations::testing::ClearAllVariationParams();
 
     std::map<std::string, std::string> params;
@@ -494,4 +492,4 @@
   EXPECT_FALSE(tab_manager.GetWebContentsData(tab2)->is_purged());
 }
 
-}  // namespace memory
+}  // namespace resource_coordinator
diff --git a/chrome/browser/memory/tab_manager_web_contents_data.cc b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc
similarity index 96%
rename from chrome/browser/memory/tab_manager_web_contents_data.cc
rename to chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc
index 1fd82e9..af91c398 100644
--- a/chrome/browser/memory/tab_manager_web_contents_data.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/memory/tab_manager_web_contents_data.h"
+#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 
 #include "base/metrics/histogram_macros.h"
 #include "base/time/tick_clock.h"
@@ -15,9 +15,10 @@
 using base::TimeTicks;
 using content::WebContents;
 
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(memory::TabManager::WebContentsData);
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(
+    resource_coordinator::TabManager::WebContentsData);
 
-namespace memory {
+namespace resource_coordinator {
 
 TabManager::WebContentsData::WebContentsData(content::WebContents* web_contents)
     : WebContentsObserver(web_contents),
@@ -201,4 +202,4 @@
   return tab_data_.is_auto_discardable;
 }
 
-}  // namespace memory
+}  // namespace resource_coordinator
diff --git a/chrome/browser/memory/tab_manager_web_contents_data.h b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
similarity index 92%
rename from chrome/browser/memory/tab_manager_web_contents_data.h
rename to chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
index 8ed8607c..26749d43 100644
--- a/chrome/browser/memory/tab_manager_web_contents_data.h
+++ b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_MEMORY_TAB_MANAGER_WEB_CONTENTS_DATA_H_
-#define CHROME_BROWSER_MEMORY_TAB_MANAGER_WEB_CONTENTS_DATA_H_
+#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_WEB_CONTENTS_DATA_H_
+#define CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_WEB_CONTENTS_DATA_H_
 
 #include "base/macros.h"
 #include "base/time/time.h"
-#include "chrome/browser/memory/tab_manager.h"
+#include "chrome/browser/resource_coordinator/tab_manager.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 
@@ -19,7 +19,7 @@
 class WebContents;
 }
 
-namespace memory {
+namespace resource_coordinator {
 
 // Internal class used by TabManager to record the needed data for
 // WebContentses.
@@ -147,6 +147,6 @@
   DISALLOW_COPY_AND_ASSIGN(WebContentsData);
 };
 
-}  // namespace memory
+}  // namespace resource_coordinator
 
-#endif  // CHROME_BROWSER_MEMORY_TAB_MANAGER_WEB_CONTENTS_DATA_H_
+#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_WEB_CONTENTS_DATA_H_
diff --git a/chrome/browser/memory/tab_manager_web_contents_data_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc
similarity index 97%
rename from chrome/browser/memory/tab_manager_web_contents_data_unittest.cc
rename to chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc
index e8adeefb..f2c6628 100644
--- a/chrome/browser/memory/tab_manager_web_contents_data_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/memory/tab_manager_web_contents_data.h"
+#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 
 #include "base/test/histogram_tester.h"
 #include "base/test/simple_test_tick_clock.h"
@@ -15,7 +15,7 @@
 using content::WebContents;
 using content::WebContentsTester;
 
-namespace memory {
+namespace resource_coordinator {
 namespace {
 
 class TabManagerWebContentsDataTest : public ChromeRenderViewHostTestHarness {
@@ -204,4 +204,4 @@
   histograms.ExpectBucketCount(kHistogramName, 12000, 1);
 }
 
-}  // namespace memory
+}  // namespace resource_coordinator
diff --git a/chrome/browser/memory/tab_stats.cc b/chrome/browser/resource_coordinator/tab_stats.cc
similarity index 76%
rename from chrome/browser/memory/tab_stats.cc
rename to chrome/browser/resource_coordinator/tab_stats.cc
index f0f1439a..9a9f5376 100644
--- a/chrome/browser/memory/tab_stats.cc
+++ b/chrome/browser/resource_coordinator/tab_stats.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/resource_coordinator/tab_stats.h"
 #include "build/build_config.h"
-#include "chrome/browser/memory/tab_stats.h"
 
-namespace memory {
+namespace resource_coordinator {
 
 TabStats::TabStats() = default;
 
@@ -17,4 +17,4 @@
 
 TabStats& TabStats::operator=(const TabStats& other) = default;
 
-}  // namespace memory
+}  // namespace resource_coordinator
diff --git a/chrome/browser/memory/tab_stats.h b/chrome/browser/resource_coordinator/tab_stats.h
similarity index 85%
rename from chrome/browser/memory/tab_stats.h
rename to chrome/browser/resource_coordinator/tab_stats.h
index 38cdb01..53cef5b3 100644
--- a/chrome/browser/memory/tab_stats.h
+++ b/chrome/browser/resource_coordinator/tab_stats.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_MEMORY_TAB_STATS_H_
-#define CHROME_BROWSER_MEMORY_TAB_STATS_H_
+#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_STATS_H_
+#define CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_STATS_H_
 
 #include <stdint.h>
 
@@ -18,7 +18,7 @@
 class RenderProcessHost;
 }  // namespace content
 
-namespace memory {
+namespace resource_coordinator {
 
 struct TabStats {
   TabStats();
@@ -52,6 +52,6 @@
 
 typedef std::vector<TabStats> TabStatsList;
 
-}  // namespace memory
+}  // namespace resource_coordinator
 
-#endif  // CHROME_BROWSER_MEMORY_TAB_STATS_H_
+#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_STATS_H_
diff --git a/chrome/browser/resources/chromeos/login/md_header_bar.css b/chrome/browser/resources/chromeos/login/md_header_bar.css
index 53a13eb6..1a49fc5f 100644
--- a/chrome/browser/resources/chromeos/login/md_header_bar.css
+++ b/chrome/browser/resources/chromeos/login/md_header_bar.css
@@ -80,6 +80,7 @@
   position: absolute;
   text-align: center;
   white-space: nowrap;
+  z-index: 3;
 }
 
 #more-settings-header-bar-item.active button.add-supervised-user-menu:focus {
@@ -121,11 +122,14 @@
 #login-header-bar #restart-button,
 #login-header-bar #add-user-button,
 #login-header-bar #guest-user-button,
-#login-header-bar #more-settings-button,
 #login-header-bar #cancel-multiple-sign-in-button {
   padding: 0 14px;
 }
 
+#login-header-bar #more-settings-button {
+  padding: 0 10px 0 18px;
+}
+
 #login-header-bar #more-settings-header-bar-item {
   position: relative;
 }
diff --git a/chrome/browser/resources/chromeos/login/md_header_bar.js b/chrome/browser/resources/chromeos/login/md_header_bar.js
index f02ba20c..d219926 100644
--- a/chrome/browser/resources/chromeos/login/md_header_bar.js
+++ b/chrome/browser/resources/chromeos/login/md_header_bar.js
@@ -128,7 +128,7 @@
       if (active == this.isMoreSettingsActive)
         return;
       this.getMoreSettingsMenu.classList.toggle('active', active);
-      $('more-settings-button').tabIndex = active ? -1 : 0;
+      $('more-settings-button').tabIndex = active ? -1 : 4;
     },
 
     /**
diff --git a/chrome/browser/resources/settings/controls/settings_slider.html b/chrome/browser/resources/settings/controls/settings_slider.html
index 7981bbd05..c3b61dc 100644
--- a/chrome/browser/resources/settings/controls/settings_slider.html
+++ b/chrome/browser/resources/settings/controls/settings_slider.html
@@ -67,7 +67,7 @@
       <paper-slider id="slider"
           disabled$="[[disableSlider_]]" snaps
           on-immediate-value-changed="onSliderChanged_" max="[[max]]"
-          min="[[min]]">
+          min="[[min]]" on-up="resetTrackLock_">
       </paper-slider>
       <div id="labels" disabled$="[[disableSlider_]]">
         <div id="label-begin">[[labelMin]]</div>
diff --git a/chrome/browser/resources/settings/controls/settings_slider.js b/chrome/browser/resources/settings/controls/settings_slider.js
index 5c5388af..d187a7c4 100644
--- a/chrome/browser/resources/settings/controls/settings_slider.js
+++ b/chrome/browser/resources/settings/controls/settings_slider.js
@@ -148,4 +148,13 @@
     assert(typeof closestIndex != 'undefined');
     return closestIndex;
   },
+
+  /**
+   * TODO(scottchen): temporary fix until polymer gesture bug resolved. See:
+   * https://github.com/PolymerElements/paper-slider/issues/186
+   * @private
+   */
+  resetTrackLock_: function() {
+    Polymer.Gestures.gestures.tap.reset();
+  },
 });
diff --git a/chrome/browser/resources/settings/controls/settings_toggle_button.html b/chrome/browser/resources/settings/controls/settings_toggle_button.html
index e939cf69..b2087e3 100644
--- a/chrome/browser/resources/settings/controls/settings_toggle_button.html
+++ b/chrome/browser/resources/settings/controls/settings_toggle_button.html
@@ -53,7 +53,7 @@
       </template>
       <paper-toggle-button id="control" checked="{{checked}}"
           on-change="notifyChangedByUserInteraction" aria-labelledby="label"
-          aria-describedby="subLabel"
+          aria-describedby="subLabel" on-up="resetTrackLock_"
           disabled="[[controlDisabled_(disabled, pref)]]">
       </paper-toggle-button>
     </div>
diff --git a/chrome/browser/resources/settings/controls/settings_toggle_button.js b/chrome/browser/resources/settings/controls/settings_toggle_button.js
index 5a05d71..5b4c77f 100644
--- a/chrome/browser/resources/settings/controls/settings_toggle_button.js
+++ b/chrome/browser/resources/settings/controls/settings_toggle_button.js
@@ -31,4 +31,13 @@
     this.checked = !this.checked;
     this.notifyChangedByUserInteraction();
   },
+
+  /**
+   * TODO(scottchen): temporary fix until polymer gesture bug resolved. See:
+   * https://github.com/PolymerElements/paper-slider/issues/186
+   * @private
+   */
+  resetTrackLock_: function() {
+    Polymer.Gestures.gestures.tap.reset();
+  },
 });
diff --git a/chrome/browser/search_engines/template_url_fetcher_unittest.cc b/chrome/browser/search_engines/template_url_fetcher_unittest.cc
index 35ca95c..b6119bb 100644
--- a/chrome/browser/search_engines/template_url_fetcher_unittest.cc
+++ b/chrome/browser/search_engines/template_url_fetcher_unittest.cc
@@ -182,6 +182,25 @@
   EXPECT_TRUE(t_url->safe_for_autoreplace());
 }
 
+// This test is similar to the BasicAutodetectedTest except the xml file
+// provided doesn't include a short name for the search engine.  We should
+// fall back to the hostname.
+TEST_F(TemplateURLFetcherTest, InvalidShortName) {
+  base::string16 keyword(ASCIIToUTF16("test"));
+
+  test_util()->ChangeModelToLoadState();
+  ASSERT_FALSE(test_util()->model()->GetTemplateURLForKeyword(keyword));
+
+  std::string osdd_file_name("simple_open_search_no_name.xml");
+  StartDownload(keyword, osdd_file_name, true);
+  WaitForDownloadToFinish();
+
+  const TemplateURL* t_url =
+      test_util()->model()->GetTemplateURLForKeyword(keyword);
+  ASSERT_TRUE(t_url);
+  EXPECT_EQ(ASCIIToUTF16("example.com"), t_url->short_name());
+}
+
 TEST_F(TemplateURLFetcherTest, DuplicatesThrownAway) {
   base::string16 keyword(ASCIIToUTF16("test"));
 
diff --git a/chrome/browser/shell_integration.cc b/chrome/browser/shell_integration.cc
index a846887..e18e93ea 100644
--- a/chrome/browser/shell_integration.cc
+++ b/chrome/browser/shell_integration.cc
@@ -11,6 +11,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/policy/policy_path_parser.h"
@@ -44,6 +45,18 @@
 
 const struct AppModeInfo* gAppModeInfo = nullptr;
 
+scoped_refptr<base::SequencedTaskRunner>
+CreateTaskRunnerForDefaultWebClientWorker() {
+#if defined(OS_WIN)
+  if (base::win::GetVersion() >= base::win::VERSION_WIN10)
+    // TODO(pmonette): Windows 10's implementation uses a base::Timer which
+    // currently still requires a SingleThreadTaskRunner. Change this to a
+    // SequencedTaskRunner when crbug.com/552633 is fixed.
+    return base::CreateSingleThreadTaskRunnerWithTraits({base::MayBlock()});
+#endif  // defined(OS_WIN)
+  return base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()});
+}
+
 }  // namespace
 
 bool CanSetAsDefaultBrowser() {
@@ -136,15 +149,14 @@
 //
 
 void DefaultWebClientWorker::StartCheckIsDefault() {
-  BrowserThread::PostTask(
-      BrowserThread::FILE, FROM_HERE,
+  GetTaskRunner()->PostTask(
+      FROM_HERE,
       base::Bind(&DefaultWebClientWorker::CheckIsDefault, this, false));
 }
 
 void DefaultWebClientWorker::StartSetAsDefault() {
-  BrowserThread::PostTask(
-      BrowserThread::FILE, FROM_HERE,
-      base::Bind(&DefaultWebClientWorker::SetAsDefault, this));
+  GetTaskRunner()->PostTask(
+      FROM_HERE, base::Bind(&DefaultWebClientWorker::SetAsDefault, this));
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -170,8 +182,27 @@
 ///////////////////////////////////////////////////////////////////////////////
 // DefaultWebClientWorker, private:
 
+// static
+scoped_refptr<base::SequencedTaskRunner>
+DefaultWebClientWorker::GetTaskRunner() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  // TODO(pmonette): The better way to make sure all instances of
+  // DefaultWebClient share a SequencedTaskRunner is to make the worker a
+  // singleton.
+  static scoped_refptr<base::SequencedTaskRunner>* task_runner = nullptr;
+
+  if (!task_runner) {
+    task_runner = new scoped_refptr<base::SequencedTaskRunner>(
+        CreateTaskRunnerForDefaultWebClientWorker());
+  }
+
+  return *task_runner;
+}
+
 void DefaultWebClientWorker::CheckIsDefault(bool is_following_set_as_default) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::ThreadRestrictions::AssertIOAllowed();
+
   DefaultWebClientState state = CheckIsDefaultImpl();
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
@@ -180,7 +211,7 @@
 }
 
 void DefaultWebClientWorker::SetAsDefault() {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::ThreadRestrictions::AssertIOAllowed();
 
   // SetAsDefaultImpl will make sure the callback is executed exactly once.
   SetAsDefaultImpl(
diff --git a/chrome/browser/shell_integration.h b/chrome/browser/shell_integration.h
index 7730a029..e6b1bbb 100644
--- a/chrome/browser/shell_integration.h
+++ b/chrome/browser/shell_integration.h
@@ -18,6 +18,7 @@
 
 namespace base {
 class CommandLine;
+class SequencedTaskRunner;
 }
 
 namespace shell_integration {
@@ -129,9 +130,9 @@
 
 //  Helper objects that handle checking if Chrome is the default browser
 //  or application for a url protocol on Windows and Linux, and also setting
-//  it as the default. These operations are performed asynchronously on the
-//  file thread since registry access (on Windows) or the preference database
-//  (on Linux) are involved and this can be slow.
+//  it as the default. These operations are performed asynchronously on a
+//  blocking sequence since registry access (on Windows) or the preference
+//  database (on Linux) are involved and this can be slow.
 //  By default, the worker will present the user with an interactive flow if
 //  required by the platform. This can be suppressed via
 //  set_interactive_permitted(), in which case an attempt to set Chrome as
@@ -174,12 +175,18 @@
   bool interactive_permitted_ = true;
 
  private:
-  // Checks whether Chrome is the default web client. Always called on the
-  // FILE thread. When |is_following_set_as_default| is true, The default state
-  // will be reported to UMA as the result of the set-as-default operation.
+  // Returns the global task runner that sequences all the file operations of
+  // each workers.
+  static scoped_refptr<base::SequencedTaskRunner> GetTaskRunner();
+
+  // Checks whether Chrome is the default web client. Always called on a
+  // blocking sequence. When |is_following_set_as_default| is true, The default
+  // state will be reported to UMA as the result of the set-as-default
+  // operation.
   void CheckIsDefault(bool is_following_set_as_default);
 
-  // Sets Chrome as the default web client. Always called on the FILE thread.
+  // Sets Chrome as the default web client. Always called on a blocking
+  // sequence.
   void SetAsDefault();
 
   // Implementation of CheckIsDefault() and SetAsDefault() for subclasses.
diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc
index f34c9ff..a9a1e98 100644
--- a/chrome/browser/shell_integration_linux.cc
+++ b/chrome/browser/shell_integration_linux.cc
@@ -50,13 +50,10 @@
 #include "chrome/common/features.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "components/version_info/version_info.h"
-#include "content/public/browser/browser_thread.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image_family.h"
 #include "url/gurl.h"
 
-using content::BrowserThread;
-
 namespace shell_integration {
 
 namespace {
@@ -565,13 +562,13 @@
 }  // namespace
 
 base::FilePath GetDataWriteLocation(base::Environment* env) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::ThreadRestrictions::AssertIOAllowed();
 
   return base::nix::GetXDGDirectory(env, "XDG_DATA_HOME", ".local/share");
 }
 
 std::vector<base::FilePath> GetDataSearchLocations(base::Environment* env) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::ThreadRestrictions::AssertIOAllowed();
 
   std::vector<base::FilePath> search_paths;
   base::FilePath write_location = GetDataWriteLocation(env);
@@ -682,7 +679,7 @@
     const base::FilePath& profile_path,
     const std::string& extension_id,
     const base::FilePath& desktop_path) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::ThreadRestrictions::AssertIOAllowed();
 
   base::FilePath shortcut_filename = GetExtensionShortcutFilename(
       profile_path, extension_id);
@@ -713,7 +710,7 @@
 bool GetExistingShortcutContents(base::Environment* env,
                                  const base::FilePath& desktop_filename,
                                  std::string* output) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::ThreadRestrictions::AssertIOAllowed();
 
   std::vector<base::FilePath> search_paths = GetDataSearchLocations(env);
 
@@ -774,7 +771,7 @@
 std::vector<base::FilePath> GetExistingProfileShortcutFilenames(
     const base::FilePath& profile_path,
     const base::FilePath& directory) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::ThreadRestrictions::AssertIOAllowed();
 
   // Use a prefix, because xdg-desktop-menu requires it.
   std::string prefix(chrome::kBrowserProcessExecutableName);
@@ -939,7 +936,7 @@
 bool CreateDesktopShortcut(
     const web_app::ShortcutInfo& shortcut_info,
     const web_app::ShortcutLocations& creation_locations) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::ThreadRestrictions::AssertIOAllowed();
 
   base::FilePath shortcut_filename;
   if (!shortcut_info.extension_id.empty()) {
@@ -1032,7 +1029,7 @@
 bool CreateAppListDesktopShortcut(
     const std::string& wm_class,
     const std::string& title) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::ThreadRestrictions::AssertIOAllowed();
 
   base::FilePath desktop_name(kAppListDesktopName);
   base::FilePath shortcut_filename = desktop_name.AddExtension("desktop");
@@ -1072,7 +1069,7 @@
 
 void DeleteDesktopShortcuts(const base::FilePath& profile_path,
                             const std::string& extension_id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::ThreadRestrictions::AssertIOAllowed();
 
   base::FilePath shortcut_filename = GetExtensionShortcutFilename(
       profile_path, extension_id);
@@ -1088,7 +1085,7 @@
 }
 
 void DeleteAllDesktopShortcuts(const base::FilePath& profile_path) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::ThreadRestrictions::AssertIOAllowed();
 
   std::unique_ptr<base::Environment> env(base::Environment::Create());
 
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc
index 06dbc42..c8fc1ac 100644
--- a/chrome/browser/shell_integration_win.cc
+++ b/chrome/browser/shell_integration_win.cc
@@ -32,6 +32,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "base/win/registry.h"
@@ -54,12 +55,9 @@
 #include "chrome/installer/util/scoped_user_protocol_entry.h"
 #include "chrome/installer/util/shell_util.h"
 #include "components/variations/variations_associated_data.h"
-#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/utility_process_mojo_client.h"
 #include "ui/base/l10n/l10n_util.h"
 
-using content::BrowserThread;
-
 namespace shell_integration {
 
 namespace {
@@ -150,8 +148,7 @@
 }
 
 void MigrateTaskbarPinsCallback() {
-  // This should run on the file thread.
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::ThreadRestrictions::AssertIOAllowed();
 
   // Get full path of chrome.
   base::FilePath chrome_exe;
@@ -328,7 +325,7 @@
   // watched. The array must contain at least one element.
   static void Begin(const wchar_t* const protocols[],
                     const base::Closure& on_finished_callback) {
-    DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+    base::ThreadRestrictions::AssertIOAllowed();
 
     delete instance_;
     instance_ = new OpenSystemSettingsHelper(protocols, on_finished_callback);
@@ -364,13 +361,16 @@
                    weak_ptr_factory_.GetWeakPtr(), ConcludeReason::TIMEOUT));
   }
 
+  ~OpenSystemSettingsHelper() {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  }
+
   // Called when a change is detected on one of the registry keys being watched.
   // Note: All types of modification to the registry key will trigger this
   //       function even if the value change is the only one that matters. This
   //       is good enough for now.
   void OnRegistryKeyChanged() {
-    DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     // Make sure all the registry watchers have fired.
     if (--registry_watcher_count_ == 0) {
       UMA_HISTOGRAM_MEDIUM_TIMES(
@@ -385,7 +385,7 @@
   // |on_finished_callback_| and then dispose of this class instance to make
   // sure the callback won't get called subsequently.
   void ConcludeInteraction(ConcludeReason conclude_reason) {
-    DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
     UMA_HISTOGRAM_ENUMERATION(
         "DefaultBrowser.SettingsInteraction.ConcludeReason", conclude_reason,
@@ -398,6 +398,8 @@
   // Helper function to create a registry watcher for a given |key_path|. Do
   // nothing on initialization failure.
   void AddRegistryKeyWatcher(const wchar_t* key_path) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
     auto reg_key = base::MakeUnique<base::win::RegKey>(HKEY_CURRENT_USER,
                                                        key_path, KEY_NOTIFY);
 
@@ -433,6 +435,8 @@
   // Records the time it takes for the final registry watcher to get signaled.
   base::TimeTicks start_time_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   // Weak ptrs are used to bind this class to the callbacks of the timer and the
   // registry watcher. This makes it possible to self-delete after one of the
   // callbacks is executed to cancel the remaining ones.
@@ -464,6 +468,8 @@
   ErrorCallback error_callback_;
   ResultCallback result_callback_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(IsPinnedToTaskbarHelper);
 };
 
@@ -497,6 +503,8 @@
 }
 
 void IsPinnedToTaskbarHelper::OnConnectionError() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   error_callback_.Run();
   delete this;
 }
@@ -504,6 +512,8 @@
 void IsPinnedToTaskbarHelper::OnIsPinnedToTaskbarResult(
     bool succeeded,
     bool is_pinned_to_taskbar) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   result_callback_.Run(succeeded, is_pinned_to_taskbar);
   delete this;
 }
@@ -511,6 +521,8 @@
 }  // namespace
 
 bool SetAsDefaultBrowser() {
+  base::ThreadRestrictions::AssertIOAllowed();
+
   base::FilePath chrome_exe;
   if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
     LOG(ERROR) << "Error getting app exe path";
@@ -530,6 +542,8 @@
 }
 
 bool SetAsDefaultProtocolClient(const std::string& protocol) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
   if (protocol.empty())
     return false;
 
@@ -625,6 +639,8 @@
 namespace win {
 
 bool SetAsDefaultBrowserUsingIntentPicker() {
+  base::ThreadRestrictions::AssertIOAllowed();
+
   base::FilePath chrome_exe;
   if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
     NOTREACHED() << "Error getting app exe path";
@@ -643,7 +659,7 @@
 
 void SetAsDefaultBrowserUsingSystemSettings(
     const base::Closure& on_finished_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::ThreadRestrictions::AssertIOAllowed();
 
   base::FilePath chrome_exe;
   if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
@@ -670,6 +686,8 @@
 }
 
 bool SetAsDefaultProtocolClientUsingIntentPicker(const std::string& protocol) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
   base::FilePath chrome_exe;
   if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
     NOTREACHED() << "Error getting app exe path";
@@ -691,7 +709,7 @@
 void SetAsDefaultProtocolClientUsingSystemSettings(
     const std::string& protocol,
     const base::Closure& on_finished_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::ThreadRestrictions::AssertIOAllowed();
 
   base::FilePath chrome_exe;
   if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
@@ -731,14 +749,12 @@
   if (base::win::GetVersion() < base::win::VERSION_WIN7)
     return;
 
-  // This needs to happen eventually (e.g. so that the appid is fixed and the
-  // run-time Chrome icon is merged with the taskbar shortcut), but this is not
-  // urgent and shouldn't delay Chrome startup.
-  static const int64_t kMigrateTaskbarPinsDelaySeconds = 15;
-  BrowserThread::PostDelayedTask(
-      BrowserThread::FILE, FROM_HERE,
-      base::Bind(&MigrateTaskbarPinsCallback),
-      base::TimeDelta::FromSeconds(kMigrateTaskbarPinsDelaySeconds));
+  // This needs to happen (e.g. so that the appid is fixed and the
+  // run-time Chrome icon is merged with the taskbar shortcut), but it is not an
+  // urgent task.
+  base::PostTaskWithTraits(FROM_HERE,
+                           {base::MayBlock(), base::TaskPriority::BACKGROUND},
+                           base::Bind(&MigrateTaskbarPinsCallback));
 }
 
 void GetIsPinnedToTaskbarState(
diff --git a/chrome/browser/sync/test/integration/bookmarks_helper.cc b/chrome/browser/sync/test/integration/bookmarks_helper.cc
index 9208fb3..18dc172 100644
--- a/chrome/browser/sync/test/integration/bookmarks_helper.cc
+++ b/chrome/browser/sync/test/integration/bookmarks_helper.cc
@@ -235,7 +235,8 @@
     model->GetFavicon(node);
     observer.WaitForGetFavicon();
   }
-  return FaviconData(model->GetFavicon(node), node->icon_url());
+  return FaviconData(model->GetFavicon(node),
+                     node->icon_url() ? *node->icon_url() : GURL());
 }
 
 // Sets the favicon for |profile| and |node|. |profile| may be
diff --git a/chrome/browser/translate/chrome_translate_client.cc b/chrome/browser/translate/chrome_translate_client.cc
index 85eed92..c29d82f 100644
--- a/chrome/browser/translate/chrome_translate_client.cc
+++ b/chrome/browser/translate/chrome_translate_client.cc
@@ -42,6 +42,7 @@
 #include "components/translate/core/browser/translate_manager.h"
 #include "components/translate/core/browser/translate_prefs.h"
 #include "components/translate/core/common/language_detection_details.h"
+#include "components/translate/core/common/language_detection_logging_helper.h"
 #include "components/variations/service/variations_service.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/notification_service.h"
@@ -70,28 +71,6 @@
   }
 }
 
-std::unique_ptr<sync_pb::UserEventSpecifics> ConstructLanguageDetectionEvent(
-    const int entry_id,
-    const translate::LanguageDetectionDetails& details) {
-  auto specifics = base::MakeUnique<sync_pb::UserEventSpecifics>();
-  specifics->set_event_time_usec(base::Time::Now().ToInternalValue());
-
-  // TODO(renjieliu): Revisit this field when the best way to identify
-  // navigations is determined.
-  specifics->set_navigation_id(base::Time::Now().ToInternalValue());
-
-  sync_pb::LanguageDetection lang_detection;
-  auto* const lang = lang_detection.add_detected_languages();
-  lang->set_language_code(details.cld_language);
-  lang->set_is_reliable(details.is_cld_reliable);
-  // Only set adopted_language when it's different from cld_language.
-  if (details.adopted_language != details.cld_language) {
-    lang_detection.set_adopted_language_code(details.adopted_language);
-  }
-  *specifics->mutable_language_detection() = lang_detection;
-  return specifics;
-}
-
 void LogLanguageDetectionEvent(
     const content::WebContents* const web_contents,
     const translate::LanguageDetectionDetails& details) {
@@ -109,7 +88,7 @@
   // blank page.
   if (entry != nullptr) {
     user_event_service->RecordUserEvent(
-        ConstructLanguageDetectionEvent(entry->GetUniqueID(), details));
+        translate::ConstructLanguageDetectionEvent(details));
   }
 }
 
diff --git a/chrome/browser/ui/app_list/arc/arc_app_utils.cc b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
index 5056bcc..1952536 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_utils.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
@@ -9,7 +9,6 @@
 
 #include "ash/shell.h"
 #include "base/bind.h"
-#include "base/feature_list.h"
 #include "base/json/json_writer.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/values.h"
@@ -22,7 +21,6 @@
 #include "chrome/browser/ui/ash/launcher/arc_app_shelf_id.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "components/arc/arc_bridge_service.h"
-#include "components/arc/arc_features.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
 #include "components/arc/common/intent_helper.mojom.h"
@@ -172,15 +170,10 @@
 const char kLegacyPlayStoreAppId[] = "gpkmicpkkebkmabiaedjognfppcchdfa";
 const char kPlayStorePackage[] = "com.android.vending";
 const char kPlayStoreActivity[] = "com.android.vending.AssetBrowserActivity";
-const char kFilesAppId[] = "clippbnfpgifdekheldlleoeiiababjg";
 const char kSettingsAppId[] = "mconboelelhjpkbdhhiijkgcimoangdj";
 
 bool ShouldShowInLauncher(const std::string& app_id) {
-  if (app_id == kFilesAppId) {
-    return base::FeatureList::IsEnabled(kShowArcFilesAppFeature);
-  } else {
-    return (app_id != kSettingsAppId);
-  }
+  return (app_id != kSettingsAppId);
 }
 
 bool LaunchAppWithRect(content::BrowserContext* context,
diff --git a/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc b/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc
index 4a0807d..d0fe966 100644
--- a/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc
+++ b/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc
@@ -4,8 +4,6 @@
 
 #include "chrome/browser/ui/ash/app_list/app_list_controller_ash.h"
 
-#include "ash/shelf/shelf_model.h"
-#include "ash/shell.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h"
@@ -39,7 +37,7 @@
 }
 
 bool AppListControllerDelegateAsh::IsAppPinned(const std::string& app_id) {
-  return ash::Shell::Get()->shelf_model()->IsAppPinned(app_id);
+  return ChromeLauncherController::instance()->IsAppPinned(app_id);
 }
 
 bool AppListControllerDelegateAsh::IsAppOpen(const std::string& app_id) const {
@@ -47,11 +45,11 @@
 }
 
 void AppListControllerDelegateAsh::PinApp(const std::string& app_id) {
-  ash::Shell::Get()->shelf_model()->PinAppWithID(app_id);
+  ChromeLauncherController::instance()->PinAppWithID(app_id);
 }
 
 void AppListControllerDelegateAsh::UnpinApp(const std::string& app_id) {
-  ash::Shell::Get()->shelf_model()->UnpinAppWithID(app_id);
+  ChromeLauncherController::instance()->UnpinAppWithID(app_id);
 }
 
 AppListControllerDelegate::Pinnable AppListControllerDelegateAsh::GetPinnable(
diff --git a/chrome/browser/ui/ash/chrome_keyboard_ui.cc b/chrome/browser/ui/ash/chrome_keyboard_ui.cc
index cf54830..4354548b 100644
--- a/chrome/browser/ui/ash/chrome_keyboard_ui.cc
+++ b/chrome/browser/ui/ash/chrome_keyboard_ui.cc
@@ -201,7 +201,7 @@
     return false;
 
   ash::RootWindowController* root_window_controller =
-      ash::GetRootWindowController(root_window);
+      ash::RootWindowController::ForWindow(root_window);
   // Shell ime window container contains virtual keyboard windows and IME
   // windows(IME windows are created by chrome.app.window.create api). They
   // should never be overscrolled.
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index 465ef44..8908e85 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 
 #include "ash/multi_profile_uma.h"
+#include "ash/public/cpp/remote_shelf_item_delegate.h"
 #include "ash/public/cpp/shelf_item.h"
 #include "ash/public/interfaces/constants.mojom.h"
 #include "ash/resources/grit/ash_resources.h"
@@ -20,6 +21,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
+#include "chrome/browser/chromeos/ash_config.h"
 #include "chrome/browser/extensions/chrome_app_icon_loader.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/prefs/pref_service_syncable_util.h"
@@ -279,6 +281,9 @@
     ash::mojom::ShelfObserverAssociatedPtrInfo ptr_info;
     observer_binding_.Bind(mojo::MakeRequest(&ptr_info));
     shelf_controller_->AddObserver(std::move(ptr_info));
+    // ShelfModel's constructor should have initialized the app list item.
+    DCHECK_EQ(1, model_->item_count());
+    DCHECK_EQ(ash::kAppListId, model_->items()[0].id.app_id);
   }
 
   CreateBrowserShortcutLauncherItem();
@@ -1268,12 +1273,92 @@
   SetShelfAutoHideBehaviorPref(profile_->GetPrefs(), display_id, auto_hide);
 }
 
+void ChromeLauncherController::OnShelfItemAdded(int32_t index,
+                                                const ash::ShelfItem& item) {
+  DCHECK(ash_util::IsRunningInMash()) << "Unexpected model synchronization";
+  DCHECK(!applying_remote_shelf_model_changes_) << "Unexpected model change";
+
+  // Ignore notifications of adding the AppList item; it should already exist.
+  if (item.id.app_id == ash::kAppListId) {
+    DCHECK_EQ(0, model_->ItemIndexByID(item.id));
+    return;
+  }
+
+  DCHECK_LE(index, model_->item_count()) << "Index out of bounds";
+  DCHECK_GT(index, 0) << "Items can not preceed the AppList";
+  index = std::min(std::max(index, 1), model_->item_count());
+  base::AutoReset<bool> reset(&applying_remote_shelf_model_changes_, true);
+  model_->AddAt(index, item);
+}
+
+void ChromeLauncherController::OnShelfItemRemoved(const ash::ShelfID& id) {
+  DCHECK(ash_util::IsRunningInMash()) << "Unexpected model synchronization";
+  DCHECK(!applying_remote_shelf_model_changes_) << "Unexpected model change";
+  const int index = model_->ItemIndexByID(id);
+  DCHECK_GE(index, 0) << "Item not found";
+  DCHECK_NE(index, 0) << "The AppList shelf item cannot be removed";
+  if (index <= 0)
+    return;
+  base::AutoReset<bool> reset(&applying_remote_shelf_model_changes_, true);
+  model_->RemoveItemAt(index);
+}
+
+void ChromeLauncherController::OnShelfItemMoved(const ash::ShelfID& id,
+                                                int32_t index) {
+  DCHECK(ash_util::IsRunningInMash()) << "Unexpected model synchronization";
+  DCHECK(!applying_remote_shelf_model_changes_) << "Unexpected model change";
+  const int current_index = model_->ItemIndexByID(id);
+  DCHECK_GE(current_index, 0) << "No item found with the given id";
+  DCHECK_NE(current_index, 0) << "The AppList shelf item cannot be moved";
+  if (current_index <= 0)
+    return;
+  DCHECK_GT(index, 0) << "Items can not preceed the AppList";
+  DCHECK_LT(index, model_->item_count()) << "Index out of bounds";
+  index = std::min(std::max(index, 1), model_->item_count() - 1);
+  DCHECK_NE(current_index, index) << "The item is already at the given index";
+  if (current_index == index)
+    return;
+  base::AutoReset<bool> reset(&applying_remote_shelf_model_changes_, true);
+  model_->Move(current_index, index);
+}
+
+void ChromeLauncherController::OnShelfItemUpdated(const ash::ShelfItem& item) {
+  DCHECK(ash_util::IsRunningInMash()) << "Unexpected model synchronization";
+  DCHECK(!applying_remote_shelf_model_changes_) << "Unexpected model change";
+  const int index = model_->ItemIndexByID(item.id);
+  DCHECK_GE(index, 0) << "No item found with the given id";
+  if (index < 0)
+    return;
+  base::AutoReset<bool> reset(&applying_remote_shelf_model_changes_, true);
+  model_->Set(index, item);
+}
+
+void ChromeLauncherController::OnShelfItemDelegateChanged(
+    const ash::ShelfID& id,
+    ash::mojom::ShelfItemDelegatePtr delegate) {
+  DCHECK(ash_util::IsRunningInMash()) << "Unexpected model synchronization";
+  DCHECK(!applying_remote_shelf_model_changes_) << "Unexpected model change";
+  base::AutoReset<bool> reset(&applying_remote_shelf_model_changes_, true);
+  if (delegate.is_bound()) {
+    model_->SetShelfItemDelegate(id,
+                                 base::MakeUnique<ash::RemoteShelfItemDelegate>(
+                                     id, std::move(delegate)));
+  } else {
+    model_->SetShelfItemDelegate(id, nullptr);
+  }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // ash::ShelfModelObserver:
 
 void ChromeLauncherController::ShelfItemAdded(int index) {
-  // Update the pin position preference as needed.
   ash::ShelfItem item = model_->items()[index];
+  if (shelf_controller_ && !applying_remote_shelf_model_changes_ &&
+      chromeos::GetAshConfig() == ash::Config::MASH) {
+    shelf_controller_->AddShelfItem(index, item);
+  }
+
+  // Update the pin position preference as needed.
   if (ItemTypeIsPinned(item) && should_sync_pin_changes_)
     SyncPinPosition(item.id);
 
@@ -1301,12 +1386,17 @@
       needs_update = true;
       item.status = status;
     }
-    if (needs_update)
+    if (needs_update) {
+      // Ensure these changes are reported back to Ash.
+      base::AutoReset<bool> reset(&applying_remote_shelf_model_changes_, false);
       model_->Set(index, item);
+    }
   }
 
   // Construct a ShelfItemDelegate for the item if one does not yet exist.
   if (!model_->GetShelfItemDelegate(item.id)) {
+    // Ensure these changes are reported back to Ash.
+    base::AutoReset<bool> reset(&applying_remote_shelf_model_changes_, false);
     model_->SetShelfItemDelegate(
         item.id, AppShortcutLauncherItemController::Create(item.id));
   }
@@ -1315,6 +1405,11 @@
 void ChromeLauncherController::ShelfItemRemoved(
     int index,
     const ash::ShelfItem& old_item) {
+  if (shelf_controller_ && !applying_remote_shelf_model_changes_ &&
+      chromeos::GetAshConfig() == ash::Config::MASH) {
+    shelf_controller_->RemoveShelfItem(old_item.id);
+  }
+
   // Remove the pin position from preferences as needed.
   if (ItemTypeIsPinned(old_item) && should_sync_pin_changes_)
     RemovePinPosition(profile(), old_item.id);
@@ -1326,8 +1421,13 @@
 
 void ChromeLauncherController::ShelfItemMoved(int start_index,
                                               int target_index) {
-  // Update the pin position preference as needed.
   const ash::ShelfItem& item = model_->items()[target_index];
+  if (shelf_controller_ && !applying_remote_shelf_model_changes_ &&
+      chromeos::GetAshConfig() == ash::Config::MASH) {
+    shelf_controller_->MoveShelfItem(item.id, target_index);
+  }
+
+  // Update the pin position preference as needed.
   DCHECK_NE(ash::TYPE_APP_LIST, item.type);
   if (ItemTypeIsPinned(item) && should_sync_pin_changes_)
     SyncPinPosition(item.id);
@@ -1336,10 +1436,15 @@
 void ChromeLauncherController::ShelfItemChanged(
     int index,
     const ash::ShelfItem& old_item) {
+  const ash::ShelfItem& item = model_->items()[index];
+  if (shelf_controller_ && !applying_remote_shelf_model_changes_ &&
+      chromeos::GetAshConfig() == ash::Config::MASH) {
+    shelf_controller_->UpdateShelfItem(item);
+  }
+
   if (!should_sync_pin_changes_)
     return;
 
-  const ash::ShelfItem& item = model_->items()[index];
   // Add or remove the pin position from preferences as needed.
   if (!ItemTypeIsPinned(old_item) && ItemTypeIsPinned(item))
     SyncPinPosition(item.id);
@@ -1347,6 +1452,17 @@
     RemovePinPosition(profile(), old_item.id);
 }
 
+void ChromeLauncherController::ShelfItemDelegateChanged(
+    const ash::ShelfID& id,
+    ash::ShelfItemDelegate* delegate) {
+  if (shelf_controller_ && !applying_remote_shelf_model_changes_ &&
+      chromeos::GetAshConfig() == ash::Config::MASH) {
+    shelf_controller_->SetShelfItemDelegate(
+        id, delegate ? delegate->CreateInterfacePtrAndBind()
+                     : ash::mojom::ShelfItemDelegatePtr());
+  }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // ash::WindowTreeHostManager::Observer:
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
index 33d3ba6..00d59c4 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
@@ -26,6 +26,8 @@
 #include "components/prefs/pref_change_registrar.h"
 #include "components/sync_preferences/pref_service_syncable_observer.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/interface_ptr_set.h"
 
 class AccountId;
 class AppIconLoader;
@@ -356,12 +358,21 @@
                           int64_t display_id) override;
   void OnAutoHideBehaviorChanged(ash::ShelfAutoHideBehavior auto_hide,
                                  int64_t display_id) override;
+  void OnShelfItemAdded(int32_t index, const ash::ShelfItem& item) override;
+  void OnShelfItemRemoved(const ash::ShelfID& id) override;
+  void OnShelfItemMoved(const ash::ShelfID& id, int32_t index) override;
+  void OnShelfItemUpdated(const ash::ShelfItem& item) override;
+  void OnShelfItemDelegateChanged(
+      const ash::ShelfID& id,
+      ash::mojom::ShelfItemDelegatePtr delegate) override;
 
   // ash::ShelfModelObserver:
   void ShelfItemAdded(int index) override;
   void ShelfItemRemoved(int index, const ash::ShelfItem& old_item) override;
   void ShelfItemMoved(int start_index, int target_index) override;
   void ShelfItemChanged(int index, const ash::ShelfItem& old_item) override;
+  void ShelfItemDelegateChanged(const ash::ShelfID& id,
+                                ash::ShelfItemDelegate* delegate) override;
 
   // ash::WindowTreeHostManager::Observer:
   void OnDisplayConfigurationChanged() override;
@@ -385,6 +396,9 @@
   // multi-profile use cases this might change over time.
   Profile* profile_ = nullptr;
 
+  // In classic Ash, this the ShelfModel owned by ash::Shell's ShelfController.
+  // In the mash config, this is a separate ShelfModel instance, owned by
+  // ChromeBrowserMainExtraPartsAsh, and synchronized with Ash's ShelfModel.
   ash::ShelfModel* model_;
 
   // Ash's mojom::ShelfController used to change shelf state.
@@ -396,6 +410,10 @@
   // True when setting a shelf pref in response to an observer notification.
   bool updating_shelf_pref_from_observer_ = false;
 
+  // True when applying changes from the remote ShelfModel owned by Ash.
+  // Changes to the local ShelfModel should not be reported during this time.
+  bool applying_remote_shelf_model_changes_ = false;
+
   // When true, changes to pinned shelf items should update the sync model.
   bool should_sync_pin_changes_ = true;
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
index 4d5aa7c4..68545599 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -2501,3 +2501,13 @@
   ASSERT_FALSE(
       IsItemPresentInMenu(menu2.get(), LauncherContextMenu::MENU_CLOSE));
 }
+
+// Chrome's ShelfModel should have AppList and browser items and delegates.
+IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, ShelfModelInitialization) {
+  ash::ShelfModel* model = controller_->shelf_model();
+  EXPECT_EQ(2, model->item_count());
+  EXPECT_EQ(ash::kAppListId, model->items()[0].id.app_id);
+  EXPECT_TRUE(model->GetShelfItemDelegate(model->items()[0].id));
+  EXPECT_EQ(extension_misc::kChromeAppId, model->items()[1].id.app_id);
+  EXPECT_TRUE(model->GetShelfItemDelegate(model->items()[1].id));
+}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
index 4b970670..bff4044 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -42,6 +42,7 @@
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
+#include "chrome/browser/chromeos/ash_config.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
@@ -127,8 +128,6 @@
 constexpr char kGmailUrl[] = "https://mail.google.com/mail/u";
 constexpr char kGmailLaunchURL[] = "https://mail.google.com/mail/ca";
 
-constexpr char kAppListId[] = "jlfapfmkapbjlfbpjedlinehodkccjee";
-
 // An extension prefix.
 constexpr char kCrxAppPrefix[] = "_crx_";
 
@@ -162,6 +161,9 @@
     last_index_ = target_index;
   }
 
+  void ShelfItemDelegateChanged(const ash::ShelfID&,
+                                ash::ShelfItemDelegate*) override {}
+
   void clear_counts() {
     added_ = 0;
     removed_ = 0;
@@ -275,7 +277,7 @@
   DISALLOW_COPY_AND_ASSIGN(TestV2AppLauncherItemController);
 };
 
-// A test ShelfController implementation that tracks alignment and auto-hide.
+// A test ShelfController implementation that tracks state and function calls.
 class TestShelfController : public ash::mojom::ShelfController {
  public:
   TestShelfController() : binding_(this) {}
@@ -287,6 +289,9 @@
   size_t alignment_change_count() const { return alignment_change_count_; }
   size_t auto_hide_change_count() const { return auto_hide_change_count_; }
 
+  size_t added_count() const { return added_count_; }
+  size_t removed_count() const { return removed_count_; }
+
   ash::mojom::ShelfControllerPtr CreateInterfacePtrAndBind() {
     return binding_.CreateInterfacePtrAndBind();
   }
@@ -308,12 +313,12 @@
     auto_hide_ = auto_hide;
     observer_->OnAutoHideBehaviorChanged(auto_hide_, display_id);
   }
-  void PinItem(
-      const ash::ShelfItem& item,
-      ash::mojom::ShelfItemDelegateAssociatedPtrInfo delegate) override {}
-  void UnpinItem(const std::string& app_id) override {}
-  void SetItemImage(const std::string& app_id, const SkBitmap& image) override {
-  }
+  void AddShelfItem(int32_t, const ash::ShelfItem&) override { added_count_++; }
+  void RemoveShelfItem(const ash::ShelfID&) override { removed_count_++; }
+  void MoveShelfItem(const ash::ShelfID&, int32_t) override {}
+  void UpdateShelfItem(const ash::ShelfItem&) override {}
+  void SetShelfItemDelegate(const ash::ShelfID&,
+                            ash::mojom::ShelfItemDelegatePtr) override {}
 
  private:
   ash::ShelfAlignment alignment_ = ash::SHELF_ALIGNMENT_BOTTOM_LOCKED;
@@ -322,6 +327,9 @@
   size_t alignment_change_count_ = 0;
   size_t auto_hide_change_count_ = 0;
 
+  size_t added_count_ = 0;
+  size_t removed_count_ = 0;
+
   ash::mojom::ShelfObserverAssociatedPtr observer_;
   mojo::Binding<ash::mojom::ShelfController> binding_;
 
@@ -373,30 +381,22 @@
 // TODO(msw): Avoid relying on TestShellDelegate's ShelfInitializer.
 class ChromeLauncherTestShellDelegate : public ash::test::TestShellDelegate {
  public:
-  ChromeLauncherTestShellDelegate() {}
-
-  // Create a ChromeLauncherController instance.
-  ChromeLauncherController* CreateLauncherController(Profile* profile) {
-    launcher_controller_ = base::MakeUnique<ChromeLauncherController>(
-        profile, ash::Shell::Get()->shelf_model());
-    return launcher_controller_.get();
-  }
+  explicit ChromeLauncherTestShellDelegate(ash::ShelfModel* shelf_model)
+      : shelf_model_(shelf_model) {}
 
   // Create a TestChromeLauncherController instance.
-  TestChromeLauncherController* CreateTestLauncherController(Profile* profile) {
-    auto controller = base::MakeUnique<TestChromeLauncherController>(
-        profile, ash::Shell::Get()->shelf_model());
-    TestChromeLauncherController* controller_weak = controller.get();
-    launcher_controller_ = std::move(controller);
-    launcher_controller_->Init();
-    return controller_weak;
+  TestChromeLauncherController* CreateLauncherController(Profile* profile) {
+    launcher_controller_ =
+        base::MakeUnique<TestChromeLauncherController>(profile, shelf_model_);
+    return launcher_controller_.get();
   }
 
   // ash::test::TestShellDelegate:
   void ShelfShutdown() override { launcher_controller_.reset(); }
 
  private:
-  std::unique_ptr<ChromeLauncherController> launcher_controller_;
+  ash::ShelfModel* shelf_model_;
+  std::unique_ptr<TestChromeLauncherController> launcher_controller_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeLauncherTestShellDelegate);
 };
@@ -414,7 +414,7 @@
 
     app_list::AppListSyncableServiceFactory::SetUseInTesting();
 
-    shell_delegate_ = new ChromeLauncherTestShellDelegate();
+    shell_delegate_ = new ChromeLauncherTestShellDelegate(&model_);
     ash_test_helper()->set_test_shell_delegate(shell_delegate_);
 
     BrowserWithTestWindowTest::SetUp();
@@ -425,9 +425,8 @@
       ASSERT_TRUE(profile_manager_->SetUp());
     }
 
-    model_ = ash::Shell::Get()->shelf_controller()->model();
     model_observer_.reset(new TestShelfModelObserver);
-    model_->AddObserver(model_observer_.get());
+    model_.AddObserver(model_observer_.get());
 
     base::DictionaryValue manifest;
     manifest.SetString(extensions::manifest_keys::kName,
@@ -530,7 +529,7 @@
         base::MakeUnique<TestV2AppLauncherItemController>(app_id);
     test_controller_ = controller.get();
     ash::ShelfID id = launcher_controller_->InsertAppLauncherItem(
-        std::move(controller), ash::STATUS_RUNNING, model_->item_count(),
+        std::move(controller), ash::STATUS_RUNNING, model_.item_count(),
         ash::TYPE_APP);
     DCHECK(launcher_controller_->IsPlatformApp(id));
   }
@@ -578,7 +577,7 @@
 
   void TearDown() override {
     arc_test_.TearDown();
-    model_->RemoveObserver(model_observer_.get());
+    model_.RemoveObserver(model_observer_.get());
     model_observer_.reset();
     launcher_controller_ = nullptr;
     BrowserWithTestWindowTest::TearDown();
@@ -596,13 +595,6 @@
         CreateBrowser(profile, Browser::TYPE_TABBED, false, browser_window));
   }
 
-  void AddAppListLauncherItem() {
-    ash::ShelfItem app_list;
-    app_list.id = ash::ShelfID(kAppListId);
-    app_list.type = ash::TYPE_APP_LIST;
-    model_->Add(app_list);
-  }
-
   // Create a launcher controller instance, owned by the test shell delegate.
   // Returns a pointer to the uninitialized controller.
   ChromeLauncherController* CreateLauncherController() {
@@ -633,9 +625,10 @@
   ChromeLauncherController* RecreateLauncherController() {
     // Destroy any existing controller first; only one may exist at a time.
     ResetLauncherController();
-    while (model_->item_count() > 0)
-      model_->RemoveItemAt(0);
-    AddAppListLauncherItem();
+    DCHECK_GE(model_.item_count(), 1);
+    DCHECK_EQ(ash::kAppListId, model_.items()[0].id.app_id);
+    while (model_.item_count() > 1)
+      model_.RemoveItemAt(1);
     return CreateLauncherController();
   }
 
@@ -828,7 +821,7 @@
   void GetPinnedAppIds(ChromeLauncherController* controller,
                        std::vector<std::string>* app_ids) {
     app_ids->clear();
-    for (const auto& item : model_->items()) {
+    for (const auto& item : model_.items()) {
       if (item.type == ash::TYPE_PINNED_APP)
         app_ids->push_back(item.id.app_id);
     }
@@ -840,14 +833,14 @@
   // pinned V2 app will start with a '*' + small letter.
   std::string GetPinnedAppStatus() {
     std::string result;
-    for (int i = 0; i < model_->item_count(); i++) {
+    for (int i = 0; i < model_.item_count(); i++) {
       if (!result.empty())
         result.append(", ");
-      switch (model_->items()[i].type) {
+      switch (model_.items()[i].type) {
         case ash::TYPE_APP: {
-          if (launcher_controller_->IsPlatformApp(model_->items()[i].id))
+          if (launcher_controller_->IsPlatformApp(model_.items()[i].id))
             result += "*";
-          const std::string& app = model_->items()[i].id.app_id;
+          const std::string& app = model_.items()[i].id.app_id;
           EXPECT_FALSE(launcher_controller_->IsAppPinned(app));
           if (app == extension1_->id()) {
             result += "app1";
@@ -873,9 +866,9 @@
           break;
         }
         case ash::TYPE_PINNED_APP: {
-          if (launcher_controller_->IsPlatformApp(model_->items()[i].id))
+          if (launcher_controller_->IsPlatformApp(model_.items()[i].id))
             result += "*";
-          const std::string& app = model_->items()[i].id.app_id;
+          const std::string& app = model_.items()[i].id.app_id;
           EXPECT_TRUE(launcher_controller_->IsAppPinned(app));
           if (app == extension1_->id()) {
             result += "App1";
@@ -1050,7 +1043,7 @@
   ChromeLauncherController* launcher_controller_ = nullptr;
   ChromeLauncherTestShellDelegate* shell_delegate_ = nullptr;
   std::unique_ptr<TestShelfModelObserver> model_observer_;
-  ash::ShelfModel* model_ = nullptr;
+  ash::ShelfModel model_;
   std::unique_ptr<TestingProfileManager> profile_manager_;
 
   // |item_delegate_manager_| owns |test_controller_|.
@@ -1354,7 +1347,7 @@
 TEST_F(ChromeLauncherControllerTest, DefaultApps) {
   InitLauncherController();
   // The model should only contain the browser shortcut and app list items.
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
@@ -1427,10 +1420,10 @@
             GetPinnedAppStatus());
 
   // Now move pins on ARC enabled platform.
-  model_->Move(1, 4);
-  model_->Move(3, 1);
-  model_->Move(3, 5);
-  model_->Move(4, 2);
+  model_.Move(1, 4);
+  model_.Move(3, 1);
+  model_.Move(3, 5);
+  model_.Move(4, 2);
   EXPECT_EQ("AppList, App2, Fake App 1, Chrome, App1, Fake App 0, App3",
             GetPinnedAppStatus());
 
@@ -1460,7 +1453,7 @@
   EXPECT_EQ("AppList, App2, Chrome, App1, App3", GetPinnedAppStatus());
 
   // Now move/remove pins on ARC disabled platform.
-  model_->Move(4, 2);
+  model_.Move(4, 2);
   launcher_controller_->UnpinAppWithID(extension2_->id());
   EXPECT_EQ("AppList, App3, Chrome, App1", GetPinnedAppStatus());
   EnablePlayStore(true);
@@ -1698,76 +1691,76 @@
 TEST_F(ChromeLauncherControllerTest, V1AppRunActivateClose) {
   InitLauncherController();
   // The model should only contain the browser shortcut and app list items.
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_EQ(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
 
   // Reporting that the app is running should create a new shelf item.
   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_RUNNING);
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_APP, model_->items()[2].type);
-  EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[2].status);
+  EXPECT_EQ(3, model_.item_count());
+  EXPECT_EQ(ash::TYPE_APP, model_.items()[2].type);
+  EXPECT_EQ(ash::STATUS_RUNNING, model_.items()[2].status);
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_NE(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
 
   // Reporting an active status should just update the existing item.
   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_ACTIVE);
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::STATUS_ACTIVE, model_->items()[2].status);
+  EXPECT_EQ(3, model_.item_count());
+  EXPECT_EQ(ash::STATUS_ACTIVE, model_.items()[2].status);
 
   // Reporting that the app is closed should remove its shelf item.
   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_EQ(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
 
   // Reporting that the app is closed again should have no effect.
   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
 }
 
 // Test the V1 app interaction flow: pin it, run it, close it, unpin it.
 TEST_F(ChromeLauncherControllerTest, V1AppPinRunCloseUnpin) {
   InitLauncherController();
   // The model should only contain the browser shortcut and app list items.
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_EQ(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
 
   // Pinning the app should create a new shelf item.
   launcher_controller_->PinAppWithID(extension1_->id());
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
-  EXPECT_EQ(ash::STATUS_CLOSED, model_->items()[2].status);
+  EXPECT_EQ(3, model_.item_count());
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[2].type);
+  EXPECT_EQ(ash::STATUS_CLOSED, model_.items()[2].status);
   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_NE(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
 
   // Reporting that the app is running should just update the existing item.
   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_RUNNING);
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
-  EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[2].status);
+  EXPECT_EQ(3, model_.item_count());
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[2].type);
+  EXPECT_EQ(ash::STATUS_RUNNING, model_.items()[2].status);
   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_NE(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
 
   // Reporting that the app is closed should just update the existing item.
   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
-  EXPECT_EQ(ash::STATUS_CLOSED, model_->items()[2].status);
+  EXPECT_EQ(3, model_.item_count());
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[2].type);
+  EXPECT_EQ(ash::STATUS_CLOSED, model_.items()[2].status);
   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_NE(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
 
   // Unpinning the app should remove its shelf item.
   launcher_controller_->UnpinAppWithID(extension1_->id());
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_EQ(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
@@ -1777,41 +1770,41 @@
 TEST_F(ChromeLauncherControllerTest, V1AppRunPinCloseUnpin) {
   InitLauncherController();
   // The model should only contain the browser shortcut and app list items.
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_EQ(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
 
   // Reporting that the app is running should create a new shelf item.
   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_RUNNING);
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_APP, model_->items()[2].type);
-  EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[2].status);
+  EXPECT_EQ(3, model_.item_count());
+  EXPECT_EQ(ash::TYPE_APP, model_.items()[2].type);
+  EXPECT_EQ(ash::STATUS_RUNNING, model_.items()[2].status);
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_NE(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
 
   // Pinning the app should just update the existing item.
   launcher_controller_->PinAppWithID(extension1_->id());
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
-  EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[2].status);
+  EXPECT_EQ(3, model_.item_count());
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[2].type);
+  EXPECT_EQ(ash::STATUS_RUNNING, model_.items()[2].status);
   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_NE(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
 
   // Reporting that the app is closed should just update the existing item.
   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
-  EXPECT_EQ(ash::STATUS_CLOSED, model_->items()[2].status);
+  EXPECT_EQ(3, model_.item_count());
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[2].type);
+  EXPECT_EQ(ash::STATUS_CLOSED, model_.items()[2].status);
   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_NE(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
 
   // Unpinning the app should remove its shelf item.
   launcher_controller_->UnpinAppWithID(extension1_->id());
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_EQ(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
@@ -1821,41 +1814,41 @@
 TEST_F(ChromeLauncherControllerTest, V1AppPinRunUnpinClose) {
   InitLauncherController();
   // The model should only contain the browser shortcut and app list items.
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_EQ(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
 
   // Pinning the app should create a new shelf item.
   launcher_controller_->PinAppWithID(extension1_->id());
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
-  EXPECT_EQ(ash::STATUS_CLOSED, model_->items()[2].status);
+  EXPECT_EQ(3, model_.item_count());
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[2].type);
+  EXPECT_EQ(ash::STATUS_CLOSED, model_.items()[2].status);
   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_NE(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
 
   // Reporting that the app is running should just update the existing item.
   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_RUNNING);
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
-  EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[2].status);
+  EXPECT_EQ(3, model_.item_count());
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[2].type);
+  EXPECT_EQ(ash::STATUS_RUNNING, model_.items()[2].status);
   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_NE(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
 
   // Unpinning the app should just update the existing item.
   launcher_controller_->UnpinAppWithID(extension1_->id());
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_APP, model_->items()[2].type);
-  EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[2].status);
+  EXPECT_EQ(3, model_.item_count());
+  EXPECT_EQ(ash::TYPE_APP, model_.items()[2].type);
+  EXPECT_EQ(ash::STATUS_RUNNING, model_.items()[2].status);
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_NE(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
 
   // Reporting that the app is closed should remove its shelf item.
   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_EQ(nullptr,
             launcher_controller_->GetItem(ash::ShelfID(extension1_->id())));
@@ -1865,13 +1858,13 @@
 TEST_F(ChromeLauncherControllerTest, CheckRunningV1AppOrder) {
   InitLauncherController();
   // The model should only contain the browser shortcut and app list items.
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
 
   // Add a few running applications.
   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_RUNNING);
   launcher_controller_->SetV1AppStatus(extension2_->id(), ash::STATUS_RUNNING);
   launcher_controller_->SetV1AppStatus(extension3_->id(), ash::STATUS_RUNNING);
-  EXPECT_EQ(5, model_->item_count());
+  EXPECT_EQ(5, model_.item_count());
   // Note that this not only checks the order of applications but also the
   // running type.
   EXPECT_EQ("AppList, Chrome, app1, app2, app3", GetPinnedAppStatus());
@@ -1883,7 +1876,7 @@
 
   // Switch some items and check that restoring a user which was not yet
   // remembered changes nothing.
-  model_->Move(2, 3);
+  model_.Move(2, 3);
   EXPECT_EQ("AppList, Chrome, app2, app1, app3", GetPinnedAppStatus());
   const AccountId second_fake_account_id(
       AccountId::FromUserEmail("second-fake-user@fake.com"));
@@ -1896,7 +1889,7 @@
 
   // Switch again some items and even delete one - making sure that the missing
   // item gets properly handled.
-  model_->Move(3, 4);
+  model_.Move(3, 4);
   launcher_controller_->SetV1AppStatus(extension1_->id(), ash::STATUS_CLOSED);
   EXPECT_EQ("AppList, Chrome, app3, app2", GetPinnedAppStatus());
   RestoreUnpinnedRunningApplicationOrder(current_account_id);
@@ -1951,7 +1944,7 @@
   // We activated arc_app_id1 twice but expect one close for item controller
   // stops launching request.
   ash::ShelfItemDelegate* item_delegate =
-      model_->GetShelfItemDelegate(shelf_id_app_1);
+      model_.GetShelfItemDelegate(shelf_id_app_1);
   ASSERT_NE(nullptr, item_delegate);
   item_delegate->Close();
   base::RunLoop().RunUntilIdle();
@@ -2007,7 +2000,7 @@
 
   // Play Store app is ARC app that might be represented by native Chrome
   // platform app.
-  model_->SetShelfItemDelegate(
+  model_.SetShelfItemDelegate(
       shelf_id,
       base::MakeUnique<ExtensionAppWindowLauncherItemController>(shelf_id));
   launcher_controller_->SetItemStatus(shelf_id, ash::STATUS_RUNNING);
@@ -2324,7 +2317,7 @@
                                             std::string());
   EXPECT_TRUE(launcher_controller_->GetItem(ash::ShelfID(arc_app_id)));
   ash::ShelfItemDelegate* item_delegate =
-      model_->GetShelfItemDelegate(ash::ShelfID(arc_app_id));
+      model_.GetShelfItemDelegate(ash::ShelfID(arc_app_id));
   ASSERT_TRUE(item_delegate);
 
   // No custom icon set. Acitivating windows should not change icon.
@@ -2365,12 +2358,12 @@
   // Create a browser item in the LauncherController.
   InitLauncherController();
 
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
   {
     // Create a "windowed gmail app".
     std::unique_ptr<V1App> v1_app(
         CreateRunningV1App(profile(), extension_misc::kGmailAppId, kGmailUrl));
-    EXPECT_EQ(3, model_->item_count());
+    EXPECT_EQ(3, model_.item_count());
 
     // After switching to a second user the item should be gone.
     std::string user2 = "user2";
@@ -2380,14 +2373,14 @@
     const AccountId account_id(
         multi_user_util::GetAccountIdFromProfile(profile()));
     SwitchActiveUser(account_id2);
-    EXPECT_EQ(2, model_->item_count());
+    EXPECT_EQ(2, model_.item_count());
 
     // After switching back the item should be back.
     SwitchActiveUser(account_id);
-    EXPECT_EQ(3, model_->item_count());
+    EXPECT_EQ(3, model_.item_count());
     // Note we destroy now the gmail app with the closure end.
   }
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
 }
 
 // Check edge cases with multi profile V1 apps in the shelf.
@@ -2407,23 +2400,23 @@
     // Create a "windowed gmail app".
     std::unique_ptr<V1App> v1_app(
         CreateRunningV1App(profile2, extension_misc::kGmailAppId, kGmailUrl));
-    EXPECT_EQ(2, model_->item_count());
+    EXPECT_EQ(2, model_.item_count());
 
     // However - switching to the user should show it.
     SwitchActiveUser(account_id2);
-    EXPECT_EQ(3, model_->item_count());
+    EXPECT_EQ(3, model_.item_count());
 
     // Second test: Remove the app when the user is not active and see that it
     // works.
     SwitchActiveUser(account_id);
-    EXPECT_EQ(2, model_->item_count());
+    EXPECT_EQ(2, model_.item_count());
     // Note: the closure ends and the browser will go away.
   }
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
   SwitchActiveUser(account_id2);
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
   SwitchActiveUser(account_id);
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
 }
 
 // Check edge case where a visiting V1 app gets closed (crbug.com/321374).
@@ -2446,28 +2439,28 @@
     // Create a "windowed gmail app".
     std::unique_ptr<V1App> v1_app(CreateRunningV1App(
         profile(), extension_misc::kGmailAppId, kGmailLaunchURL));
-    EXPECT_EQ(3, model_->item_count());
+    EXPECT_EQ(3, model_.item_count());
 
     // Transfer the app to the other screen and switch users.
     manager->ShowWindowForUser(v1_app->browser()->window()->GetNativeWindow(),
                                account_id2);
-    EXPECT_EQ(3, model_->item_count());
+    EXPECT_EQ(3, model_.item_count());
     SwitchActiveUser(account_id2);
-    EXPECT_EQ(2, model_->item_count());
+    EXPECT_EQ(2, model_.item_count());
   }
   // After the app was destroyed, switch back. (which caused already a crash).
   SwitchActiveUser(account_id);
 
   // Create the same app again - which was also causing the crash.
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
   {
     // Create a "windowed gmail app".
     std::unique_ptr<V1App> v1_app(CreateRunningV1App(
         profile(), extension_misc::kGmailAppId, kGmailLaunchURL));
-    EXPECT_EQ(3, model_->item_count());
+    EXPECT_EQ(3, model_.item_count());
   }
   SwitchActiveUser(account_id2);
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
 }
 
 // Check edge cases with multi profile V1 apps in the shelf.
@@ -2488,23 +2481,23 @@
     // Create a "windowed gmail app".
     std::unique_ptr<V1App> v1_app(
         CreateRunningV1App(profile(), extension_misc::kGmailAppId, kGmailUrl));
-    EXPECT_EQ(2, model_->item_count());
+    EXPECT_EQ(2, model_.item_count());
 
     // However - switching to the user should show it.
     SwitchActiveUser(account_id);
-    EXPECT_EQ(3, model_->item_count());
+    EXPECT_EQ(3, model_.item_count());
 
     // Second test: Remove the app when the user is not active and see that it
     // works.
     SwitchActiveUser(account_id2);
-    EXPECT_EQ(2, model_->item_count());
+    EXPECT_EQ(2, model_.item_count());
     v1_app.reset();
   }
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
   SwitchActiveUser(account_id);
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
   SwitchActiveUser(account_id2);
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
 }
 
 // Check that activating an item which is on another user's desktop, will bring
@@ -2747,17 +2740,17 @@
   // Only |extension1_| should get pinned. |extension2_| is specified but not
   // installed, and |extension3_| is part of the default set, but that shouldn't
   // take effect when the policy override is in place.
-  ASSERT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
+  ASSERT_EQ(3, model_.item_count());
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[1].type);
   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
 
   // Installing |extension2_| should add it to the launcher.
   extension_service_->AddExtension(extension2_.get());
-  ASSERT_EQ(4, model_->item_count());
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
+  ASSERT_EQ(4, model_.item_count());
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[1].type);
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[2].type);
   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
@@ -2767,8 +2760,8 @@
   policy_value.Remove(0, NULL);
   profile()->GetTestingPrefService()->SetManagedPref(
       prefs::kPolicyPinnedLauncherApps, policy_value.CreateDeepCopy());
-  EXPECT_EQ(4, model_->item_count());
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
+  EXPECT_EQ(4, model_.item_count());
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[2].type);
   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
   EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
@@ -3039,7 +3032,7 @@
   InitLauncherControllerWithBrowser();
 
   // The model should only contain the browser shortcut and app list items.
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
   EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
 
   // Installing |extension3_| pins it to the launcher.
@@ -3152,19 +3145,19 @@
   const AccountId account_id2(
       multi_user_util::GetAccountIdFromProfile(profile2));
   // Check that there is a browser and a app launcher.
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
 
   // Add a v2 app.
   V2App v2_app(profile(), extension1_.get());
-  EXPECT_EQ(3, model_->item_count());
+  EXPECT_EQ(3, model_.item_count());
 
   // After switching users the item should go away.
   SwitchActiveUser(account_id2);
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
 
   // And it should come back when switching back.
   SwitchActiveUser(account_id);
-  EXPECT_EQ(3, model_->item_count());
+  EXPECT_EQ(3, model_.item_count());
 }
 
 // Check that V2 applications are creating items properly in edge cases:
@@ -3180,35 +3173,35 @@
   const AccountId account_id2(
       multi_user_util::GetAccountIdFromProfile(profile2));
   // Check that there is a browser and a app launcher.
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
 
   // Switch to an inactive user.
   SwitchActiveUser(account_id2);
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
 
   // Add the v2 app to the inactive user and check that no item was added to
   // the launcher.
   {
     V2App v2_app(profile(), extension1_.get());
-    EXPECT_EQ(2, model_->item_count());
+    EXPECT_EQ(2, model_.item_count());
 
     // Switch to the primary user and check that the item is shown.
     SwitchActiveUser(account_id);
-    EXPECT_EQ(3, model_->item_count());
+    EXPECT_EQ(3, model_.item_count());
 
     // Switch to the second user and check that the item goes away - even if the
     // item gets closed.
     SwitchActiveUser(account_id2);
-    EXPECT_EQ(2, model_->item_count());
+    EXPECT_EQ(2, model_.item_count());
   }
 
   // After the application was killed there should be still 2 items.
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
 
   // Switching then back to the default user should not show the additional item
   // anymore.
   SwitchActiveUser(account_id);
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
 }
 
 // Check that V2 applications will be made visible on the target desktop if
@@ -3294,64 +3287,64 @@
   const AccountId account_id2(
       multi_user_util::GetAccountIdFromProfile(profile2));
   SwitchActiveUser(account_id);
-  EXPECT_EQ(2, model_->item_count());
+  EXPECT_EQ(2, model_.item_count());
 
   V2App v2_app_1(profile(), extension1_.get());
-  EXPECT_EQ(3, model_->item_count());
+  EXPECT_EQ(3, model_.item_count());
   {
     // Hide and show the app.
     v2_app_1.window()->Hide();
-    EXPECT_EQ(2, model_->item_count());
+    EXPECT_EQ(2, model_.item_count());
 
     v2_app_1.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
-    EXPECT_EQ(3, model_->item_count());
+    EXPECT_EQ(3, model_.item_count());
   }
   {
     // Switch user, hide and show the app and switch back.
     SwitchActiveUser(account_id2);
-    EXPECT_EQ(2, model_->item_count());
+    EXPECT_EQ(2, model_.item_count());
 
     v2_app_1.window()->Hide();
-    EXPECT_EQ(2, model_->item_count());
+    EXPECT_EQ(2, model_.item_count());
 
     v2_app_1.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
-    EXPECT_EQ(2, model_->item_count());
+    EXPECT_EQ(2, model_.item_count());
 
     SwitchActiveUser(account_id);
-    EXPECT_EQ(3, model_->item_count());
+    EXPECT_EQ(3, model_.item_count());
   }
   {
     // Switch user, hide the app, switch back and then show it again.
     SwitchActiveUser(account_id2);
-    EXPECT_EQ(2, model_->item_count());
+    EXPECT_EQ(2, model_.item_count());
 
     v2_app_1.window()->Hide();
-    EXPECT_EQ(2, model_->item_count());
+    EXPECT_EQ(2, model_.item_count());
 
     SwitchActiveUser(account_id);
     // The following expectation does not work in current impl. It was working
     // before because MultiUserWindowManagerChromeOS is not attached to user
     // associated with profile() hence not actually handling windows for the
     // user. It is a real bug. See http://crbug.com/693634
-    // EXPECT_EQ(2, model_->item_count());
+    // EXPECT_EQ(2, model_.item_count());
 
     v2_app_1.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
-    EXPECT_EQ(3, model_->item_count());
+    EXPECT_EQ(3, model_.item_count());
   }
   {
     // Create a second app, hide and show it and then hide both apps.
     V2App v2_app_2(profile(), extension1_.get());
-    EXPECT_EQ(3, model_->item_count());
+    EXPECT_EQ(3, model_.item_count());
 
     v2_app_2.window()->Hide();
-    EXPECT_EQ(3, model_->item_count());
+    EXPECT_EQ(3, model_.item_count());
 
     v2_app_2.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
-    EXPECT_EQ(3, model_->item_count());
+    EXPECT_EQ(3, model_.item_count());
 
     v2_app_1.window()->Hide();
     v2_app_2.window()->Hide();
-    EXPECT_EQ(2, model_->item_count());
+    EXPECT_EQ(2, model_.item_count());
   }
 }
 
@@ -3376,8 +3369,7 @@
   item_gmail.id = gmail_id;
   base::string16 two_menu_items[] = {title1, title2};
   CheckAppMenu(launcher_controller_, item_gmail, 2, two_menu_items);
-  ash::ShelfItemDelegate* item_delegate =
-      model_->GetShelfItemDelegate(gmail_id);
+  ash::ShelfItemDelegate* item_delegate = model_.GetShelfItemDelegate(gmail_id);
   ASSERT_TRUE(item_delegate);
   EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
   // Execute the second item in the menu, after the title and two separators,
@@ -3425,8 +3417,7 @@
   base::string16 two_menu_items[] = {title1, title2};
   CheckAppMenu(launcher_controller_, item_gmail, 2, two_menu_items);
 
-  ash::ShelfItemDelegate* item_delegate =
-      model_->GetShelfItemDelegate(gmail_id);
+  ash::ShelfItemDelegate* item_delegate = model_.GetShelfItemDelegate(gmail_id);
   ASSERT_TRUE(item_delegate);
   int tabs = browser()->tab_strip_model()->count();
   // Activate the proper tab through the menu item.
@@ -3446,48 +3437,6 @@
   }
 }
 
-// Tests that panels create launcher items correctly
-TEST_F(ChromeLauncherControllerTest, AppPanels) {
-  InitLauncherController();
-  model_observer_->clear_counts();
-  const std::string app_id = extension1_->id();
-
-  // app_icon_loader is owned by ChromeLauncherController.
-  TestAppIconLoaderImpl* app_icon_loader = new TestAppIconLoaderImpl();
-  app_icon_loader->AddSupportedApp(app_id);
-  SetAppIconLoader(std::unique_ptr<AppIconLoader>(app_icon_loader));
-
-  // Make an app panel; the ShelfItem is added by ash::ShelfWindowWatcher.
-  std::unique_ptr<V2App> app_panel1 = base::MakeUnique<V2App>(
-      profile(), extension1_.get(), extensions::AppWindow::WINDOW_TYPE_PANEL);
-  EXPECT_TRUE(app_panel1->window()->GetNativeWindow()->IsVisible());
-  int panel_index = model_observer_->last_index();
-  EXPECT_EQ(1, model_observer_->added());
-  EXPECT_EQ(1, app_icon_loader->fetch_count());
-  model_observer_->clear_counts();
-
-  // App panels should have a separate identifier than the app id
-  EXPECT_FALSE(launcher_controller_->GetItem(ash::ShelfID(app_id)));
-
-  // Setting the app image should not change the panel, which has a window icon.
-  gfx::ImageSkia image;
-  launcher_controller_->OnAppImageUpdated(app_id, image);
-  EXPECT_EQ(0, model_observer_->changed());
-  model_observer_->clear_counts();
-
-  // Make a second app panel and verify that it gets the same index as the first
-  // panel, being added to the left of the existing panel.
-  std::unique_ptr<V2App> app_panel2 = base::MakeUnique<V2App>(
-      profile(), extension2_.get(), extensions::AppWindow::WINDOW_TYPE_PANEL);
-  EXPECT_EQ(panel_index, model_observer_->last_index());
-  EXPECT_EQ(1, model_observer_->added());
-  model_observer_->clear_counts();
-
-  app_panel1.reset();
-  app_panel2.reset();
-  EXPECT_EQ(2, model_observer_->removed());
-}
-
 // Tests that the Gmail extension matches more than the app itself claims with
 // the manifest file.
 TEST_F(ChromeLauncherControllerTest, GmailMatching) {
@@ -3546,8 +3495,8 @@
   TestLauncherControllerHelper* helper = new TestLauncherControllerHelper;
   SetLauncherControllerHelper(helper);
 
-  EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type);
-  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[1].type);
+  EXPECT_EQ(ash::TYPE_APP_LIST, model_.items()[0].type);
+  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_.items()[1].type);
 
   TabStripModel* tab_strip_model = browser()->tab_strip_model();
   EXPECT_EQ(0, tab_strip_model->count());
@@ -3562,17 +3511,17 @@
   EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
   launcher_controller_->PinAppWithID("2");
 
-  EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type);
-  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[1].type);
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[3].type);
+  EXPECT_EQ(ash::TYPE_APP_LIST, model_.items()[0].type);
+  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_.items()[1].type);
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[2].type);
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[3].type);
 
   // Move browser shortcut item from index 1 to index 3.
-  model_->Move(1, 3);
-  EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type);
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
-  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[3].type);
+  model_.Move(1, 3);
+  EXPECT_EQ(ash::TYPE_APP_LIST, model_.items()[0].type);
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[1].type);
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[2].type);
+  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_.items()[3].type);
 
   RecreateLauncherController();
   helper = new TestLauncherControllerHelper(profile());
@@ -3582,16 +3531,16 @@
   launcher_controller_->Init();
 
   // Check ShelfItems are restored after resetting ChromeLauncherController.
-  EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[0].type);
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[1].type);
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[2].type);
-  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[3].type);
+  EXPECT_EQ(ash::TYPE_APP_LIST, model_.items()[0].type);
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[1].type);
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[2].type);
+  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_.items()[3].type);
 }
 
 // Verifies pinned apps are persisted and restored.
 TEST_F(ChromeLauncherControllerTest, PersistPinned) {
   InitLauncherControllerWithBrowser();
-  size_t initial_size = model_->items().size();
+  size_t initial_size = model_.items().size();
 
   TabStripModel* tab_strip_model = browser()->tab_strip_model();
   EXPECT_EQ(1, tab_strip_model->count());
@@ -3607,12 +3556,12 @@
   EXPECT_EQ(0, app_icon_loader->fetch_count());
 
   launcher_controller_->PinAppWithID("1");
-  const int app_index = model_->ItemIndexByID(ash::ShelfID("1"));
+  const int app_index = model_.ItemIndexByID(ash::ShelfID("1"));
   EXPECT_EQ(1, app_icon_loader->fetch_count());
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[app_index].type);
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[app_index].type);
   EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
   EXPECT_FALSE(launcher_controller_->IsAppPinned("0"));
-  EXPECT_EQ(initial_size + 1, model_->items().size());
+  EXPECT_EQ(initial_size + 1, model_.items().size());
 
   RecreateLauncherController();
   helper = new TestLauncherControllerHelper(profile());
@@ -3625,13 +3574,13 @@
   launcher_controller_->Init();
 
   EXPECT_EQ(1, app_icon_loader->fetch_count());
-  ASSERT_EQ(initial_size + 1, model_->items().size());
+  ASSERT_EQ(initial_size + 1, model_.items().size());
   EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
   EXPECT_FALSE(launcher_controller_->IsAppPinned("0"));
-  EXPECT_EQ(ash::TYPE_PINNED_APP, model_->items()[app_index].type);
+  EXPECT_EQ(ash::TYPE_PINNED_APP, model_.items()[app_index].type);
 
   launcher_controller_->UnpinAppWithID("1");
-  ASSERT_EQ(initial_size, model_->items().size());
+  ASSERT_EQ(initial_size, model_.items().size());
 }
 
 TEST_F(ChromeLauncherControllerTest, MultipleAppIconLoaders) {
@@ -3795,7 +3744,7 @@
 
   const std::string app_id = ArcAppTest::GetAppId(appinfo);
   ash::ShelfItemDelegate* item_delegate =
-      model_->GetShelfItemDelegate(ash::ShelfID(app_id));
+      model_.GetShelfItemDelegate(ash::ShelfID(app_id));
   ASSERT_TRUE(item_delegate);
 
   // Selecting the item will show its application menu. It does not change the
@@ -4135,7 +4084,7 @@
 
   // Simulate click. This should schedule Play Store for deferred launch.
   ash::ShelfItemDelegate* item_delegate =
-      model_->GetShelfItemDelegate(ash::ShelfID(arc::kPlayStoreAppId));
+      model_.GetShelfItemDelegate(ash::ShelfID(arc::kPlayStoreAppId));
   EXPECT_TRUE(item_delegate);
   SelectItem(item_delegate);
   EXPECT_TRUE(launcher_controller_->IsAppPinned(arc::kPlayStoreAppId));
@@ -4176,7 +4125,7 @@
   // Move Chrome between App1 and App2.
   // Note, move target_index is in context when moved element is removed from
   // array first.
-  model_->Move(1, 2);
+  model_.Move(1, 2);
   EXPECT_EQ("AppList, App1, Chrome, App2, App3", GetPinnedAppStatus());
 
   // Expect sync positions for only Chrome is updated and its resolution is
@@ -4234,7 +4183,8 @@
   prefs->SetString(prefs::kShelfAutoHideBehavior, "Always");
 
   TestChromeLauncherController* test_launcher_controller =
-      shell_delegate_->CreateTestLauncherController(profile());
+      shell_delegate_->CreateLauncherController(profile());
+  test_launcher_controller->Init();
 
   // Simulate login for the test controller.
   test_launcher_controller->ReleaseProfile();
@@ -4254,7 +4204,8 @@
 // Tests that the shelf controller's changes are not wastefully echoed back.
 TEST_F(ChromeLauncherControllerTest, DoNotEchoShelfControllerChanges) {
   TestChromeLauncherController* test_launcher_controller =
-      shell_delegate_->CreateTestLauncherController(profile());
+      shell_delegate_->CreateLauncherController(profile());
+  test_launcher_controller->Init();
 
   // Simulate login for the test controller.
   test_launcher_controller->ReleaseProfile();
@@ -4292,3 +4243,57 @@
   EXPECT_EQ("Always", prefs->GetString(prefs::kShelfAutoHideBehaviorLocal));
   EXPECT_EQ("Always", prefs->GetString(prefs::kShelfAutoHideBehavior));
 }
+
+// Ensure Ash and Chrome ShelfModel changes are synchronized correctly in Mash.
+TEST_F(ChromeLauncherControllerTest, ShelfModelSyncMash) {
+  if (chromeos::GetAshConfig() != ash::Config::MASH)
+    return;
+
+  // The ShelfModel constructor adds an AppList shelf item.
+  TestChromeLauncherController* launcher_controller =
+      shell_delegate_->CreateLauncherController(profile());
+  TestShelfController* shelf_controller =
+      launcher_controller->test_shelf_controller();
+  EXPECT_EQ(0u, shelf_controller->added_count());
+  EXPECT_EQ(0u, shelf_controller->removed_count());
+  EXPECT_EQ(1, model_.item_count());
+  EXPECT_EQ(ash::kAppListId, model_.items()[0].id.app_id);
+
+  // Init should add the browser shelf item to Chrome's ShelfModel.
+  // Ash's ShelfController should be notified about the new browser item.
+  launcher_controller->Init();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(2, model_.item_count());
+  EXPECT_EQ(extension_misc::kChromeAppId, model_.items()[1].id.app_id);
+  EXPECT_EQ(1u, shelf_controller->added_count());
+  EXPECT_EQ(0u, shelf_controller->removed_count());
+
+  // Add a shelf item using the ShelfController interface.
+  ash::ShelfItem item;
+  item.type = ash::TYPE_PINNED_APP;
+  item.id = ash::ShelfID(kDummyAppId);
+  shelf_controller->AddShelfItem(2, item);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(2u, shelf_controller->added_count());
+  EXPECT_EQ(0u, shelf_controller->removed_count());
+
+  // Remove a shelf item using the ShelfController interface.
+  shelf_controller->RemoveShelfItem(item.id);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(2u, shelf_controller->added_count());
+  EXPECT_EQ(1u, shelf_controller->removed_count());
+
+  // Add an item to Chrome's model; ShelfController should be notified.
+  model_.Add(item);
+  EXPECT_EQ(3, model_.item_count());
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(3u, shelf_controller->added_count());
+  EXPECT_EQ(1u, shelf_controller->removed_count());
+
+  // Remove an item from Chrome's model; ShelfController should be notified.
+  model_.RemoveItemAt(2);
+  EXPECT_EQ(2, model_.item_count());
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(3u, shelf_controller->added_count());
+  EXPECT_EQ(2u, shelf_controller->removed_count());
+}
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
index 630dbdb7..274bed9 100644
--- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
@@ -33,7 +33,6 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/accessibility/magnification_manager.h"
 #include "chrome/browser/chromeos/events/system_key_event_listener.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/login/login_wizard.h"
 #include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
 #include "chrome/browser/chromeos/profiles/multiprofiles_intro_dialog.h"
@@ -61,6 +60,7 @@
 #include "content/public/browser/notification_service.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/time_format.h"
 #include "ui/chromeos/events/pref_names.h"
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index c94dca161..8653eeb 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -64,7 +64,6 @@
 #include "chrome/browser/lifetime/keep_alive_types.h"
 #include "chrome/browser/lifetime/scoped_keep_alive.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
-#include "chrome/browser/memory/tab_manager_web_contents_data.h"
 #include "chrome/browser/notifications/notification_ui_manager.h"
 #include "chrome/browser/pepper_broker_infobar_delegate.h"
 #include "chrome/browser/permissions/permission_request_manager.h"
@@ -75,6 +74,7 @@
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/browser/profiles/profiles_state.h"
 #include "chrome/browser/repost_form_warning_controller.h"
+#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/sessions/session_restore.h"
 #include "chrome/browser/sessions/session_service.h"
diff --git a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc
index 05888bc..aab4bb8 100644
--- a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc
@@ -102,7 +102,6 @@
   if (ash_util::IsRunningInMash()) {
     DCHECK(!ash::Shell::HasInstance());
     DCHECK(!ChromeLauncherController::instance());
-    // TODO(crbug.com/557406): Synchronize this ShelfModel with the one in Ash.
     chrome_shelf_model_ = base::MakeUnique<ash::ShelfModel>();
     chrome_launcher_controller_ = base::MakeUnique<ChromeLauncherController>(
         nullptr, chrome_shelf_model_.get());
diff --git a/chrome/browser/ui/views/profiles/avatar_button.cc b/chrome/browser/ui/views/profiles/avatar_button.cc
index 20d0f3f..60f417c 100644
--- a/chrome/browser/ui/views/profiles/avatar_button.cc
+++ b/chrome/browser/ui/views/profiles/avatar_button.cc
@@ -200,13 +200,14 @@
   if (apply_ink_drop) {
     SetInkDropMode(InkDropMode::ON);
     SetFocusPainter(nullptr);
-    constexpr int kIconSize = 16;
 #if defined(OS_LINUX)
+    constexpr int kIconSize = 16;
     set_ink_drop_base_color(SK_ColorWHITE);
     SetBorder(base::MakeUnique<AvatarButtonThemedBorder>());
     generic_avatar_ = gfx::CreateVectorIcon(kProfileSwitcherOutlineIcon,
                                             kIconSize, gfx::kPlaceholderColor);
 #elif defined(OS_WIN)
+    constexpr int kIconSize = 16;
     DCHECK_EQ(AvatarButtonStyle::NATIVE, button_style);
     set_ink_drop_base_color(SK_ColorBLACK);
     SetBorder(views::CreateEmptyBorder(kBorderInsets));
diff --git a/chrome/browser/ui/webui/about_ui.cc b/chrome/browser/ui/webui/about_ui.cc
index c3f0cc3..67182676 100644
--- a/chrome/browser/ui/webui/about_ui.cc
+++ b/chrome/browser/ui/webui/about_ui.cc
@@ -38,11 +38,11 @@
 #include "chrome/browser/about_flags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/defaults.h"
-#include "chrome/browser/memory/tab_manager.h"
-#include "chrome/browser/memory/tab_stats.h"
 #include "chrome/browser/net/predictor.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/resource_coordinator/tab_manager.h"
+#include "chrome/browser/resource_coordinator/tab_stats.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/url_constants.h"
@@ -465,12 +465,13 @@
 }
 
 std::vector<std::string> GetHtmlTabDescriptorsForDiscardPage() {
-  memory::TabManager* tab_manager = g_browser_process->GetTabManager();
-  memory::TabStatsList stats = tab_manager->GetTabStats();
+  resource_coordinator::TabManager* tab_manager =
+      g_browser_process->GetTabManager();
+  resource_coordinator::TabStatsList stats = tab_manager->GetTabStats();
   std::vector<std::string> titles;
   titles.reserve(stats.size());
-  for (memory::TabStatsList::iterator it = stats.begin(); it != stats.end();
-       ++it) {
+  for (resource_coordinator::TabStatsList::iterator it = stats.begin();
+       it != stats.end(); ++it) {
     std::string str;
     str.reserve(4096);
     str += "<b>";
@@ -499,7 +500,8 @@
 std::string AboutDiscards(const std::string& path) {
   std::string output;
   int64_t web_content_id;
-  memory::TabManager* tab_manager = g_browser_process->GetTabManager();
+  resource_coordinator::TabManager* tab_manager =
+      g_browser_process->GetTabManager();
 
   std::vector<std::string> path_split = base::SplitString(
       path, "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index ed43fa4..67f3955d 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -16,7 +16,6 @@
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_shutdown.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/language_preferences.h"
 #include "chrome/browser/chromeos/login/screens/network_error.h"
 #include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
@@ -50,6 +49,7 @@
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 
 using content::BrowserThread;
 namespace em = enterprise_management;
diff --git a/chrome/browser/ui/webui/chromeos/login/l10n_util.cc b/chrome/browser/ui/webui/chromeos/login/l10n_util.cc
index 3b961134..986fd3bf 100644
--- a/chrome/browser/ui/webui/chromeos/login/l10n_util.cc
+++ b/chrome/browser/ui/webui/chromeos/login/l10n_util.cc
@@ -30,7 +30,6 @@
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/customization/customization_document.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/grit/generated_resources.h"
@@ -38,6 +37,7 @@
 #include "ui/base/ime/chromeos/component_extension_ime_manager.h"
 #include "ui/base/ime/chromeos/input_method_descriptor.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace chromeos {
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index 29426e30..902da5a 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -34,7 +34,6 @@
 #include "chrome/browser/browser_shutdown.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/language_preferences.h"
 #include "chrome/browser/chromeos/lock_screen_apps/state_controller.h"
 #include "chrome/browser/chromeos/login/error_screens_histogram_helper.h"
@@ -100,6 +99,7 @@
 #include "ui/base/ime/chromeos/ime_keyboard.h"
 #include "ui/base/ime/chromeos/input_method_descriptor.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 #include "ui/base/webui/web_ui_util.h"
 
 namespace {
diff --git a/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.cc
index 183fcde..8811f6ac 100644
--- a/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.cc
@@ -17,7 +17,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
@@ -39,6 +38,7 @@
 #include "ui/base/ime/chromeos/component_extension_ime_manager.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 #include "ui/base/l10n/l10n_util.h"
 
 using base::UserMetricsAction;
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
index cd129cb..e5d02eb 100644
--- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
@@ -53,7 +53,10 @@
   UMA_HISTOGRAM_ENUMERATION("Printing.CUPS.PpdSource", source, kPpdSourceMax);
 }
 
-void OnRemovedPrinter(bool success) {}
+void OnRemovedPrinter(const Printer::PrinterProtocol& protocol, bool success) {
+  UMA_HISTOGRAM_ENUMERATION("Printing.CUPS.PrinterRemoved", protocol,
+                            Printer::PrinterProtocol::kProtocolMax);
+}
 
 std::unique_ptr<base::DictionaryValue> GetPrinterInfo(const Printer& printer) {
   std::unique_ptr<base::DictionaryValue> printer_info =
@@ -184,12 +187,19 @@
   std::string printer_name;
   CHECK(args->GetString(0, &printer_id));
   CHECK(args->GetString(1, &printer_name));
-  PrintersManagerFactory::GetForBrowserContext(profile_)->RemovePrinter(
-      printer_id);
+  PrintersManager* prefs =
+      PrintersManagerFactory::GetForBrowserContext(profile_);
+  auto printer = prefs->GetPrinter(printer_id);
+  if (!printer)
+    return;
+
+  Printer::PrinterProtocol protocol = printer->GetProtocol();
+  prefs->RemovePrinter(printer_id);
 
   chromeos::DebugDaemonClient* client =
       chromeos::DBusThreadManager::Get()->GetDebugDaemonClient();
-  client->CupsRemovePrinter(printer_name, base::Bind(&OnRemovedPrinter),
+  client->CupsRemovePrinter(printer_name,
+                            base::Bind(&OnRemovedPrinter, protocol),
                             base::Bind(&base::DoNothing));
 }
 
@@ -270,6 +280,8 @@
                             chromeos::PrinterSetupResult::kMaxValue);
   switch (result_code) {
     case chromeos::PrinterSetupResult::kSuccess: {
+      UMA_HISTOGRAM_ENUMERATION("Printing.CUPS.PrinterAdded",
+                                printer->GetProtocol(), Printer::kProtocolMax);
       auto* manager = PrintersManagerFactory::GetForBrowserContext(profile_);
       manager->PrinterInstalled(*printer);
       manager->RegisterPrinter(std::move(printer));
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 4c3aee0..76e85e60 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -64,12 +64,6 @@
 const char kSwitchAccessExtensionId[] = "pmehocpgjmkenlokgjfkaichfjdhpeol";
 const char kSwitchAccessExtensionPath[] = "chromeos/switch_access";
 const char kGuestManifestFilename[] = "manifest_guest.json";
-const char kBrailleImeExtensionId[] =
-    "jddehjeebkoimngcbdkaahpobgicbffp";
-const char kBrailleImeExtensionPath[] =
-    "chromeos/braille_ime";
-const char kBrailleImeEngineId[] =
-    "_comp_ime_jddehjeebkoimngcbdkaahpobgicbffpbraille";
 const char kConnectivityDiagnosticsPath[] =
     "/usr/share/chromeos-assets/connectivity_diagnostics";
 const char kConnectivityDiagnosticsLauncherPath[] =
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index adb7e78..049567f 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -209,11 +209,6 @@
 // Name of the manifest file in an extension when a special manifest is used
 // for guest mode.
 extern const char kGuestManifestFilename[];
-// Extension id, path (relative to |chrome::DIR_RESOURCES|) and IME engine
-// id for the builtin-in Braille IME extension.
-extern const char kBrailleImeExtensionId[];
-extern const char kBrailleImeExtensionPath[];
-extern const char kBrailleImeEngineId[];
 // Path to preinstalled Connectivity Diagnostics extension.
 extern const char kConnectivityDiagnosticsPath[];
 extern const char kConnectivityDiagnosticsLauncherPath[];
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 013b968..c9df284 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1499,8 +1499,6 @@
       "../browser/media_galleries/fileapi/media_file_validator_browsertest.cc",
       "../browser/media_galleries/media_galleries_dialog_controller_mock.cc",
       "../browser/media_galleries/media_galleries_dialog_controller_mock.h",
-      "../browser/memory/tab_manager_browsertest.cc",
-      "../browser/memory/tab_manager_observer_browsertest.cc",
       "../browser/metrics/metrics_memory_details_browsertest.cc",
       "../browser/metrics/metrics_service_browsertest.cc",
       "../browser/metrics/process_memory_metrics_emitter_browsertest.cc",
@@ -1581,6 +1579,8 @@
       "../browser/renderer_context_menu/spelling_menu_observer_browsertest.cc",
       "../browser/renderer_host/render_process_host_chrome_browsertest.cc",
       "../browser/repost_form_warning_browsertest.cc",
+      "../browser/resource_coordinator/tab_manager_browsertest.cc",
+      "../browser/resource_coordinator/tab_manager_observer_browsertest.cc",
       "../browser/safe_browsing/chrome_cleaner/reporter_runner_browsertest_win.cc",
       "../browser/safe_json_parser_browsertest.cc",
       "../browser/search/hotword_installer_browsertest.cc",
@@ -2281,8 +2281,6 @@
         "../browser/ui/webui/options/chromeos/guest_mode_options_browsertest.h",
         "../browser/ui/webui/options/chromeos/guest_mode_options_ui_browsertest.cc",
         "../browser/ui/webui/options/chromeos/shared_options_browsertest.cc",
-        "//ui/base/ime/chromeos/input_method_whitelist.cc",
-        "//ui/base/ime/chromeos/input_method_whitelist.h",
       ]
       sources -= [
         "../../apps/load_and_launch_browsertest.cc",
@@ -2303,7 +2301,6 @@
       ]
       deps += [
         "//chrome/browser/chromeos:arc_test_support",
-        "//chromeos/ime:gencode",
         "//components/arc:arc_test_support",
         "//components/prefs",
         "//components/user_manager:test_support",
@@ -3548,9 +3545,9 @@
       "../browser/media_galleries/media_galleries_preferences_unittest.cc",
       "../browser/media_galleries/win/mtp_device_delegate_impl_win_unittest.cc",
       "../browser/media_galleries/win/mtp_device_object_enumerator_unittest.cc",
-      "../browser/memory/tab_manager_delegate_chromeos_unittest.cc",
-      "../browser/memory/tab_manager_unittest.cc",
-      "../browser/memory/tab_manager_web_contents_data_unittest.cc",
+      "../browser/resource_coordinator/tab_manager_delegate_chromeos_unittest.cc",
+      "../browser/resource_coordinator/tab_manager_unittest.cc",
+      "../browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc",
 
       # Android does not use the Message Center notification system.
       "../browser/net/firefox_proxy_settings_unittest.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/InfoBarUtil.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/InfoBarUtil.java
index f1524a4..6b0f842 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/InfoBarUtil.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/InfoBarUtil.java
@@ -22,7 +22,7 @@
      * Finds, and optionally clicks, the button with the specified ID in the given InfoBar.
      * @return True if the View was found.
      */
-    private static boolean findButton(InfoBar infoBar, int buttonId, boolean click) {
+    public static boolean findButton(InfoBar infoBar, int buttonId, boolean click) {
         final View button = infoBar.getView().findViewById(buttonId);
         if (button == null) return false;
         if (click) {
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/TranslateUtil.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/TranslateUtil.java
index e64931ca..fed5f4f 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/TranslateUtil.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/TranslateUtil.java
@@ -16,10 +16,13 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.infobar.InfoBar;
 import org.chromium.chrome.browser.infobar.InfoBarCompactLayout;
+import org.chromium.chrome.browser.infobar.TranslateCompactInfoBar;
+import org.chromium.chrome.browser.infobar.translate.TranslateMenu;
 import org.chromium.chrome.browser.infobar.translate.TranslateTabLayout;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content.browser.test.util.TestTouchUtils;
 
-
 /**
  * Utility functions for dealing with Translate InfoBars.
  */
@@ -73,6 +76,73 @@
         Assert.assertTrue(tabLayout instanceof TranslateTabLayout);
     }
 
+    public static void assertHasAtLeastTwoLanguageTabs(TranslateCompactInfoBar infoBar) {
+        View content = infoBar.getView().findViewById(R.id.translate_infobar_content);
+        Assert.assertNotNull(content);
+
+        TranslateTabLayout tabLayout =
+                (TranslateTabLayout) content.findViewById(R.id.translate_infobar_tabs);
+        Assert.assertTrue(tabLayout.getTabCount() >= 2);
+    }
+
+    /**
+     * Checks if the menu button exists on the InfoBar.
+     * @return True if the View was found.
+     */
+    public static boolean hasMenuButton(InfoBar infoBar) {
+        return InfoBarUtil.findButton(infoBar, R.id.translate_infobar_menu_button, false);
+    }
+
+    /**
+     * Simulates clicking the menu button in the specified infobar.
+     * @return True if the View was found.
+     */
+    public static boolean clickMenuButton(InfoBar infoBar) {
+        return InfoBarUtil.findButton(infoBar, R.id.translate_infobar_menu_button, true);
+    }
+
+    /**
+     * Simulates clicking the menu button and check if overflow menu is shown.
+     */
+    public static void clickMenuButtonAndAssertMenuShown(final TranslateCompactInfoBar infoBar) {
+        clickMenuButton(infoBar);
+        CriteriaHelper.pollInstrumentationThread(new Criteria("Overflow menu did not show") {
+            @Override
+            public boolean isSatisfied() {
+                return infoBar.isShowingOverflowMenuForTesting();
+            }
+        });
+    }
+
+    /**
+     * Simulates clicking the 'More Language' menu item and check if language menu is shown.
+     */
+    public static void clickMoreLanguageButtonAndAssertLanguageMenuShown(
+            Instrumentation instrumentation, final TranslateCompactInfoBar infoBar) {
+        invokeOverflowMenuActionSync(
+                instrumentation, infoBar, TranslateMenu.ID_OVERFLOW_MORE_LANGUAGE);
+        CriteriaHelper.pollInstrumentationThread(new Criteria("Language menu did not show") {
+            @Override
+            public boolean isSatisfied() {
+                return infoBar.isShowingLanguageMenuForTesting();
+            }
+        });
+    }
+
+    /**
+     * Execute a particular menu item from the overflow menu.
+     * The item is executed even if it is disabled or not visible.
+     */
+    public static void invokeOverflowMenuActionSync(
+            Instrumentation instrumentation, final TranslateCompactInfoBar infoBar, final int id) {
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                infoBar.onOverflowMenuItemClicked(id);
+            }
+        });
+    }
+
     private static String findInfoBarText(View view) {
         TextView text = (TextView) view.findViewById(R.id.infobar_message);
         return text != null ? text.getText().toString() : null;
diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc
index 9344652..803f8fe5 100644
--- a/chrome/test/base/testing_browser_process.cc
+++ b/chrome/test/base/testing_browser_process.cc
@@ -12,11 +12,11 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_impl.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
-#include "chrome/browser/memory/tab_manager.h"
 #include "chrome/browser/notifications/notification_platform_bridge.h"
 #include "chrome/browser/notifications/notification_ui_manager.h"
 #include "chrome/browser/printing/print_job_manager.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/resource_coordinator/tab_manager.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/features.h"
@@ -391,10 +391,10 @@
   return nullptr;
 }
 
-memory::TabManager* TestingBrowserProcess::GetTabManager() {
+resource_coordinator::TabManager* TestingBrowserProcess::GetTabManager() {
 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
   if (!tab_manager_.get())
-    tab_manager_.reset(new memory::TabManager());
+    tab_manager_.reset(new resource_coordinator::TabManager());
   return tab_manager_.get();
 #else
   return nullptr;
diff --git a/chrome/test/base/testing_browser_process.h b/chrome/test/base/testing_browser_process.h
index 9c6b80f..3f8d891 100644
--- a/chrome/test/base/testing_browser_process.h
+++ b/chrome/test/base/testing_browser_process.h
@@ -129,7 +129,7 @@
   network_time::NetworkTimeTracker* network_time_tracker() override;
 
   gcm::GCMDriver* gcm_driver() override;
-  memory::TabManager* GetTabManager() override;
+  resource_coordinator::TabManager* GetTabManager() override;
   shell_integration::DefaultWebClientState CachedDefaultWebClientState()
       override;
   physical_web::PhysicalWebDataSource* GetPhysicalWebDataSource() override;
@@ -188,7 +188,7 @@
   // |tab_manager_| is null by default and will be created when
   // GetTabManager() is invoked on supported platforms.
 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
-  std::unique_ptr<memory::TabManager> tab_manager_;
+  std::unique_ptr<resource_coordinator::TabManager> tab_manager_;
 #endif
 
   // The following objects are not owned by TestingBrowserProcess:
diff --git a/chrome/test/data/simple_open_search_no_name.xml b/chrome/test/data/simple_open_search_no_name.xml
new file mode 100644
index 0000000..bbfbe4f
--- /dev/null
+++ b/chrome/test/data/simple_open_search_no_name.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
+<ShortName/>
+<Description>Not a creative description.</Description>
+<Url type="text/html" template="http://example.com/{searchTerms}/other_stuff"/>
+</OpenSearchDescription>
diff --git a/chromeos/components/tether/fake_host_scan_cache.cc b/chromeos/components/tether/fake_host_scan_cache.cc
index 917a13a..fae2ff6 100644
--- a/chromeos/components/tether/fake_host_scan_cache.cc
+++ b/chromeos/components/tether/fake_host_scan_cache.cc
@@ -51,7 +51,8 @@
     const std::string& device_name,
     const std::string& carrier,
     int battery_percentage,
-    int signal_strength) {
+    int signal_strength,
+    bool setup_required) {
   auto it = cache_.find(tether_network_guid);
   if (it != cache_.end()) {
     // If already in the cache, update the cache with new values.
@@ -59,13 +60,14 @@
     it->second.carrier = carrier;
     it->second.battery_percentage = battery_percentage;
     it->second.signal_strength = signal_strength;
+    it->second.setup_required = setup_required;
     return;
   }
 
   // Otherwise, add a new entry.
-  cache_.emplace(
-      tether_network_guid,
-      CacheEntry{device_name, carrier, battery_percentage, signal_strength});
+  cache_.emplace(tether_network_guid,
+                 CacheEntry{device_name, carrier, battery_percentage,
+                            signal_strength, setup_required});
 }
 
 bool FakeHostScanCache::RemoveHostScanResult(
@@ -86,6 +88,15 @@
   }
 }
 
+bool FakeHostScanCache::DoesHostRequireSetup(
+    const std::string& tether_network_guid) {
+  auto it = cache_.find(tether_network_guid);
+  if (it != cache_.end())
+    return it->second.setup_required;
+
+  return false;
+}
+
 void FakeHostScanCache::OnPreviouslyConnectedHostIdsChanged() {}
 
 }  // namespace tether
diff --git a/chromeos/components/tether/fake_host_scan_cache.h b/chromeos/components/tether/fake_host_scan_cache.h
index 1b39018..e63c3fb8 100644
--- a/chromeos/components/tether/fake_host_scan_cache.h
+++ b/chromeos/components/tether/fake_host_scan_cache.h
@@ -23,6 +23,7 @@
     std::string carrier;
     int battery_percentage;
     int signal_strength;
+    bool setup_required;
   };
 
   FakeHostScanCache();
@@ -52,9 +53,11 @@
                          const std::string& device_name,
                          const std::string& carrier,
                          int battery_percentage,
-                         int signal_strength) override;
+                         int signal_strength,
+                         bool setup_required) override;
   bool RemoveHostScanResult(const std::string& tether_network_guid) override;
   void ClearCacheExceptForActiveHost() override;
+  bool DoesHostRequireSetup(const std::string& tether_network_guid) override;
   void OnPreviouslyConnectedHostIdsChanged() override;
 
  private:
diff --git a/chromeos/components/tether/host_scan_cache.cc b/chromeos/components/tether/host_scan_cache.cc
index c059aeb..51696431 100644
--- a/chromeos/components/tether/host_scan_cache.cc
+++ b/chromeos/components/tether/host_scan_cache.cc
@@ -41,7 +41,8 @@
                                       const std::string& device_name,
                                       const std::string& carrier,
                                       int battery_percentage,
-                                      int signal_strength) {
+                                      int signal_strength,
+                                      bool setup_required) {
   DCHECK(!tether_network_guid.empty());
 
   auto found_iter = tether_guid_to_timer_map_.find(tether_network_guid);
@@ -72,6 +73,11 @@
                  << "new signal strength: " << signal_strength;
   }
 
+  if (setup_required)
+    setup_required_tether_guids_.insert(tether_network_guid);
+  else
+    setup_required_tether_guids_.erase(tether_network_guid);
+
   StartTimer(tether_network_guid);
 }
 
@@ -95,6 +101,7 @@
   }
 
   tether_guid_to_timer_map_.erase(it);
+  setup_required_tether_guids_.erase(tether_network_guid);
   return network_state_handler_->RemoveTetherNetworkState(tether_network_guid);
 }
 
@@ -133,6 +140,12 @@
   }
 }
 
+bool HostScanCache::DoesHostRequireSetup(
+    const std::string& tether_network_guid) {
+  return setup_required_tether_guids_.find(tether_network_guid) !=
+         setup_required_tether_guids_.end();
+}
+
 void HostScanCache::OnPreviouslyConnectedHostIdsChanged() {
   for (auto& map_entry : tether_guid_to_timer_map_) {
     const std::string& tether_network_guid = map_entry.first;
diff --git a/chromeos/components/tether/host_scan_cache.h b/chromeos/components/tether/host_scan_cache.h
index 3d705e48..762f3ef 100644
--- a/chromeos/components/tether/host_scan_cache.h
+++ b/chromeos/components/tether/host_scan_cache.h
@@ -58,11 +58,15 @@
   // Note: |signal_strength| should be in the range [0, 100]. This is different
   // from the |connection_strength| field received in ConnectTetheringResponse
   // and KeepAliveTickleResponse messages (the range is [0, 4] in those cases).
+  // |battery_percentage| should also be in the range [0, 100].
+  // |setup_required| indicates that the host device requires first-time setup,
+  // i.e., user interaction to allow tethering.
   virtual void SetHostScanResult(const std::string& tether_network_guid,
                                  const std::string& device_name,
                                  const std::string& carrier,
                                  int battery_percentage,
-                                 int signal_strength);
+                                 int signal_strength,
+                                 bool setup_required);
 
   // Removes the scan result with GUID |tether_network_guid| from the cache. If
   // no cache result with that GUID was present in the cache, this function is
@@ -74,6 +78,10 @@
   // connecting/connected to ensure the UI is up to date.
   virtual void ClearCacheExceptForActiveHost();
 
+  // Returns true if the host device requires first-time setup, i.e., user
+  // interaction to allow tethering.
+  virtual bool DoesHostRequireSetup(const std::string& tether_network_guid);
+
   // TetherHostResponseRecorder::Observer:
   void OnPreviouslyConnectedHostIdsChanged() override;
 
@@ -99,6 +107,7 @@
   // host).
   std::unordered_map<std::string, std::unique_ptr<base::Timer>>
       tether_guid_to_timer_map_;
+  std::unordered_set<std::string> setup_required_tether_guids_;
   base::WeakPtrFactory<HostScanCache> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(HostScanCache);
diff --git a/chromeos/components/tether/host_scan_cache_unittest.cc b/chromeos/components/tether/host_scan_cache_unittest.cc
index d0e3640..ae09f5e 100644
--- a/chromeos/components/tether/host_scan_cache_unittest.cc
+++ b/chromeos/components/tether/host_scan_cache_unittest.cc
@@ -58,6 +58,11 @@
 const int kTetherSignalStrength2 = 75;
 const int kTetherSignalStrength3 = 100;
 
+const bool kTetherSetupRequired0 = true;
+const bool kTetherSetupRequired1 = false;
+const bool kTetherSetupRequired2 = true;
+const bool kTetherSetupRequired3 = false;
+
 // MockTimer which invokes a callback in its destructor.
 class ExtendedMockTimer : public base::MockTimer {
  public:
@@ -205,6 +210,7 @@
     std::string carrier;
     int battery_percentage;
     int signal_strength;
+    bool setup_required;
 
     switch (index) {
       case 0:
@@ -213,6 +219,7 @@
         carrier = kTetherCarrier0;
         battery_percentage = kTetherBatteryPercentage0;
         signal_strength = kTetherSignalStrength0;
+        setup_required = kTetherSetupRequired0;
         break;
       case 1:
         tether_network_guid = kTetherGuid1;
@@ -220,6 +227,7 @@
         carrier = kTetherCarrier1;
         battery_percentage = kTetherBatteryPercentage1;
         signal_strength = kTetherSignalStrength1;
+        setup_required = kTetherSetupRequired1;
         break;
       case 2:
         tether_network_guid = kTetherGuid2;
@@ -227,6 +235,7 @@
         carrier = kTetherCarrier2;
         battery_percentage = kTetherBatteryPercentage2;
         signal_strength = kTetherSignalStrength2;
+        setup_required = kTetherSetupRequired2;
         break;
       case 3:
         tether_network_guid = kTetherGuid3;
@@ -234,34 +243,37 @@
         carrier = kTetherCarrier3;
         battery_percentage = kTetherBatteryPercentage3;
         signal_strength = kTetherSignalStrength3;
+        setup_required = kTetherSetupRequired3;
         break;
       default:
         NOTREACHED();
-        // Set values for |battery_percentage| and |signal_strength| here to
-        // prevent a compiler warning which says that they may be unset at this
-        // point.
+        // Set values for |battery_percentage|, |signal_strength| and
+        // |setup_required| here to prevent a compiler warning which says that
+        // they may be unset at this point.
         battery_percentage = 0;
         signal_strength = 0;
+        setup_required = false;
         break;
     }
 
     SetHostScanResult(tether_network_guid, device_name, carrier,
-                      battery_percentage, signal_strength);
+                      battery_percentage, signal_strength, setup_required);
   }
 
   void SetHostScanResult(const std::string& tether_network_guid,
                          const std::string& device_name,
                          const std::string& carrier,
                          int battery_percentage,
-                         int signal_strength) {
+                         int signal_strength,
+                         bool setup_required) {
     test_timer_factory_->set_tether_network_guid_for_next_timer(
         tether_network_guid);
     host_scan_cache_->SetHostScanResult(tether_network_guid, device_name,
                                         carrier, battery_percentage,
-                                        signal_strength);
+                                        signal_strength, setup_required);
     expected_cache_->SetHostScanResult(tether_network_guid, device_name,
                                        carrier, battery_percentage,
-                                       signal_strength);
+                                       signal_strength, setup_required);
   }
 
   void RemoveHostScanResult(const std::string& tether_network_guid) {
@@ -300,6 +312,8 @@
                 tether_network_state->battery_percentage());
       EXPECT_EQ(cache_entry.signal_strength,
                 tether_network_state->signal_strength());
+      EXPECT_EQ(cache_entry.setup_required,
+                host_scan_cache_->DoesHostRequireSetup(tether_network_guid));
       EXPECT_EQ(HasConnectedToHost(tether_network_guid),
                 tether_network_state->tether_has_connected_to_host());
 
@@ -373,7 +387,8 @@
   // Change the fields for tether network with GUID |kTetherGuid0| to the
   // fields corresponding to |kTetherGuid1|.
   SetHostScanResult(kTetherGuid0, kTetherDeviceName0, kTetherCarrier1,
-                    kTetherBatteryPercentage1, kTetherSignalStrength1);
+                    kTetherBatteryPercentage1, kTetherSignalStrength1,
+                    kTetherSetupRequired1);
   EXPECT_EQ(1u, expected_cache_->size());
   VerifyCacheMatchesNetworkStack();
 
diff --git a/chromeos/components/tether/host_scanner.cc b/chromeos/components/tether/host_scanner.cc
index a8616ef..31308e8 100644
--- a/chromeos/components/tether/host_scanner.cc
+++ b/chromeos/components/tether/host_scanner.cc
@@ -167,7 +167,8 @@
   host_scan_cache_->SetHostScanResult(
       device_id_tether_network_guid_map_->GetTetherNetworkGuidForDeviceId(
           remote_device.GetDeviceId()),
-      remote_device.name, carrier, battery_percentage, signal_strength);
+      remote_device.name, carrier, battery_percentage, signal_strength,
+      scanned_device_info.setup_required);
 }
 
 }  // namespace tether
diff --git a/chromeos/components/tether/host_scanner_unittest.cc b/chromeos/components/tether/host_scanner_unittest.cc
index e793b40..b954d3cf 100644
--- a/chromeos/components/tether/host_scanner_unittest.cc
+++ b/chromeos/components/tether/host_scanner_unittest.cc
@@ -196,10 +196,10 @@
         cell_provider_name, battery_percentage, connection_strength);
 
     // Require set-up for odd-numbered device indices.
-    bool set_up_required = i % 2 == 0;
+    bool setup_required = i % 2 == 0;
 
     scanned_device_infos.push_back(HostScannerOperation::ScannedDeviceInfo(
-        remote_devices[i], device_status, set_up_required));
+        remote_devices[i], device_status, setup_required));
   }
 
   return scanned_device_infos;
@@ -332,6 +332,8 @@
       EXPECT_EQ(0, cache_item.signal_strength);
     else
       EXPECT_EQ(status.connection_strength() * 25, cache_item.signal_strength);
+
+    EXPECT_EQ(scanned_device_info.setup_required, cache_item.setup_required);
   }
 
   const std::vector<cryptauth::RemoteDevice> test_devices_;
diff --git a/components/arc/arc_features.cc b/components/arc/arc_features.cc
index 66bf95a..fa8397d 100644
--- a/components/arc/arc_features.cc
+++ b/components/arc/arc_features.cc
@@ -17,9 +17,4 @@
     "ArcBootCompletedBroadcast", base::FEATURE_ENABLED_BY_DEFAULT
 };
 
-// Controls whether we show ARC Files app in Chrome launcher.
-const base::Feature kShowArcFilesAppFeature {
-    "ShowArcFilesApp", base::FEATURE_DISABLED_BY_DEFAULT
-};
-
 }  // namespace arc
diff --git a/components/arc/arc_features.h b/components/arc/arc_features.h
index 6366960..d0499bb 100644
--- a/components/arc/arc_features.h
+++ b/components/arc/arc_features.h
@@ -14,7 +14,6 @@
 // Please keep alphabetized.
 extern const base::Feature kArcUseAuthEndpointFeature;
 extern const base::Feature kBootCompletedBroadcastFeature;
-extern const base::Feature kShowArcFilesAppFeature;
 
 }  // namespace arc
 
diff --git a/components/bookmarks/browser/bookmark_codec.cc b/components/bookmarks/browser/bookmark_codec.cc
index abbb1cd..81aca1f8 100644
--- a/components/bookmarks/browser/bookmark_codec.cc
+++ b/components/bookmarks/browser/bookmark_codec.cc
@@ -433,6 +433,11 @@
     const std::string& prefix,
     BookmarkNode::MetaInfoMap* meta_info_map) {
   for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
+    // Deprecated keys should be excluded after removing enhanced bookmarks
+    // feature crrev.com/1638413003.
+    if (base::StartsWith(it.key(), "stars.", base::CompareCase::SENSITIVE))
+      continue;
+
     if (it.value().IsType(base::Value::Type::DICTIONARY)) {
       const base::DictionaryValue* subdict;
       it.value().GetAsDictionary(&subdict);
diff --git a/components/bookmarks/browser/bookmark_model.cc b/components/bookmarks/browser/bookmark_model.cc
index f9d58ce..689ef75 100644
--- a/components/bookmarks/browser/bookmark_model.cc
+++ b/components/bookmarks/browser/bookmark_model.cc
@@ -482,7 +482,7 @@
 
     base::AutoLock url_lock(url_lock_);
     for (const BookmarkNode* node : nodes_ordered_by_url_set_) {
-      if (icon_url == node->icon_url())
+      if (node->icon_url() && icon_url == *node->icon_url())
         to_update.insert(node);
     }
   }
diff --git a/components/bookmarks/browser/bookmark_node.cc b/components/bookmarks/browser/bookmark_node.cc
index 8bc1c292..1977fcb 100644
--- a/components/bookmarks/browser/bookmark_node.cc
+++ b/components/bookmarks/browser/bookmark_node.cc
@@ -123,7 +123,7 @@
 }
 
 void BookmarkNode::InvalidateFavicon() {
-  icon_url_ = GURL();
+  icon_url_.reset();
   favicon_ = gfx::Image();
   favicon_type_ = favicon_base::INVALID_ICON;
   favicon_state_ = INVALID_FAVICON;
diff --git a/components/bookmarks/browser/bookmark_node.h b/components/bookmarks/browser/bookmark_node.h
index d125c44..c3d26e50 100644
--- a/components/bookmarks/browser/bookmark_node.h
+++ b/components/bookmarks/browser/bookmark_node.h
@@ -10,6 +10,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/time/time.h"
 #include "components/bookmarks/browser/titled_url_node.h"
@@ -69,7 +70,7 @@
 
   // Returns the favicon's URL. Returns an empty URL if there is no favicon
   // associated with this bookmark.
-  const GURL& icon_url() const { return icon_url_; }
+  const GURL* icon_url() const { return icon_url_ ? icon_url_.get() : nullptr; }
 
   Type type() const { return type_; }
   void set_type(Type type) { type_ = type; }
@@ -134,7 +135,7 @@
 
   // Sets the favicon's URL.
   void set_icon_url(const GURL& icon_url) {
-    icon_url_ = icon_url;
+    icon_url_ = base::MakeUnique<GURL>(icon_url);
   }
 
   // Returns the favicon. In nearly all cases you should use the method
@@ -179,7 +180,7 @@
   favicon_base::IconType favicon_type_;
 
   // The URL of the node's favicon.
-  GURL icon_url_;
+  std::unique_ptr<GURL> icon_url_;
 
   // The loading state of the favicon.
   FaviconState favicon_state_;
diff --git a/components/bookmarks/browser/titled_url_index.cc b/components/bookmarks/browser/titled_url_index.cc
index fa9ed764..eb95ed32 100644
--- a/components/bookmarks/browser/titled_url_index.cc
+++ b/components/bookmarks/browser/titled_url_index.cc
@@ -207,16 +207,10 @@
     while (i != index_.end() &&
            i->first.size() >= term.size() &&
            term.compare(0, term.size(), i->first, 0, term.size()) == 0) {
-#if !defined(OS_ANDROID)
-      prefix_matches->insert(i->second.begin(), i->second.end());
-#else
-      // Work around a bug in the implementation of std::set::insert in the STL
-      // used on android (http://crbug.com/367050).
       for (TitledUrlNodeSet::const_iterator n = i->second.begin();
-           n != i->second.end();
-           ++n)
+           n != i->second.end(); ++n) {
         prefix_matches->insert(prefix_matches->end(), *n);
-#endif
+      }
       ++i;
     }
     if (!first_term) {
diff --git a/components/bookmarks/browser/titled_url_index.h b/components/bookmarks/browser/titled_url_index.h
index d6a0fba..f6df598 100644
--- a/components/bookmarks/browser/titled_url_index.h
+++ b/components/bookmarks/browser/titled_url_index.h
@@ -8,10 +8,10 @@
 #include <stddef.h>
 
 #include <map>
-#include <set>
 #include <string>
 #include <vector>
 
+#include "base/containers/flat_set.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "components/query_parser/query_parser.h"
@@ -50,7 +50,7 @@
 
  private:
   using TitledUrlNodes = std::vector<const TitledUrlNode*>;
-  using TitledUrlNodeSet = std::set<const TitledUrlNode*>;
+  using TitledUrlNodeSet = base::flat_set<const TitledUrlNode*>;
   using Index = std::map<base::string16, TitledUrlNodeSet>;
 
   // Constructs |sorted_nodes| by copying the matches in |matches| and sorting
diff --git a/components/bookmarks/browser/titled_url_node_sorter.h b/components/bookmarks/browser/titled_url_node_sorter.h
index 3327b59..7913ef0 100644
--- a/components/bookmarks/browser/titled_url_node_sorter.h
+++ b/components/bookmarks/browser/titled_url_node_sorter.h
@@ -5,9 +5,10 @@
 #ifndef COMPONENTS_BOOKMARKS_BROWSER_TITLED_URL_NODE_SORTER_H_
 #define COMPONENTS_BOOKMARKS_BROWSER_TITLED_URL_NODE_SORTER_H_
 
-#include <set>
 #include <vector>
 
+#include "base/containers/flat_set.h"
+
 namespace bookmarks {
 
 class TitledUrlNode;
@@ -15,7 +16,7 @@
 class TitledUrlNodeSorter {
  public:
   using TitledUrlNodes = std::vector<const TitledUrlNode*>;
-  using TitledUrlNodeSet = std::set<const TitledUrlNode*>;
+  using TitledUrlNodeSet = base::flat_set<const TitledUrlNode*>;
 
   virtual ~TitledUrlNodeSorter() {};
 
diff --git a/components/offline_pages/core/archive_manager.cc b/components/offline_pages/core/archive_manager.cc
index a397648f..cd817767 100644
--- a/components/offline_pages/core/archive_manager.cc
+++ b/components/offline_pages/core/archive_manager.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/offline_pages/core/archive_manager.h"
-
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/files/file_enumerator.h"
@@ -13,8 +11,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/sequenced_task_runner.h"
 #include "base/sys_info.h"
-#include "base/task_runner_util.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/core/archive_manager.h"
 
 namespace offline_pages {
 
@@ -23,13 +21,8 @@
 using StorageStatsCallback =
     base::Callback<void(const ArchiveManager::StorageStats& storage_stats)>;
 
-ArchiveManager::ArchivesDirCreationResult EnsureArchivesDirCreatedImpl(
-    const base::FilePath& archives_dir) {
-  if (base::PathExists(archives_dir))
-    return ArchiveManager::ArchivesDirCreationResult::ALREADY_EXISTS;
-  if (base::CreateDirectory(archives_dir))
-    return ArchiveManager::ArchivesDirCreationResult::SUCCESS;
-  return ArchiveManager::ArchivesDirCreationResult::FAILURE;
+void EnsureArchivesDirCreatedImpl(const base::FilePath& archives_dir) {
+  CHECK(base::CreateDirectory(archives_dir));
 }
 
 void ExistsArchiveImpl(const base::FilePath& file_path,
@@ -86,11 +79,10 @@
 
 ArchiveManager::~ArchiveManager() {}
 
-void ArchiveManager::EnsureArchivesDirCreated(
-    const base::Callback<void(ArchivesDirCreationResult)>& callback) {
-  base::PostTaskAndReplyWithResult(
-      task_runner_.get(), FROM_HERE,
-      base::Bind(EnsureArchivesDirCreatedImpl, archives_dir_), callback);
+void ArchiveManager::EnsureArchivesDirCreated(const base::Closure& callback) {
+  task_runner_->PostTaskAndReply(
+      FROM_HERE, base::Bind(EnsureArchivesDirCreatedImpl, archives_dir_),
+      callback);
 }
 
 void ArchiveManager::ExistsArchive(const base::FilePath& archive_path,
diff --git a/components/offline_pages/core/archive_manager.h b/components/offline_pages/core/archive_manager.h
index f4c823e2..dc92e7d 100644
--- a/components/offline_pages/core/archive_manager.h
+++ b/components/offline_pages/core/archive_manager.h
@@ -28,19 +28,12 @@
     int64_t total_archives_size;
   };
 
-  enum class ArchivesDirCreationResult {
-    SUCCESS,
-    ALREADY_EXISTS,
-    FAILURE,
-  };
-
   ArchiveManager(const base::FilePath& archives_dir,
                  const scoped_refptr<base::SequencedTaskRunner>& task_runner);
   virtual ~ArchiveManager();
 
   // Creates archives directory if one does not exist yet;
-  virtual void EnsureArchivesDirCreated(
-      const base::Callback<void(ArchivesDirCreationResult)>& callback);
+  virtual void EnsureArchivesDirCreated(const base::Closure& callback);
 
   // Checks whether an archive with specified |archive_path| exists.
   virtual void ExistsArchive(const base::FilePath& archive_path,
diff --git a/components/offline_pages/core/archive_manager_unittest.cc b/components/offline_pages/core/archive_manager_unittest.cc
index d3c949ea..57f868a8 100644
--- a/components/offline_pages/core/archive_manager_unittest.cc
+++ b/components/offline_pages/core/archive_manager_unittest.cc
@@ -43,15 +43,10 @@
   void GetAllArchivesCallback(const std::set<base::FilePath>& archive_paths);
   void GetStorageStatsCallback(
       const ArchiveManager::StorageStats& storage_sizes);
-  void ArchivesDirCreationCallback(
-      ArchiveManager::ArchivesDirCreationResult result);
 
   ArchiveManager* manager() { return manager_.get(); }
   const base::FilePath& temp_path() const { return temp_dir_.GetPath(); }
   CallbackStatus callback_status() const { return callback_status_; }
-  ArchiveManager::ArchivesDirCreationResult creation_result() const {
-    return creation_result_;
-  }
   const std::set<base::FilePath>& last_archive_paths() const {
     return last_archvie_paths_;
   }
@@ -66,7 +61,6 @@
 
   std::unique_ptr<ArchiveManager> manager_;
   CallbackStatus callback_status_;
-  ArchiveManager::ArchivesDirCreationResult creation_result_;
   std::set<base::FilePath> last_archvie_paths_;
   ArchiveManager::StorageStats last_storage_sizes_;
 };
@@ -111,11 +105,6 @@
   last_storage_sizes_ = storage_sizes;
 }
 
-void ArchiveManagerTest::ArchivesDirCreationCallback(
-    ArchiveManager::ArchivesDirCreationResult result) {
-  creation_result_ = result;
-}
-
 TEST_F(ArchiveManagerTest, EnsureArchivesDirCreated) {
   base::FilePath archive_dir =
       temp_path().Append(FILE_PATH_LITERAL("test_path"));
@@ -124,21 +113,17 @@
 
   // Ensure archives dir exists, when it doesn't.
   manager()->EnsureArchivesDirCreated(
-      base::Bind(&ArchiveManagerTest::ArchivesDirCreationCallback,
-                 base::Unretained(this)));
+      base::Bind(&ArchiveManagerTest::Callback, base::Unretained(this), true));
   PumpLoop();
-  EXPECT_EQ(ArchiveManager::ArchivesDirCreationResult::SUCCESS,
-            creation_result());
+  EXPECT_EQ(CallbackStatus::CALLED_TRUE, callback_status());
   EXPECT_TRUE(base::PathExists(archive_dir));
 
   // Try again when the file already exists.
   ResetResults();
   manager()->EnsureArchivesDirCreated(
-      base::Bind(&ArchiveManagerTest::ArchivesDirCreationCallback,
-                 base::Unretained(this)));
+      base::Bind(&ArchiveManagerTest::Callback, base::Unretained(this), true));
   PumpLoop();
-  EXPECT_EQ(ArchiveManager::ArchivesDirCreationResult::ALREADY_EXISTS,
-            creation_result());
+  EXPECT_EQ(CallbackStatus::CALLED_TRUE, callback_status());
   EXPECT_TRUE(base::PathExists(archive_dir));
 }
 
diff --git a/components/offline_pages/core/offline_page_model_impl.cc b/components/offline_pages/core/offline_page_model_impl.cc
index e9ba89b..0030051 100644
--- a/components/offline_pages/core/offline_page_model_impl.cc
+++ b/components/offline_pages/core/offline_page_model_impl.cc
@@ -8,7 +8,6 @@
 #include <limits>
 
 #include "base/bind.h"
-#include "base/bind_helpers.h"
 #include "base/files/file_util.h"
 #include "base/location.h"
 #include "base/logging.h"
@@ -326,10 +325,9 @@
       archive_manager_(new ArchiveManager(archives_dir, task_runner)),
       testing_clock_(nullptr),
       weak_ptr_factory_(this) {
-  const int kResetAttemptsLeft = 1;
-  store_->Initialize(base::Bind(&OfflinePageModelImpl::OnStoreInitialized,
-                                weak_ptr_factory_.GetWeakPtr(),
-                                base::TimeTicks::Now(), kResetAttemptsLeft));
+  archive_manager_->EnsureArchivesDirCreated(
+      base::Bind(&OfflinePageModelImpl::OnEnsureArchivesDirCreatedDone,
+                 weak_ptr_factory_.GetWeakPtr(), base::TimeTicks::Now()));
 }
 
 OfflinePageModelImpl::~OfflinePageModelImpl() {}
@@ -363,38 +361,6 @@
     return;
   }
 
-  archive_manager_->EnsureArchivesDirCreated(base::Bind(
-      &OfflinePageModelImpl::ContinueSavingPageWithArchivesDir,
-      weak_ptr_factory_.GetWeakPtr(), save_page_params,
-      base::Passed(std::move(archiver)), callback, base::TimeTicks::Now()));
-}
-
-void OfflinePageModelImpl::ContinueSavingPageWithArchivesDir(
-    const SavePageParams& save_page_params,
-    std::unique_ptr<OfflinePageArchiver> archiver,
-    const SavePageCallback& callback,
-    const base::TimeTicks& start_time,
-    ArchiveManager::ArchivesDirCreationResult result) {
-  // Since the archive folder might be missing when saving a page (especially
-  // temporary pages if they live in cache directory which is vulnerable to
-  // 'clear cache' actions). After the attempt to create the archive directory,
-  // as long as the result of creation is not ALREADY_EXISTS, we need to start
-  // a consistency check for saved pages.
-  // This is going to be primarily applicable when we start to use cache
-  // directory for temporary pages.
-  if (result != ArchiveManager::ArchivesDirCreationResult::ALREADY_EXISTS)
-    CheckMetadataConsistency();
-
-  if (result == ArchiveManager::ArchivesDirCreationResult::SUCCESS) {
-    UMA_HISTOGRAM_TIMES("OfflinePages.Model.ArchiveDirCreationTime",
-                        base::TimeTicks::Now() - start_time);
-  }
-  if (result == ArchiveManager::ArchivesDirCreationResult::FAILURE) {
-    InformSavePageDone(callback, SavePageResult::ARCHIVE_DIR_MISSING,
-                       save_page_params.client_id, kInvalidOfflineId);
-    return;
-  }
-
   // If we already have an offline id, use it.  If not, generate one.
   int64_t offline_id = save_page_params.proposed_offline_id;
   if (offline_id == kInvalidOfflineId)
@@ -807,6 +773,17 @@
   // should not have any impact to the UI.
 }
 
+void OfflinePageModelImpl::OnEnsureArchivesDirCreatedDone(
+    const base::TimeTicks& start_time) {
+  UMA_HISTOGRAM_TIMES("OfflinePages.Model.ArchiveDirCreationTime",
+                      base::TimeTicks::Now() - start_time);
+
+  const int kResetAttemptsLeft = 1;
+  store_->Initialize(base::Bind(&OfflinePageModelImpl::OnStoreInitialized,
+                                weak_ptr_factory_.GetWeakPtr(), start_time,
+                                kResetAttemptsLeft));
+}
+
 void OfflinePageModelImpl::OnStoreInitialized(const base::TimeTicks& start_time,
                                               int reset_attempts_left,
                                               bool success) {
diff --git a/components/offline_pages/core/offline_page_model_impl.h b/components/offline_pages/core/offline_page_model_impl.h
index 86559824..64e2e3c 100644
--- a/components/offline_pages/core/offline_page_model_impl.h
+++ b/components/offline_pages/core/offline_page_model_impl.h
@@ -120,13 +120,8 @@
 
   typedef std::vector<std::unique_ptr<OfflinePageArchiver>> PendingArchivers;
 
-  // Callback for ensuring archive directory is created when saving page.
-  void ContinueSavingPageWithArchivesDir(
-      const SavePageParams& save_page_params,
-      std::unique_ptr<OfflinePageArchiver> archiver,
-      const SavePageCallback& callback,
-      const base::TimeTicks& start_time,
-      ArchiveManager::ArchivesDirCreationResult result);
+  // Callback for ensuring archive directory is created.
+  void OnEnsureArchivesDirCreatedDone(const base::TimeTicks& start_time);
 
   void GetPagesMatchingQueryWhenLoadDone(
       std::unique_ptr<OfflinePageModelQuery> query,
diff --git a/components/offline_pages/core/offline_page_model_impl_unittest.cc b/components/offline_pages/core/offline_page_model_impl_unittest.cc
index 572bc15..5e70978 100644
--- a/components/offline_pages/core/offline_page_model_impl_unittest.cc
+++ b/components/offline_pages/core/offline_page_model_impl_unittest.cc
@@ -600,7 +600,7 @@
   archiver_ptr->set_delayed(true);
   SavePageWithArchiverAsync(
       kTestUrl, kTestClientId1, GURL(), std::move(archiver));
-  EXPECT_FALSE(archiver_ptr->create_archive_called());
+  EXPECT_TRUE(archiver_ptr->create_archive_called());
   // |remove_popup_overlay| should not be turned on on foreground mode.
   EXPECT_FALSE(archiver_ptr->create_archive_params().remove_popup_overlay);
 
@@ -672,12 +672,11 @@
   save_page_params.is_background = true;
   save_page_params.use_page_problem_detectors = false;
   SavePageWithParamsAsync(save_page_params, std::move(archiver));
-  EXPECT_FALSE(archiver_ptr->create_archive_called());
-  EXPECT_FALSE(archiver_ptr->create_archive_params().remove_popup_overlay);
+  EXPECT_TRUE(archiver_ptr->create_archive_called());
+  // |remove_popup_overlay| should be turned on on background mode.
+  EXPECT_TRUE(archiver_ptr->create_archive_params().remove_popup_overlay);
 
   PumpLoop();
-  // In the destructor of archiver, the create_archive_called() will be checked
-  // to be true. Otherwise this test case will fail.
 }
 
 TEST_F(OfflinePageModelImplTest, MarkPageAccessed) {
diff --git a/components/offline_pages/core/offline_page_types.h b/components/offline_pages/core/offline_page_types.h
index 0f16f08..e266bba41 100644
--- a/components/offline_pages/core/offline_page_types.h
+++ b/components/offline_pages/core/offline_page_types.h
@@ -38,9 +38,6 @@
   ERROR_PAGE,
   // Returned when we detect trying to save a chrome interstitial page.
   INTERSTITIAL_PAGE,
-  // Returned when we don't have an archive directory available, and the
-  // attempt to create the directory also failed.
-  ARCHIVE_DIR_MISSING,
   // NOTE: always keep this entry at the end. Add new result types only
   // immediately above this line. Make sure to update the corresponding
   // histogram enum accordingly.
diff --git a/components/search_engines/template_url_data.cc b/components/search_engines/template_url_data.cc
index 187d0a27..549d63e 100644
--- a/components/search_engines/template_url_data.cc
+++ b/components/search_engines/template_url_data.cc
@@ -78,8 +78,6 @@
 }
 
 void TemplateURLData::SetShortName(const base::string16& short_name) {
-  DCHECK(!short_name.empty());
-
   // Remove tabs, carriage returns, and the like, as they can corrupt
   // how the short name is displayed.
   short_name_ = base::CollapseWhitespace(short_name, true);
diff --git a/components/search_engines/template_url_parser.cc b/components/search_engines/template_url_parser.cc
index 9d05105..6f32a17 100644
--- a/components/search_engines/template_url_parser.cc
+++ b/components/search_engines/template_url_parser.cc
@@ -303,8 +303,7 @@
 std::unique_ptr<TemplateURL> TemplateURLParsingContext::GetTemplateURL(
     const SearchTermsData& search_terms_data) {
   // TODO(jcampan): Support engines that use POST; see http://crbug.com/18107
-  if (method_ == TemplateURLParsingContext::POST ||
-      data_.short_name().empty() || !IsHTTPRef(data_.url()) ||
+  if (method_ == TemplateURLParsingContext::POST || !IsHTTPRef(data_.url()) ||
       !IsHTTPRef(data_.suggestions_url))
     return nullptr;
   if (suggestion_method_ == TemplateURLParsingContext::POST)
@@ -321,6 +320,10 @@
   if (!has_custom_keyword_)
     data_.SetKeyword(TemplateURL::GenerateKeyword(search_url));
 
+  // If the OSDD omits or has an empty short name, use the keyword.
+  if (data_.short_name().empty())
+    data_.SetShortName(data_.keyword());
+
   // Bail if the search URL is empty or if either TemplateURLRef is invalid.
   std::unique_ptr<TemplateURL> template_url =
       base::MakeUnique<TemplateURL>(data_);
diff --git a/components/sync/protocol/proto_enum_conversions.cc b/components/sync/protocol/proto_enum_conversions.cc
index 1f0f482..8824edf 100644
--- a/components/sync/protocol/proto_enum_conversions.cc
+++ b/components/sync/protocol/proto_enum_conversions.cc
@@ -294,6 +294,23 @@
   return "";
 }
 
+const char* ProtoEnumToString(sync_pb::Translation::Interaction interaction) {
+  ASSERT_ENUM_BOUNDS(sync_pb::Translation, Interaction, UNKNOWN,
+                     AUTOMATIC_TRANSLATION);
+  switch (interaction) {
+    ENUM_CASE(sync_pb::Translation, UNKNOWN);
+    ENUM_CASE(sync_pb::Translation, ACCEPT);
+    ENUM_CASE(sync_pb::Translation, DECLINE);
+    ENUM_CASE(sync_pb::Translation, IGNORED);
+    ENUM_CASE(sync_pb::Translation, DISMISSED);
+    ENUM_CASE(sync_pb::Translation, MANUAL);
+    ENUM_CASE(sync_pb::Translation, TRANSLATION_REVERTED);
+    ENUM_CASE(sync_pb::Translation, AUTOMATIC_TRANSLATION);
+  }
+  NOTREACHED();
+  return "";
+}
+
 const char* ProtoEnumToString(
     sync_pb::WalletMaskedCreditCard::WalletCardClass wallet_card_class) {
   switch (wallet_card_class) {
diff --git a/components/sync/protocol/proto_enum_conversions.h b/components/sync/protocol/proto_enum_conversions.h
index d47f213..3a2b50c 100644
--- a/components/sync/protocol/proto_enum_conversions.h
+++ b/components/sync/protocol/proto_enum_conversions.h
@@ -65,6 +65,8 @@
 
 const char* ProtoEnumToString(sync_pb::TabNavigation::PasswordState state);
 
+const char* ProtoEnumToString(sync_pb::Translation::Interaction interaction);
+
 const char* ProtoEnumToString(
     sync_pb::WalletMaskedCreditCard::WalletCardClass wallet_card_class);
 
diff --git a/components/sync/protocol/proto_visitors.h b/components/sync/protocol/proto_visitors.h
index e035e058..0857574 100644
--- a/components/sync/protocol/proto_visitors.h
+++ b/components/sync/protocol/proto_visitors.h
@@ -847,6 +847,12 @@
   VISIT(end_time_usec);
 }
 
+VISIT_PROTO_FIELDS(const sync_pb::Translation& proto) {
+  VISIT(from_language_code);
+  VISIT(to_language_code);
+  VISIT_ENUM(interaction);
+}
+
 VISIT_PROTO_FIELDS(const sync_pb::TypeHint& proto) {
   VISIT(data_type_id);
   VISIT(has_valid_hint);
@@ -873,6 +879,7 @@
   VISIT(session_id);
   VISIT(field_trial_event);
   VISIT(language_detection);
+  VISIT(translation);
 }
 
 VISIT_PROTO_FIELDS(const sync_pb::WalletMaskedCreditCard& proto) {
diff --git a/components/sync/protocol/user_event_specifics.proto b/components/sync/protocol/user_event_specifics.proto
index d36d764..e2af33a 100644
--- a/components/sync/protocol/user_event_specifics.proto
+++ b/components/sync/protocol/user_event_specifics.proto
@@ -39,6 +39,35 @@
   optional string adopted_language_code = 2;
 }
 
+// User translated a page or interacted with translate suggestion.
+message Translation {
+  // Source language of the translation.
+  optional string from_language_code = 1;
+  // Target language of the translation.
+  optional string to_language_code = 2;
+  enum Interaction {
+    UNKNOWN = 0;
+    ACCEPT = 1;
+    DECLINE = 2;
+    // This happens when user scroll or click outside the UI without
+    // translation.
+    IGNORED = 3;
+    // This happens when user choose to close the translation window without
+    // translation.
+    DISMISSED = 4;
+    // User manually entered either language.
+    // In this case, from_language_code and to_language_code will be user chosen
+    // values.
+    MANUAL = 5;
+    // User choose to revert the translation, in this case, from_language_code
+    // and to_language_code will be previous chosen values.
+    TRANSLATION_REVERTED = 6;
+    // Automatically triggered translation.
+    AUTOMATIC_TRANSLATION = 7;
+  }
+  optional Interaction interaction = 3;
+}
+
 message UserEventSpecifics {
   // Time of event, as measured on the client (unix epoch).
   optional int64 event_time_usec = 1;
@@ -53,5 +82,6 @@
   oneof event {
     FieldTrialEvent field_trial_event = 4;
     LanguageDetection language_detection = 5;
+    Translation translation = 6;
   }
 }
diff --git a/components/sync_bookmarks/bookmark_change_processor.cc b/components/sync_bookmarks/bookmark_change_processor.cc
index 96d50b1..63930d1 100644
--- a/components/sync_bookmarks/bookmark_change_processor.cc
+++ b/components/sync_bookmarks/bookmark_change_processor.cc
@@ -968,7 +968,9 @@
         sync_node->GetBookmarkSpecifics());
     updated_specifics.set_favicon(favicon_bytes->front(),
                                   favicon_bytes->size());
-    updated_specifics.set_icon_url(bookmark_node->icon_url().spec());
+    updated_specifics.set_icon_url(bookmark_node->icon_url()
+                                       ? bookmark_node->icon_url()->spec()
+                                       : std::string());
     sync_node->SetBookmarkSpecifics(updated_specifics);
   }
 }
diff --git a/components/test/data/search_engines/simple_open_search_no_name.xml b/components/test/data/search_engines/simple_open_search_no_name.xml
new file mode 100644
index 0000000..bbfbe4f
--- /dev/null
+++ b/components/test/data/search_engines/simple_open_search_no_name.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
+<ShortName/>
+<Description>Not a creative description.</Description>
+<Url type="text/html" template="http://example.com/{searchTerms}/other_stuff"/>
+</OpenSearchDescription>
diff --git a/components/translate/DEPS b/components/translate/DEPS
index da2a500..6d31570 100644
--- a/components/translate/DEPS
+++ b/components/translate/DEPS
@@ -7,6 +7,7 @@
   "+components/prefs",
   "+components/strings/grit/components_strings.h",
   "+components/sync_preferences",
+  "+components/sync/protocol",
   "+components/variations",
   "+google_apis",
   "+net",
diff --git a/components/translate/core/common/BUILD.gn b/components/translate/core/common/BUILD.gn
index f8038c9..5aca8ab 100644
--- a/components/translate/core/common/BUILD.gn
+++ b/components/translate/core/common/BUILD.gn
@@ -6,6 +6,8 @@
   sources = [
     "language_detection_details.cc",
     "language_detection_details.h",
+    "language_detection_logging_helper.cc",
+    "language_detection_logging_helper.h",
     "translate_constants.cc",
     "translate_constants.h",
     "translate_errors.h",
@@ -19,6 +21,7 @@
 
   deps = [
     "//base",
+    "//components/sync/protocol",
     "//url",
   ]
 }
@@ -26,12 +29,14 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "language_detection_logging_helper_unittest.cc",
     "translate_metrics_unittest.cc",
     "translate_util_unittest.cc",
   ]
   deps = [
     ":common",
     "//base",
+    "//components/sync/protocol",
     "//testing/gtest",
     "//url",
   ]
diff --git a/components/translate/core/common/language_detection_logging_helper.cc b/components/translate/core/common/language_detection_logging_helper.cc
new file mode 100644
index 0000000..e632bdfb
--- /dev/null
+++ b/components/translate/core/common/language_detection_logging_helper.cc
@@ -0,0 +1,36 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/translate/core/common/language_detection_logging_helper.h"
+
+#include <memory>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "components/sync/protocol/user_event_specifics.pb.h"
+#include "components/translate/core/common/language_detection_details.h"
+
+namespace translate {
+
+std::unique_ptr<sync_pb::UserEventSpecifics> ConstructLanguageDetectionEvent(
+    const LanguageDetectionDetails& details) {
+  auto specifics = base::MakeUnique<sync_pb::UserEventSpecifics>();
+  specifics->set_event_time_usec(base::Time::Now().ToInternalValue());
+
+  // TODO(renjieliu): Revisit this field when the best way to identify
+  // navigations is determined.
+  specifics->set_navigation_id(base::Time::Now().ToInternalValue());
+
+  sync_pb::LanguageDetection lang_detection;
+  auto* const lang = lang_detection.add_detected_languages();
+  lang->set_language_code(details.cld_language);
+  lang->set_is_reliable(details.is_cld_reliable);
+  // Only set adopted_language when it's different from cld_language.
+  if (details.adopted_language != details.cld_language) {
+    lang_detection.set_adopted_language_code(details.adopted_language);
+  }
+  *specifics->mutable_language_detection() = lang_detection;
+  return specifics;
+}
+}  // namespace translate
\ No newline at end of file
diff --git a/components/translate/core/common/language_detection_logging_helper.h b/components/translate/core/common/language_detection_logging_helper.h
new file mode 100644
index 0000000..d8f67bb
--- /dev/null
+++ b/components/translate/core/common/language_detection_logging_helper.h
@@ -0,0 +1,23 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_TRANSLATE_CORE_COMMON_LANGUAGE_DETECTION_LOGGING_HELPER_H_
+#define COMPONENTS_TRANSLATE_CORE_COMMON_LANGUAGE_DETECTION_LOGGING_HELPER_H_
+
+#include <memory>
+
+namespace sync_pb {
+class UserEventSpecifics;
+}
+
+namespace translate {
+
+struct LanguageDetectionDetails;
+
+std::unique_ptr<sync_pb::UserEventSpecifics> ConstructLanguageDetectionEvent(
+    const LanguageDetectionDetails& details);
+
+}  // namespace translate
+
+#endif  // COMPONENTS_TRANSLATE_CORE_COMMON_LANGUAGE_DETECTION_LOGGING_HELPER_H_
diff --git a/components/translate/core/common/language_detection_logging_helper_unittest.cc b/components/translate/core/common/language_detection_logging_helper_unittest.cc
new file mode 100644
index 0000000..6dc27c0
--- /dev/null
+++ b/components/translate/core/common/language_detection_logging_helper_unittest.cc
@@ -0,0 +1,51 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/translate/core/common/language_detection_logging_helper.h"
+
+#include <string>
+
+#include "components/sync/protocol/user_event_specifics.pb.h"
+#include "components/translate/core/common/language_detection_details.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace translate {
+
+// Tests that sync_pb::UserEventSpecifics is correctly build.
+TEST(LanguageDetectionLoggingHelperTest, ConstructUserEventSpecifics) {
+  LanguageDetectionDetails details;
+  details.cld_language = "en";
+  details.is_cld_reliable = false;
+  details.adopted_language = "ja";
+  // Expected language detection.
+  sync_pb::LanguageDetection lang_detection;
+  auto* const lang = lang_detection.add_detected_languages();
+  lang->set_language_code(details.cld_language);
+  lang->set_is_reliable(details.is_cld_reliable);
+  lang_detection.set_adopted_language_code(details.adopted_language);
+  const std::unique_ptr<sync_pb::UserEventSpecifics> user_event =
+      ConstructLanguageDetectionEvent(details);
+  EXPECT_EQ(user_event->language_detection().SerializeAsString(),
+            lang_detection.SerializeAsString());
+}
+
+// Tests that sync_pb::UserEventSpecifics is correctly build.
+// If adopted_language is the same as cld_language, we don't set it.
+TEST(LanguageDetectionLoggingHelperTest, DontSetAdoptedLanguage) {
+  LanguageDetectionDetails details;
+  details.cld_language = "en";
+  details.is_cld_reliable = true;
+  details.adopted_language = "en";
+  // Expected language detection.
+  sync_pb::LanguageDetection lang_detection;
+  auto* const lang = lang_detection.add_detected_languages();
+  lang->set_language_code(details.cld_language);
+  lang->set_is_reliable(details.is_cld_reliable);
+  const std::unique_ptr<sync_pb::UserEventSpecifics> user_event =
+      ConstructLanguageDetectionEvent(details);
+  EXPECT_EQ(user_event->language_detection().SerializeAsString(),
+            lang_detection.SerializeAsString());
+}
+
+}  // namespace translate
\ No newline at end of file
diff --git a/content/browser/browser_side_navigation_browsertest.cc b/content/browser/browser_side_navigation_browsertest.cc
index 8734737..3dc6e81 100644
--- a/content/browser/browser_side_navigation_browsertest.cc
+++ b/content/browser/browser_side_navigation_browsertest.cc
@@ -7,14 +7,17 @@
 #include "base/command_line.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/frame_host/navigation_handle_impl.h"
 #include "content/browser/frame_host/navigation_request.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/frame_messages.h"
 #include "content/common/site_isolation_policy.h"
+#include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
@@ -26,6 +29,7 @@
 #include "content/shell/browser/shell_network_delegate.h"
 #include "content/test/content_browser_test_utils_internal.h"
 #include "ipc/ipc_security_test_util.h"
+#include "net/base/filename_util.h"
 #include "net/base/load_flags.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -425,13 +429,27 @@
             controller.GetLastCommittedEntry()->GetURL().spec());
 }
 
+class BrowserSideNavigationBrowserDisableWebSecurityTest
+    : public BrowserSideNavigationBrowserTest {
+ public:
+  BrowserSideNavigationBrowserDisableWebSecurityTest() {}
+
+ protected:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    // Simulate a compromised renderer, otherwise the cross-origin request to
+    // file: is blocked.
+    command_line->AppendSwitch(switches::kDisableWebSecurity);
+    BrowserSideNavigationBrowserTest::SetUpCommandLine(command_line);
+  }
+};
+
 // Test to verify that an exploited renderer process trying to specify a
 // non-empty URL for base_url_for_data_url on navigation is correctly
 // terminated.
 // TODO(nasko): This test case belongs better in
 // security_exploit_browsertest.cc, so move it there once PlzNavigate is on
 // by default.
-IN_PROC_BROWSER_TEST_F(BrowserSideNavigationBrowserTest,
+IN_PROC_BROWSER_TEST_F(BrowserSideNavigationBrowserDisableWebSecurityTest,
                        ValidateBaseUrlForDataUrl) {
   GURL start_url(embedded_test_server()->GetURL("/title1.html"));
   EXPECT_TRUE(NavigateToURL(shell(), start_url));
@@ -439,20 +457,32 @@
   RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
       shell()->web_contents()->GetMainFrame());
 
+  GURL data_url("data:text/html,foo");
+  base::FilePath file_path = GetTestFilePath("", "simple_page.html");
+  GURL file_url = net::FilePathToFileURL(file_path);
+
+  // To get around DataUrlNavigationThrottle. Other attempts at getting around
+  // it don't work, i.e.:
+  // -if the request is made in a child frame then the frame is torn down
+  // immediately on process killing so the navigation doesn't complete
+  // -if it's classified as same document, then a DCHECK in
+  // NavigationRequest::CreateRendererInitiated fires
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      features::kAllowContentInitiatedDataUrlNavigations);
   // Setup a BeginNavigate IPC with non-empty base_url_for_data_url.
-  GURL url(embedded_test_server()->GetURL("/title2.html"));
   CommonNavigationParams common_params(
-      url, Referrer(), ui::PAGE_TRANSITION_LINK,
+      data_url, Referrer(), ui::PAGE_TRANSITION_LINK,
       FrameMsg_Navigate_Type::DIFFERENT_DOCUMENT, true, false,
       base::TimeTicks(), FrameMsg_UILoadMetricsReportType::NO_REPORT,
-      embedded_test_server()->GetURL("foo.com",
-                                     "/title3.html"),  // base_url_for_data_url
+      file_url,  // base_url_for_data_url
       GURL(), PREVIEWS_UNSPECIFIED, base::TimeTicks::Now(), "GET", nullptr,
       base::Optional<SourceLocation>(), CSPDisposition::CHECK);
   BeginNavigationParams begin_params(
       std::string(), net::LOAD_NORMAL, false, false,
       REQUEST_CONTEXT_TYPE_LOCATION,
-      blink::WebMixedContentContextType::kBlockable, false, url::Origin(url));
+      blink::WebMixedContentContextType::kBlockable, false,
+      url::Origin(data_url));
   FrameHostMsg_BeginNavigation msg(rfh->GetRoutingID(), common_params,
                                    begin_params);
 
@@ -463,6 +493,26 @@
   IPC::IpcSecurityTestUtil::PwnMessageReceived(rfh->GetProcess()->GetChannel(),
                                                msg);
   process_exit_observer.Wait();
+
+  EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
+      rfh->GetProcess()->GetID(), file_path));
+
+  // Reload the page to create another renderer process.
+  TestNavigationObserver tab_observer(shell()->web_contents(), 1);
+  shell()->web_contents()->GetController().Reload(ReloadType::NORMAL, false);
+  tab_observer.Wait();
+
+  // Make an XHR request to check if the page has access.
+  std::string script = base::StringPrintf(
+      "var xhr = new XMLHttpRequest()\n"
+      "xhr.open('GET', '%s', false);\n"
+      "xhr.send();\n"
+      "window.domAutomationController.send(xhr.responseText);",
+      file_url.spec().c_str());
+  std::string result;
+  EXPECT_TRUE(
+      ExecuteScriptAndExtractString(shell()->web_contents(), script, &result));
+  EXPECT_TRUE(result.empty());
 }
 
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index c5c6b04..b4b4cc1 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -2203,6 +2203,7 @@
     // Kills the process. http://crbug.com/726142
     bad_message::ReceivedBadMessage(
         GetProcess(), bad_message::RFH_BASE_URL_FOR_DATA_URL_SPECIFIED);
+    return;
   }
 
   BeginNavigationParams validated_begin_params = begin_params;
diff --git a/content/browser/media/media_internals.cc b/content/browser/media/media_internals.cc
index be993d2..8eb3248c 100644
--- a/content/browser/media/media_internals.cc
+++ b/content/browser/media/media_internals.cc
@@ -333,6 +333,7 @@
     std::string video_decoder;
     GURL origin_url;
     WatchTimeInfo watch_time_info;
+    int underflow_count = 0;
   };
 
   // Helper function to report PipelineStatus associated with a player to UMA.
@@ -346,17 +347,29 @@
     return !key.ends_with("EmbeddedExperience");
   }
 
-  void RecordWatchTime(base::StringPiece key, base::TimeDelta value) {
+  void RecordWatchTime(base::StringPiece key,
+                       base::TimeDelta value,
+                       bool is_mtbr = false) {
     base::Histogram::FactoryTimeGet(
-        key.as_string(), base::TimeDelta::FromSeconds(7),
+        key.as_string(),
+        // There are a maximum of 5 underflow events possible in a given 7s
+        // watch time period, so the minimum value is 1.4s.
+        is_mtbr ? base::TimeDelta::FromSecondsD(1.4)
+                : base::TimeDelta::FromSeconds(7),
         base::TimeDelta::FromHours(10), 50,
         base::HistogramBase::kUmaTargetedHistogramFlag)
         ->AddTime(value);
   }
 
+  void RecordMeanTimeBetweenRebuffers(base::StringPiece key,
+                                      base::TimeDelta value) {
+    RecordWatchTime(key, value, true);
+  }
+
   enum class FinalizeType { EVERYTHING, POWER_ONLY };
   void FinalizeWatchTime(bool has_video,
                          const GURL& url,
+                         int* underflow_count,
                          WatchTimeInfo* watch_time_info,
                          FinalizeType finalize_type) {
     // |url| may come from an untrusted source, so ensure it's valid before
@@ -369,6 +382,20 @@
     const bool has_ukm = !!ukm::UkmRecorder::Get();
 
     if (finalize_type == FinalizeType::EVERYTHING) {
+      if (*underflow_count) {
+        // Check for watch times entries that have corresponding MTBR entries
+        // and report the MTBR value using watch_time / |underflow_count|
+        for (auto& kv : mtbr_keys_) {
+          auto it = watch_time_info->find(kv.first);
+          if (it == watch_time_info->end())
+            continue;
+          RecordMeanTimeBetweenRebuffers(kv.second,
+                                         it->second / *underflow_count);
+        }
+
+        *underflow_count = 0;
+      }
+
       std::unique_ptr<ukm::UkmEntryBuilder> builder;
       for (auto& kv : *watch_time_info) {
         RecordWatchTime(kv.first, kv.second);
@@ -420,8 +447,15 @@
   // Stores player information per renderer.
   RendererPlayerMap renderer_info_;
 
+  // Set of all possible watch time keys.
   const base::flat_set<base::StringPiece> watch_time_keys_;
+
+  // Set of only the power related watch time keys.
   const base::flat_set<base::StringPiece> watch_time_power_keys_;
+
+  // Mapping of WatchTime metric keys to MeanTimeBetweenRebuffers (MTBR) keys.
+  const base::flat_map<base::StringPiece, base::StringPiece> mtbr_keys_;
+
   content::MediaInternals* const media_internals_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaInternalsUMAHandler);
@@ -431,6 +465,19 @@
     content::MediaInternals* media_internals)
     : watch_time_keys_(media::MediaLog::GetWatchTimeKeys()),
       watch_time_power_keys_(media::MediaLog::GetWatchTimePowerKeys()),
+      mtbr_keys_({{media::MediaLog::kWatchTimeAudioSrc,
+                   media::MediaLog::kMeanTimeBetweenRebuffersAudioSrc},
+                  {media::MediaLog::kWatchTimeAudioMse,
+                   media::MediaLog::kMeanTimeBetweenRebuffersAudioMse},
+                  {media::MediaLog::kWatchTimeAudioEme,
+                   media::MediaLog::kMeanTimeBetweenRebuffersAudioEme},
+                  {media::MediaLog::kWatchTimeAudioVideoSrc,
+                   media::MediaLog::kMeanTimeBetweenRebuffersAudioVideoSrc},
+                  {media::MediaLog::kWatchTimeAudioVideoMse,
+                   media::MediaLog::kMeanTimeBetweenRebuffersAudioVideoMse},
+                  {media::MediaLog::kWatchTimeAudioVideoEme,
+                   media::MediaLog::kMeanTimeBetweenRebuffersAudioVideoEme}},
+                 base::KEEP_FIRST_OF_DUPES),
       media_internals_(media_internals) {}
 
 void MediaInternals::MediaInternalsUMAHandler::SavePlayerState(
@@ -527,12 +574,18 @@
             base::TimeDelta::FromSecondsD(it.value().GetDouble());
       }
 
+      if (event.params.HasKey(media::MediaLog::kUnderflowCount)) {
+        event.params.GetInteger(media::MediaLog::kUnderflowCount,
+                                &player_info.underflow_count);
+      }
+
       if (event.params.HasKey(media::MediaLog::kWatchTimeFinalize)) {
         bool should_finalize;
         DCHECK(event.params.GetBoolean(media::MediaLog::kWatchTimeFinalize,
                                        &should_finalize) &&
                should_finalize);
         FinalizeWatchTime(player_info.has_video, player_info.origin_url,
+                          &player_info.underflow_count,
                           &player_info.watch_time_info,
                           FinalizeType::EVERYTHING);
       } else if (event.params.HasKey(
@@ -542,6 +595,7 @@
                                        &should_finalize) &&
                should_finalize);
         FinalizeWatchTime(player_info.has_video, player_info.origin_url,
+                          &player_info.underflow_count,
                           &player_info.watch_time_info,
                           FinalizeType::POWER_ONLY);
       }
@@ -556,6 +610,7 @@
 
       ReportUMAForPipelineStatus(it->second);
       FinalizeWatchTime(it->second.has_video, it->second.origin_url,
+                        &it->second.underflow_count,
                         &(it->second.watch_time_info),
                         FinalizeType::EVERYTHING);
       player_info_map.erase(it);
@@ -662,6 +717,7 @@
   while (it != players_it->second.end()) {
     ReportUMAForPipelineStatus(it->second);
     FinalizeWatchTime(it->second.has_video, it->second.origin_url,
+                      &it->second.underflow_count,
                       &(it->second.watch_time_info), FinalizeType::EVERYTHING);
     players_it->second.erase(it++);
   }
diff --git a/content/browser/media/media_internals_unittest.cc b/content/browser/media/media_internals_unittest.cc
index ab12c49..d6ed6be 100644
--- a/content/browser/media/media_internals_unittest.cc
+++ b/content/browser/media/media_internals_unittest.cc
@@ -381,6 +381,14 @@
     }
   }
 
+  void ExpectMtbrTime(const std::vector<base::StringPiece>& keys,
+                      base::TimeDelta value) {
+    for (auto key : keys) {
+      histogram_tester_->ExpectUniqueSample(key.as_string(),
+                                            value.InMilliseconds(), 1);
+    }
+  }
+
   void ExpectUkmWatchTime(size_t entry, size_t size, base::TimeDelta value) {
     ASSERT_LT(entry, test_recorder_->entries_count());
 
@@ -425,6 +433,8 @@
   CycleWatchTimeReporter();
   ExpectWatchTime(std::vector<base::StringPiece>(), base::TimeDelta());
 
+  wtr_->OnUnderflow();
+  wtr_->OnUnderflow();
   CycleWatchTimeReporter();
   wtr_.reset();
 
@@ -433,6 +443,9 @@
        media::MediaLog::kWatchTimeAudioEme, media::MediaLog::kWatchTimeAudioAc,
        media::MediaLog::kWatchTimeAudioEmbeddedExperience},
       kWatchTimeLate);
+  ExpectMtbrTime({media::MediaLog::kMeanTimeBetweenRebuffersAudioMse,
+                  media::MediaLog::kMeanTimeBetweenRebuffersAudioEme},
+                 kWatchTimeLate / 2);
 
   ASSERT_EQ(1U, test_recorder_->sources_count());
   ExpectUkmWatchTime(0, 4, kWatchTimeLate);
@@ -454,6 +467,8 @@
   CycleWatchTimeReporter();
   ExpectWatchTime(std::vector<base::StringPiece>(), base::TimeDelta());
 
+  wtr_->OnUnderflow();
+  wtr_->OnUnderflow();
   CycleWatchTimeReporter();
   wtr_.reset();
 
@@ -463,6 +478,9 @@
                    media::MediaLog::kWatchTimeAudioVideoAc,
                    media::MediaLog::kWatchTimeAudioVideoEmbeddedExperience},
                   kWatchTimeLate);
+  ExpectMtbrTime({media::MediaLog::kMeanTimeBetweenRebuffersAudioVideoSrc,
+                  media::MediaLog::kMeanTimeBetweenRebuffersAudioVideoEme},
+                 kWatchTimeLate / 2);
 
   ASSERT_EQ(1U, test_recorder_->sources_count());
   ExpectUkmWatchTime(0, 4, kWatchTimeLate);
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index d8b0d28..0e47c20 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -318,19 +318,11 @@
     return src_origin == dest_origin;
 
   // If the schemes differ, they aren't part of the same site.
-  //
-  // Note that this happens after the isolated origin check, since blob or
-  // filesystem URLs will fail this check even though they might have the
-  // same origin.
-  //
-  // TODO(alexmos): This check seems broken for nested URLs involving
-  // non-isolated origins too.  See https://crbug.com/726370.
-  if (src_url.scheme() != dest_url.scheme())
+  if (src_origin.scheme() != dest_origin.scheme())
     return false;
 
   return net::registry_controlled_domains::SameDomainOrHost(
-      src_url,
-      dest_url,
+      src_origin, dest_origin,
       net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
 }
 
diff --git a/content/browser/site_instance_impl_unittest.cc b/content/browser/site_instance_impl_unittest.cc
index 845c274b..39246c9b 100644
--- a/content/browser/site_instance_impl_unittest.cc
+++ b/content/browser/site_instance_impl_unittest.cc
@@ -794,6 +794,48 @@
   DrainMessageLoop();
 }
 
+// Check that an URL is considered same-site with blob: and filesystem: URLs
+// with a matching inner origin.  See https://crbug.com/726370.
+TEST_F(SiteInstanceTest, IsSameWebsiteForNestedURLs) {
+  GURL foo_url("http://foo.com/");
+  GURL bar_url("http://bar.com/");
+  GURL blob_foo_url("blob:http://foo.com/uuid");
+  GURL blob_bar_url("blob:http://bar.com/uuid");
+  GURL fs_foo_url("filesystem:http://foo.com/path/");
+  GURL fs_bar_url("filesystem:http://bar.com/path/");
+
+  EXPECT_TRUE(SiteInstance::IsSameWebSite(nullptr, foo_url, blob_foo_url));
+  EXPECT_TRUE(SiteInstance::IsSameWebSite(nullptr, blob_foo_url, foo_url));
+  EXPECT_FALSE(SiteInstance::IsSameWebSite(nullptr, foo_url, blob_bar_url));
+  EXPECT_FALSE(SiteInstance::IsSameWebSite(nullptr, blob_foo_url, bar_url));
+
+  EXPECT_TRUE(SiteInstance::IsSameWebSite(nullptr, foo_url, fs_foo_url));
+  EXPECT_TRUE(SiteInstance::IsSameWebSite(nullptr, fs_foo_url, foo_url));
+  EXPECT_FALSE(SiteInstance::IsSameWebSite(nullptr, foo_url, fs_bar_url));
+  EXPECT_FALSE(SiteInstance::IsSameWebSite(nullptr, fs_foo_url, bar_url));
+
+  EXPECT_TRUE(SiteInstance::IsSameWebSite(nullptr, blob_foo_url, fs_foo_url));
+  EXPECT_FALSE(SiteInstance::IsSameWebSite(nullptr, blob_foo_url, fs_bar_url));
+  EXPECT_FALSE(
+      SiteInstance::IsSameWebSite(nullptr, blob_foo_url, blob_bar_url));
+  EXPECT_FALSE(SiteInstance::IsSameWebSite(nullptr, fs_foo_url, fs_bar_url));
+
+  // Verify that the scheme and ETLD+1 are used for comparison.
+  GURL www_bar_url("http://www.bar.com/");
+  GURL bar_org_url("http://bar.org/");
+  GURL https_bar_url("https://bar.com/");
+  EXPECT_TRUE(SiteInstance::IsSameWebSite(nullptr, www_bar_url, bar_url));
+  EXPECT_TRUE(SiteInstance::IsSameWebSite(nullptr, www_bar_url, blob_bar_url));
+  EXPECT_TRUE(SiteInstance::IsSameWebSite(nullptr, www_bar_url, fs_bar_url));
+  EXPECT_FALSE(SiteInstance::IsSameWebSite(nullptr, bar_org_url, bar_url));
+  EXPECT_FALSE(SiteInstance::IsSameWebSite(nullptr, bar_org_url, blob_bar_url));
+  EXPECT_FALSE(SiteInstance::IsSameWebSite(nullptr, bar_org_url, fs_bar_url));
+  EXPECT_FALSE(SiteInstance::IsSameWebSite(nullptr, https_bar_url, bar_url));
+  EXPECT_FALSE(
+      SiteInstance::IsSameWebSite(nullptr, https_bar_url, blob_bar_url));
+  EXPECT_FALSE(SiteInstance::IsSameWebSite(nullptr, https_bar_url, fs_bar_url));
+}
+
 TEST_F(SiteInstanceTest, DefaultSubframeSiteInstance) {
   if (AreAllSitesIsolatedForTesting())
     return;  // --top-document-isolation is not possible.
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 93e99596..68d40e9 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -332,6 +332,9 @@
   WebRuntimeFeatures::EnableOffMainThreadFetch(
       base::FeatureList::IsEnabled(features::kOffMainThreadFetch));
 
+  WebRuntimeFeatures::EnableMojoBlobs(
+      base::FeatureList::IsEnabled(features::kMojoBlobs));
+
   if (base::FeatureList::IsEnabled(features::kGamepadExtensions))
     WebRuntimeFeatures::EnableGamepadExtensions(true);
 
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 3b2ec58..7681cd24 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -151,6 +151,9 @@
 const base::Feature kMainThreadBusyScrollIntervention{
     "MainThreadBusyScrollIntervention", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Blob mojofication.
+const base::Feature kMojoBlobs("MojoBlobs", base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Experimental resource fetch optimizations for workers. See crbug.com/443374
 const base::Feature kOffMainThreadFetch{"OffMainThreadFetch",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 50f9f2f..f426387 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -46,6 +46,7 @@
 CONTENT_EXPORT extern const base::Feature kMemoryCoordinator;
 CONTENT_EXPORT extern const base::Feature kNotificationContentImage;
 CONTENT_EXPORT extern const base::Feature kMainThreadBusyScrollIntervention;
+CONTENT_EXPORT extern const base::Feature kMojoBlobs;
 CONTENT_EXPORT extern const base::Feature kOffMainThreadFetch;
 CONTENT_EXPORT extern const base::Feature kOriginTrials;
 CONTENT_EXPORT extern const base::Feature kParallelDownloading;
diff --git a/extensions/renderer/script_context.cc b/extensions/renderer/script_context.cc
index e171e0f..3dc2454a 100644
--- a/extensions/renderer/script_context.cc
+++ b/extensions/renderer/script_context.cc
@@ -29,7 +29,6 @@
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
 #include "third_party/WebKit/public/web/WebDataSource.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebView.h"
 #include "v8/include/v8.h"
@@ -290,7 +289,8 @@
 }
 
 // static
-GURL ScriptContext::GetDataSourceURLForFrame(const blink::WebFrame* frame) {
+GURL ScriptContext::GetDataSourceURLForFrame(
+    const blink::WebLocalFrame* frame) {
   // Normally we would use frame->document().url() to determine the document's
   // URL, but to decide whether to inject a content script, we use the URL from
   // the data source. This "quirk" helps prevents content scripts from
@@ -306,7 +306,8 @@
 }
 
 // static
-GURL ScriptContext::GetAccessCheckedFrameURL(const blink::WebFrame* frame) {
+GURL ScriptContext::GetAccessCheckedFrameURL(
+    const blink::WebLocalFrame* frame) {
   const blink::WebURL& weburl = frame->GetDocument().Url();
   if (weburl.IsEmpty()) {
     blink::WebDataSource* data_source = frame->ProvisionalDataSource()
@@ -322,7 +323,7 @@
 }
 
 // static
-GURL ScriptContext::GetEffectiveDocumentURL(const blink::WebFrame* frame,
+GURL ScriptContext::GetEffectiveDocumentURL(const blink::WebLocalFrame* frame,
                                             const GURL& document_url,
                                             bool match_about_blank) {
   // Common scenario. If |match_about_blank| is false (as is the case in most
diff --git a/extensions/renderer/script_context.h b/extensions/renderer/script_context.h
index 43b5114..c314d82 100644
--- a/extensions/renderer/script_context.h
+++ b/extensions/renderer/script_context.h
@@ -25,7 +25,6 @@
 #include "v8/include/v8.h"
 
 namespace blink {
-class WebFrame;
 class WebLocalFrame;
 }
 
@@ -62,7 +61,7 @@
   // See comment in HasAccessOrThrowError.
   static bool IsSandboxedPage(const GURL& url);
 
-  // Clears the WebFrame for this contexts and invalidates the associated
+  // Clears the WebLocalFrame for this contexts and invalidates the associated
   // ModuleSystem.
   void Invalidate();
 
@@ -172,19 +171,19 @@
   // Utility to get the URL we will match against for a frame. If the frame has
   // committed, this is the commited URL. Otherwise it is the provisional URL.
   // The returned URL may be invalid.
-  static GURL GetDataSourceURLForFrame(const blink::WebFrame* frame);
+  static GURL GetDataSourceURLForFrame(const blink::WebLocalFrame* frame);
 
   // Similar to GetDataSourceURLForFrame, but only returns the data source URL
   // if the frame's document url is empty and the frame has a security origin
   // that allows access to the data source url.
   // TODO(asargent/devlin) - there may be places that should switch to using
   // this instead of GetDataSourceURLForFrame.
-  static GURL GetAccessCheckedFrameURL(const blink::WebFrame* frame);
+  static GURL GetAccessCheckedFrameURL(const blink::WebLocalFrame* frame);
 
   // Returns the first non-about:-URL in the document hierarchy above and
   // including |frame|. The document hierarchy is only traversed if
   // |document_url| is an about:-URL and if |match_about_blank| is true.
-  static GURL GetEffectiveDocumentURL(const blink::WebFrame* frame,
+  static GURL GetEffectiveDocumentURL(const blink::WebLocalFrame* frame,
                                       const GURL& document_url,
                                       bool match_about_blank);
 
diff --git a/extensions/renderer/script_context_browsertest.cc b/extensions/renderer/script_context_browsertest.cc
index 4daef37..d7047ef3 100644
--- a/extensions/renderer/script_context_browsertest.cc
+++ b/extensions/renderer/script_context_browsertest.cc
@@ -10,14 +10,14 @@
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "url/gurl.h"
 
-using blink::WebFrame;
+using blink::WebLocalFrame;
 
 namespace extensions {
 namespace {
 
 class ScriptContextTest : public ChromeRenderViewTest {
  protected:
-  GURL GetEffectiveDocumentURL(const WebFrame* frame) {
+  GURL GetEffectiveDocumentURL(const WebLocalFrame* frame) {
     return ScriptContext::GetEffectiveDocumentURL(
         frame, frame->GetDocument().Url(), true);
   }
@@ -41,28 +41,28 @@
 
   const char frame3_html[] = "<iframe name='frame3_1'></iframe>";
 
-  WebFrame* frame = GetMainFrame();
+  WebLocalFrame* frame = GetMainFrame();
   ASSERT_TRUE(frame);
 
   frame->LoadHTMLString(frame_html, top_url);
   content::FrameLoadWaiter(content::RenderFrame::FromWebFrame(frame)).Wait();
 
-  WebFrame* frame1 = frame->FirstChild();
+  WebLocalFrame* frame1 = frame->FirstChild()->ToWebLocalFrame();
   ASSERT_TRUE(frame1);
   ASSERT_EQ("frame1", frame1->AssignedName());
-  WebFrame* frame1_1 = frame1->FirstChild();
+  WebLocalFrame* frame1_1 = frame1->FirstChild()->ToWebLocalFrame();
   ASSERT_TRUE(frame1_1);
   ASSERT_EQ("frame1_1", frame1_1->AssignedName());
-  WebFrame* frame1_2 = frame1_1->NextSibling();
+  WebLocalFrame* frame1_2 = frame1_1->NextSibling()->ToWebLocalFrame();
   ASSERT_TRUE(frame1_2);
   ASSERT_EQ("frame1_2", frame1_2->AssignedName());
-  WebFrame* frame2 = frame1->NextSibling();
+  WebLocalFrame* frame2 = frame1->NextSibling()->ToWebLocalFrame();
   ASSERT_TRUE(frame2);
   ASSERT_EQ("frame2", frame2->AssignedName());
-  WebFrame* frame2_1 = frame2->FirstChild();
+  WebLocalFrame* frame2_1 = frame2->FirstChild()->ToWebLocalFrame();
   ASSERT_TRUE(frame2_1);
   ASSERT_EQ("frame2_1", frame2_1->AssignedName());
-  WebFrame* frame3 = frame2->NextSibling();
+  WebLocalFrame* frame3 = frame2->NextSibling()->ToWebLocalFrame();
   ASSERT_TRUE(frame3);
   ASSERT_EQ("frame3", frame3->AssignedName());
 
@@ -70,7 +70,7 @@
   frame3->LoadHTMLString(frame3_html, different_url);
   content::FrameLoadWaiter(content::RenderFrame::FromWebFrame(frame3)).Wait();
 
-  WebFrame* frame3_1 = frame3->FirstChild();
+  WebLocalFrame* frame3_1 = frame3->FirstChild()->ToWebLocalFrame();
   ASSERT_TRUE(frame3_1);
   ASSERT_EQ("frame3_1", frame3_1->AssignedName());
 
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index 20c2508b..6bb2dc5 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -131,6 +131,7 @@
 
   ~MockTransferBuffer() override {}
 
+  base::SharedMemoryHandle shared_memory_handle() const override;
   bool Initialize(unsigned int starting_buffer_size,
                   unsigned int result_size,
                   unsigned int /* min_buffer_size */,
@@ -243,6 +244,10 @@
   DISALLOW_COPY_AND_ASSIGN(MockTransferBuffer);
 };
 
+base::SharedMemoryHandle MockTransferBuffer::shared_memory_handle() const {
+  return base::SharedMemoryHandle();
+}
+
 bool MockTransferBuffer::Initialize(
     unsigned int starting_buffer_size,
     unsigned int result_size,
diff --git a/gpu/command_buffer/client/transfer_buffer.cc b/gpu/command_buffer/client/transfer_buffer.cc
index 161c836c..0aa21049 100644
--- a/gpu/command_buffer/client/transfer_buffer.cc
+++ b/gpu/command_buffer/client/transfer_buffer.cc
@@ -11,6 +11,7 @@
 
 #include "base/bits.h"
 #include "base/logging.h"
+#include "base/memory/shared_memory_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "gpu/command_buffer/client/cmd_buffer_helper.h"
 
@@ -36,6 +37,14 @@
   Free();
 }
 
+base::SharedMemoryHandle TransferBuffer::shared_memory_handle() const {
+  if (!HaveBuffer())
+    return base::SharedMemoryHandle();
+  if (!buffer_->backing())
+    return base::SharedMemoryHandle();
+  return buffer_->backing()->shared_memory_handle();
+}
+
 bool TransferBuffer::Initialize(
     unsigned int default_buffer_size,
     unsigned int result_size,
diff --git a/gpu/command_buffer/client/transfer_buffer.h b/gpu/command_buffer/client/transfer_buffer.h
index 5f6623e..155e8b0 100644
--- a/gpu/command_buffer/client/transfer_buffer.h
+++ b/gpu/command_buffer/client/transfer_buffer.h
@@ -17,6 +17,12 @@
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
 #include "gpu/gpu_export.h"
 
+namespace base {
+
+class SharedMemoryHandle;
+
+}  // namespace base
+
 namespace gpu {
 
 class CommandBufferHelper;
@@ -27,6 +33,10 @@
   TransferBufferInterface() { }
   virtual ~TransferBufferInterface() { }
 
+  // Returns the shared memory's handle when the back end is base::SharedMemory.
+  // Otherwise, this returns an invalid handle.
+  virtual base::SharedMemoryHandle shared_memory_handle() const = 0;
+
   virtual bool Initialize(
       unsigned int buffer_size,
       unsigned int result_size,
@@ -68,6 +78,7 @@
   ~TransferBuffer() override;
 
   // Overridden from TransferBufferInterface.
+  base::SharedMemoryHandle shared_memory_handle() const override;
   bool Initialize(unsigned int default_buffer_size,
                   unsigned int result_size,
                   unsigned int min_buffer_size,
diff --git a/gpu/command_buffer/client/transfer_buffer_unittest.cc b/gpu/command_buffer/client/transfer_buffer_unittest.cc
index aba8988..bb67d53d 100644
--- a/gpu/command_buffer/client/transfer_buffer_unittest.cc
+++ b/gpu/command_buffer/client/transfer_buffer_unittest.cc
@@ -106,12 +106,16 @@
   EXPECT_EQ(
       kTransferBufferSize - kStartingOffset,
       transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
+  EXPECT_NE(base::UnguessableToken(),
+            transfer_buffer_->shared_memory_handle().GetGUID());
 }
 
 TEST_F(TransferBufferTest, Free) {
   Initialize(0);
   EXPECT_TRUE(transfer_buffer_->HaveBuffer());
   EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId());
+  EXPECT_NE(base::UnguessableToken(),
+            transfer_buffer_->shared_memory_handle().GetGUID());
 
   // Free buffer.
   EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
@@ -120,9 +124,13 @@
   transfer_buffer_->Free();
   // See it's freed.
   EXPECT_FALSE(transfer_buffer_->HaveBuffer());
+  EXPECT_EQ(base::UnguessableToken(),
+            transfer_buffer_->shared_memory_handle().GetGUID());
   // See that it gets reallocated.
   EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId());
   EXPECT_TRUE(transfer_buffer_->HaveBuffer());
+  EXPECT_NE(base::UnguessableToken(),
+            transfer_buffer_->shared_memory_handle().GetGUID());
 
   // Free buffer.
   EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
@@ -131,9 +139,13 @@
   transfer_buffer_->Free();
   // See it's freed.
   EXPECT_FALSE(transfer_buffer_->HaveBuffer());
+  EXPECT_EQ(base::UnguessableToken(),
+            transfer_buffer_->shared_memory_handle().GetGUID());
   // See that it gets reallocated.
   EXPECT_TRUE(transfer_buffer_->GetResultBuffer() != NULL);
   EXPECT_TRUE(transfer_buffer_->HaveBuffer());
+  EXPECT_NE(base::UnguessableToken(),
+            transfer_buffer_->shared_memory_handle().GetGUID());
 
   // Free buffer.
   EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
@@ -142,11 +154,15 @@
   transfer_buffer_->Free();
   // See it's freed.
   EXPECT_FALSE(transfer_buffer_->HaveBuffer());
+  EXPECT_EQ(base::UnguessableToken(),
+            transfer_buffer_->shared_memory_handle().GetGUID());
   // See that it gets reallocated.
   unsigned int size = 0;
   void* data = transfer_buffer_->AllocUpTo(1, &size);
   EXPECT_TRUE(data != NULL);
   EXPECT_TRUE(transfer_buffer_->HaveBuffer());
+  EXPECT_NE(base::UnguessableToken(),
+            transfer_buffer_->shared_memory_handle().GetGUID());
   transfer_buffer_->FreePendingToken(data, 1);
 
   // Free buffer.
@@ -156,9 +172,13 @@
   transfer_buffer_->Free();
   // See it's freed.
   EXPECT_FALSE(transfer_buffer_->HaveBuffer());
+  EXPECT_EQ(base::UnguessableToken(),
+            transfer_buffer_->shared_memory_handle().GetGUID());
   // See that it gets reallocated.
   transfer_buffer_->GetResultOffset();
   EXPECT_TRUE(transfer_buffer_->HaveBuffer());
+  EXPECT_NE(base::UnguessableToken(),
+            transfer_buffer_->shared_memory_handle().GetGUID());
 
   EXPECT_EQ(
       kTransferBufferSize - kStartingOffset,
@@ -486,5 +506,3 @@
 }
 
 }  // namespace gpu
-
-
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 540c0704..011fa94 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -2243,13 +2243,9 @@
                   transition:(ui::PageTransition)transition {
   BrowserViewController* targetBVC =
       targetMode == ApplicationMode::NORMAL ? self.mainBVC : self.otrBVC;
-  GURL currentURL;
 
   Tab* currentTabInTargetBVC = [[targetBVC tabModel] currentTab];
-  if (currentTabInTargetBVC)
-    currentURL = [currentTabInTargetBVC url];
-
-  if (!(currentTabInTargetBVC && IsURLNtp(currentURL))) {
+  if (!(currentTabInTargetBVC && IsURLNtp(currentTabInTargetBVC.visibleURL))) {
     return [targetBVC addSelectedTabWithURL:URL
                                     atIndex:NSNotFound
                                  transition:transition];
diff --git a/ios/chrome/browser/metrics/new_tab_page_uma.mm b/ios/chrome/browser/metrics/new_tab_page_uma.mm
index a11fc2d..77171a51 100644
--- a/ios/chrome/browser/metrics/new_tab_page_uma.mm
+++ b/ios/chrome/browser/metrics/new_tab_page_uma.mm
@@ -19,10 +19,11 @@
 
 namespace new_tab_page_uma {
 
-bool IsCurrentlyOnNTP(ios::ChromeBrowserState* browserState) {
-  TabModel* tabModel = GetLastActiveTabModelForChromeBrowserState(browserState);
-  return tabModel.currentTab &&
-         tabModel.currentTab.url == GURL(kChromeUINewTabURL);
+bool IsCurrentlyOnNTP(ios::ChromeBrowserState* browser_state) {
+  TabModel* tab_model =
+      GetLastActiveTabModelForChromeBrowserState(browser_state);
+  return tab_model.currentTab &&
+         tab_model.currentTab.visibleURL == GURL(kChromeUINewTabURL);
 }
 
 void RecordAction(ios::ChromeBrowserState* browserState, ActionType type) {
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm
index a86f1374..ebede09 100644
--- a/ios/chrome/browser/tabs/tab.mm
+++ b/ios/chrome/browser/tabs/tab.mm
@@ -560,7 +560,7 @@
 
 - (NSString*)description {
   return [NSString stringWithFormat:@"%p ... %@ - %s", self, self.title,
-                                    self.url.spec().c_str()];
+                                    self.visibleURL.spec().c_str()];
 }
 
 - (CRWWebController*)webController {
@@ -627,8 +627,8 @@
 
 - (NSString*)urlDisplayString {
   base::string16 urlText = url_formatter::FormatUrl(
-      self.url, url_formatter::kFormatUrlOmitNothing, net::UnescapeRule::SPACES,
-      nullptr, nullptr, nullptr);
+      self.visibleURL, url_formatter::kFormatUrlOmitNothing,
+      net::UnescapeRule::SPACES, nullptr, nullptr, nullptr);
   return base::SysUTF16ToNSString(urlText);
 }
 
@@ -661,7 +661,7 @@
 }
 
 - (void)fetchFavicon {
-  const GURL& url = self.url;
+  const GURL& url = self.visibleURL;
   if (!url.is_valid())
     return;
 
@@ -844,7 +844,8 @@
       ios::HistoryServiceFactory::GetForBrowserState(
           _browserState, ServiceAccessType::IMPLICIT_ACCESS);
   DCHECK(historyService);
-  historyService->SetPageTitle(self.url, base::SysNSStringToUTF16(title));
+  historyService->SetPageTitle(self.lastCommittedURL,
+                               base::SysNSStringToUTF16(title));
 }
 
 - (void)addCurrentEntryToHistoryDB {
@@ -1122,10 +1123,11 @@
         [self navigationManager]->GetLastCommittedItem()->GetURL().GetOrigin();
 
     // Compose u2f-x-callback URL and update urlToOpen.
-    finalURL = [_secondFactorController XCallbackFromRequestURL:finalURL
-                                                      originURL:origin
-                                                         tabURL:self.url
-                                                          tabID:self.tabId];
+    finalURL =
+        [_secondFactorController XCallbackFromRequestURL:finalURL
+                                               originURL:origin
+                                                  tabURL:self.lastCommittedURL
+                                                   tabID:self.tabId];
 
     if (!finalURL.is_valid())
       return NO;
@@ -1214,27 +1216,30 @@
       postNotificationName:kTabIsShowingExportableNotificationForCrashReporting
                     object:self];
   // Try to generate a filename by first looking at |content_disposition_|, then
-  // at the last component of |self.url| and if both of these fail use the
-  // default filename "document".
+  // at the last component of |lastCommittedURL| and if both of these fail use
+  // the default filename "document".
   std::string contentDisposition;
   if (headers)
     headers->GetNormalizedHeader("content-disposition", &contentDisposition);
   std::string defaultFilename =
       l10n_util::GetStringUTF8(IDS_IOS_OPEN_IN_FILE_DEFAULT_TITLE);
+  const GURL& committedURL = self.lastCommittedURL;
   base::string16 filename =
-      net::GetSuggestedFilename(self.url, contentDisposition,
+      net::GetSuggestedFilename(committedURL, contentDisposition,
                                 "",                 // referrer-charset
                                 "",                 // suggested-name
                                 "application/pdf",  // mime-type
                                 defaultFilename);
   [[self openInController]
-      enableWithDocumentURL:self.url
+      enableWithDocumentURL:committedURL
           suggestedFilename:base::SysUTF16ToNSString(filename)];
 }
 
 - (void)countMainFrameLoad {
-  if ([self isPrerenderTab] || [self url].SchemeIs(kChromeUIScheme))
+  if ([self isPrerenderTab] ||
+      self.lastCommittedURL.SchemeIs(kChromeUIScheme)) {
     return;
+  }
   base::RecordAction(base::UserMetricsAction("MobilePageLoaded"));
 }
 
@@ -1289,7 +1294,7 @@
   // not changed since reader mode was requested. This could happen for example
   // if the page does a late redirect itself or if the user tapped on a link and
   // triggered reader mode before the page load is detected by webState.
-  if (url == self.url)
+  if (url == self.lastCommittedURL)
     [self.webController loadHTMLForCurrentURL:html];
 
   [self.readerModeController exitReaderMode];
@@ -1390,7 +1395,8 @@
   // into a NavigationManager observer callback, so it doesn't need to be
   // checked in several places.
   if (isUserNavigationEvent && !_isPrerenderTab &&
-      ![self navigationManager]->GetPendingItem() && url != self.url) {
+      ![self navigationManager]->GetPendingItem() &&
+      url != self.lastCommittedURL) {
     base::RecordAction(base::UserMetricsAction("MobileTabClobbered"));
     if ([_parentTabModel tabUsageRecorder])
       [_parentTabModel tabUsageRecorder]->RecordPageLoadStart(self);
diff --git a/ios/web_view/shell/shell_view_controller.m b/ios/web_view/shell/shell_view_controller.m
index 3815f50..3aa390b 100644
--- a/ios/web_view/shell/shell_view_controller.m
+++ b/ios/web_view/shell/shell_view_controller.m
@@ -42,7 +42,7 @@
 - (void)forward;
 - (void)stopLoading;
 // Disconnects and release the |webView|.
-- (void)resetWebView;
+- (void)removeWebView;
 @end
 
 @implementation ShellViewController
@@ -157,33 +157,8 @@
 
   [CWVWebView setUserAgentProduct:@"Dummy/1.0"];
 
-  CWVWebViewConfiguration* configuration =
-      [CWVWebViewConfiguration defaultConfiguration];
-  self.webView = [[CWVWebView alloc] initWithFrame:[_containerView bounds]
-                                     configuration:configuration];
-  // Gives a restoration identifier so that state restoration works.
-  _webView.restorationIdentifier = @"webView";
-  _webView.navigationDelegate = self;
-  _webView.UIDelegate = self;
-  _translationDelegate = [[ShellTranslationDelegate alloc] init];
-  _webView.translationController.delegate = _translationDelegate;
-
-  [_webView setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
-                                UIViewAutoresizingFlexibleHeight];
-  [_containerView addSubview:_webView];
-
-  [_webView addObserver:self
-             forKeyPath:@"canGoBack"
-                options:NSKeyValueObservingOptionNew
-                context:nil];
-  [_webView addObserver:self
-             forKeyPath:@"canGoForward"
-                options:NSKeyValueObservingOptionNew
-                context:nil];
-
-  NSURLRequest* request = [NSURLRequest
-      requestWithURL:[NSURL URLWithString:@"https://www.google.com/"]];
-  [_webView loadRequest:request];
+  [self createWebViewWithConfiguration:[CWVWebViewConfiguration
+                                           defaultConfiguration]];
 }
 
 - (void)observeValueForKeyPath:(NSString*)keyPath
@@ -239,20 +214,73 @@
                                          [weakSelf.webView reload];
                                        }]];
 
-  // Removes the web view from the view hierarchy and releases it. For
-  // testing deallocation behavior, because there have been multiple crash bugs
-  // on deallocation of CWVWebView.
+  // Toggles the incognito mode.
+  NSString* incognitoActionTitle = _webView.configuration.persistent
+                                       ? @"Enter incognito"
+                                       : @"Exit incognito";
   [alertController
-      addAction:[UIAlertAction actionWithTitle:@"Deallocate web view"
+      addAction:[UIAlertAction actionWithTitle:incognitoActionTitle
                                          style:UIAlertActionStyleDefault
                                        handler:^(UIAlertAction* action) {
-                                         [weakSelf resetWebView];
+                                         [weakSelf toggleIncognito];
                                        }]];
 
+  // Removes the web view from the view hierarchy, releases it, and recreates
+  // the web view with the same configuration. This is for testing deallocation
+  // and sharing configuration.
+  [alertController
+      addAction:[UIAlertAction
+                    actionWithTitle:@"Recreate web view"
+                              style:UIAlertActionStyleDefault
+                            handler:^(UIAlertAction* action) {
+                              CWVWebViewConfiguration* configuration =
+                                  weakSelf.webView.configuration;
+                              [weakSelf removeWebView];
+                              [weakSelf
+                                  createWebViewWithConfiguration:configuration];
+                            }]];
+
   [self presentViewController:alertController animated:YES completion:nil];
 }
 
-- (void)resetWebView {
+- (void)toggleIncognito {
+  BOOL wasPersistent = _webView.configuration.persistent;
+  [self removeWebView];
+  CWVWebViewConfiguration* newConfiguration =
+      wasPersistent ? [CWVWebViewConfiguration incognitoConfiguration]
+                    : [CWVWebViewConfiguration defaultConfiguration];
+  [self createWebViewWithConfiguration:newConfiguration];
+}
+
+- (void)createWebViewWithConfiguration:(CWVWebViewConfiguration*)configuration {
+  self.webView = [[CWVWebView alloc] initWithFrame:[_containerView bounds]
+                                     configuration:configuration];
+  // Gives a restoration identifier so that state restoration works.
+  _webView.restorationIdentifier = @"webView";
+  _webView.navigationDelegate = self;
+  _webView.UIDelegate = self;
+  _translationDelegate = [[ShellTranslationDelegate alloc] init];
+  _webView.translationController.delegate = _translationDelegate;
+
+  [_webView setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
+                                UIViewAutoresizingFlexibleHeight];
+  [_containerView addSubview:_webView];
+
+  [_webView addObserver:self
+             forKeyPath:@"canGoBack"
+                options:NSKeyValueObservingOptionNew
+                context:nil];
+  [_webView addObserver:self
+             forKeyPath:@"canGoForward"
+                options:NSKeyValueObservingOptionNew
+                context:nil];
+
+  NSURLRequest* request = [NSURLRequest
+      requestWithURL:[NSURL URLWithString:@"https://www.google.com/"]];
+  [_webView loadRequest:request];
+}
+
+- (void)removeWebView {
   [_webView removeFromSuperview];
   [_webView removeObserver:self forKeyPath:@"canGoBack"];
   [_webView removeObserver:self forKeyPath:@"canGoForward"];
diff --git a/media/base/media_log.cc b/media/base/media_log.cc
index 6ebaed7..7e732c3f 100644
--- a/media/base/media_log.cc
+++ b/media/base/media_log.cc
@@ -61,6 +61,21 @@
 const char MediaLog::kWatchTimeFinalize[] = "FinalizeWatchTime";
 const char MediaLog::kWatchTimeFinalizePower[] = "FinalizePowerWatchTime";
 
+const char MediaLog::kUnderflowCount[] = "UnderflowCount";
+
+const char MediaLog::kMeanTimeBetweenRebuffersAudioSrc[] =
+    "Media.MeanTimeBetweenRebuffers.Audio.SRC";
+const char MediaLog::kMeanTimeBetweenRebuffersAudioMse[] =
+    "Media.MeanTimeBetweenRebuffers.Audio.MSE";
+const char MediaLog::kMeanTimeBetweenRebuffersAudioEme[] =
+    "Media.MeanTimeBetweenRebuffers.Audio.EME";
+const char MediaLog::kMeanTimeBetweenRebuffersAudioVideoSrc[] =
+    "Media.MeanTimeBetweenRebuffers.AudioVideo.SRC";
+const char MediaLog::kMeanTimeBetweenRebuffersAudioVideoMse[] =
+    "Media.MeanTimeBetweenRebuffers.AudioVideo.MSE";
+const char MediaLog::kMeanTimeBetweenRebuffersAudioVideoEme[] =
+    "Media.MeanTimeBetweenRebuffers.AudioVideo.EME";
+
 base::flat_set<base::StringPiece> MediaLog::GetWatchTimeKeys() {
   return base::flat_set<base::StringPiece>(
       {kWatchTimeAudioAll,
diff --git a/media/base/media_log.h b/media/base/media_log.h
index dbcbf72..9f508159 100644
--- a/media/base/media_log.h
+++ b/media/base/media_log.h
@@ -136,6 +136,17 @@
   static const char kWatchTimeFinalize[];
   static const char kWatchTimeFinalizePower[];
 
+  // Count of the number of underflow events during a media session.
+  static const char kUnderflowCount[];
+
+  // UMA keys for MTBR samples.
+  static const char kMeanTimeBetweenRebuffersAudioSrc[];
+  static const char kMeanTimeBetweenRebuffersAudioMse[];
+  static const char kMeanTimeBetweenRebuffersAudioEme[];
+  static const char kMeanTimeBetweenRebuffersAudioVideoSrc[];
+  static const char kMeanTimeBetweenRebuffersAudioVideoMse[];
+  static const char kMeanTimeBetweenRebuffersAudioVideoEme[];
+
   static base::flat_set<base::StringPiece> GetWatchTimeKeys();
   static base::flat_set<base::StringPiece> GetWatchTimePowerKeys();
 
diff --git a/media/blink/watch_time_reporter.cc b/media/blink/watch_time_reporter.cc
index cad61c4..7ca8dc1 100644
--- a/media/blink/watch_time_reporter.cc
+++ b/media/blink/watch_time_reporter.cc
@@ -167,6 +167,16 @@
          initial_video_size_.width() >= kMinimumVideoSize.width();
 }
 
+void WatchTimeReporter::OnUnderflow() {
+  if (!reporting_timer_.IsRunning())
+    return;
+
+  // In the event of a pending finalize, we don't want to count underflow events
+  // that occurred after the finalize time. Yet if the finalize is canceled we
+  // want to ensure they are all recorded.
+  pending_underflow_events_.push_back(get_media_time_cb_.Run());
+}
+
 void WatchTimeReporter::OnPowerStateChange(bool on_battery_power) {
   if (!reporting_timer_.IsRunning())
     return;
@@ -216,6 +226,7 @@
   if (reporting_timer_.IsRunning())
     return;
 
+  underflow_count_ = 0;
   last_media_timestamp_ = last_media_power_timestamp_ =
       end_timestamp_for_power_ = kNoTimestamp;
   is_on_battery_power_ = IsOnBatteryPower();
@@ -315,6 +326,23 @@
   }
 #undef RECORD_WATCH_TIME
 
+  // Pass along any underflow events which have occurred since the last report.
+  if (!pending_underflow_events_.empty()) {
+    if (!is_finalizing) {
+      // The maximum value here per period is ~5 events, so int cast is okay.
+      underflow_count_ += static_cast<int>(pending_underflow_events_.size());
+    } else {
+      // Only count underflow events prior to finalize.
+      for (auto& ts : pending_underflow_events_) {
+        if (ts <= end_timestamp_)
+          underflow_count_++;
+      }
+    }
+
+    log_event->params.SetInteger(MediaLog::kUnderflowCount, underflow_count_);
+    pending_underflow_events_.clear();
+  }
+
   // Always send finalize, even if we don't currently have any data, it's
   // harmless to send since nothing will be logged if we've already finalized.
   if (is_finalizing)
@@ -337,6 +365,7 @@
   // Stop the timer if this is supposed to be our last tick.
   if (is_finalizing) {
     end_timestamp_ = kNoTimestamp;
+    underflow_count_ = 0;
     reporting_timer_.Stop();
   }
 }
diff --git a/media/blink/watch_time_reporter.h b/media/blink/watch_time_reporter.h
index 9887ae27..0ff48fd8 100644
--- a/media/blink/watch_time_reporter.h
+++ b/media/blink/watch_time_reporter.h
@@ -5,6 +5,8 @@
 #ifndef MEDIA_BLINK_WATCH_TIME_REPORTER_H_
 #define MEDIA_BLINK_WATCH_TIME_REPORTER_H_
 
+#include <vector>
+
 #include "base/callback.h"
 #include "base/power_monitor/power_observer.h"
 #include "base/time/time.h"
@@ -107,6 +109,11 @@
   // recorded for playback.
   bool IsSizeLargeEnoughToReportWatchTime() const;
 
+  // Indicates a rebuffering event occurred during playback. When watch time is
+  // finalized the total watch time for a given category will be divided by the
+  // number of rebuffering events. Reset to zero after a finalize event.
+  void OnUnderflow();
+
   // Setup the reporting interval to be immediate to avoid spinning real time
   // within the unit test.
   void set_reporting_interval_for_testing() {
@@ -171,6 +178,8 @@
   bool is_playing_ = false;
   bool is_visible_ = true;
   double volume_ = 1.0;
+  int underflow_count_ = 0;
+  std::vector<base::TimeDelta> pending_underflow_events_;
 
   // The last media timestamp seen by UpdateWatchTime().
   base::TimeDelta last_media_timestamp_ = kNoTimestamp;
diff --git a/media/blink/watch_time_reporter_unittest.cc b/media/blink/watch_time_reporter_unittest.cc
index 7e075e3..7464ed0 100644
--- a/media/blink/watch_time_reporter_unittest.cc
+++ b/media/blink/watch_time_reporter_unittest.cc
@@ -66,6 +66,12 @@
           continue;
         }
 
+        int underflow_count;
+        if (it.value().GetAsInteger(&underflow_count)) {
+          OnUnderflowUpdate(underflow_count);
+          continue;
+        }
+
         double in_seconds;
         ASSERT_TRUE(it.value().GetAsDouble(&in_seconds));
         OnWatchTimeUpdate(it.key(), base::TimeDelta::FromSecondsD(in_seconds));
@@ -75,6 +81,7 @@
     MOCK_METHOD0(OnWatchTimeFinalized, void(void));
     MOCK_METHOD0(OnPowerWatchTimeFinalized, void(void));
     MOCK_METHOD2(OnWatchTimeUpdate, void(const std::string&, base::TimeDelta));
+    MOCK_METHOD1(OnUnderflowUpdate, void(int));
 
    protected:
     ~WatchTimeLogMonitor() override {}
@@ -340,16 +347,55 @@
   // any chance to pump.
   CycleReportingTimer();
 
+  wtr_->OnUnderflow();
+  wtr_->OnUnderflow();
   EXPECT_WATCH_TIME(Ac, kWatchTimeLate);
   EXPECT_WATCH_TIME(All, kWatchTimeLate);
   EXPECT_WATCH_TIME(Eme, kWatchTimeLate);
   EXPECT_WATCH_TIME(Mse, kWatchTimeLate);
+  EXPECT_CALL(media_log_, OnUnderflowUpdate(2));
   CycleReportingTimer();
 
   EXPECT_WATCH_TIME_FINALIZED();
   wtr_.reset();
 }
 
+TEST_P(WatchTimeReporterTest, WatchTimeReporterUnderflow) {
+  constexpr base::TimeDelta kWatchTimeEarly = base::TimeDelta::FromSeconds(10);
+  constexpr base::TimeDelta kWatchTimeLate = base::TimeDelta::FromSeconds(15);
+  EXPECT_CALL(*this, GetCurrentMediaTime())
+      .WillOnce(testing::Return(base::TimeDelta()))
+      .WillOnce(testing::Return(base::TimeDelta::FromSeconds(5)))
+      .WillOnce(testing::Return(kWatchTimeEarly))
+      .WillOnce(testing::Return(kWatchTimeEarly))
+      .WillRepeatedly(testing::Return(kWatchTimeLate));
+  Initialize(true, true, true, kSizeJustRight);
+  wtr_->OnPlaying();
+  EXPECT_TRUE(IsMonitoring());
+
+  // No log should have been generated yet since the message loop has not had
+  // any chance to pump.
+  CycleReportingTimer();
+
+  wtr_->OnUnderflow();
+  wtr_->OnVolumeChange(0);
+
+  // This underflow call should be ignored since it happens after the finalize.
+  // Note: We use a muted call above to trigger finalize instead of say a pause
+  // since media time will be the same in the event of a pause and no underflow
+  // should trigger after a pause in any case.
+  wtr_->OnUnderflow();
+
+  EXPECT_WATCH_TIME(Ac, kWatchTimeEarly);
+  EXPECT_WATCH_TIME(All, kWatchTimeEarly);
+  EXPECT_WATCH_TIME(Eme, kWatchTimeEarly);
+  EXPECT_WATCH_TIME(Mse, kWatchTimeEarly);
+  EXPECT_CALL(media_log_, OnUnderflowUpdate(1));
+  EXPECT_WATCH_TIME_FINALIZED();
+  CycleReportingTimer();
+  wtr_.reset();
+}
+
 TEST_P(WatchTimeReporterTest, WatchTimeReporterShownHidden) {
   constexpr base::TimeDelta kWatchTimeEarly = base::TimeDelta::FromSeconds(8);
   constexpr base::TimeDelta kWatchTimeLate = base::TimeDelta::FromSeconds(25);
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index 4f083257..f30404f 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -1405,8 +1405,11 @@
     // Report the number of times we've entered the underflow state. Ensure we
     // only report the value when transitioning from HAVE_ENOUGH to
     // HAVE_NOTHING.
-    if (ready_state_ == WebMediaPlayer::kReadyStateHaveEnoughData)
+    if (ready_state_ == WebMediaPlayer::kReadyStateHaveEnoughData &&
+        !seeking_) {
       underflow_timer_.reset(new base::ElapsedTimer());
+      watch_time_reporter_->OnUnderflow();
+    }
 
     // It shouldn't be possible to underflow if we've not advanced past
     // HAVE_CURRENT_DATA.
diff --git a/net/cert/internal/nist_pkits_unittest.cc b/net/cert/internal/nist_pkits_unittest.cc
index 6e65dff..8980709 100644
--- a/net/cert/internal/nist_pkits_unittest.cc
+++ b/net/cert/internal/nist_pkits_unittest.cc
@@ -27,33 +27,56 @@
 const uint8_t kTestPolicy6[] = {0x60, 0x86, 0x48, 0x01, 0x65,
                                 0x03, 0x02, 0x01, 0x30, 0x06};
 
-}  // namespace
-
-PkitsTestSettings::PkitsTestSettings() {
-  SetInitialPolicySet("anyPolicy");
-}
-
-PkitsTestSettings::~PkitsTestSettings() = default;
-
-void PkitsTestSettings::SetInitialPolicySet(const char* const policy_names) {
-  initial_policy_set.clear();
+void SetPolicySetFromString(const char* const policy_names,
+                            std::set<der::Input>* out) {
+  out->clear();
   std::vector<std::string> names = base::SplitString(
       policy_names, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
   for (const std::string& policy_name : names) {
     if (policy_name == "anyPolicy") {
-      initial_policy_set.insert(AnyPolicy());
+      out->insert(AnyPolicy());
     } else if (policy_name == "NIST-test-policy-1") {
-      initial_policy_set.insert(der::Input(kTestPolicy1));
+      out->insert(der::Input(kTestPolicy1));
     } else if (policy_name == "NIST-test-policy-2") {
-      initial_policy_set.insert(der::Input(kTestPolicy2));
+      out->insert(der::Input(kTestPolicy2));
     } else if (policy_name == "NIST-test-policy-3") {
-      initial_policy_set.insert(der::Input(kTestPolicy3));
+      out->insert(der::Input(kTestPolicy3));
     } else if (policy_name == "NIST-test-policy-6") {
-      initial_policy_set.insert(der::Input(kTestPolicy6));
+      out->insert(der::Input(kTestPolicy6));
     } else {
       ADD_FAILURE() << "Unknown policy name: " << policy_name;
     }
   }
 }
 
+}  // namespace
+
+PkitsTestInfo::PkitsTestInfo() {
+  SetInitialPolicySet("anyPolicy");
+  SetUserConstrainedPolicySet("NIST-test-policy-1");
+}
+
+void PkitsTestInfo::SetInitialExplicitPolicy(bool b) {
+  initial_explicit_policy = b;
+}
+
+void PkitsTestInfo::SetInitialPolicyMappingInhibit(bool b) {
+  initial_policy_mapping_inhibit = b;
+}
+
+void PkitsTestInfo::SetInitialInhibitAnyPolicy(bool b) {
+  initial_inhibit_any_policy = b;
+}
+
+PkitsTestInfo::~PkitsTestInfo() = default;
+
+void PkitsTestInfo::SetInitialPolicySet(const char* const policy_names) {
+  SetPolicySetFromString(policy_names, &initial_policy_set);
+}
+
+void PkitsTestInfo::SetUserConstrainedPolicySet(
+    const char* const policy_names) {
+  SetPolicySetFromString(policy_names, &user_constrained_policy_set);
+}
+
 }  // namespace net
diff --git a/net/cert/internal/nist_pkits_unittest.h b/net/cert/internal/nist_pkits_unittest.h
index 265f332..adc064b6 100644
--- a/net/cert/internal/nist_pkits_unittest.h
+++ b/net/cert/internal/nist_pkits_unittest.h
@@ -8,22 +8,40 @@
 #include <set>
 
 #include "net/cert/internal/test_helpers.h"
+#include "net/der/parse_values.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
 
-// Describes additional inputs to verification in the PKITS tests
-// (which are referred to as "settings" in that document).
-struct PkitsTestSettings {
+// Describes the inputs and outputs (other than the certificates) for
+// the PKITS tests.
+struct PkitsTestInfo {
   // Default construction results in the "default settings".
-  PkitsTestSettings();
-  ~PkitsTestSettings();
+  PkitsTestInfo();
+  ~PkitsTestInfo();
 
   // Sets |initial_policy_set| to the specified policies. The
   // policies are described as comma-separated symbolic strings like
   // "anyPolicy" and "NIST-test-policy-1".
+  //
+  // If this isn't called, the default is "anyPolicy".
   void SetInitialPolicySet(const char* const policy_names);
 
+  // Sets |user_constrained_policy_set| to the specified policies. The
+  // policies are described as comma-separated symbolic strings like
+  // "anyPolicy" and "NIST-test-policy-1".
+  //
+  // If this isn't called, the default is "NIST-test-policy-1".
+  void SetUserConstrainedPolicySet(const char* const policy_names);
+
+  void SetInitialExplicitPolicy(bool b);
+  void SetInitialPolicyMappingInhibit(bool b);
+  void SetInitialInhibitAnyPolicy(bool b);
+
+  // ----------------
+  // Inputs
+  // ----------------
+
   // A set of policy OIDs to use for "initial-policy-set".
   std::set<der::Input> initial_policy_set;
 
@@ -35,19 +53,31 @@
 
   // The value of "initial-inhibit-any-policy".
   bool initial_inhibit_any_policy = false;
+
+  // This is the time when PKITS was published.
+  der::GeneralizedTime time = {2011, 4, 15, 0, 0, 0};
+
+  // ----------------
+  // Expected outputs
+  // ----------------
+
+  // Whether path validation should succeed.
+  bool should_validate = false;
+
+  std::set<der::Input> user_constrained_policy_set;
 };
 
 // Parameterized test class for PKITS tests.
 // The instantiating code should define a PkitsTestDelegate with an appropriate
-// static Verify method, and then INSTANTIATE_TYPED_TEST_CASE_P for each
+// static RunTest method, and then INSTANTIATE_TYPED_TEST_CASE_P for each
 // testcase (each TYPED_TEST_CASE_P in pkits_testcases-inl.h).
 template <typename PkitsTestDelegate>
 class PkitsTest : public ::testing::Test {
  public:
   template <size_t num_certs, size_t num_crls>
-  bool Verify(const char* const (&cert_names)[num_certs],
-              const char* const (&crl_names)[num_crls],
-              const PkitsTestSettings& settings) {
+  void RunTest(const char* const (&cert_names)[num_certs],
+               const char* const (&crl_names)[num_crls],
+               const PkitsTestInfo& info) {
     std::vector<std::string> cert_ders;
     for (const std::string& s : cert_names)
       cert_ders.push_back(net::ReadTestFileToString(
@@ -56,7 +86,7 @@
     for (const std::string& s : crl_names)
       crl_ders.push_back(net::ReadTestFileToString(
           "net/third_party/nist-pkits/crls/" + s + ".crl"));
-    return PkitsTestDelegate::Verify(cert_ders, crl_ders, settings);
+    PkitsTestDelegate::RunTest(cert_ders, crl_ders, info);
   }
 };
 
diff --git a/net/cert/internal/path_builder_pkits_unittest.cc b/net/cert/internal/path_builder_pkits_unittest.cc
index 81eceee..5b14575 100644
--- a/net/cert/internal/path_builder_pkits_unittest.cc
+++ b/net/cert/internal/path_builder_pkits_unittest.cc
@@ -51,25 +51,19 @@
 
 class PathBuilderPkitsTestDelegate {
  public:
-  static bool Verify(std::vector<std::string> cert_ders,
-                     std::vector<std::string> crl_ders,
-                     const PkitsTestSettings& settings) {
-    if (cert_ders.empty()) {
-      ADD_FAILURE() << "cert_ders is empty";
-      return false;
-    }
+  static void RunTest(std::vector<std::string> cert_ders,
+                      std::vector<std::string> crl_ders,
+                      const PkitsTestInfo& info) {
+    ASSERT_FALSE(cert_ders.empty());
     ParsedCertificateList certs;
     for (const std::string& der : cert_ders) {
       CertErrors errors;
-      if (!ParsedCertificate::CreateAndAddToVector(
-              bssl::UniquePtr<CRYPTO_BUFFER>(CRYPTO_BUFFER_new(
-                  reinterpret_cast<const uint8_t*>(der.data()), der.size(),
-                  nullptr)),
-              {}, &certs, &errors)) {
-        ADD_FAILURE() << "ParseCertificate::CreateAndAddToVector() failed:\n"
-                      << errors.ToDebugString();
-        return false;
-      }
+      ASSERT_TRUE(ParsedCertificate::CreateAndAddToVector(
+          bssl::UniquePtr<CRYPTO_BUFFER>(
+              CRYPTO_BUFFER_new(reinterpret_cast<const uint8_t*>(der.data()),
+                                der.size(), nullptr)),
+          {}, &certs, &errors))
+          << errors.ToDebugString();
     }
     // First entry in the PKITS chain is the trust anchor.
     // TODO(mattm): test with all possible trust anchors in the trust store?
@@ -86,18 +80,15 @@
 
     SimpleSignaturePolicy signature_policy(1024);
 
-    // Run all tests at the time the PKITS was published.
-    der::GeneralizedTime time = {2011, 4, 15, 0, 0, 0};
-
     CertPathBuilder::Result result;
     CertPathBuilder path_builder(std::move(target_cert), &trust_store,
-                                 &signature_policy, time, KeyPurpose::ANY_EKU,
-                                 &result);
+                                 &signature_policy, info.time,
+                                 KeyPurpose::ANY_EKU, &result);
     path_builder.AddCertIssuerSource(&cert_issuer_source);
 
     path_builder.Run();
 
-    return result.HasValidPath();
+    ASSERT_EQ(info.should_validate, result.HasValidPath());
   }
 };
 
@@ -113,7 +104,10 @@
                                "ValidDSASignaturesTest4EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "DSACACRL"};
   // DSA signatures are intentionally unsupported.
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // Modified version of 4.1.5 Valid DSA Parameter Inheritance Test5
@@ -125,7 +119,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL", "DSACACRL",
                               "DSAParametersInheritedCACRL"};
   // DSA signatures are intentionally unsupported.
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 class PkitsTest13SignatureVerificationCustomPathBuilderFoo
@@ -140,7 +137,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "nameConstraintsRFC822CA1CRL"};
   // Name constraints on rfc822Names are not supported.
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // Modified version of 4.13.23 Valid RFC822 nameConstraints Test23
@@ -152,7 +152,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "nameConstraintsRFC822CA2CRL"};
   // Name constraints on rfc822Names are not supported.
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // Modified version of 4.13.25 Valid RFC822 nameConstraints Test25
@@ -164,7 +167,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "nameConstraintsRFC822CA3CRL"};
   // Name constraints on rfc822Names are not supported.
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // Modified version of 4.13.27 Valid DN and RFC822 nameConstraints Test27
@@ -177,7 +183,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN1CACRL",
                               "nameConstraintsDN1subCA3CRL"};
   // Name constraints on rfc822Names are not supported.
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // Modified version of 4.13.34 Valid URI nameConstraints Test34
@@ -188,7 +197,10 @@
                                "ValidURInameConstraintsTest34EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsURI1CACRL"};
   // Name constraints on uniformResourceIdentifiers are not supported.
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // Modified version of 4.13.36 Valid URI nameConstraints Test36
@@ -199,7 +211,10 @@
                                "ValidURInameConstraintsTest36EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsURI2CACRL"};
   // Name constraints on uniformResourceIdentifiers are not supported.
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
diff --git a/net/cert/internal/verify_certificate_chain_pkits_unittest.cc b/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
index 8c16a3a6e..8138dae9 100644
--- a/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
+++ b/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
@@ -47,13 +47,10 @@
 
 class VerifyCertificateChainPkitsTestDelegate {
  public:
-  static bool Verify(std::vector<std::string> cert_ders,
-                     std::vector<std::string> crl_ders,
-                     const PkitsTestSettings& settings) {
-    if (cert_ders.empty()) {
-      ADD_FAILURE() << "cert_ders is empty";
-      return false;
-    }
+  static void RunTest(std::vector<std::string> cert_ders,
+                      std::vector<std::string> crl_ders,
+                      const PkitsTestInfo& info) {
+    ASSERT_FALSE(cert_ders.empty());
 
     // PKITS lists chains from trust anchor to target, whereas
     // VerifyCertificateChain takes them starting with the target and ending
@@ -61,29 +58,26 @@
     std::vector<scoped_refptr<net::ParsedCertificate>> input_chain;
     CertErrors parsing_errors;
     for (auto i = cert_ders.rbegin(); i != cert_ders.rend(); ++i) {
-      if (!net::ParsedCertificate::CreateAndAddToVector(
-              bssl::UniquePtr<CRYPTO_BUFFER>(
-                  CRYPTO_BUFFER_new(reinterpret_cast<const uint8_t*>(i->data()),
-                                    i->size(), nullptr)),
-              {}, &input_chain, &parsing_errors)) {
-        ADD_FAILURE() << "Cert failed to parse:\n"
-                      << parsing_errors.ToDebugString();
-        return false;
-      }
+      ASSERT_TRUE(net::ParsedCertificate::CreateAndAddToVector(
+          bssl::UniquePtr<CRYPTO_BUFFER>(CRYPTO_BUFFER_new(
+              reinterpret_cast<const uint8_t*>(i->data()), i->size(), nullptr)),
+          {}, &input_chain, &parsing_errors))
+          << parsing_errors.ToDebugString();
     }
 
     SimpleSignaturePolicy signature_policy(1024);
 
-    // Run all tests at the time the PKITS was published.
-    der::GeneralizedTime time = {2011, 4, 15, 0, 0, 0};
-
     CertPathErrors path_errors;
     VerifyCertificateChain(input_chain, CertificateTrust::ForTrustAnchor(),
-                           &signature_policy, time, KeyPurpose::ANY_EKU,
+                           &signature_policy, info.time, KeyPurpose::ANY_EKU,
                            &path_errors);
+    bool did_succeed = !path_errors.ContainsHighSeverityErrors();
 
     //  TODO(crbug.com/634443): Test errors on failure?
-    return !path_errors.ContainsHighSeverityErrors();
+    if (info.should_validate != did_succeed) {
+      ASSERT_EQ(info.should_validate, did_succeed)
+          << path_errors.ToDebugString(input_chain);
+    }
   }
 };
 
@@ -99,7 +93,10 @@
                                "ValidDSASignaturesTest4EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "DSACACRL"};
   // DSA signatures are intentionally unsupported.
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // Modified version of 4.1.5 Valid DSA Parameter Inheritance Test5
@@ -111,7 +108,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL", "DSACACRL",
                               "DSAParametersInheritedCACRL"};
   // DSA signatures are intentionally unsupported.
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 class PkitsTest13SignatureVerificationCustom
@@ -126,7 +126,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "nameConstraintsRFC822CA1CRL"};
   // Name constraints on rfc822Names are not supported.
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // Modified version of 4.13.23 Valid RFC822 nameConstraints Test23
@@ -138,7 +141,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "nameConstraintsRFC822CA2CRL"};
   // Name constraints on rfc822Names are not supported.
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // Modified version of 4.13.25 Valid RFC822 nameConstraints Test25
@@ -150,7 +156,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "nameConstraintsRFC822CA3CRL"};
   // Name constraints on rfc822Names are not supported.
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // Modified version of 4.13.27 Valid DN and RFC822 nameConstraints Test27
@@ -163,7 +172,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN1CACRL",
                               "nameConstraintsDN1subCA3CRL"};
   // Name constraints on rfc822Names are not supported.
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // Modified version of 4.13.34 Valid URI nameConstraints Test34
@@ -174,7 +186,10 @@
                                "ValidURInameConstraintsTest34EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsURI1CACRL"};
   // Name constraints on uniformResourceIdentifiers are not supported.
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // Modified version of 4.13.36 Valid URI nameConstraints Test36
@@ -185,7 +200,10 @@
                                "ValidURInameConstraintsTest36EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsURI2CACRL"};
   // Name constraints on uniformResourceIdentifiers are not supported.
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain,
diff --git a/net/dns/dns_util.cc b/net/dns/dns_util.cc
index 8eff1c64..06becc2 100644
--- a/net/dns/dns_util.cc
+++ b/net/dns/dns_util.cc
@@ -15,7 +15,9 @@
 #include "base/strings/string_split.h"
 #include "build/build_config.h"
 #include "net/base/address_list.h"
+#include "net/base/url_util.h"
 #include "net/dns/dns_protocol.h"
+#include "url/url_canon.h"
 
 namespace {
 
@@ -74,13 +76,20 @@
       return false;
     if (!IsValidHostLabelCharacter(ch, labellen == 0)) {
       // TODO(palmer): In the future, when we can remove support for invalid
-      // names, return false here instead (and remove the UMA counter).
+      // names, return false here instead (and remove the Net.Valid*DNSName UMA
+      // counters).
       valid_name = false;
     }
     label[labellen++] = ch;
   }
 
   UMA_HISTOGRAM_BOOLEAN("Net.ValidDNSName", valid_name);
+  if (valid_name) {
+    url::CanonHostInfo info;
+    UMA_HISTOGRAM_BOOLEAN("Net.DNSNameCompliantIfValid",
+                          net::IsCanonicalizedHostCompliant(
+                              net::CanonicalizeHost(dotted, &info)));
+  }
 
   // Allow empty label at end of name to disable suffix search.
   if (labellen) {
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl.cc b/net/quic/chromium/bidirectional_stream_quic_impl.cc
index 8a714f0..c3864fce8 100644
--- a/net/quic/chromium/bidirectional_stream_quic_impl.cc
+++ b/net/quic/chromium/bidirectional_stream_quic_impl.cc
@@ -266,27 +266,29 @@
 void BidirectionalStreamQuicImpl::OnStreamReady(int rv) {
   DCHECK_NE(ERR_IO_PENDING, rv);
   DCHECK(rv == OK || !stream_);
-  if (rv == OK) {
-    stream_ = session_->ReleaseStream(this);
-
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::ReadInitialHeaders,
-                              weak_factory_.GetWeakPtr()));
-
-    NotifyStreamReady();
-  } else {
+  if (rv != OK) {
     NotifyError(rv);
+    return;
   }
+
+  stream_ = session_->ReleaseStream(this);
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::ReadInitialHeaders,
+                            weak_factory_.GetWeakPtr()));
+
+  NotifyStreamReady();
 }
 
 void BidirectionalStreamQuicImpl::OnSendDataComplete(int rv) {
   DCHECK(rv == OK || !stream_);
-  if (rv == OK) {
-    if (delegate_)
-      delegate_->OnDataSent();
-  } else {
+  if (rv != 0) {
     NotifyError(rv);
+    return;
   }
+
+  if (delegate_)
+    delegate_->OnDataSent();
 }
 
 void BidirectionalStreamQuicImpl::OnReadInitialHeadersComplete(int rv) {
diff --git a/net/spdy/chromium/spdy_network_transaction_unittest.cc b/net/spdy/chromium/spdy_network_transaction_unittest.cc
index c962b906..3c5183e 100644
--- a/net/spdy/chromium/spdy_network_transaction_unittest.cc
+++ b/net/spdy/chromium/spdy_network_transaction_unittest.cc
@@ -2748,7 +2748,7 @@
   SpdySerializedFrame stream2_priority(
       spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
   SpdySerializedFrame stream3_rst(
-      spdy_util_.ConstructSpdyRstStream(4, ERROR_CODE_PROTOCOL_ERROR));
+      spdy_util_.ConstructSpdyRstStream(4, ERROR_CODE_REFUSED_STREAM));
   MockWrite writes[] = {
       CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
       CreateMockWrite(stream3_rst, 5),
@@ -2918,7 +2918,7 @@
       response_spdy_framer.SerializeFrame(push_promise));
 
   SpdySerializedFrame stream2_rst(
-      spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_PROTOCOL_ERROR));
+      spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_REFUSED_STREAM));
 
   MockWrite writes[] = {CreateMockWrite(req, 0),
                         CreateMockWrite(stream2_rst, 2)};
@@ -2978,7 +2978,7 @@
       spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true));
   SpdySerializedFrame stream1_body(spdy_util_.ConstructSpdyDataFrame(1, true));
   SpdySerializedFrame stream2_rst(
-      spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_PROTOCOL_ERROR));
+      spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_REFUSED_STREAM));
   MockWrite writes[] = {
       CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_rst, 3),
   };
diff --git a/net/spdy/chromium/spdy_session.cc b/net/spdy/chromium/spdy_session.cc
index 7158a1fa..57519f1 100644
--- a/net/spdy/chromium/spdy_session.cc
+++ b/net/spdy/chromium/spdy_session.cc
@@ -1591,7 +1591,7 @@
   GURL gurl = GetUrlFromHeaderBlock(headers);
   if (!gurl.is_valid()) {
     EnqueueResetStreamFrame(
-        stream_id, request_priority, ERROR_CODE_PROTOCOL_ERROR,
+        stream_id, request_priority, ERROR_CODE_REFUSED_STREAM,
         "Pushed stream url was invalid: " + gurl.possibly_invalid_spec());
     return;
   }
@@ -1660,7 +1660,7 @@
   if (pushed_it != unclaimed_pushed_streams_.end() &&
       pushed_it->first == gurl) {
     EnqueueResetStreamFrame(
-        stream_id, request_priority, ERROR_CODE_PROTOCOL_ERROR,
+        stream_id, request_priority, ERROR_CODE_REFUSED_STREAM,
         "Received duplicate pushed stream with url: " + gurl.spec());
     return;
   }
diff --git a/net/third_party/nist-pkits/generate_tests.py b/net/third_party/nist-pkits/generate_tests.py
index ac83c6f..04afc6f8 100644
--- a/net/third_party/nist-pkits/generate_tests.py
+++ b/net/third_party/nist-pkits/generate_tests.py
@@ -36,6 +36,10 @@
   return "true" if b else "false"
 
 
+def make_policies_string(policies):
+  return '"' + ','.join(policies) + '"'
+
+
 def output_test(test_case_name, test_number, raw_test_name, subpart_number,
                 info, certs, crls, sanitized_test_names, output):
   '''Writes a test case to |output|, and appends the test name to
@@ -43,17 +47,18 @@
   sanitized_test_name = 'Section%s%s' % (test_number.split('.')[1],
                                          sanitize_name(raw_test_name))
 
+  subpart_comment = ''
   if subpart_number is not None:
     sanitized_test_name += "Subpart%d" % (subpart_number)
+    subpart_comment = ' (Subpart %d)' % (subpart_number)
 
   sanitized_test_names.append(sanitized_test_name)
 
   certs_formatted = ', '.join('"%s"' % n for n in certs)
   crls_formatted = ', '.join('"%s"' % n for n in crls)
-  assert_function = 'ASSERT_TRUE' if info.should_validate else 'ASSERT_FALSE'
 
   output.write('''
-// %(test_number)s %(raw_test_name)s
+// %(test_number)s %(raw_test_name)s%(subpart_comment)s
 WRAPPED_TYPED_TEST_P(%(test_case_name)s, %(sanitized_test_name)s) {
   const char* const certs[] = {
     %(certs_formatted)s
@@ -63,43 +68,39 @@
   };
 ''' % vars())
 
-  default_settings = TestInfo(False)
+  default_info = TestInfo(None)
 
-  settings_str = ''
+  output.write('''PkitsTestInfo info;
+  info.should_validate = %s;
+''' % (bool_to_str(info.should_validate)))
 
-  # Output any non-default settings. Only settings that differ from
-  # the default settings are written, so as to keep the generated
-  # file more readable.
-  if info.initial_policy_set != default_settings.initial_policy_set:
-    settings_str += '''  settings.SetInitialPolicySet("%s");
-''' % (','.join(info.initial_policy_set))
+  # Output any non-default inputs/outputs. Only properties that differ from
+  # the defaults are written, so as to keep the generated file more readable.
+  if info.initial_policy_set != default_info.initial_policy_set:
+    output.write('''  info.SetInitialPolicySet(%s);
+''' % make_policies_string(info.initial_policy_set))
 
-  if info.initial_explicit_policy != default_settings.initial_explicit_policy:
-    settings_str += '''  settings.initial_explicit_policy = %s;
-''' % bool_to_str(info.initial_explicit_policy)
+  if info.initial_explicit_policy != default_info.initial_explicit_policy:
+    output.write('''  info.SetInitialExplicitPolicy(%s);
+''' % bool_to_str(info.initial_explicit_policy))
 
   if (info.initial_policy_mapping_inhibit !=
-          default_settings.initial_policy_mapping_inhibit):
-    settings_str += '''  settings.initial_policy_mapping_inhibit = %s;
-''' % bool_to_str(info.initial_policy_mapping_inhibit)
+          default_info.initial_policy_mapping_inhibit):
+    output.write('''  info.SetInitialPolicyMappingInhibit(%s);
+''' % bool_to_str(info.initial_policy_mapping_inhibit))
 
   if (info.initial_inhibit_any_policy !=
-          default_settings.initial_inhibit_any_policy):
-    settings_str += '''settings.initial_inhibit_any_policy = %s;
-''' % bool_to_str(info.initial_inhibit_any_policy)
+          default_info.initial_inhibit_any_policy):
+    output.write('''  info.SetInitialInhibitAnyPolicy(%s);
+''' % bool_to_str(info.initial_inhibit_any_policy))
 
-  settings_param_str = '{}'
+  if (info.user_constrained_policy_set !=
+          default_info.user_constrained_policy_set):
+    output.write('''  info.SetUserConstrainedPolicySet(%s);
+''' % make_policies_string(info.user_constrained_policy_set))
 
-  if settings_str != '':
-    output.write('''
-  // Custom settings
-  PkitsTestSettings settings;
-''')
-    output.write(settings_str)
-    output.write('\n')
-    settings_param_str = 'settings'
-
-  output.write('''  %(assert_function)s(this->Verify(certs, crls, %(settings_param_str)s));
+  output.write('''
+  this->RunTest(certs, crls, info);
 }
 ''' % vars())
 
@@ -225,14 +226,10 @@
 TEST_POLICY_3 = 'NIST-test-policy-3'
 TEST_POLICY_6 = 'NIST-test-policy-6'
 
-# TODO(eroman): This omits a few outputs from PKITS:
+# Note: This omits some outputs from PKITS:
 #
 #  * authorities-constrained-policy-set
-#  * user-constrained-policy-set
 #  * explicit-policy-indicator
-#
-#  Consider adding the constrained policy sets in the future, if our
-#  verification code supports outputting them.
 class TestInfo(object):
   """This structure describes a test inputs and outputs"""
 
@@ -241,61 +238,72 @@
                initial_policy_set = [ANY_POLICY],
                initial_explicit_policy = False,
                initial_policy_mapping_inhibit = False,
-               initial_inhibit_any_policy = False):
+               initial_inhibit_any_policy = False,
+               # In all of the tests that are not related to policy processing,
+               # each certificate in the path asserts the certificate policy
+               # 2.16.840.1.101.3.2.1.48.1
+               user_constrained_policy_set = [TEST_POLICY_1]):
     self.should_validate = should_validate
     self.initial_policy_set = initial_policy_set
     self.initial_explicit_policy = initial_explicit_policy
     self.initial_policy_mapping_inhibit = initial_policy_mapping_inhibit
     self.initial_inhibit_any_policy = initial_inhibit_any_policy
+    self.user_constrained_policy_set = user_constrained_policy_set
 
 
 TEST_OVERRIDES = {
   '4.8.1': [ # All Certificates Same Policy Test1
     # 1. default settings, but with initial-explicit-policy set. The path
     # should validate successfully
-    TestInfo(True, initial_explicit_policy=True),
+    TestInfo(True, initial_explicit_policy=True,
+             user_constrained_policy_set=[TEST_POLICY_1]),
 
     # 2. default settings, but with initial-explicit-policy set and
     # initial-policy-set = {NIST-test-policy-1}. The path should validate
     # successfully. 
     TestInfo(True, initial_explicit_policy=True,
-             initial_policy_set=[TEST_POLICY_1]),
+             initial_policy_set=[TEST_POLICY_1],
+             user_constrained_policy_set=[TEST_POLICY_1]),
 
     # 3. default settings, but with initial-explicit-policy set and
     # initial-policy-set = {NIST-test-policy-2}. The path should not validate
     # successfully. 
     TestInfo(False, initial_explicit_policy=True,
-             initial_policy_set=[TEST_POLICY_2]),
+             initial_policy_set=[TEST_POLICY_2],
+             user_constrained_policy_set=[]),
 
     # 4. default settings, but with initial-explicit-policy set and
     # initial-policy-set = {NIST-test-policy-1, NIST-test-policy-2}. The path
     # should validate successfully. 
     TestInfo(True, initial_explicit_policy=True,
-             initial_policy_set=[TEST_POLICY_1, TEST_POLICY_2]),
+             initial_policy_set=[TEST_POLICY_1, TEST_POLICY_2],
+             user_constrained_policy_set=[TEST_POLICY_1]),
   ],
 
   '4.8.2': [ # All Certificates No Policies Test2
     # 1. default settings. The path should validate successfully.
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[]),
 
     # 2. default settings, but with initial-explicit-policy set. The path
     # should not validate successfully
-    TestInfo(False, initial_explicit_policy=True),
+    TestInfo(False, initial_explicit_policy=True,
+             user_constrained_policy_set=[]),
   ],
 
   '4.8.3': [ # Different Policies Test3
     # 1. default settings. The path should validate successfully.
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[]),
 
     # 2. default settings, but with initial-explicit-policy set. The path
     # should not validate successfully.
-    TestInfo(False, initial_explicit_policy=True),
+    TestInfo(False, initial_explicit_policy=True, user_constrained_policy_set=[]),
 
     # 3. default settings, but with initial-explicit-policy set and
     # initial-policy-set = {NIST-test-policy-1, NIST-test-policy-2}. The path
     # should not validate successfully. 
     TestInfo(False, initial_explicit_policy=True,
-             initial_policy_set=[TEST_POLICY_1, TEST_POLICY_2]),
+             initial_policy_set=[TEST_POLICY_1, TEST_POLICY_2],
+             user_constrained_policy_set=[]),
   ],
 
   '4.8.4': [ # Different Policies Test4 
@@ -310,7 +318,7 @@
     # then the path should not validate successfully. If the application can
     # not process the policyConstraints extension, then the path should
     # validate successfully.
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.8.5': [ # 4.8.5 Different Policies Test5
@@ -325,20 +333,22 @@
     # then the path should not validate successfully. If the application can
     # not process the policyConstraints extension, then the path should
     # validate successfully
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.8.6': [ # Overlapping Policies Test6
     # 1. default settings. The path should validate successfully.
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[TEST_POLICY_1]),
 
     # 2. default settings, but with initial-policy-set = {NIST-test-policy-1}.
     # The path should validate successfully.
-    TestInfo(True, initial_policy_set=[TEST_POLICY_1]),
+    TestInfo(True, initial_policy_set=[TEST_POLICY_1],
+             user_constrained_policy_set=[TEST_POLICY_1]),
 
     # 3. default settings, but with initial-policy-set = {NIST-test-policy-2}.
     # The path should not validate successfully. 
-    TestInfo(False, initial_policy_set=[TEST_POLICY_2]),
+    TestInfo(False, initial_policy_set=[TEST_POLICY_2],
+             user_constrained_policy_set=[]),
   ],
 
   '4.8.7': [ # Different Policies Test7
@@ -353,7 +363,7 @@
     # policyConstraints extension, then the path should not validate
     # successfully. If the application can not process the policyConstraints
     # extension, then the path should validate successfully. 
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.8.8': [ # Different Policies Test8 
@@ -368,7 +378,7 @@
     # then the path should not validate successfully. If the application can
     # not process the policyConstraints extension, then the path should
     # validate successfully.
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.8.9': [ # Different Policies Test9
@@ -383,29 +393,32 @@
     # extension, then the path should not validate successfully. If the
     # application can not process the policyConstraints extension, then the
     # path should validate successfully. 
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.8.10': [ # All Certificates Same Policies Test10
     # 1. default settings. The path should validate successfully.
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[TEST_POLICY_1, TEST_POLICY_2]),
     
     # 2. default settings, but with initial-policy-set = {NIST-test-policy-1}.
     # The path should validate successfully.
-    TestInfo(True, initial_policy_set=[TEST_POLICY_1]),
+    TestInfo(True, initial_policy_set=[TEST_POLICY_1],
+             user_constrained_policy_set=[TEST_POLICY_1]),
 
     # 3. default settings, but with initial-policy-set = {NIST-test-policy-2}.
     # The path should validate successfully.
-    TestInfo(True, initial_policy_set=[TEST_POLICY_2]),
+    TestInfo(True, initial_policy_set=[TEST_POLICY_2],
+             user_constrained_policy_set=[TEST_POLICY_2]),
   ],
 
   '4.8.11': [ # All Certificates AnyPolicy Test11
     # 1. default settings. The path should validate successfully.
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[ANY_POLICY]),
 
     # 2. default settings, but with initial-policy-set = {NIST-test-policy-1}.
     # The path should validate successfully. 
-    TestInfo(True, initial_policy_set=[TEST_POLICY_1]),
+    TestInfo(True, initial_policy_set=[TEST_POLICY_1],
+             user_constrained_policy_set=[TEST_POLICY_1]),
   ],
 
   '4.8.12': [ # Different Policies Test12
@@ -420,31 +433,36 @@
     # extension, then the path should not validate successfully. If the
     # application can not process the policyConstraints extension, then the
     # path should validate successfully. 
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.8.13': [ # All Certificates Same Policies Test13
     # 1. default settings, but with initial-policy-set = {NIST-test-policy-1}.
     # The path should validate successfully.
-    TestInfo(True, initial_policy_set=[TEST_POLICY_1]),
+    TestInfo(True, initial_policy_set=[TEST_POLICY_1],
+             user_constrained_policy_set=[TEST_POLICY_1]),
 
     # 2. default settings, but with initial-policy-set = {NIST-test-policy-2}.
     # The path should validate successfully.
-    TestInfo(True, initial_policy_set=[TEST_POLICY_2]),
+    TestInfo(True, initial_policy_set=[TEST_POLICY_2],
+             user_constrained_policy_set=[TEST_POLICY_2]),
 
     # 3. default settings, but with initial-policy-set = {NIST-test-policy-3}.
     # The path should validate successfully. 
-    TestInfo(True, initial_policy_set=[TEST_POLICY_3]),
+    TestInfo(True, initial_policy_set=[TEST_POLICY_3],
+             user_constrained_policy_set=[TEST_POLICY_3]),
   ],
 
   '4.8.14': [ # AnyPolicy Test14
     # 1. default settings, but with initial-policy-set = {NIST-test-policy-1}.
     # The path should validate successfully.
-    TestInfo(True, initial_policy_set=[TEST_POLICY_1]),
+    TestInfo(True, initial_policy_set=[TEST_POLICY_1],
+             user_constrained_policy_set=[TEST_POLICY_1]),
 
     # 2. default settings, but with initial-policy-set = {NIST-test-policy-2}.
     # The path should not validate successfully. 
-    TestInfo(False, initial_policy_set=[TEST_POLICY_2]),
+    TestInfo(False, initial_policy_set=[TEST_POLICY_2],
+             user_constrained_policy_set=[]),
   ],
 
   '4.8.15': [ # User Notice Qualifier Test15
@@ -462,7 +480,7 @@
     # NIST-test-policy-1, then the path should be rejected, otherwise it should
     # validate successfully. If the path validates successfully, then the
     # application should display the user notice.
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[TEST_POLICY_1]),
   ],
 
   '4.8.16': [ # User Notice Qualifier Test16
@@ -482,7 +500,7 @@
     # application should display the user notice associated with
     # NIST-test-policy-1. The user notice associated with NIST-test-policy-2
     # should not be displayed. 
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[TEST_POLICY_1]),
   ],
 
   '4.8.17': [ # User Notice Qualifier Test17
@@ -500,19 +518,21 @@
     # NIST-test-policy-1, then the path should be rejected, otherwise it should
     # validate successfully. If the path validates successfully, then the
     # application should display the user notice associated with anyPolicy. 
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[TEST_POLICY_1]),
   ],
 
   '4.8.18': [ # User Notice Qualifier Test18 
     # 1. default settings, but with initial-policy-set = {NIST-test-policy-1}.
     # The path should validate successfully and the qualifier associated with
     # NIST-test-policy-1 in the end entity certificate should be displayed.
-    TestInfo(True, initial_policy_set=[TEST_POLICY_1]),
+    TestInfo(True, initial_policy_set=[TEST_POLICY_1],
+             user_constrained_policy_set=[TEST_POLICY_1]),
 
     # 2. default settings, but with initial-policy-set = {NIST-test-policy-2}.
     # The path should validate successfully and the qualifier associated with
     # anyPolicy in the end entity certificate should be displayed. 
-    TestInfo(True, initial_policy_set=[TEST_POLICY_2]),
+    TestInfo(True, initial_policy_set=[TEST_POLICY_2],
+             user_constrained_policy_set=[TEST_POLICY_2]),
   ],
 
   '4.8.19': [ # User Notice Qualifier Test19
@@ -532,7 +552,7 @@
     # of 200 characters, the application may choose to reject the certificate.
     # If the application accepts the certificate, display of the user notice is
     # optional. 
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[TEST_POLICY_1]),
   ],
 
   '4.8.20': [ # CPS Pointer Qualifier Test20
@@ -557,40 +577,77 @@
     # if NIST-test-policy-1 is in that set). There are no processing
     # requirements associated with the CPS pointer qualifier. 
     TestInfo(True, initial_explicit_policy=True,
-             initial_policy_set=[TEST_POLICY_1]),
+             initial_policy_set=[TEST_POLICY_1],
+             user_constrained_policy_set=[TEST_POLICY_1]),
+  ],
+
+  '4.9.1': [ # Valid RequireExplicitPolicy Test1
+    # Procedure: Validate Valid requireExplicitPolicy Test1 EE using the
+    # default settings or open and verify Signed Test Message 6.2.2.86 using
+    # the default settings.
+    #
+    # Expected Result: The path should validate successfully since the
+    # explicit-policy-indicator is not set.
+    TestInfo(True, user_constrained_policy_set=[]),
+  ],
+
+  '4.9.2': [ # Valid RequireExplicitPolicy Test2
+    # Procedure: Validate Valid requireExplicitPolicy Test2 EE using the
+    # default settings or open and verify Signed Test Message 6.2.2.87 using
+    # the default settings.
+    #
+    # Expected Result: The path should validate successfully since the
+    # explicit-policy-indicator is not set
+    TestInfo(True, user_constrained_policy_set=[]),
+  ],
+
+  '4.9.6': [ # Valid Self-Issued requireExplicitPolicy Test6
+    # Procedure: Validate Valid Self-Issued requireExplicitPolicy Test6 EE using
+    # the default settings or open and verify Signed Test Message 6.2.2.91 using
+    # the default settings.
+    #
+    # Expected Result: The path should validate successfully since the
+    # explicit-policy-indicator is not set.
+    TestInfo(True, user_constrained_policy_set=[]),
   ],
 
   '4.10.1': [ # Valid Policy Mapping Test1
     # 1. default settings, but with initial-policy-set = {NIST-test-policy-1}.
     # The path should validate successfully.
-    TestInfo(True, initial_policy_set=[TEST_POLICY_1]),
+    TestInfo(True, initial_policy_set=[TEST_POLICY_1],
+             user_constrained_policy_set=[TEST_POLICY_1]),
 
     # 2. default settings, but with initial-policy-set = {NIST-test-policy-2}.
     # The path should not validate successfully. 
-    TestInfo(False, initial_policy_set=[TEST_POLICY_2]),
+    TestInfo(False, initial_policy_set=[TEST_POLICY_2],
+             user_constrained_policy_set=[]),
 
     # 3. default settings, but with initial-policy-mapping-inhibit set. The
     # path should not validate successfully.
-    TestInfo(False, initial_policy_mapping_inhibit=True),
+    TestInfo(False, initial_policy_mapping_inhibit=True,
+             user_constrained_policy_set=[]),
   ],
 
   '4.10.2': [ # Invalid Policy Mapping Test2
     # 1. default settings. The path should not validate successfully.
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
 
     # 2. default settings, but with initial-policy-mapping-inhibit set. The
     # path should not validate successfully. 
-    TestInfo(False, initial_policy_mapping_inhibit=True),
+    TestInfo(False, initial_policy_mapping_inhibit=True,
+             user_constrained_policy_set=[]),
   ],
 
   '4.10.3': [ # Valid Policy Mapping Test3
     # 1. default settings, but with initial-policy-set = {NIST-test-policy-1}.
     # The path should not validate successfully.
-    TestInfo(False, initial_policy_set=[TEST_POLICY_1]),
+    TestInfo(False, initial_policy_set=[TEST_POLICY_1],
+             user_constrained_policy_set=[]),
 
     # 2. default settings, but with initial-policy-set = {NIST-test-policy-2}.
     # The path should validate successfully. 
-    TestInfo(True, initial_policy_set=[TEST_POLICY_2]),
+    TestInfo(True, initial_policy_set=[TEST_POLICY_2],
+             user_constrained_policy_set=[TEST_POLICY_2]),
   ],
 
   '4.10.4': [ # Invalid Policy Mapping Test4
@@ -604,27 +661,44 @@
     # policyConstraints extension). If the application can process the
     # policyConstraints extension, then the path should be rejected, otherwise
     # it should validate successfully. 
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.10.5': [ # Valid Policy Mapping Test5
     # 1. default settings, but with initial-policy-set = {NIST-test-policy-1}.
     # The path should validate successfully.
-    TestInfo(True, initial_policy_set=[TEST_POLICY_1]),
+    TestInfo(True, initial_policy_set=[TEST_POLICY_1],
+             user_constrained_policy_set=[TEST_POLICY_1]),
 
     # 2. default settings, but with initial-policy-set = {NIST-test-policy-6}.
     # The path should not validate successfully. 
-    TestInfo(False, initial_policy_set=[TEST_POLICY_6]),
+    TestInfo(False, initial_policy_set=[TEST_POLICY_6],
+             user_constrained_policy_set=[]),
   ],
 
   '4.10.6': [ # Valid Policy Mapping Test6
     # 1. default settings, but with initial-policy-set = {NIST-test-policy-1}.
     # The path should validate successfully.
-    TestInfo(True, initial_policy_set=[TEST_POLICY_1]),
+    TestInfo(True, initial_policy_set=[TEST_POLICY_1],
+                   user_constrained_policy_set=[TEST_POLICY_1]),
 
     # 2. default settings, but with initial-policy-set = {NIST-test-policy-6}.
     # The path should not validate successfully. 
-    TestInfo(False, initial_policy_set=[TEST_POLICY_6]),
+    TestInfo(False, initial_policy_set=[TEST_POLICY_6],
+             user_constrained_policy_set=[]),
+  ],
+
+  '4.10.8': [ # Invalid Mapping To anyPolicy Test8
+    # Procedure: Validate Invalid Mapping To anyPolicy Test8 EE using the
+    # default settings or open and verify Signed Test Message 6.2.2.101 using
+    # the default settings.
+    #
+    # Expected Result: The path should not validate successfully since the
+    # intermediate certificate includes a policy mapping extension in which
+    # anyPolicy appears as an subjectDomainPolicy.
+    #
+    # TODO(eroman): What should user_constrained_policy_set be?
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.10.9': [ # Valid Policy Mapping Test9
@@ -655,7 +729,7 @@
     # policyConstraints extension). If the application can process the
     # policyConstraints extension, then the path should be rejected, otherwise
     # it should validate successfully.
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.10.11': [ # Valid Policy Mapping Test11
@@ -672,7 +746,7 @@
     # empty. If the initial-policy-set does not include NIST-test-policy-1 (and
     # the application can process the policyConstraints extension), then the
     # path should be rejected, otherwise it should validate successfully. 
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[TEST_POLICY_1]),
   ],
 
   '4.10.12': [ # Valid Policy Mapping Test12
@@ -680,12 +754,14 @@
     # The path should validate successfully and the application should display
     # the user notice associated with NIST-test-policy-3 in the end entity
     # certificate.
-    TestInfo(True, initial_policy_set=[TEST_POLICY_1]),
+    TestInfo(True, initial_policy_set=[TEST_POLICY_1],
+             user_constrained_policy_set=[TEST_POLICY_1]),
 
     # 2. default settings, but with initial-policy-set = {NIST-test-policy-2}.
     # The path should validate successfully and the application should display
     # the user notice associated with anyPolicy in the end entity certificate. 
-    TestInfo(True, initial_policy_set=[TEST_POLICY_2]),
+    TestInfo(True, initial_policy_set=[TEST_POLICY_2],
+             user_constrained_policy_set=[TEST_POLICY_2]),
   ],
 
   '4.10.13': [ # Valid Policy Mapping Test13
@@ -704,7 +780,7 @@
     # path should be rejected, otherwise it should validate successfully. If
     # the path is accepted, the application should display the user notice
     # associated with NIST-testpolicy-1 in the intermediate certificate. 
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[TEST_POLICY_1]),
   ],
 
   '4.10.14': [ # Valid Policy Mapping Test14
@@ -723,7 +799,7 @@
     # path should be rejected, otherwise it should validate successfully. If
     # the path is accepted, the application should display the user notice
     # associated with anyPolicy in the intermediate certificate
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[TEST_POLICY_1]),
   ],
 
   '4.11.1': [ # Invalid inhibitPolicyMapping Test1 
@@ -734,7 +810,7 @@
     # Expected Result: The authorities-constrained-policy-set and the
     # user-constrained-policy-set will be empty. The explicit-policy-indicator
     # will be set.  The path should not validate successfully. 
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.11.2': [ # Valid inhibitPolicyMapping Test2
@@ -746,7 +822,7 @@
     # {NIST-test-policy-1} and the explicit-policy-indicator will be set. If
     # the initial-policy-set is any-policy or otherwise includes
     # NIST-test-policy-1, then the path should validate successfully. 
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[TEST_POLICY_1]),
   ],
 
   '4.11.3': [ # Invalid inhibitPolicyMapping Test3 
@@ -758,7 +834,7 @@
     # user-constrained-policy-set will be empty and the
     # explicit-policy-indicator will be set.  The path should not validate
     # successfully. 
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.11.4': [ # Valid inhibitPolicyMapping Test4
@@ -770,7 +846,7 @@
     # {NIST-test-policy-2} and the explicit-policy-indicator will be set. If
     # the initial-policy-set is any-policy or otherwise includes
     # NIST-test-policy-2, then the path should validate successfully. 
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[TEST_POLICY_2]),
   ],
 
   '4.11.5': [ # Invalid inhibitPolicyMapping Test5
@@ -782,7 +858,7 @@
     # user-constrained-policy-set will be empty and the
     # explicit-policy-indicator will be set.  The path should not validate
     # successfully. 
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.11.6': [ # Invalid inhibitPolicyMapping Test6
@@ -794,7 +870,7 @@
     # user-constrained-policy-set will be empty and the
     # explicit-policy-indicator will be set. The path should not validate
     # successfully. 
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.11.7': [ # Valid Self-Issued inhibitPolicyMapping Test7
@@ -806,7 +882,7 @@
     # {NIST-test-policy-1} and the explicit-policy-indicator will be set. If
     # the initial-policy-set is any-policy or otherwise includes
     # NIST-test-policy-1, then the path should validate successfully. 
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[TEST_POLICY_1]),
   ],
 
   '4.11.8': [ # Invalid Self-Issued inhibitPolicyMapping Test8
@@ -818,7 +894,7 @@
     # user-constrained-policy-set will be empty and the
     # explicit-policy-indicator will be set. The path should not validate
     # successfully. 
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.11.9': [ # Invalid Self-Issued inhibitPolicyMapping Test9
@@ -830,7 +906,7 @@
     # user-constrained-policy-set will be empty and the
     # explicit-policy-indicator will be set. The path should not validate
     # successfully. 
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.11.10': [ # Invalid Self-Issued inhibitPolicyMapping Test10
@@ -842,7 +918,7 @@
     # user-constrained-policy-set will be empty and the
     # explicit-policy-indicator will be set. The path should not validate
     # successfully. 
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.11.11': [ # Invalid Self-Issued inhibitPolicyMapping Test11
@@ -854,7 +930,7 @@
     # user-constrained-policy-set will be empty and the
     # explicit-policy-indicator will be set. The path should not validate
     # successfully. 
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.12.1': [ # Invalid inhibitAnyPolicy Test1
@@ -868,7 +944,7 @@
     # policyConstraints extension). If the application can process the
     # policyConstraints extension, then the path should not validate
     # successfully. 
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.12.2': [ # Valid inhibitAnyPolicy Test2
@@ -886,17 +962,17 @@
     # user-constrained-policy-set is empty and the application can process the
     # policyConstraints extension, then the path should not validate
     # successfully. 
-
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[TEST_POLICY_1]),
   ],
 
   '4.12.3': [ # inhibitAnyPolicy Test3 
      # 1. default settings. The path should validate successfully.
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[TEST_POLICY_1]),
 
      # 2. default settings, but with initial-inhibit-any-policy set. The path
      # should not validate successfully. 
-    TestInfo(False, initial_inhibit_any_policy=True),
+    TestInfo(False, initial_inhibit_any_policy=True,
+             user_constrained_policy_set=[]),
   ],
 
   '4.12.4': [ # Invalid inhibitAnyPolicy Test4
@@ -910,7 +986,7 @@
     # policyConstraints extension). If the application can process the
     # policyConstraints extension, then the path should not validate
     # successfully. 
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.12.5': [ # Invalid inhibitAnyPolicy Test5 
@@ -924,7 +1000,7 @@
     # policyConstraints extension). If the application can process the
     # policyConstraints extension, then the path should not validate
     # successfully.
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.12.6': [ # Invalid inhibitAnyPolicy Test6
@@ -938,7 +1014,7 @@
     # policyConstraints extension). If the application can process the
     # policyConstraints extension, then the path should not validate
     # successfully. 
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.12.7': [ # Valid Self-Issued inhibitAnyPolicy Test7
@@ -956,7 +1032,7 @@
     # user-constrained-policy-set is empty and the application can process the
     # policyConstraints extension, then the path should not validate
     # successfully. 
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[TEST_POLICY_1]),
   ],
 
   '4.12.8': [ # Invalid Self-Issued inhibitAnyPolicy Test8 
@@ -970,7 +1046,7 @@
     # policyConstraints extension). If the application can process the
     # policyConstraints extension, then the path should not validate
     # successfully. 
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 
   '4.12.9': [ # Valid Self-Issued inhibitAnyPolicy Test9
@@ -988,7 +1064,7 @@
     # user-constrained-policy-set is empty and the application can process the
     # policyConstraints extension, then the path should not validate
     # successfully. 
-    TestInfo(True),
+    TestInfo(True, user_constrained_policy_set=[TEST_POLICY_1]),
   ],
 
   '4.12.10': [ # Invalid Self-Issued inhibitAnyPolicy Test10
@@ -1002,7 +1078,7 @@
     # policyConstraints extension). If the application can process the
     # policyConstraints extension, then the path should not validate
     # successfully. 
-    TestInfo(False),
+    TestInfo(False, user_constrained_policy_set=[]),
   ],
 }
 
@@ -1048,6 +1124,21 @@
     # Initializes with default settings.
     info = TestInfo(result_match.group(1) == 'should validate')
 
+    # Special case the 4.9 test failures (require explicit policy) to set
+    # user_constrained_policy_set to empty. This is only done for the 4.9
+    # tests, because the other policy tests are special cased as overrides and
+    # hence set this manually on a per-test basis.
+    #
+    # user_constrained_policy_set enumerates the subset of the initial policy
+    # set (anyPolicy in the default case) that were valid for the path. For
+    # non-policy tests the expectation for user_constrained_policy_set is
+    # [TEST_POLICY_1] since each policy asserts that. However for these tests,
+    # the expectation is an empty user_constrained_policy_set since there was
+    # no valid policy for the path (in fact, that is why the path validation is
+    # expected to fail).
+    if test_number.startswith('4.9.') and not info.should_validate:
+      info.user_constrained_policy_set = []
+
     output_test(test_case_name, test_number, test_name, None, info, certs,
                 crls, sanitized_test_names, output)
   else:
diff --git a/net/third_party/nist-pkits/pkits_testcases-inl.h b/net/third_party/nist-pkits/pkits_testcases-inl.h
index 7ff0864..d4b709d 100644
--- a/net/third_party/nist-pkits/pkits_testcases-inl.h
+++ b/net/third_party/nist-pkits/pkits_testcases-inl.h
@@ -17,7 +17,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "ValidCertificatePathTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.1.2 Invalid CA Signature Test2
@@ -26,7 +29,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "BadSignedCACert",
                                "InvalidCASignatureTest2EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "BadSignedCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.1.3 Invalid EE Signature Test3
@@ -35,7 +41,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "InvalidEESignatureTest3EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.1.4 Valid DSA Signatures Test4
@@ -44,7 +53,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "DSACACert",
                                "ValidDSASignaturesTest4EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "DSACACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.1.5 Valid DSA Parameter Inheritance Test5
@@ -55,7 +67,10 @@
                                "ValidDSAParameterInheritanceTest5EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "DSACACRL",
                               "DSAParametersInheritedCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.1.6 Invalid DSA Signature Test6
@@ -64,7 +79,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "DSACACert",
                                "InvalidDSASignatureTest6EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "DSACACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 WRAPPED_REGISTER_TYPED_TEST_CASE_P(PkitsTest01SignatureVerification,
@@ -86,7 +104,10 @@
                                "BadnotBeforeDateCACert",
                                "InvalidCAnotBeforeDateTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "BadnotBeforeDateCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.2.2 Invalid EE notBefore Date Test2
@@ -95,7 +116,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "InvalidEEnotBeforeDateTest2EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.2.3 Valid pre2000 UTC notBefore Date Test3
@@ -104,7 +128,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "Validpre2000UTCnotBeforeDateTest3EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.2.4 Valid GeneralizedTime notBefore Date Test4
@@ -113,7 +140,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "ValidGeneralizedTimenotBeforeDateTest4EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.2.5 Invalid CA notAfter Date Test5
@@ -123,7 +153,10 @@
                                "BadnotAfterDateCACert",
                                "InvalidCAnotAfterDateTest5EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "BadnotAfterDateCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.2.6 Invalid EE notAfter Date Test6
@@ -132,7 +165,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "InvalidEEnotAfterDateTest6EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.2.7 Invalid pre2000 UTC EE notAfter Date Test7
@@ -141,7 +177,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "Invalidpre2000UTCEEnotAfterDateTest7EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.2.8 Valid GeneralizedTime notAfter Date Test8
@@ -150,7 +189,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "ValidGeneralizedTimenotAfterDateTest8EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 WRAPPED_REGISTER_TYPED_TEST_CASE_P(
@@ -174,7 +216,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "InvalidNameChainingTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.3.2 Invalid Name Chaining Order Test2
@@ -184,7 +229,10 @@
                                "NameOrderingCACert",
                                "InvalidNameChainingOrderTest2EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "NameOrderCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.3.3 Valid Name Chaining Whitespace Test3
@@ -193,7 +241,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "ValidNameChainingWhitespaceTest3EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.3.4 Valid Name Chaining Whitespace Test4
@@ -202,7 +253,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "ValidNameChainingWhitespaceTest4EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.3.5 Valid Name Chaining Capitalization Test5
@@ -211,7 +265,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "ValidNameChainingCapitalizationTest5EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.3.6 Valid Name Chaining UIDs Test6
@@ -220,7 +277,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "UIDCACert",
                                "ValidNameUIDsTest6EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "UIDCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.3.7 Valid RFC3280 Mandatory Attribute Types Test7
@@ -231,7 +291,10 @@
                                "ValidRFC3280MandatoryAttributeTypesTest7EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "RFC3280MandatoryAttributeTypesCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.3.8 Valid RFC3280 Optional Attribute Types Test8
@@ -242,7 +305,10 @@
                                "ValidRFC3280OptionalAttributeTypesTest8EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "RFC3280OptionalAttributeTypesCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.3.9 Valid UTF8String Encoded Names Test9
@@ -253,7 +319,10 @@
                                "ValidUTF8StringEncodedNamesTest9EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "UTF8StringEncodedNamesCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.3.10 Valid Rollover from PrintableString to UTF8String Test10
@@ -266,7 +335,10 @@
       "ValidRolloverfromPrintableStringtoUTF8StringTest10EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "RolloverfromPrintableStringtoUTF8StringCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.3.11 Valid UTF8String Case Insensitive Match Test11
@@ -277,7 +349,10 @@
                                "ValidUTF8StringCaseInsensitiveMatchTest11EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "UTF8StringCaseInsensitiveMatchCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 WRAPPED_REGISTER_TYPED_TEST_CASE_P(
@@ -305,7 +380,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "NoCRLCACert",
                                "InvalidMissingCRLTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.2 Invalid Revoked CA Test2
@@ -315,7 +393,10 @@
                                "RevokedsubCACert", "InvalidRevokedCATest2EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL",
                               "RevokedsubCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.3 Invalid Revoked EE Test3
@@ -324,7 +405,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "InvalidRevokedEETest3EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.4 Invalid Bad CRL Signature Test4
@@ -334,7 +418,10 @@
                                "BadCRLSignatureCACert",
                                "InvalidBadCRLSignatureTest4EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "BadCRLSignatureCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.5 Invalid Bad CRL Issuer Name Test5
@@ -344,7 +431,10 @@
                                "BadCRLIssuerNameCACert",
                                "InvalidBadCRLIssuerNameTest5EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "BadCRLIssuerNameCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.6 Invalid Wrong CRL Test6
@@ -353,7 +443,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "WrongCRLCACert",
                                "InvalidWrongCRLTest6EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "WrongCRLCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.7 Valid Two CRLs Test7
@@ -363,7 +456,10 @@
                                "ValidTwoCRLsTest7EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "TwoCRLsCAGoodCRL",
                               "TwoCRLsCABadCRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.8 Invalid Unknown CRL Entry Extension Test8
@@ -374,7 +470,10 @@
                                "InvalidUnknownCRLEntryExtensionTest8EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "UnknownCRLEntryExtensionCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.9 Invalid Unknown CRL Extension Test9
@@ -384,7 +483,10 @@
                                "UnknownCRLExtensionCACert",
                                "InvalidUnknownCRLExtensionTest9EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "UnknownCRLExtensionCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.10 Invalid Unknown CRL Extension Test10
@@ -394,7 +496,10 @@
                                "UnknownCRLExtensionCACert",
                                "InvalidUnknownCRLExtensionTest10EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "UnknownCRLExtensionCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.11 Invalid Old CRL nextUpdate Test11
@@ -404,7 +509,10 @@
                                "OldCRLnextUpdateCACert",
                                "InvalidOldCRLnextUpdateTest11EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "OldCRLnextUpdateCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.12 Invalid pre2000 CRL nextUpdate Test12
@@ -416,7 +524,10 @@
                                "uctiontoSection4.4formoreinformation."};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "pre2000CRLnextUpdateCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.13 Valid GeneralizedTime CRL nextUpdate Test13
@@ -427,7 +538,10 @@
                                "ValidGeneralizedTimeCRLnextUpdateTest13EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "GeneralizedTimeCRLnextUpdateCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.14 Valid Negative Serial Number Test14
@@ -438,7 +552,10 @@
                                "ValidNegativeSerialNumberTest14EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "NegativeSerialNumberCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.15 Invalid Negative Serial Number Test15
@@ -449,7 +566,10 @@
                                "InvalidNegativeSerialNumberTest15EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "NegativeSerialNumberCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.16 Valid Long Serial Number Test16
@@ -459,7 +579,10 @@
                                "LongSerialNumberCACert",
                                "ValidLongSerialNumberTest16EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "LongSerialNumberCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.17 Valid Long Serial Number Test17
@@ -469,7 +592,10 @@
                                "LongSerialNumberCACert",
                                "ValidLongSerialNumberTest17EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "LongSerialNumberCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.18 Invalid Long Serial Number Test18
@@ -479,7 +605,10 @@
                                "LongSerialNumberCACert",
                                "InvalidLongSerialNumberTest18EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "LongSerialNumberCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.19 Valid Separate Certificate and CRL Keys Test19
@@ -492,7 +621,10 @@
       "ValidSeparateCertificateandCRLKeysTest19EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "SeparateCertificateandCRLKeysCRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.20 Invalid Separate Certificate and CRL Keys Test20
@@ -505,7 +637,10 @@
       "InvalidSeparateCertificateandCRLKeysTest20EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "SeparateCertificateandCRLKeysCRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.4.21 Invalid Separate Certificate and CRL Keys Test21
@@ -518,7 +653,10 @@
       "InvalidSeparateCertificateandCRLKeysTest21EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "SeparateCertificateandCRLKeysCA2CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 WRAPPED_REGISTER_TYPED_TEST_CASE_P(
@@ -559,7 +697,10 @@
                                "ValidBasicSelfIssuedOldWithNewTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "BasicSelfIssuedNewKeyCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.5.2 Invalid Basic Self-Issued Old With New Test2
@@ -571,7 +712,10 @@
                                "InvalidBasicSelfIssuedOldWithNewTest2EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "BasicSelfIssuedNewKeyCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.5.3 Valid Basic Self-Issued New With Old Test3
@@ -584,7 +728,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "BasicSelfIssuedOldKeySelfIssuedCertCRL",
                               "BasicSelfIssuedOldKeyCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.5.4 Valid Basic Self-Issued New With Old Test4
@@ -597,7 +744,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "BasicSelfIssuedOldKeySelfIssuedCertCRL",
                               "BasicSelfIssuedOldKeyCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.5.5 Invalid Basic Self-Issued New With Old Test5
@@ -610,7 +760,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "BasicSelfIssuedOldKeySelfIssuedCertCRL",
                               "BasicSelfIssuedOldKeyCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.5.6 Valid Basic Self-Issued CRL Signing Key Test6
@@ -623,7 +776,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "BasicSelfIssuedCRLSigningKeyCRLCertCRL",
                               "BasicSelfIssuedCRLSigningKeyCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.5.7 Invalid Basic Self-Issued CRL Signing Key Test7
@@ -636,7 +792,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "BasicSelfIssuedCRLSigningKeyCRLCertCRL",
                               "BasicSelfIssuedCRLSigningKeyCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.5.8 Invalid Basic Self-Issued CRL Signing Key Test8
@@ -649,7 +808,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "BasicSelfIssuedCRLSigningKeyCRLCertCRL",
                               "BasicSelfIssuedCRLSigningKeyCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 WRAPPED_REGISTER_TYPED_TEST_CASE_P(
@@ -676,7 +838,10 @@
                                "InvalidMissingbasicConstraintsTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "MissingbasicConstraintsCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.6.2 Invalid cA False Test2
@@ -687,7 +852,10 @@
                                "InvalidcAFalseTest2EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "basicConstraintsCriticalcAFalseCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.6.3 Invalid cA False Test3
@@ -698,7 +866,10 @@
                                "InvalidcAFalseTest3EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "basicConstraintsNotCriticalcAFalseCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.6.4 Valid basicConstraints Not Critical Test4
@@ -709,7 +880,10 @@
                                "ValidbasicConstraintsNotCriticalTest4EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "basicConstraintsNotCriticalCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.6.5 Invalid pathLenConstraint Test5
@@ -720,7 +894,10 @@
       "pathLenConstraint0subCACert", "InvalidpathLenConstraintTest5EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "pathLenConstraint0CACRL",
                               "pathLenConstraint0subCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.6.6 Invalid pathLenConstraint Test6
@@ -731,7 +908,10 @@
       "pathLenConstraint0subCACert", "InvalidpathLenConstraintTest6EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "pathLenConstraint0CACRL",
                               "pathLenConstraint0subCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.6.7 Valid pathLenConstraint Test7
@@ -741,7 +921,10 @@
                                "pathLenConstraint0CACert",
                                "ValidpathLenConstraintTest7EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "pathLenConstraint0CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.6.8 Valid pathLenConstraint Test8
@@ -751,7 +934,10 @@
                                "pathLenConstraint0CACert",
                                "ValidpathLenConstraintTest8EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "pathLenConstraint0CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.6.9 Invalid pathLenConstraint Test9
@@ -764,7 +950,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL", "pathLenConstraint6CACRL",
                               "pathLenConstraint6subCA0CRL",
                               "pathLenConstraint6subsubCA00CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.6.10 Invalid pathLenConstraint Test10
@@ -777,7 +966,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL", "pathLenConstraint6CACRL",
                               "pathLenConstraint6subCA0CRL",
                               "pathLenConstraint6subsubCA00CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.6.11 Invalid pathLenConstraint Test11
@@ -793,7 +985,10 @@
                               "pathLenConstraint6subCA1CRL",
                               "pathLenConstraint6subsubCA11CRL",
                               "pathLenConstraint6subsubsubCA11XCRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.6.12 Invalid pathLenConstraint Test12
@@ -809,7 +1004,10 @@
                               "pathLenConstraint6subCA1CRL",
                               "pathLenConstraint6subsubCA11CRL",
                               "pathLenConstraint6subsubsubCA11XCRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.6.13 Valid pathLenConstraint Test13
@@ -825,7 +1023,10 @@
                               "pathLenConstraint6subCA4CRL",
                               "pathLenConstraint6subsubCA41CRL",
                               "pathLenConstraint6subsubsubCA41XCRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.6.14 Valid pathLenConstraint Test14
@@ -841,7 +1042,10 @@
                               "pathLenConstraint6subCA4CRL",
                               "pathLenConstraint6subsubCA41CRL",
                               "pathLenConstraint6subsubsubCA41XCRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.6.15 Valid Self-Issued pathLenConstraint Test15
@@ -852,7 +1056,10 @@
                                "pathLenConstraint0SelfIssuedCACert",
                                "ValidSelfIssuedpathLenConstraintTest15EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "pathLenConstraint0CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.6.16 Invalid Self-Issued pathLenConstraint Test16
@@ -864,7 +1071,10 @@
       "InvalidSelfIssuedpathLenConstraintTest16EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "pathLenConstraint0CACRL",
                               "pathLenConstraint0subCA2CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.6.17 Valid Self-Issued pathLenConstraint Test17
@@ -878,7 +1088,10 @@
                                "ValidSelfIssuedpathLenConstraintTest17EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "pathLenConstraint1CACRL",
                               "pathLenConstraint1subCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 WRAPPED_REGISTER_TYPED_TEST_CASE_P(
@@ -913,7 +1126,10 @@
       "InvalidkeyUsageCriticalkeyCertSignFalseTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "keyUsageCriticalkeyCertSignFalseCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.7.2 Invalid keyUsage Not Critical keyCertSign False Test2
@@ -924,7 +1140,10 @@
       "InvalidkeyUsageNotCriticalkeyCertSignFalseTest2EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "keyUsageNotCriticalkeyCertSignFalseCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.7.3 Valid keyUsage Not Critical Test3
@@ -934,7 +1153,10 @@
                                "keyUsageNotCriticalCACert",
                                "ValidkeyUsageNotCriticalTest3EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "keyUsageNotCriticalCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.7.4 Invalid keyUsage Critical cRLSign False Test4
@@ -945,7 +1167,10 @@
                                "InvalidkeyUsageCriticalcRLSignFalseTest4EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "keyUsageCriticalcRLSignFalseCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.7.5 Invalid keyUsage Not Critical cRLSign False Test5
@@ -956,7 +1181,10 @@
                                "InvalidkeyUsageNotCriticalcRLSignFalseTest5EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "keyUsageNotCriticalcRLSignFalseCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 WRAPPED_REGISTER_TYPED_TEST_CASE_P(
@@ -971,89 +1199,90 @@
 class PkitsTest08CertificatePolicies : public PkitsTest<PkitsTestDelegate> {};
 TYPED_TEST_CASE_P(PkitsTest08CertificatePolicies);
 
-// 4.8.1 All Certificates Same Policy Test1
+// 4.8.1 All Certificates Same Policy Test1 (Subpart 1)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8AllCertificatesSamePolicyTest1Subpart1) {
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "ValidCertificatePathTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialExplicitPolicy(true);
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.initial_explicit_policy = true;
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.1 All Certificates Same Policy Test1
+// 4.8.1 All Certificates Same Policy Test1 (Subpart 2)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8AllCertificatesSamePolicyTest1Subpart2) {
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "ValidCertificatePathTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-1");
+  info.SetInitialExplicitPolicy(true);
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-1");
-  settings.initial_explicit_policy = true;
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.1 All Certificates Same Policy Test1
+// 4.8.1 All Certificates Same Policy Test1 (Subpart 3)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8AllCertificatesSamePolicyTest1Subpart3) {
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "ValidCertificatePathTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetInitialPolicySet("NIST-test-policy-2");
+  info.SetInitialExplicitPolicy(true);
+  info.SetUserConstrainedPolicySet("");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-2");
-  settings.initial_explicit_policy = true;
-
-  ASSERT_FALSE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.1 All Certificates Same Policy Test1
+// 4.8.1 All Certificates Same Policy Test1 (Subpart 4)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8AllCertificatesSamePolicyTest1Subpart4) {
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "ValidCertificatePathTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-1,NIST-test-policy-2");
+  info.SetInitialExplicitPolicy(true);
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-1,NIST-test-policy-2");
-  settings.initial_explicit_policy = true;
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.2 All Certificates No Policies Test2
+// 4.8.2 All Certificates No Policies Test2 (Subpart 1)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8AllCertificatesNoPoliciesTest2Subpart1) {
   const char* const certs[] = {"TrustAnchorRootCertificate", "NoPoliciesCACert",
                                "AllCertificatesNoPoliciesTest2EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "NoPoliciesCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.2 All Certificates No Policies Test2
+// 4.8.2 All Certificates No Policies Test2 (Subpart 2)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8AllCertificatesNoPoliciesTest2Subpart2) {
   const char* const certs[] = {"TrustAnchorRootCertificate", "NoPoliciesCACert",
                                "AllCertificatesNoPoliciesTest2EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "NoPoliciesCACRL"};
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetInitialExplicitPolicy(true);
+  info.SetUserConstrainedPolicySet("");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.initial_explicit_policy = true;
-
-  ASSERT_FALSE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.3 Different Policies Test3
+// 4.8.3 Different Policies Test3 (Subpart 1)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8DifferentPoliciesTest3Subpart1) {
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
@@ -1061,10 +1290,14 @@
                                "DifferentPoliciesTest3EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL",
                               "PoliciesP2subCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.3 Different Policies Test3
+// 4.8.3 Different Policies Test3 (Subpart 2)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8DifferentPoliciesTest3Subpart2) {
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
@@ -1072,15 +1305,15 @@
                                "DifferentPoliciesTest3EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL",
                               "PoliciesP2subCACRL"};
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetInitialExplicitPolicy(true);
+  info.SetUserConstrainedPolicySet("");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.initial_explicit_policy = true;
-
-  ASSERT_FALSE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.3 Different Policies Test3
+// 4.8.3 Different Policies Test3 (Subpart 3)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8DifferentPoliciesTest3Subpart3) {
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
@@ -1088,13 +1321,13 @@
                                "DifferentPoliciesTest3EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL",
                               "PoliciesP2subCACRL"};
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetInitialPolicySet("NIST-test-policy-1,NIST-test-policy-2");
+  info.SetInitialExplicitPolicy(true);
+  info.SetUserConstrainedPolicySet("");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-1,NIST-test-policy-2");
-  settings.initial_explicit_policy = true;
-
-  ASSERT_FALSE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
 // 4.8.4 Different Policies Test4
@@ -1104,7 +1337,11 @@
                                "GoodsubCACert", "DifferentPoliciesTest4EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL",
                               "GoodsubCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.8.5 Different Policies Test5
@@ -1115,10 +1352,14 @@
                                "DifferentPoliciesTest5EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL",
                               "PoliciesP2subCA2CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.6 Overlapping Policies Test6
+// 4.8.6 Overlapping Policies Test6 (Subpart 1)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8OverlappingPoliciesTest6Subpart1) {
   const char* const certs[] = {
@@ -1128,10 +1369,13 @@
   const char* const crls[] = {"TrustAnchorRootCRL", "PoliciesP1234CACRL",
                               "PoliciesP1234subCAP123CRL",
                               "PoliciesP1234subsubCAP123P12CRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.6 Overlapping Policies Test6
+// 4.8.6 Overlapping Policies Test6 (Subpart 2)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8OverlappingPoliciesTest6Subpart2) {
   const char* const certs[] = {
@@ -1141,15 +1385,14 @@
   const char* const crls[] = {"TrustAnchorRootCRL", "PoliciesP1234CACRL",
                               "PoliciesP1234subCAP123CRL",
                               "PoliciesP1234subsubCAP123P12CRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-1");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-1");
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.6 Overlapping Policies Test6
+// 4.8.6 Overlapping Policies Test6 (Subpart 3)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8OverlappingPoliciesTest6Subpart3) {
   const char* const certs[] = {
@@ -1159,12 +1402,12 @@
   const char* const crls[] = {"TrustAnchorRootCRL", "PoliciesP1234CACRL",
                               "PoliciesP1234subCAP123CRL",
                               "PoliciesP1234subsubCAP123P12CRL"};
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetInitialPolicySet("NIST-test-policy-2");
+  info.SetUserConstrainedPolicySet("");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-2");
-
-  ASSERT_FALSE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
 // 4.8.7 Different Policies Test7
@@ -1177,7 +1420,11 @@
   const char* const crls[] = {"TrustAnchorRootCRL", "PoliciesP123CACRL",
                               "PoliciesP123subCAP12CRL",
                               "PoliciesP123subsubCAP12P1CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.8.8 Different Policies Test8
@@ -1190,7 +1437,11 @@
   const char* const crls[] = {"TrustAnchorRootCRL", "PoliciesP12CACRL",
                               "PoliciesP12subCAP1CRL",
                               "PoliciesP12subsubCAP1P2CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.8.9 Different Policies Test9
@@ -1203,70 +1454,80 @@
   const char* const crls[] = {
       "TrustAnchorRootCRL", "PoliciesP123CACRL", "PoliciesP123subCAP12CRL",
       "PoliciesP123subsubCAP2P2CRL", "PoliciesP123subsubsubCAP12P2P1CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.10 All Certificates Same Policies Test10
+// 4.8.10 All Certificates Same Policies Test10 (Subpart 1)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8AllCertificatesSamePoliciesTest10Subpart1) {
   const char* const certs[] = {"TrustAnchorRootCertificate",
                                "PoliciesP12CACert",
                                "AllCertificatesSamePoliciesTest10EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "PoliciesP12CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetUserConstrainedPolicySet("NIST-test-policy-1,NIST-test-policy-2");
+
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.10 All Certificates Same Policies Test10
+// 4.8.10 All Certificates Same Policies Test10 (Subpart 2)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8AllCertificatesSamePoliciesTest10Subpart2) {
   const char* const certs[] = {"TrustAnchorRootCertificate",
                                "PoliciesP12CACert",
                                "AllCertificatesSamePoliciesTest10EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "PoliciesP12CACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-1");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-1");
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.10 All Certificates Same Policies Test10
+// 4.8.10 All Certificates Same Policies Test10 (Subpart 3)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8AllCertificatesSamePoliciesTest10Subpart3) {
   const char* const certs[] = {"TrustAnchorRootCertificate",
                                "PoliciesP12CACert",
                                "AllCertificatesSamePoliciesTest10EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "PoliciesP12CACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-2");
+  info.SetUserConstrainedPolicySet("NIST-test-policy-2");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-2");
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.11 All Certificates AnyPolicy Test11
+// 4.8.11 All Certificates AnyPolicy Test11 (Subpart 1)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8AllCertificatesAnyPolicyTest11Subpart1) {
   const char* const certs[] = {"TrustAnchorRootCertificate", "anyPolicyCACert",
                                "AllCertificatesanyPolicyTest11EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "anyPolicyCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetUserConstrainedPolicySet("anyPolicy");
+
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.11 All Certificates AnyPolicy Test11
+// 4.8.11 All Certificates AnyPolicy Test11 (Subpart 2)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8AllCertificatesAnyPolicyTest11Subpart2) {
   const char* const certs[] = {"TrustAnchorRootCertificate", "anyPolicyCACert",
                                "AllCertificatesanyPolicyTest11EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "anyPolicyCACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-1");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-1");
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
 // 4.8.12 Different Policies Test12
@@ -1275,80 +1536,82 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "PoliciesP3CACert",
                                "DifferentPoliciesTest12EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "PoliciesP3CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.13 All Certificates Same Policies Test13
+// 4.8.13 All Certificates Same Policies Test13 (Subpart 1)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8AllCertificatesSamePoliciesTest13Subpart1) {
   const char* const certs[] = {"TrustAnchorRootCertificate",
                                "PoliciesP123CACert",
                                "AllCertificatesSamePoliciesTest13EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "PoliciesP123CACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-1");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-1");
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.13 All Certificates Same Policies Test13
+// 4.8.13 All Certificates Same Policies Test13 (Subpart 2)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8AllCertificatesSamePoliciesTest13Subpart2) {
   const char* const certs[] = {"TrustAnchorRootCertificate",
                                "PoliciesP123CACert",
                                "AllCertificatesSamePoliciesTest13EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "PoliciesP123CACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-2");
+  info.SetUserConstrainedPolicySet("NIST-test-policy-2");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-2");
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.13 All Certificates Same Policies Test13
+// 4.8.13 All Certificates Same Policies Test13 (Subpart 3)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8AllCertificatesSamePoliciesTest13Subpart3) {
   const char* const certs[] = {"TrustAnchorRootCertificate",
                                "PoliciesP123CACert",
                                "AllCertificatesSamePoliciesTest13EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "PoliciesP123CACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-3");
+  info.SetUserConstrainedPolicySet("NIST-test-policy-3");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-3");
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.14 AnyPolicy Test14
+// 4.8.14 AnyPolicy Test14 (Subpart 1)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8AnyPolicyTest14Subpart1) {
   const char* const certs[] = {"TrustAnchorRootCertificate", "anyPolicyCACert",
                                "AnyPolicyTest14EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "anyPolicyCACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-1");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-1");
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.14 AnyPolicy Test14
+// 4.8.14 AnyPolicy Test14 (Subpart 2)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8AnyPolicyTest14Subpart2) {
   const char* const certs[] = {"TrustAnchorRootCertificate", "anyPolicyCACert",
                                "AnyPolicyTest14EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "anyPolicyCACRL"};
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetInitialPolicySet("NIST-test-policy-2");
+  info.SetUserConstrainedPolicySet("");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-2");
-
-  ASSERT_FALSE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
 // 4.8.15 User Notice Qualifier Test15
@@ -1357,7 +1620,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate",
                                "UserNoticeQualifierTest15EE"};
   const char* const crls[] = {"TrustAnchorRootCRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.8.16 User Notice Qualifier Test16
@@ -1366,7 +1632,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "UserNoticeQualifierTest16EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.8.17 User Notice Qualifier Test17
@@ -1375,37 +1644,39 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "UserNoticeQualifierTest17EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.18 User Notice Qualifier Test18
+// 4.8.18 User Notice Qualifier Test18 (Subpart 1)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8UserNoticeQualifierTest18Subpart1) {
   const char* const certs[] = {"TrustAnchorRootCertificate",
                                "PoliciesP12CACert",
                                "UserNoticeQualifierTest18EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "PoliciesP12CACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-1");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-1");
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.8.18 User Notice Qualifier Test18
+// 4.8.18 User Notice Qualifier Test18 (Subpart 2)
 WRAPPED_TYPED_TEST_P(PkitsTest08CertificatePolicies,
                      Section8UserNoticeQualifierTest18Subpart2) {
   const char* const certs[] = {"TrustAnchorRootCertificate",
                                "PoliciesP12CACert",
                                "UserNoticeQualifierTest18EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "PoliciesP12CACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-2");
+  info.SetUserConstrainedPolicySet("NIST-test-policy-2");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-2");
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
 // 4.8.19 User Notice Qualifier Test19
@@ -1414,7 +1685,10 @@
   const char* const certs[] = {"TrustAnchorRootCertificate",
                                "UserNoticeQualifierTest19EE"};
   const char* const crls[] = {"TrustAnchorRootCRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.8.20 CPS Pointer Qualifier Test20
@@ -1423,13 +1697,12 @@
   const char* const certs[] = {"TrustAnchorRootCertificate", "GoodCACert",
                                "CPSPointerQualifierTest20EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-1");
+  info.SetInitialExplicitPolicy(true);
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-1");
-  settings.initial_explicit_policy = true;
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
 WRAPPED_REGISTER_TYPED_TEST_CASE_P(
@@ -1487,7 +1760,11 @@
       "TrustAnchorRootCRL", "requireExplicitPolicy10CACRL",
       "requireExplicitPolicy10subCACRL", "requireExplicitPolicy10subsubCACRL",
       "requireExplicitPolicy10subsubsubCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.9.2 Valid RequireExplicitPolicy Test2
@@ -1503,7 +1780,11 @@
       "TrustAnchorRootCRL", "requireExplicitPolicy5CACRL",
       "requireExplicitPolicy5subCACRL", "requireExplicitPolicy5subsubCACRL",
       "requireExplicitPolicy5subsubsubCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.9.3 Invalid RequireExplicitPolicy Test3
@@ -1519,7 +1800,11 @@
       "TrustAnchorRootCRL", "requireExplicitPolicy4CACRL",
       "requireExplicitPolicy4subCACRL", "requireExplicitPolicy4subsubCACRL",
       "requireExplicitPolicy4subsubsubCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.9.4 Valid RequireExplicitPolicy Test4
@@ -1535,7 +1820,10 @@
       "TrustAnchorRootCRL", "requireExplicitPolicy0CACRL",
       "requireExplicitPolicy0subCACRL", "requireExplicitPolicy0subsubCACRL",
       "requireExplicitPolicy0subsubsubCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.9.5 Invalid RequireExplicitPolicy Test5
@@ -1552,7 +1840,11 @@
                               "requireExplicitPolicy7subCARE2CRL",
                               "requireExplicitPolicy7subsubCARE2RE4CRL",
                               "requireExplicitPolicy7subsubsubCARE2RE4CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.9.6 Valid Self-Issued requireExplicitPolicy Test6
@@ -1564,7 +1856,11 @@
                                "ValidSelfIssuedrequireExplicitPolicyTest6EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "requireExplicitPolicy2CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.9.7 Invalid Self-Issued requireExplicitPolicy Test7
@@ -1578,7 +1874,11 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "requireExplicitPolicy2CACRL",
                               "requireExplicitPolicy2subCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.9.8 Invalid Self-Issued requireExplicitPolicy Test8
@@ -1593,7 +1893,11 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "requireExplicitPolicy2CACRL",
                               "requireExplicitPolicy2subCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 WRAPPED_REGISTER_TYPED_TEST_CASE_P(
@@ -1611,77 +1915,80 @@
 class PkitsTest10PolicyMappings : public PkitsTest<PkitsTestDelegate> {};
 TYPED_TEST_CASE_P(PkitsTest10PolicyMappings);
 
-// 4.10.1 Valid Policy Mapping Test1
+// 4.10.1 Valid Policy Mapping Test1 (Subpart 1)
 WRAPPED_TYPED_TEST_P(PkitsTest10PolicyMappings,
                      Section10ValidPolicyMappingTest1Subpart1) {
   const char* const certs[] = {"TrustAnchorRootCertificate",
                                "Mapping1to2CACert",
                                "ValidPolicyMappingTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "Mapping1to2CACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-1");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-1");
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.10.1 Valid Policy Mapping Test1
+// 4.10.1 Valid Policy Mapping Test1 (Subpart 2)
 WRAPPED_TYPED_TEST_P(PkitsTest10PolicyMappings,
                      Section10ValidPolicyMappingTest1Subpart2) {
   const char* const certs[] = {"TrustAnchorRootCertificate",
                                "Mapping1to2CACert",
                                "ValidPolicyMappingTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "Mapping1to2CACRL"};
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetInitialPolicySet("NIST-test-policy-2");
+  info.SetUserConstrainedPolicySet("");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-2");
-
-  ASSERT_FALSE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.10.1 Valid Policy Mapping Test1
+// 4.10.1 Valid Policy Mapping Test1 (Subpart 3)
 WRAPPED_TYPED_TEST_P(PkitsTest10PolicyMappings,
                      Section10ValidPolicyMappingTest1Subpart3) {
   const char* const certs[] = {"TrustAnchorRootCertificate",
                                "Mapping1to2CACert",
                                "ValidPolicyMappingTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "Mapping1to2CACRL"};
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetInitialPolicyMappingInhibit(true);
+  info.SetUserConstrainedPolicySet("");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.initial_policy_mapping_inhibit = true;
-
-  ASSERT_FALSE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.10.2 Invalid Policy Mapping Test2
+// 4.10.2 Invalid Policy Mapping Test2 (Subpart 1)
 WRAPPED_TYPED_TEST_P(PkitsTest10PolicyMappings,
                      Section10InvalidPolicyMappingTest2Subpart1) {
   const char* const certs[] = {"TrustAnchorRootCertificate",
                                "Mapping1to2CACert",
                                "InvalidPolicyMappingTest2EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "Mapping1to2CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
-// 4.10.2 Invalid Policy Mapping Test2
+// 4.10.2 Invalid Policy Mapping Test2 (Subpart 2)
 WRAPPED_TYPED_TEST_P(PkitsTest10PolicyMappings,
                      Section10InvalidPolicyMappingTest2Subpart2) {
   const char* const certs[] = {"TrustAnchorRootCertificate",
                                "Mapping1to2CACert",
                                "InvalidPolicyMappingTest2EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "Mapping1to2CACRL"};
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetInitialPolicyMappingInhibit(true);
+  info.SetUserConstrainedPolicySet("");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.initial_policy_mapping_inhibit = true;
-
-  ASSERT_FALSE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.10.3 Valid Policy Mapping Test3
+// 4.10.3 Valid Policy Mapping Test3 (Subpart 1)
 WRAPPED_TYPED_TEST_P(PkitsTest10PolicyMappings,
                      Section10ValidPolicyMappingTest3Subpart1) {
   const char* const certs[] = {
@@ -1691,15 +1998,15 @@
   const char* const crls[] = {"TrustAnchorRootCRL", "P12Mapping1to3CACRL",
                               "P12Mapping1to3subCACRL",
                               "P12Mapping1to3subsubCACRL"};
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetInitialPolicySet("NIST-test-policy-1");
+  info.SetUserConstrainedPolicySet("");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-1");
-
-  ASSERT_FALSE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.10.3 Valid Policy Mapping Test3
+// 4.10.3 Valid Policy Mapping Test3 (Subpart 2)
 WRAPPED_TYPED_TEST_P(PkitsTest10PolicyMappings,
                      Section10ValidPolicyMappingTest3Subpart2) {
   const char* const certs[] = {
@@ -1709,12 +2016,12 @@
   const char* const crls[] = {"TrustAnchorRootCRL", "P12Mapping1to3CACRL",
                               "P12Mapping1to3subCACRL",
                               "P12Mapping1to3subsubCACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-2");
+  info.SetUserConstrainedPolicySet("NIST-test-policy-2");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-2");
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
 // 4.10.4 Invalid Policy Mapping Test4
@@ -1727,10 +2034,14 @@
   const char* const crls[] = {"TrustAnchorRootCRL", "P12Mapping1to3CACRL",
                               "P12Mapping1to3subCACRL",
                               "P12Mapping1to3subsubCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
-// 4.10.5 Valid Policy Mapping Test5
+// 4.10.5 Valid Policy Mapping Test5 (Subpart 1)
 WRAPPED_TYPED_TEST_P(PkitsTest10PolicyMappings,
                      Section10ValidPolicyMappingTest5Subpart1) {
   const char* const certs[] = {
@@ -1738,15 +2049,14 @@
       "P1Mapping1to234subCACert", "ValidPolicyMappingTest5EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "P1Mapping1to234CACRL",
                               "P1Mapping1to234subCACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-1");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-1");
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.10.5 Valid Policy Mapping Test5
+// 4.10.5 Valid Policy Mapping Test5 (Subpart 2)
 WRAPPED_TYPED_TEST_P(PkitsTest10PolicyMappings,
                      Section10ValidPolicyMappingTest5Subpart2) {
   const char* const certs[] = {
@@ -1754,15 +2064,15 @@
       "P1Mapping1to234subCACert", "ValidPolicyMappingTest5EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "P1Mapping1to234CACRL",
                               "P1Mapping1to234subCACRL"};
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetInitialPolicySet("NIST-test-policy-6");
+  info.SetUserConstrainedPolicySet("");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-6");
-
-  ASSERT_FALSE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.10.6 Valid Policy Mapping Test6
+// 4.10.6 Valid Policy Mapping Test6 (Subpart 1)
 WRAPPED_TYPED_TEST_P(PkitsTest10PolicyMappings,
                      Section10ValidPolicyMappingTest6Subpart1) {
   const char* const certs[] = {
@@ -1770,15 +2080,14 @@
       "P1Mapping1to234subCACert", "ValidPolicyMappingTest6EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "P1Mapping1to234CACRL",
                               "P1Mapping1to234subCACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-1");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-1");
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.10.6 Valid Policy Mapping Test6
+// 4.10.6 Valid Policy Mapping Test6 (Subpart 2)
 WRAPPED_TYPED_TEST_P(PkitsTest10PolicyMappings,
                      Section10ValidPolicyMappingTest6Subpart2) {
   const char* const certs[] = {
@@ -1786,12 +2095,12 @@
       "P1Mapping1to234subCACert", "ValidPolicyMappingTest6EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "P1Mapping1to234CACRL",
                               "P1Mapping1to234subCACRL"};
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetInitialPolicySet("NIST-test-policy-6");
+  info.SetUserConstrainedPolicySet("");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-6");
-
-  ASSERT_FALSE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
 // 4.10.7 Invalid Mapping From anyPolicy Test7
@@ -1802,7 +2111,10 @@
                                "InvalidMappingFromanyPolicyTest7EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "MappingFromanyPolicyCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.10.8 Invalid Mapping To anyPolicy Test8
@@ -1812,7 +2124,11 @@
                                "MappingToanyPolicyCACert",
                                "InvalidMappingToanyPolicyTest8EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "MappingToanyPolicyCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.10.9 Valid Policy Mapping Test9
@@ -1823,7 +2139,10 @@
                                "ValidPolicyMappingTest9EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "PanyPolicyMapping1to2CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.10.10 Invalid Policy Mapping Test10
@@ -1834,7 +2153,11 @@
                                "InvalidPolicyMappingTest10EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL",
                               "GoodsubCAPanyPolicyMapping1to2CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.10.11 Valid Policy Mapping Test11
@@ -1845,37 +2168,39 @@
                                "ValidPolicyMappingTest11EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL",
                               "GoodsubCAPanyPolicyMapping1to2CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
-// 4.10.12 Valid Policy Mapping Test12
+// 4.10.12 Valid Policy Mapping Test12 (Subpart 1)
 WRAPPED_TYPED_TEST_P(PkitsTest10PolicyMappings,
                      Section10ValidPolicyMappingTest12Subpart1) {
   const char* const certs[] = {"TrustAnchorRootCertificate",
                                "P12Mapping1to3CACert",
                                "ValidPolicyMappingTest12EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "P12Mapping1to3CACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-1");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-1");
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
-// 4.10.12 Valid Policy Mapping Test12
+// 4.10.12 Valid Policy Mapping Test12 (Subpart 2)
 WRAPPED_TYPED_TEST_P(PkitsTest10PolicyMappings,
                      Section10ValidPolicyMappingTest12Subpart2) {
   const char* const certs[] = {"TrustAnchorRootCertificate",
                                "P12Mapping1to3CACert",
                                "ValidPolicyMappingTest12EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "P12Mapping1to3CACRL"};
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetInitialPolicySet("NIST-test-policy-2");
+  info.SetUserConstrainedPolicySet("NIST-test-policy-2");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.SetInitialPolicySet("NIST-test-policy-2");
-
-  ASSERT_TRUE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
 // 4.10.13 Valid Policy Mapping Test13
@@ -1886,7 +2211,10 @@
                                "ValidPolicyMappingTest13EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "P1anyPolicyMapping1to2CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.10.14 Valid Policy Mapping Test14
@@ -1897,7 +2225,10 @@
                                "ValidPolicyMappingTest14EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "P1anyPolicyMapping1to2CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 WRAPPED_REGISTER_TYPED_TEST_CASE_P(PkitsTest10PolicyMappings,
@@ -1936,7 +2267,11 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "inhibitPolicyMapping0CACRL",
                               "inhibitPolicyMapping0subCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.11.2 Valid inhibitPolicyMapping Test2
@@ -1948,7 +2283,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "inhibitPolicyMapping1P12CACRL",
                               "inhibitPolicyMapping1P12subCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.11.3 Invalid inhibitPolicyMapping Test3
@@ -1963,7 +2301,11 @@
                               "inhibitPolicyMapping1P12CACRL",
                               "inhibitPolicyMapping1P12subCACRL",
                               "inhibitPolicyMapping1P12subsubCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.11.4 Valid inhibitPolicyMapping Test4
@@ -1978,7 +2320,11 @@
                               "inhibitPolicyMapping1P12CACRL",
                               "inhibitPolicyMapping1P12subCACRL",
                               "inhibitPolicyMapping1P12subsubCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+  info.SetUserConstrainedPolicySet("NIST-test-policy-2");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.11.5 Invalid inhibitPolicyMapping Test5
@@ -1994,7 +2340,11 @@
       "TrustAnchorRootCRL", "inhibitPolicyMapping5CACRL",
       "inhibitPolicyMapping5subCACRL", "inhibitPolicyMapping5subsubCACRL",
       "inhibitPolicyMapping5subsubsubCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.11.6 Invalid inhibitPolicyMapping Test6
@@ -2009,7 +2359,11 @@
                               "inhibitPolicyMapping1P12CACRL",
                               "inhibitPolicyMapping1P12subCAIPM5CRL",
                               "inhibitPolicyMapping1P12subsubCAIPM5CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.11.7 Valid Self-Issued inhibitPolicyMapping Test7
@@ -2023,7 +2377,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "inhibitPolicyMapping1P1CACRL",
                               "inhibitPolicyMapping1P1subCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.11.8 Invalid Self-Issued inhibitPolicyMapping Test8
@@ -2038,7 +2395,11 @@
   const char* const crls[] = {
       "TrustAnchorRootCRL", "inhibitPolicyMapping1P1CACRL",
       "inhibitPolicyMapping1P1subCACRL", "inhibitPolicyMapping1P1subsubCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.11.9 Invalid Self-Issued inhibitPolicyMapping Test9
@@ -2053,7 +2414,11 @@
   const char* const crls[] = {
       "TrustAnchorRootCRL", "inhibitPolicyMapping1P1CACRL",
       "inhibitPolicyMapping1P1subCACRL", "inhibitPolicyMapping1P1subsubCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.11.10 Invalid Self-Issued inhibitPolicyMapping Test10
@@ -2068,7 +2433,11 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "inhibitPolicyMapping1P1CACRL",
                               "inhibitPolicyMapping1P1subCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.11.11 Invalid Self-Issued inhibitPolicyMapping Test11
@@ -2083,7 +2452,11 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "inhibitPolicyMapping1P1CACRL",
                               "inhibitPolicyMapping1P1subCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 WRAPPED_REGISTER_TYPED_TEST_CASE_P(
@@ -2111,7 +2484,11 @@
                                "inhibitAnyPolicy0CACert",
                                "InvalidinhibitAnyPolicyTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "inhibitAnyPolicy0CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.12.2 Valid inhibitAnyPolicy Test2
@@ -2121,10 +2498,13 @@
                                "inhibitAnyPolicy0CACert",
                                "ValidinhibitAnyPolicyTest2EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "inhibitAnyPolicy0CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
-// 4.12.3 inhibitAnyPolicy Test3
+// 4.12.3 inhibitAnyPolicy Test3 (Subpart 1)
 WRAPPED_TYPED_TEST_P(PkitsTest12InhibitAnyPolicy,
                      Section12inhibitAnyPolicyTest3Subpart1) {
   const char* const certs[] = {
@@ -2132,10 +2512,13 @@
       "inhibitAnyPolicy1subCA1Cert", "inhibitAnyPolicyTest3EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "inhibitAnyPolicy1CACRL",
                               "inhibitAnyPolicy1subCA1CRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
-// 4.12.3 inhibitAnyPolicy Test3
+// 4.12.3 inhibitAnyPolicy Test3 (Subpart 2)
 WRAPPED_TYPED_TEST_P(PkitsTest12InhibitAnyPolicy,
                      Section12inhibitAnyPolicyTest3Subpart2) {
   const char* const certs[] = {
@@ -2143,12 +2526,12 @@
       "inhibitAnyPolicy1subCA1Cert", "inhibitAnyPolicyTest3EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "inhibitAnyPolicy1CACRL",
                               "inhibitAnyPolicy1subCA1CRL"};
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetInitialInhibitAnyPolicy(true);
+  info.SetUserConstrainedPolicySet("");
 
-  // Custom settings
-  PkitsTestSettings settings;
-  settings.initial_inhibit_any_policy = true;
-
-  ASSERT_FALSE(this->Verify(certs, crls, settings));
+  this->RunTest(certs, crls, info);
 }
 
 // 4.12.4 Invalid inhibitAnyPolicy Test4
@@ -2159,7 +2542,11 @@
       "inhibitAnyPolicy1subCA1Cert", "InvalidinhibitAnyPolicyTest4EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "inhibitAnyPolicy1CACRL",
                               "inhibitAnyPolicy1subCA1CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.12.5 Invalid inhibitAnyPolicy Test5
@@ -2172,7 +2559,11 @@
   const char* const crls[] = {"TrustAnchorRootCRL", "inhibitAnyPolicy5CACRL",
                               "inhibitAnyPolicy5subCACRL",
                               "inhibitAnyPolicy5subsubCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.12.6 Invalid inhibitAnyPolicy Test6
@@ -2183,7 +2574,11 @@
       "inhibitAnyPolicy1subCAIAP5Cert", "InvalidinhibitAnyPolicyTest6EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "inhibitAnyPolicy1CACRL",
                               "inhibitAnyPolicy1subCAIAP5CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.12.7 Valid Self-Issued inhibitAnyPolicy Test7
@@ -2195,7 +2590,10 @@
       "ValidSelfIssuedinhibitAnyPolicyTest7EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "inhibitAnyPolicy1CACRL",
                               "inhibitAnyPolicy1subCA2CRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.12.8 Invalid Self-Issued inhibitAnyPolicy Test8
@@ -2210,7 +2608,11 @@
   const char* const crls[] = {"TrustAnchorRootCRL", "inhibitAnyPolicy1CACRL",
                               "inhibitAnyPolicy1subCA2CRL",
                               "inhibitAnyPolicy1subsubCA2CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.12.9 Valid Self-Issued inhibitAnyPolicy Test9
@@ -2224,7 +2626,10 @@
                                "ValidSelfIssuedinhibitAnyPolicyTest9EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "inhibitAnyPolicy1CACRL",
                               "inhibitAnyPolicy1subCA2CRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.12.10 Invalid Self-Issued inhibitAnyPolicy Test10
@@ -2236,7 +2641,11 @@
       "InvalidSelfIssuedinhibitAnyPolicyTest10EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "inhibitAnyPolicy1CACRL",
                               "inhibitAnyPolicy1subCA2CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
+
+  this->RunTest(certs, crls, info);
 }
 
 WRAPPED_REGISTER_TYPED_TEST_CASE_P(
@@ -2264,7 +2673,10 @@
                                "nameConstraintsDN1CACert",
                                "ValidDNnameConstraintsTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN1CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.2 Invalid DN nameConstraints Test2
@@ -2274,7 +2686,10 @@
                                "nameConstraintsDN1CACert",
                                "InvalidDNnameConstraintsTest2EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN1CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.3 Invalid DN nameConstraints Test3
@@ -2284,7 +2699,10 @@
                                "nameConstraintsDN1CACert",
                                "InvalidDNnameConstraintsTest3EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN1CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.4 Valid DN nameConstraints Test4
@@ -2294,7 +2712,10 @@
                                "nameConstraintsDN1CACert",
                                "ValidDNnameConstraintsTest4EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN1CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.5 Valid DN nameConstraints Test5
@@ -2304,7 +2725,10 @@
                                "nameConstraintsDN2CACert",
                                "ValidDNnameConstraintsTest5EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN2CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.6 Valid DN nameConstraints Test6
@@ -2314,7 +2738,10 @@
                                "nameConstraintsDN3CACert",
                                "ValidDNnameConstraintsTest6EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN3CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.7 Invalid DN nameConstraints Test7
@@ -2324,7 +2751,10 @@
                                "nameConstraintsDN3CACert",
                                "InvalidDNnameConstraintsTest7EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN3CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.8 Invalid DN nameConstraints Test8
@@ -2334,7 +2764,10 @@
                                "nameConstraintsDN4CACert",
                                "InvalidDNnameConstraintsTest8EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN4CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.9 Invalid DN nameConstraints Test9
@@ -2344,7 +2777,10 @@
                                "nameConstraintsDN4CACert",
                                "InvalidDNnameConstraintsTest9EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN4CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.10 Invalid DN nameConstraints Test10
@@ -2354,7 +2790,10 @@
                                "nameConstraintsDN5CACert",
                                "InvalidDNnameConstraintsTest10EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN5CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.11 Valid DN nameConstraints Test11
@@ -2364,7 +2803,10 @@
                                "nameConstraintsDN5CACert",
                                "ValidDNnameConstraintsTest11EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN5CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.12 Invalid DN nameConstraints Test12
@@ -2375,7 +2817,10 @@
       "nameConstraintsDN1subCA1Cert", "InvalidDNnameConstraintsTest12EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN1CACRL",
                               "nameConstraintsDN1subCA1CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.13 Invalid DN nameConstraints Test13
@@ -2386,7 +2831,10 @@
       "nameConstraintsDN1subCA2Cert", "InvalidDNnameConstraintsTest13EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN1CACRL",
                               "nameConstraintsDN1subCA2CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.14 Valid DN nameConstraints Test14
@@ -2397,7 +2845,10 @@
       "nameConstraintsDN1subCA2Cert", "ValidDNnameConstraintsTest14EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN1CACRL",
                               "nameConstraintsDN1subCA2CRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.15 Invalid DN nameConstraints Test15
@@ -2408,7 +2859,10 @@
       "nameConstraintsDN3subCA1Cert", "InvalidDNnameConstraintsTest15EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN3CACRL",
                               "nameConstraintsDN3subCA1CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.16 Invalid DN nameConstraints Test16
@@ -2419,7 +2873,10 @@
       "nameConstraintsDN3subCA1Cert", "InvalidDNnameConstraintsTest16EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN3CACRL",
                               "nameConstraintsDN3subCA1CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.17 Invalid DN nameConstraints Test17
@@ -2430,7 +2887,10 @@
       "nameConstraintsDN3subCA2Cert", "InvalidDNnameConstraintsTest17EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN3CACRL",
                               "nameConstraintsDN3subCA2CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.18 Valid DN nameConstraints Test18
@@ -2441,7 +2901,10 @@
       "nameConstraintsDN3subCA2Cert", "ValidDNnameConstraintsTest18EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN3CACRL",
                               "nameConstraintsDN3subCA2CRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.19 Valid Self-Issued DN nameConstraints Test19
@@ -2451,7 +2914,10 @@
       "TrustAnchorRootCertificate", "nameConstraintsDN1CACert",
       "nameConstraintsDN1SelfIssuedCACert", "ValidDNnameConstraintsTest19EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN1CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.20 Invalid Self-Issued DN nameConstraints Test20
@@ -2461,7 +2927,10 @@
                                "nameConstraintsDN1CACert",
                                "InvalidDNnameConstraintsTest20EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN1CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.21 Valid RFC822 nameConstraints Test21
@@ -2472,7 +2941,10 @@
                                "ValidRFC822nameConstraintsTest21EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "nameConstraintsRFC822CA1CRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.22 Invalid RFC822 nameConstraints Test22
@@ -2483,7 +2955,10 @@
                                "InvalidRFC822nameConstraintsTest22EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "nameConstraintsRFC822CA1CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.23 Valid RFC822 nameConstraints Test23
@@ -2494,7 +2969,10 @@
                                "ValidRFC822nameConstraintsTest23EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "nameConstraintsRFC822CA2CRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.24 Invalid RFC822 nameConstraints Test24
@@ -2505,7 +2983,10 @@
                                "InvalidRFC822nameConstraintsTest24EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "nameConstraintsRFC822CA2CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.25 Valid RFC822 nameConstraints Test25
@@ -2516,7 +2997,10 @@
                                "ValidRFC822nameConstraintsTest25EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "nameConstraintsRFC822CA3CRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.26 Invalid RFC822 nameConstraints Test26
@@ -2527,7 +3011,10 @@
                                "InvalidRFC822nameConstraintsTest26EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "nameConstraintsRFC822CA3CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.27 Valid DN and RFC822 nameConstraints Test27
@@ -2539,7 +3026,10 @@
                                "ValidDNandRFC822nameConstraintsTest27EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN1CACRL",
                               "nameConstraintsDN1subCA3CRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.28 Invalid DN and RFC822 nameConstraints Test28
@@ -2551,7 +3041,10 @@
                                "InvalidDNandRFC822nameConstraintsTest28EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN1CACRL",
                               "nameConstraintsDN1subCA3CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.29 Invalid DN and RFC822 nameConstraints Test29
@@ -2563,7 +3056,10 @@
                                "InvalidDNandRFC822nameConstraintsTest29EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN1CACRL",
                               "nameConstraintsDN1subCA3CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.30 Valid DNS nameConstraints Test30
@@ -2573,7 +3069,10 @@
                                "nameConstraintsDNS1CACert",
                                "ValidDNSnameConstraintsTest30EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDNS1CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.31 Invalid DNS nameConstraints Test31
@@ -2583,7 +3082,10 @@
                                "nameConstraintsDNS1CACert",
                                "InvalidDNSnameConstraintsTest31EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDNS1CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.32 Valid DNS nameConstraints Test32
@@ -2593,7 +3095,10 @@
                                "nameConstraintsDNS2CACert",
                                "ValidDNSnameConstraintsTest32EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDNS2CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.33 Invalid DNS nameConstraints Test33
@@ -2603,7 +3108,10 @@
                                "nameConstraintsDNS2CACert",
                                "InvalidDNSnameConstraintsTest33EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDNS2CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.34 Valid URI nameConstraints Test34
@@ -2613,7 +3121,10 @@
                                "nameConstraintsURI1CACert",
                                "ValidURInameConstraintsTest34EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsURI1CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.35 Invalid URI nameConstraints Test35
@@ -2623,7 +3134,10 @@
                                "nameConstraintsURI1CACert",
                                "InvalidURInameConstraintsTest35EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsURI1CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.36 Valid URI nameConstraints Test36
@@ -2633,7 +3147,10 @@
                                "nameConstraintsURI2CACert",
                                "ValidURInameConstraintsTest36EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsURI2CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.37 Invalid URI nameConstraints Test37
@@ -2643,7 +3160,10 @@
                                "nameConstraintsURI2CACert",
                                "InvalidURInameConstraintsTest37EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsURI2CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.13.38 Invalid DNS nameConstraints Test38
@@ -2653,7 +3173,10 @@
                                "nameConstraintsDNS1CACert",
                                "InvalidDNSnameConstraintsTest38EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDNS1CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 WRAPPED_REGISTER_TYPED_TEST_CASE_P(
@@ -2708,7 +3231,10 @@
                                "distributionPoint1CACert",
                                "ValiddistributionPointTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "distributionPoint1CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.2 Invalid distributionPoint Test2
@@ -2718,7 +3244,10 @@
                                "distributionPoint1CACert",
                                "InvaliddistributionPointTest2EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "distributionPoint1CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.3 Invalid distributionPoint Test3
@@ -2728,7 +3257,10 @@
                                "distributionPoint1CACert",
                                "InvaliddistributionPointTest3EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "distributionPoint1CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.4 Valid distributionPoint Test4
@@ -2738,7 +3270,10 @@
                                "distributionPoint1CACert",
                                "ValiddistributionPointTest4EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "distributionPoint1CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.5 Valid distributionPoint Test5
@@ -2748,7 +3283,10 @@
                                "distributionPoint2CACert",
                                "ValiddistributionPointTest5EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "distributionPoint2CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.6 Invalid distributionPoint Test6
@@ -2758,7 +3296,10 @@
                                "distributionPoint2CACert",
                                "InvaliddistributionPointTest6EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "distributionPoint2CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.7 Valid distributionPoint Test7
@@ -2768,7 +3309,10 @@
                                "distributionPoint2CACert",
                                "ValiddistributionPointTest7EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "distributionPoint2CACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.8 Invalid distributionPoint Test8
@@ -2778,7 +3322,10 @@
                                "distributionPoint2CACert",
                                "InvaliddistributionPointTest8EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "distributionPoint2CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.9 Invalid distributionPoint Test9
@@ -2788,7 +3335,10 @@
                                "distributionPoint2CACert",
                                "InvaliddistributionPointTest9EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "distributionPoint2CACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.10 Valid No issuingDistributionPoint Test10
@@ -2799,7 +3349,10 @@
                                "ValidNoissuingDistributionPointTest10EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "NoissuingDistributionPointCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.11 Invalid onlyContainsUserCerts CRL Test11
@@ -2810,7 +3363,10 @@
                                "InvalidonlyContainsUserCertsTest11EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "onlyContainsUserCertsCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.12 Invalid onlyContainsCACerts CRL Test12
@@ -2820,7 +3376,10 @@
                                "onlyContainsCACertsCACert",
                                "InvalidonlyContainsCACertsTest12EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "onlyContainsCACertsCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.13 Valid onlyContainsCACerts CRL Test13
@@ -2830,7 +3389,10 @@
                                "onlyContainsCACertsCACert",
                                "ValidonlyContainsCACertsTest13EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "onlyContainsCACertsCACRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.14 Invalid onlyContainsAttributeCerts Test14
@@ -2841,7 +3403,10 @@
                                "InvalidonlyContainsAttributeCertsTest14EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "onlyContainsAttributeCertsCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.15 Invalid onlySomeReasons Test15
@@ -2853,7 +3418,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "onlySomeReasonsCA1compromiseCRL",
                               "onlySomeReasonsCA1otherreasonsCRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.16 Invalid onlySomeReasons Test16
@@ -2865,7 +3433,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "onlySomeReasonsCA1compromiseCRL",
                               "onlySomeReasonsCA1otherreasonsCRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.17 Invalid onlySomeReasons Test17
@@ -2876,7 +3447,10 @@
                                "InvalidonlySomeReasonsTest17EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "onlySomeReasonsCA2CRL1",
                               "onlySomeReasonsCA2CRL2"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.18 Valid onlySomeReasons Test18
@@ -2888,7 +3462,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "onlySomeReasonsCA3compromiseCRL",
                               "onlySomeReasonsCA3otherreasonsCRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.19 Valid onlySomeReasons Test19
@@ -2900,7 +3477,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "onlySomeReasonsCA4compromiseCRL",
                               "onlySomeReasonsCA4otherreasonsCRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.20 Invalid onlySomeReasons Test20
@@ -2912,7 +3492,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "onlySomeReasonsCA4compromiseCRL",
                               "onlySomeReasonsCA4otherreasonsCRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.21 Invalid onlySomeReasons Test21
@@ -2924,7 +3507,10 @@
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "onlySomeReasonsCA4compromiseCRL",
                               "onlySomeReasonsCA4otherreasonsCRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.22 Valid IDP with indirectCRL Test22
@@ -2934,7 +3520,10 @@
                                "indirectCRLCA1Cert",
                                "ValidIDPwithindirectCRLTest22EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "indirectCRLCA1CRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.23 Invalid IDP with indirectCRL Test23
@@ -2944,7 +3533,10 @@
                                "indirectCRLCA1Cert",
                                "InvalidIDPwithindirectCRLTest23EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "indirectCRLCA1CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.24 Valid IDP with indirectCRL Test24
@@ -2954,7 +3546,10 @@
                                "indirectCRLCA2Cert", "indirectCRLCA1Cert",
                                "ValidIDPwithindirectCRLTest24EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "indirectCRLCA1CRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.25 Valid IDP with indirectCRL Test25
@@ -2964,7 +3559,10 @@
                                "indirectCRLCA2Cert", "indirectCRLCA1Cert",
                                "ValidIDPwithindirectCRLTest25EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "indirectCRLCA1CRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.26 Invalid IDP with indirectCRL Test26
@@ -2974,7 +3572,10 @@
                                "indirectCRLCA2Cert", "indirectCRLCA1Cert",
                                "InvalidIDPwithindirectCRLTest26EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "indirectCRLCA1CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.27 Invalid cRLIssuer Test27
@@ -2984,7 +3585,10 @@
                                "indirectCRLCA2Cert", "GoodCACert",
                                "InvalidcRLIssuerTest27EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "GoodCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.28 Valid cRLIssuer Test28
@@ -2995,7 +3599,10 @@
       "indirectCRLCA3cRLIssuerCert", "ValidcRLIssuerTest28EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "indirectCRLCA3CRL",
                               "indirectCRLCA3cRLIssuerCRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.29 Valid cRLIssuer Test29
@@ -3006,7 +3613,10 @@
       "indirectCRLCA3cRLIssuerCert", "ValidcRLIssuerTest29EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "indirectCRLCA3CRL",
                               "indirectCRLCA3cRLIssuerCRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.30 Valid cRLIssuer Test30
@@ -3017,7 +3627,10 @@
       "indirectCRLCA4cRLIssuerCert", "ValidcRLIssuerTest30EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "indirectCRLCA4cRLIssuerCRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.31 Invalid cRLIssuer Test31
@@ -3027,7 +3640,10 @@
                                "indirectCRLCA5Cert", "indirectCRLCA6Cert",
                                "InvalidcRLIssuerTest31EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "indirectCRLCA5CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.32 Invalid cRLIssuer Test32
@@ -3037,7 +3653,10 @@
                                "indirectCRLCA5Cert", "indirectCRLCA6Cert",
                                "InvalidcRLIssuerTest32EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "indirectCRLCA5CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.33 Valid cRLIssuer Test33
@@ -3047,7 +3666,10 @@
                                "indirectCRLCA5Cert", "indirectCRLCA6Cert",
                                "ValidcRLIssuerTest33EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "indirectCRLCA5CRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.34 Invalid cRLIssuer Test34
@@ -3057,7 +3679,10 @@
                                "indirectCRLCA5Cert",
                                "InvalidcRLIssuerTest34EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "indirectCRLCA5CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.14.35 Invalid cRLIssuer Test35
@@ -3067,7 +3692,10 @@
                                "indirectCRLCA5Cert",
                                "InvalidcRLIssuerTest35EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "indirectCRLCA5CRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 WRAPPED_REGISTER_TYPED_TEST_CASE_P(
@@ -3120,7 +3748,10 @@
                                "InvaliddeltaCRLIndicatorNoBaseTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL",
                               "deltaCRLIndicatorNoBaseCACRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.15.2 Valid delta-CRL Test2
@@ -3129,7 +3760,10 @@
                                "ValiddeltaCRLTest2EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "deltaCRLCA1CRL",
                               "deltaCRLCA1deltaCRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.15.3 Invalid delta-CRL Test3
@@ -3138,7 +3772,10 @@
                                "InvaliddeltaCRLTest3EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "deltaCRLCA1CRL",
                               "deltaCRLCA1deltaCRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.15.4 Invalid delta-CRL Test4
@@ -3147,7 +3784,10 @@
                                "InvaliddeltaCRLTest4EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "deltaCRLCA1CRL",
                               "deltaCRLCA1deltaCRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.15.5 Valid delta-CRL Test5
@@ -3156,7 +3796,10 @@
                                "ValiddeltaCRLTest5EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "deltaCRLCA1CRL",
                               "deltaCRLCA1deltaCRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.15.6 Invalid delta-CRL Test6
@@ -3165,7 +3808,10 @@
                                "InvaliddeltaCRLTest6EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "deltaCRLCA1CRL",
                               "deltaCRLCA1deltaCRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.15.7 Valid delta-CRL Test7
@@ -3174,7 +3820,10 @@
                                "ValiddeltaCRLTest7EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "deltaCRLCA1CRL",
                               "deltaCRLCA1deltaCRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.15.8 Valid delta-CRL Test8
@@ -3183,7 +3832,10 @@
                                "ValiddeltaCRLTest8EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "deltaCRLCA2CRL",
                               "deltaCRLCA2deltaCRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.15.9 Invalid delta-CRL Test9
@@ -3192,7 +3844,10 @@
                                "InvaliddeltaCRLTest9EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "deltaCRLCA2CRL",
                               "deltaCRLCA2deltaCRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.15.10 Invalid delta-CRL Test10
@@ -3201,7 +3856,10 @@
                                "InvaliddeltaCRLTest10EE"};
   const char* const crls[] = {"TrustAnchorRootCRL", "deltaCRLCA3CRL",
                               "deltaCRLCA3deltaCRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 WRAPPED_REGISTER_TYPED_TEST_CASE_P(PkitsTest15DeltaCRLs,
@@ -3229,7 +3887,10 @@
       "TrustAnchorRootCertificate",
       "ValidUnknownNotCriticalCertificateExtensionTest1EE"};
   const char* const crls[] = {"TrustAnchorRootCRL"};
-  ASSERT_TRUE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = true;
+
+  this->RunTest(certs, crls, info);
 }
 
 // 4.16.2 Invalid Unknown Critical Certificate Extension Test2
@@ -3239,7 +3900,10 @@
       "TrustAnchorRootCertificate",
       "InvalidUnknownCriticalCertificateExtensionTest2EE"};
   const char* const crls[] = {"TrustAnchorRootCRL"};
-  ASSERT_FALSE(this->Verify(certs, crls, {}));
+  PkitsTestInfo info;
+  info.should_validate = false;
+
+  this->RunTest(certs, crls, info);
 }
 
 WRAPPED_REGISTER_TYPED_TEST_CASE_P(
diff --git a/services/ui/public/interfaces/window_manager.mojom b/services/ui/public/interfaces/window_manager.mojom
index 563697d..3ddbe2c 100644
--- a/services/ui/public/interfaces/window_manager.mojom
+++ b/services/ui/public/interfaces/window_manager.mojom
@@ -44,6 +44,9 @@
   // Whether the window should be initially focusable or not. Type: bool.
   const string kFocusable_InitProperty = "init:focusable";
 
+  // Whether the window should be opaque.
+  const string kTranslucent_InitProperty = "init:translucent";
+
   // Initial bounds to create the window at. If empty the WindowManager decides
   // the initial bounds. Type: gfx::Rect.
   const string kBounds_InitProperty = "init:bounds";
diff --git a/storage/public/interfaces/BUILD.gn b/storage/public/interfaces/BUILD.gn
new file mode 100644
index 0000000..18a0f430
--- /dev/null
+++ b/storage/public/interfaces/BUILD.gn
@@ -0,0 +1,20 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+  sources = [
+    "blobs.mojom",
+  ]
+
+  public_deps = [
+    "//mojo/common:common_custom_types",
+    "//url/mojo:url_mojom_gurl",
+  ]
+
+  export_class_attribute_blink = "BLINK_PLATFORM_EXPORT"
+  export_define_blink = "BLINK_PLATFORM_IMPLEMENTATION=1"
+  export_header_blink = "third_party/WebKit/public/platform/WebCommon.h"
+}
diff --git a/storage/public/interfaces/OWNERS b/storage/public/interfaces/OWNERS
new file mode 100644
index 0000000..08850f4
--- /dev/null
+++ b/storage/public/interfaces/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/storage/public/interfaces/blobs.mojom b/storage/public/interfaces/blobs.mojom
new file mode 100644
index 0000000..0d4bb62
--- /dev/null
+++ b/storage/public/interfaces/blobs.mojom
@@ -0,0 +1,107 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module storage.mojom;
+
+import "mojo/common/file.mojom";
+import "mojo/common/time.mojom";
+import "url/mojo/url.mojom";
+
+// This interface provides access to a blob in the blob system.
+interface Blob {
+  // Creates a copy of this Blob reference.
+  Clone(Blob& blob);
+
+  // This method is an implementation detail of the blob system. You should not
+  // ever need to call it directly.
+  // This returns the internal UUID of the blob, used by the blob system to
+  // identify the blob.
+  GetInternalUUID() => (string uuid);
+};
+
+// This interface is the primary access point to the blob system. This interface
+// provides methods to register new blobs and get references to existing blobs.
+interface BlobRegistry {
+  // Registers a new blob with the blob registry.
+  // TODO(mek): Make this method non-sync and get rid of the UUID parameter once
+  // enough of the rest of the system doesn't rely on the UUID anymore.
+  [Sync] Register(Blob& blob, string uuid,
+                  string content_type, string content_disposition,
+                  array<DataElement> elements) => ();
+
+  // Returns a reference to an existing blob. Should not be used by new code,
+  // is only exposed to make converting existing blob using code easier.
+  GetBlobFromUUID(Blob& blob, string uuid);
+};
+
+// A blob is built up of elements of various types.
+union DataElement {
+  // Bytes send asynchronously at the request of the blob registry.
+  DataElementBytes bytes;
+  // A reference to a file on disk.
+  DataElementFile file;
+  // A reference to a file as a filesystem URL.
+  DataElementFilesystemURL file_filesystem;
+  // A reference to another blob.
+  DataElementBlob blob;
+};
+
+// Bytes send asynchronously at the request of the blob registry. Can
+// optionally also directly contain the data, in which case the blob registry
+// can decide to either use the embedded data or later request the data again.
+struct DataElementBytes {
+  // Size of the data.
+  uint64 length;
+  // Optionally embedded data. If present, the size of this array should be
+  // equal to |length|.
+  array<uint8>? embedded_data;
+  // Interface through which the blob registry can request the data.
+  BytesProvider data;
+};
+
+// Interface through which the blob registry can request data when it is ready
+// for it.
+interface BytesProvider {
+  // TODO(mek): Define methods.
+};
+
+// A reference to a slice of a file on disk.
+struct DataElementFile {
+  // Path of the file.
+  string path;
+  // Offset inside the file.
+  uint64 offset;
+  // Length of the slice. Can be uint64_max if the length is unknown. If this is
+  // the case the offset is always 0 and this DataElement should be the only
+  // element making up the blob.
+  uint64 length;
+  // Expected modification time of the file being referenced. Can be null if the
+  // modification time is unknown.
+  mojo.common.mojom.Time? expected_modification_time;
+};
+
+// A reference to a slice of a file as a filesystem URL.
+struct DataElementFilesystemURL {
+  // URL of the file.
+  url.mojom.Url url;
+  // Offset inside the file.
+  uint64 offset;
+  // Length of the slice. Can be uint64_max if the length is unknown. If this is
+  // the case the offset is always 0 and this DataElement should be the only
+  // element making up the blob.
+  uint64 length;
+  // Expected modification time of the file being referenced. Can be null if the
+  // modification time is unknown.
+  mojo.common.mojom.Time? expected_modification_time;
+};
+
+// A reference to a slice of another blob.
+struct DataElementBlob {
+  // The blob being referenced.
+  Blob blob;
+  // Offset to the beginning of the slice.
+  uint64 offset;
+  // Length of the slice.
+  uint64 length;
+};
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
index 7b016cc..a25a05a0 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -107,6 +107,7 @@
 
 Bug(none) paint/transparency/compositing-alpha-fold-crash.html [ Failure ]
 Bug(none) paint/invalidation/table/row-change-background-rowspan-cell.html [ Failure ]
+Bug(none) paint/invalidation/clip-flex-text.html [ Failure ]
 Bug(none) virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering.html [ Failure ]
 Bug(none) virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering.html [ Failure ]
 Bug(none) paint/invalidation/compositing/newly-composited-repaint-rect.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests
index 26c0f085..c3d008a 100644
--- a/third_party/WebKit/LayoutTests/NeverFixTests
+++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -750,6 +750,8 @@
 external/wpt/css/css-writing-modes-3/page-flow-direction-003.xht [ WontFix ]
 external/wpt/css/css-writing-modes-3/page-flow-direction-slr-005.xht [ WontFix ]
 external/wpt/css/css-writing-modes-3/page-flow-direction-srl-004.xht [ WontFix ]
+external/wpt/2dcontext/drawing-paths-to-the-canvas/canvas_focus_drawFocusIfNeeded_AAPI_001-manual.html [ WontFix ]
+external/wpt/html/semantics/embedded-content/the-img-element/ismap/img-ismap-coordinates-manual.html [ WontFix ]
 
 # These directories have manual tests that don't have to run with
 # run-webkit-tests; see https://crbug.com/359838.
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index f08c741..d21de14 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2133,16 +2133,14 @@
 
 # ====== New tests from wpt-importer added here ======
 crbug.com/626703 external/wpt/scroll-into-view/check-scroll-position.html [ Timeout ]
-crbug.com/626703 [ Android Linux Mac Retina Win ] external/wpt/2dcontext/building-paths/canvas_complexshapes_arcto_001.htm [ Failure ]
-crbug.com/626703 [ Android Linux Mac Retina Win ] external/wpt/2dcontext/building-paths/canvas_complexshapes_beziercurveto_001.htm [ Failure ]
-crbug.com/626703 [ Android Linux Mac Retina Win ] external/wpt/2dcontext/drawing-images-to-the-canvas/drawimage_canvas_11.html [ Failure ]
-crbug.com/626703 [ Android Linux Mac Retina Win ] external/wpt/2dcontext/drawing-images-to-the-canvas/drawimage_canvas_12.html [ Failure ]
-crbug.com/626703 [ Android Linux Win ] external/wpt/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_11.html [ Failure ]
-crbug.com/626703 [ Android Linux Mac Retina Win ] external/wpt/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_12.html [ Failure ]
-crbug.com/626703 [ Android Linux Mac Retina Win ] external/wpt/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_13.html [ Failure ]
-crbug.com/626703 [ Android Linux Mac Retina Win ] external/wpt/2dcontext/drawing-paths-to-the-canvas/canvas_focus_drawFocusIfNeeded_AAPI_001-manual.html [ Skip ]
-crbug.com/626703 [ Android Mac Retina ] external/wpt/2dcontext/the-canvas-state/canvas_state_restore_001.htm [ Failure ]
-crbug.com/626703 [ Android Linux Mac Retina Win ] external/wpt/html/semantics/embedded-content/the-img-element/ismap/img-ismap-coordinates-manual.html [ Skip ]
+crbug.com/626703 external/wpt/2dcontext/building-paths/canvas_complexshapes_arcto_001.htm [ Failure ]
+crbug.com/626703 external/wpt/2dcontext/building-paths/canvas_complexshapes_beziercurveto_001.htm [ Failure ]
+crbug.com/626703 external/wpt/2dcontext/drawing-images-to-the-canvas/drawimage_canvas_11.html [ Failure ]
+crbug.com/626703 external/wpt/2dcontext/drawing-images-to-the-canvas/drawimage_canvas_12.html [ Failure ]
+crbug.com/626703 [ Linux Win ] external/wpt/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_11.html [ Failure ]
+crbug.com/626703 external/wpt/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_12.html [ Failure ]
+crbug.com/626703 external/wpt/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_13.html [ Failure ]
+crbug.com/626703 [ Mac ] external/wpt/2dcontext/the-canvas-state/canvas_state_restore_001.htm [ Failure ]
 crbug.com/626703 [ Win ] external/wpt/css/css-writing-modes-3/box-offsets-rel-pos-vlr-005.xht [ Failure ]
 crbug.com/626703 [ Win ] external/wpt/css/css-writing-modes-3/box-offsets-rel-pos-vrl-004.xht [ Failure ]
 crbug.com/626703 [ Mac ] external/wpt/WebCryptoAPI/generateKey/test_successes_RSA-OAEP.https.html [ Timeout ]
@@ -2606,8 +2604,8 @@
 
 crbug.com/697971 [ Mac10.12 ] fast/text/flexbox-selection-nested.html [ Skip ]
 crbug.com/697971 [ Mac10.12 ] fast/text/flexbox-selection.html [ Skip ]
-crbug.com/697971 [ Mac10.12 ] http/tests/inspector/appcache/appcache-manifest-with-non-existing-file.html [ Timeout ]
-crbug.com/697971 [ Mac10.12 ] virtual/mojo-loading/http/tests/inspector/appcache/appcache-iframe-manifests.html [ Timeout ]
+crbug.com/678481 http/tests/inspector/appcache/appcache-manifest-with-non-existing-file.html [ Timeout ]
+crbug.com/678481 virtual/mojo-loading/http/tests/inspector/appcache/appcache-iframe-manifests.html [ Timeout ]
 
 crbug.com/701047 [ Mac10.12 ] editing/caret/caret-color.html [ Failure ]
 crbug.com/701047 [ Mac10.12 ] editing/deleting/delete-at-paragraph-boundaries-011.html [ Failure ]
@@ -2996,9 +2994,9 @@
 crbug.com/727014 [ Linux ] external/wpt/IndexedDB/large-nested-cloning.html [ Pass Timeout ]
 crbug.com/727252 [ Win7 ] external/wpt/media-source/mediasource-endofstream.html [ Pass Timeout ]
 
-# Sheriff failures 2017-05-30
-# Failing on try (with patch) and Linux FYI too frequently.
-crbug.com/727505 [ Linux ] virtual/threaded/fast/compositorworker/basic-plumbing-main-to-worker.html [ Pass Crash ]
-
-# Sheriff failures 2017-05-31
-crbug.com/727991 [ Linux Mac ] virtual/threaded/fast/compositorworker/visual-update.html [ Pass Failure ]
+# Compositor worker tests are flaky, crashing and timing out
+crbug.com/727991 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/visual-update.html [ Pass Failure Timeout Crash ]
+crbug.com/728036 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/compositor-proxy-supports.html [ Pass Failure Timeout Crash ]
+crbug.com/727505 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/basic-plumbing-main-to-worker.html [ Pass Failure Timeout Crash ]
+crbug.com/727505 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/basic-plumbing-worker-to-main.html [ Pass Failure Timeout Crash ]
+crbug.com/727505 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/request-animation-frame.html [ Pass Failure Timeout Crash ]
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/resources/style-matching-test.js b/third_party/WebKit/LayoutTests/css3/fonts/resources/style-matching-test.js
index c5f964ba..58a883fd 100644
--- a/third_party/WebKit/LayoutTests/css3/fonts/resources/style-matching-test.js
+++ b/third_party/WebKit/LayoutTests/css3/fonts/resources/style-matching-test.js
@@ -183,22 +183,14 @@
         }
     }
 
-    function platformFontsForElementWithSelector(selector)
+    async function platformFontsForElementWithSelector(selector)
     {
-        InspectorTest.requestNodeId(documentNodeId, selector, onNodeId);
-
-        function onNodeId(nodeId)
-        {
-            InspectorTest.sendCommandOrDie("CSS.getPlatformFontsForNode",
-                                           { nodeId: nodeId },
-                                           onGotComputedFonts);
-        }
-
-        function onGotComputedFonts(response)
-        {
-            logResults(response);
-            nextTest();
-        }
+        var nodeId = await InspectorTest.requestNodeId(documentNodeId, selector);
+        await InspectorTest.sendCommandOrDie("CSS.enable", {});
+        var response = await InspectorTest.sendCommandOrDie("CSS.getPlatformFontsForNode",
+                                                            { nodeId: nodeId });
+        logResults(response);
+        nextTest();
     }
 
     function logResults(response)
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/resetting-a-form/reset-form-2-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/resetting-a-form/reset-form-2-expected.txt
deleted file mode 100644
index ceeedca..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/resetting-a-form/reset-form-2-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL integration test on reset for a created-from-script form assert_equals: option should reset dirtyness to false expected false but got true
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/dom-protocol-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/dom-protocol-test.js
index e8ee26a..1be873c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/dom-protocol-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/dom-protocol-test.js
@@ -3,48 +3,44 @@
 
 InspectorTest.trackGetChildNodesEvents = function(nodeInfo, callback)
 {
-    InspectorTest.eventHandler["DOM.setChildNodes"] = setChildNodes;
+  InspectorTest.eventHandler["DOM.setChildNodes"] = setChildNodes;
 
-    function setChildNodes(message)
-    {
-        var nodes = message.params.nodes;
-        for (var i = 0; i < nodes.length; ++i)
-            InspectorTest.addNode(nodeInfo, nodes[i]);
-        if (callback)
-            callback();
-    }
+  function setChildNodes(message)
+  {
+      var nodes = message.params.nodes;
+      for (var i = 0; i < nodes.length; ++i)
+        InspectorTest.addNode(nodeInfo, nodes[i]);
+      if (callback)
+        callback();
+  }
 }
 
 InspectorTest.addNode = function(nodeInfo, node)
 {
-    nodeInfo[node.nodeId] = node;
-    delete node.nodeId;
-    var children = node.children || [];
-    for (var i = 0; i < children.length; ++i)
-        InspectorTest.addNode(nodeInfo, children[i]);
-    var shadowRoots = node.shadowRoots || [];
-    for (var i = 0; i < shadowRoots.length; ++i)
-        InspectorTest.addNode(nodeInfo, shadowRoots[i]);
+  nodeInfo[node.nodeId] = node;
+  delete node.nodeId;
+  var children = node.children || [];
+  for (var i = 0; i < children.length; ++i)
+    InspectorTest.addNode(nodeInfo, children[i]);
+  var shadowRoots = node.shadowRoots || [];
+  for (var i = 0; i < shadowRoots.length; ++i)
+    InspectorTest.addNode(nodeInfo, shadowRoots[i]);
 }
 
-InspectorTest.requestDocumentNodeId = function(callback)
+InspectorTest.requestDocumentNodeId = async function(callback)
 {
-    InspectorTest.sendCommandOrDie("DOM.getDocument", {}, onGotDocument);
-
-    function onGotDocument(result)
-    {
-        callback(result.root.nodeId);
-    }
+    var result = await InspectorTest.sendCommandOrDie("DOM.getDocument", {});
+    if (callback)
+      callback(result.root.nodeId);
+    return result.root.nodeId;
 };
 
-InspectorTest.requestNodeId = function(documentNodeId, selector, callback)
+InspectorTest.requestNodeId = async function(documentNodeId, selector, callback)
 {
-    InspectorTest.sendCommandOrDie("DOM.querySelector", { "nodeId": documentNodeId , "selector": selector }, onGotNode);
-
-    function onGotNode(result)
-    {
-        callback(result.nodeId);
-    }
+    var result = await InspectorTest.sendCommandOrDie("DOM.querySelector", { "nodeId": documentNodeId , "selector": selector });
+    if (callback)
+      callback(result.nodeId);
+    return result.nodeId;
 };
 
 }
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/protocol-test.html b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/protocol-test.html
index 510b441..1f3ce3c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/protocol-test.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/protocol-test.html
@@ -62,6 +62,9 @@
 
 InspectorTest.sendCommandOrDie = function(command, properties, callback)
 {
+    var fulfill;
+    var result = new Promise(f => fulfill = f);
+
     InspectorTest.sendCommand(command, properties || {}, commandCallback);
     function commandCallback(msg)
     {
@@ -72,7 +75,9 @@
         }
         if (callback)
             callback(msg.result);
+        fulfill(msg.result);
     }
+    return result;
 }
 
 InspectorTest.sendCommandPromise = function(method, params)
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/css/css-get-platform-fonts.html b/third_party/WebKit/LayoutTests/inspector-protocol/css/css-get-platform-fonts.html
index 616c5941..bc8d880 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/css/css-get-platform-fonts.html
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/css/css-get-platform-fonts.html
@@ -28,20 +28,13 @@
     }
 
 
-    function platformFontsForElementWithSelector(selector, callback)
+    async function platformFontsForElementWithSelector(selector, callback)
     {
-        InspectorTest.requestNodeId(documentNodeId, selector, onNodeId);
-
-        function onNodeId(nodeId)
-        {
-            InspectorTest.sendCommandOrDie("CSS.getPlatformFontsForNode", { nodeId: nodeId }, onGotComputedFonts);
-        }
-
-        function onGotComputedFonts(response)
-        {
-            dumpComputedFonts(response);
-            callback();
-        }
+        var nodeId = await InspectorTest.requestNodeId(documentNodeId, selector);
+        await InspectorTest.sendCommandOrDie("CSS.enable", {  });
+        var response = await InspectorTest.sendCommandOrDie("CSS.getPlatformFontsForNode", { nodeId: nodeId });
+        dumpComputedFonts(response);
+        callback();
     }
 
     function dumpComputedFonts(response)
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/css/css-set-inline-styleSheetText.html b/third_party/WebKit/LayoutTests/inspector-protocol/css/css-set-inline-styleSheetText.html
index 44e8920..9667efb 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/css/css-set-inline-styleSheetText.html
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/css/css-set-inline-styleSheetText.html
@@ -9,47 +9,29 @@
 
     InspectorTest.sendCommand("CSS.enable", {}, cssWasEnabled);
 
-    function cssWasEnabled()
+    async function cssWasEnabled()
     {
-        InspectorTest.sendCommandOrDie("DOM.getDocument", {}, onGotDocument);
-    }
-
-    function onGotDocument(result)
-    {
+        var result = await InspectorTest.sendCommandOrDie("DOM.getDocument", {});
         var root = result.root;
-        InspectorTest.sendCommandOrDie("DOM.querySelector", {
+        var node = await InspectorTest.sendCommandOrDie("DOM.querySelector", {
             nodeId: root.nodeId,
             selector: "#inliner"
-        }, onGotNode);
-    }
+        });
 
-    function onGotNode(node)
-    {
-        InspectorTest.sendCommandOrDie("CSS.getInlineStylesForNode", { nodeId: node.nodeId }, onGotInlineStyles);
-    }
+        await InspectorTest.sendCommandOrDie("CSS.enable", {  });
 
-    function onGotInlineStyles(result)
-    {
+        result = await InspectorTest.sendCommandOrDie("CSS.getInlineStylesForNode", { nodeId: node.nodeId });
         inlineStyleSheetId = result.inlineStyle.styleSheetId;
-        InspectorTest.sendCommandOrDie("CSS.getStyleSheetText", { styleSheetId: inlineStyleSheetId }, onReceiveStyleSheetText);
-    }
 
-    function onReceiveStyleSheetText(result)
-    {
+        result = await InspectorTest.sendCommandOrDie("CSS.getStyleSheetText", { styleSheetId: inlineStyleSheetId });
         InspectorTest.log(result.text);
-        InspectorTest.sendCommandOrDie("CSS.setStyleSheetText", {
+
+        result = await InspectorTest.sendCommandOrDie("CSS.setStyleSheetText", {
             styleSheetId: inlineStyleSheetId,
             text: "border: 1px solid black;"
-        }, onSetStyleSheetBody);
-    }
+        });
 
-    function onSetStyleSheetBody(result)
-    {
-        InspectorTest.sendCommandOrDie("CSS.getStyleSheetText", { styleSheetId: inlineStyleSheetId }, onCheckStyleSheetBody);
-    }
-
-    function onCheckStyleSheetBody(result)
-    {
+        result = await InspectorTest.sendCommandOrDie("CSS.getStyleSheetText", { styleSheetId: inlineStyleSheetId });
         InspectorTest.log(result.text);
         InspectorTest.completeTest();
     }
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/css/pseudo-element-matching-selectors.html b/third_party/WebKit/LayoutTests/inspector-protocol/css/pseudo-element-matching-selectors.html
index 980b0285..b658c98 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/css/pseudo-element-matching-selectors.html
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/css/pseudo-element-matching-selectors.html
@@ -8,61 +8,37 @@
     document.getElementById("style").textContent = "#for-pseudo:before { content: \"BEFORE\" }";
 }
 
-function test()
+async function test()
 {
     var nodeInfo = {};
     var childrenCallback;
 
     InspectorTest.eventHandler["DOM.setChildNodes"] = setChildNodes;
-    getDocument();
+    await InspectorTest.sendCommandOrDie("DOM.enable", {});
+    await InspectorTest.sendCommandOrDie("CSS.enable", {});
 
-    function getDocument()
-    {
-        step({
-            name: "Get the Document",
-            command: "DOM.getDocument",
-            parameters: {},
-            callback: getImmediateChildren
-        });
-    };
+    InspectorTest.log("\n=== Get the Document ===\n");
+    var result = await InspectorTest.sendCommandOrDie("DOM.getDocument", {});
+    var bodyId = result.root.children[0].children[1].nodeId;
 
-    function getImmediateChildren(result)
-    {
-        var bodyId = result.root.children[0].children[1].nodeId;
-        childrenCallback = onChildrenRequested;
-        step({
-            name: "Get immediate children of the body",
-            command: "DOM.requestChildNodes",
-            parameters: {"nodeId": bodyId}
-        });
-    };
+    InspectorTest.log("\n=== Get immediate children of the body ===\n");
+    result = await InspectorTest.sendCommandOrDie("DOM.requestChildNodes", {"nodeId": bodyId});
+    var node = findNodeById("for-pseudo");
+    var beforeNode = node.pseudoElements[0];
 
-    function onChildrenRequested()
-    {
-        var node = findNodeById("for-pseudo");
-        var beforeNode = node.pseudoElements[0];
-        step({
-            name: "Request matching styles for #for-pseudo::before",
-            command: "CSS.getMatchedStylesForNode",
-            parameters: {nodeId: beforeNode.nodeId},
-            callback: stylesReceived
-        });
-    }
-
-    function stylesReceived(result)
-    {
-        var matchedRules = result.matchedCSSRules;
-        for (var i = 0; i < matchedRules.length; ++i) {
-            var match = matchedRules[i];
-            if (match.rule.selectorList.text === "#for-pseudo::before") {
-                InspectorTest.log("#for-pseudo::before matching the :before element: " + (match.matchingSelectors[0] === 0));
-                InspectorTest.completeTest();
-                return;
-            }
+    InspectorTest.log("\n=== Request matching styles for #for-pseudo::before ===\n");
+    result = await InspectorTest.sendCommandOrDie("CSS.getMatchedStylesForNode", {nodeId: beforeNode.nodeId});
+    var matchedRules = result.matchedCSSRules;
+    for (var i = 0; i < matchedRules.length; ++i) {
+        var match = matchedRules[i];
+        if (match.rule.selectorList.text === "#for-pseudo::before") {
+            InspectorTest.log("#for-pseudo::before matching the :before element: " + (match.matchingSelectors[0] === 0));
+            InspectorTest.completeTest();
+            return;
         }
-        InspectorTest.log("#for-pseudo::before rule not received");
-        InspectorTest.completeTest();
     }
+    InspectorTest.log("#for-pseudo::before rule not received");
+    InspectorTest.completeTest();
 
     function setChildNodes(message)
     {
@@ -75,18 +51,6 @@
             callback();
     }
 
-    function step(test)
-    {
-        InspectorTest.log("\n=== " + test.name + " ===\n");
-        InspectorTest.sendCommand(test.command, test.parameters, function(messageObject) {
-            if (messageObject.hasOwnProperty("error"))
-                InspectorTest.log("Backend error: " + messageObject.error.message + " (" + messageObject.error.code + ")\n");
-
-            if (test.callback)
-                test.callback(messageObject.result);
-        });
-    }
-
     function findNodeById(id)
     {
         for (var nodeId in nodeInfo) {
@@ -105,18 +69,10 @@
         return null;
     }
 
-    function addNodesRecursive(root)
-    {
-        addNode(root);
-        if (!root.children)
-            return;
-        for (var i = 0; i < root.children.length; ++i)
-            addNodesRecursive(root.children[i]);
-    }
-
-    function addNode(node)
+    function addNodesRecursive(node)
     {
         nodeInfo[node.nodeId] = node;
+        (node.children || []).forEach(addNodesRecursive);
     }
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/layout-fonts/resources/layout-font-test.js b/third_party/WebKit/LayoutTests/inspector-protocol/layout-fonts/resources/layout-font-test.js
index f3efc86..996ca6b 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/layout-fonts/resources/layout-font-test.js
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/layout-fonts/resources/layout-font-test.js
@@ -57,20 +57,13 @@
 
     }
 
-    function platformFontsForElementWithSelector(selector)
+    async function platformFontsForElementWithSelector(selector)
     {
-        InspectorTest.requestNodeId(documentNodeId, selector, onNodeId);
-
-        function onNodeId(nodeId)
-        {
-            InspectorTest.sendCommandOrDie("CSS.getPlatformFontsForNode", { nodeId: nodeId }, onGotComputedFonts);
-        }
-
-        function onGotComputedFonts(response)
-        {
-            collectResults(response);
-            testNextPageElement();
-        }
+        var nodeId = await InspectorTest.requestNodeId(documentNodeId, selector);
+        await InspectorTest.sendCommandOrDie("CSS.enable", {});
+        var response = await InspectorTest.sendCommandOrDie("CSS.getPlatformFontsForNode", { nodeId: nodeId });
+        collectResults(response);
+        testNextPageElement();
     }
 
     function collectResults(response)
diff --git a/third_party/WebKit/LayoutTests/inspector/initial-modules-load-expected.txt b/third_party/WebKit/LayoutTests/inspector/initial-modules-load-expected.txt
index 0b7a95b..944214e 100644
--- a/third_party/WebKit/LayoutTests/inspector/initial-modules-load-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/initial-modules-load-expected.txt
@@ -13,7 +13,7 @@
     help
     host
     main
-    network_conditions
+    mobile_throttling
     network_log
     persistence
     platform
@@ -41,7 +41,7 @@
     host
     inline_editor
     main
-    network_conditions
+    mobile_throttling
     network_log
     object_ui
     persistence
@@ -75,9 +75,10 @@
     host
     inline_editor
     main
+    mobile_throttling
     network
-    network_conditions
     network_log
+    network_priorities
     object_ui
     perf_ui
     persistence
@@ -114,9 +115,10 @@
     host
     inline_editor
     main
+    mobile_throttling
     network
-    network_conditions
     network_log
+    network_priorities
     object_ui
     perf_ui
     persistence
@@ -156,9 +158,10 @@
     host
     inline_editor
     main
+    mobile_throttling
     network
-    network_conditions
     network_log
+    network_priorities
     object_ui
     perf_ui
     persistence
diff --git a/third_party/WebKit/LayoutTests/paint/selection/text-selection-with-composition.html b/third_party/WebKit/LayoutTests/paint/selection/text-selection-with-composition.html
new file mode 100644
index 0000000..3f52a2d2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/selection/text-selection-with-composition.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function runTest() {
+  if (!window.testRunner)
+    return;
+
+  var input = document.getElementById('test');
+  input.focus();
+  textInputController.setComposition('Hello, world!');
+  input.selectionStart = 0;
+  input.selectionEnd = 13;
+}
+</script>
+</head>
+<body onload="runTest()">
+<input id="test" />
+</body>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/selection/text-selection-with-composition-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/selection/text-selection-with-composition-expected.png
new file mode 100644
index 0000000..9309ddb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/selection/text-selection-with-composition-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/selection/text-selection-with-composition-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/selection/text-selection-with-composition-expected.txt
new file mode 100644
index 0000000..418dfdb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/selection/text-selection-with-composition-expected.txt
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x38
+  LayoutBlockFlow {HTML} at (0,0) size 800x38
+    LayoutBlockFlow {BODY} at (8,8) size 784x22
+      LayoutTextControl {INPUT} at (0,0) size 154x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
+      LayoutText {#text} at (0,0) size 0x0
+layer at (10,11) size 150x16
+  LayoutBlockFlow {DIV} at (2,3) size 150x16
+    LayoutText {#text} at (0,0) size 71x16
+      text run at (0,0) width 71: "Hello, world!"
+selection start: position 0 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
+selection end:   position 13 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png
new file mode 100644
index 0000000..9309ddb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt
new file mode 100644
index 0000000..418dfdb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x38
+  LayoutBlockFlow {HTML} at (0,0) size 800x38
+    LayoutBlockFlow {BODY} at (8,8) size 784x22
+      LayoutTextControl {INPUT} at (0,0) size 154x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
+      LayoutText {#text} at (0,0) size 0x0
+layer at (10,11) size 150x16
+  LayoutBlockFlow {DIV} at (2,3) size 150x16
+    LayoutText {#text} at (0,0) size 71x16
+      text run at (0,0) width 71: "Hello, world!"
+selection start: position 0 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
+selection end:   position 13 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/selection/text-selection-with-composition-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/selection/text-selection-with-composition-expected.png
new file mode 100644
index 0000000..9ac0c32
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/selection/text-selection-with-composition-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/selection/text-selection-with-composition-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/selection/text-selection-with-composition-expected.txt
new file mode 100644
index 0000000..c77cc5a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/selection/text-selection-with-composition-expected.txt
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x35
+  LayoutBlockFlow {HTML} at (0,0) size 800x35
+    LayoutBlockFlow {BODY} at (8,8) size 784x19
+      LayoutTextControl {INPUT} at (0,0) size 131x19 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
+      LayoutText {#text} at (0,0) size 0x0
+layer at (11,11) size 125x13
+  LayoutBlockFlow {DIV} at (3,3) size 125x13
+    LayoutText {#text} at (0,0) size 63x13
+      text run at (0,0) width 63: "Hello, world!"
+selection start: position 0 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
+selection end:   position 13 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png
new file mode 100644
index 0000000..9ac0c32
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt
new file mode 100644
index 0000000..c77cc5a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x35
+  LayoutBlockFlow {HTML} at (0,0) size 800x35
+    LayoutBlockFlow {BODY} at (8,8) size 784x19
+      LayoutTextControl {INPUT} at (0,0) size 131x19 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
+      LayoutText {#text} at (0,0) size 0x0
+layer at (11,11) size 125x13
+  LayoutBlockFlow {DIV} at (3,3) size 125x13
+    LayoutText {#text} at (0,0) size 63x13
+      text run at (0,0) width 63: "Hello, world!"
+selection start: position 0 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
+selection end:   position 13 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/paint/selection/text-selection-with-composition-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/paint/selection/text-selection-with-composition-expected.png
new file mode 100644
index 0000000..e1b66ad2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/paint/selection/text-selection-with-composition-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/paint/selection/text-selection-with-composition-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/paint/selection/text-selection-with-composition-expected.txt
new file mode 100644
index 0000000..edb3272
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/paint/selection/text-selection-with-composition-expected.txt
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x35
+  LayoutBlockFlow {HTML} at (0,0) size 800x35
+    LayoutBlockFlow {BODY} at (8,8) size 784x19
+      LayoutTextControl {INPUT} at (0,0) size 131x19 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
+      LayoutText {#text} at (0,0) size 0x0
+layer at (11,11) size 125x13
+  LayoutBlockFlow {DIV} at (3,3) size 125x13
+    LayoutText {#text} at (0,0) size 65x13
+      text run at (0,0) width 65: "Hello, world!"
+selection start: position 0 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
+selection end:   position 13 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png
new file mode 100644
index 0000000..e1b66ad2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt
new file mode 100644
index 0000000..edb3272
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x35
+  LayoutBlockFlow {HTML} at (0,0) size 800x35
+    LayoutBlockFlow {BODY} at (8,8) size 784x19
+      LayoutTextControl {INPUT} at (0,0) size 131x19 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
+      LayoutText {#text} at (0,0) size 0x0
+layer at (11,11) size 125x13
+  LayoutBlockFlow {DIV} at (3,3) size 125x13
+    LayoutText {#text} at (0,0) size 65x13
+      text run at (0,0) width 65: "Hello, world!"
+selection start: position 0 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
+selection end:   position 13 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/selection/text-selection-with-composition-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/selection/text-selection-with-composition-expected.png
new file mode 100644
index 0000000..a1dcf3bd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/selection/text-selection-with-composition-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/selection/text-selection-with-composition-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/selection/text-selection-with-composition-expected.txt
new file mode 100644
index 0000000..e5b72cb0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/selection/text-selection-with-composition-expected.txt
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x35
+  LayoutBlockFlow {HTML} at (0,0) size 800x35
+    LayoutBlockFlow {BODY} at (8,8) size 784x19
+      LayoutTextControl {INPUT} at (0,0) size 123x19 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
+      LayoutText {#text} at (0,0) size 0x0
+layer at (11,11) size 117x13
+  LayoutBlockFlow {DIV} at (3,3) size 117x13
+    LayoutText {#text} at (0,0) size 68x13
+      text run at (0,0) width 68: "Hello, world!"
+selection start: position 0 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
+selection end:   position 13 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png
new file mode 100644
index 0000000..a1dcf3bd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt
new file mode 100644
index 0000000..e5b72cb0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x35
+  LayoutBlockFlow {HTML} at (0,0) size 800x35
+    LayoutBlockFlow {BODY} at (8,8) size 784x19
+      LayoutTextControl {INPUT} at (0,0) size 123x19 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
+      LayoutText {#text} at (0,0) size 0x0
+layer at (11,11) size 117x13
+  LayoutBlockFlow {DIV} at (3,3) size 117x13
+    LayoutText {#text} at (0,0) size 68x13
+      text run at (0,0) width 68: "Hello, world!"
+selection start: position 0 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
+selection end:   position 13 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/paint/selection/text-selection-with-composition-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/paint/selection/text-selection-with-composition-expected.png
new file mode 100644
index 0000000..e1b66ad2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/paint/selection/text-selection-with-composition-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/paint/selection/text-selection-with-composition-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/paint/selection/text-selection-with-composition-expected.txt
new file mode 100644
index 0000000..edb3272
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/paint/selection/text-selection-with-composition-expected.txt
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x35
+  LayoutBlockFlow {HTML} at (0,0) size 800x35
+    LayoutBlockFlow {BODY} at (8,8) size 784x19
+      LayoutTextControl {INPUT} at (0,0) size 131x19 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
+      LayoutText {#text} at (0,0) size 0x0
+layer at (11,11) size 125x13
+  LayoutBlockFlow {DIV} at (3,3) size 125x13
+    LayoutText {#text} at (0,0) size 65x13
+      text run at (0,0) width 65: "Hello, world!"
+selection start: position 0 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
+selection end:   position 13 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png
new file mode 100644
index 0000000..e1b66ad2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt
new file mode 100644
index 0000000..edb3272
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x35
+  LayoutBlockFlow {HTML} at (0,0) size 800x35
+    LayoutBlockFlow {BODY} at (8,8) size 784x19
+      LayoutTextControl {INPUT} at (0,0) size 131x19 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
+      LayoutText {#text} at (0,0) size 0x0
+layer at (11,11) size 125x13
+  LayoutBlockFlow {DIV} at (3,3) size 125x13
+    LayoutText {#text} at (0,0) size 65x13
+      text run at (0,0) width 65: "Hello, world!"
+selection start: position 0 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
+selection end:   position 13 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/selection/text-selection-with-composition-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/selection/text-selection-with-composition-expected.png
new file mode 100644
index 0000000..eea1972
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/selection/text-selection-with-composition-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/selection/text-selection-with-composition-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/selection/text-selection-with-composition-expected.txt
new file mode 100644
index 0000000..6469e68
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/selection/text-selection-with-composition-expected.txt
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x35
+  LayoutBlockFlow {HTML} at (0,0) size 800x35
+    LayoutBlockFlow {BODY} at (8,8) size 784x19
+      LayoutTextControl {INPUT} at (0,0) size 131x19 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
+      LayoutText {#text} at (0,0) size 0x0
+layer at (11,11) size 125x13
+  LayoutBlockFlow {DIV} at (3,3) size 125x13
+    LayoutText {#text} at (0,0) size 66x13
+      text run at (0,0) width 66: "Hello, world!"
+selection start: position 0 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
+selection end:   position 13 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png
new file mode 100644
index 0000000..eea1972
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt
new file mode 100644
index 0000000..6469e68
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x35
+  LayoutBlockFlow {HTML} at (0,0) size 800x35
+    LayoutBlockFlow {BODY} at (8,8) size 784x19
+      LayoutTextControl {INPUT} at (0,0) size 131x19 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
+      LayoutText {#text} at (0,0) size 0x0
+layer at (11,11) size 125x13
+  LayoutBlockFlow {DIV} at (3,3) size 125x13
+    LayoutText {#text} at (0,0) size 66x13
+      text run at (0,0) width 66: "Hello, world!"
+selection start: position 0 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
+selection end:   position 13 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/selection/text-selection-with-composition-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/selection/text-selection-with-composition-expected.png
new file mode 100644
index 0000000..603e24f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/selection/text-selection-with-composition-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/selection/text-selection-with-composition-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/selection/text-selection-with-composition-expected.txt
new file mode 100644
index 0000000..b7fff3f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/selection/text-selection-with-composition-expected.txt
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x38
+  LayoutBlockFlow {HTML} at (0,0) size 800x38
+    LayoutBlockFlow {BODY} at (8,8) size 784x22
+      LayoutTextControl {INPUT} at (0,0) size 173x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
+      LayoutText {#text} at (0,0) size 0x0
+layer at (10,11) size 169x16
+  LayoutBlockFlow {DIV} at (2,3) size 169x16
+    LayoutText {#text} at (0,0) size 70x16
+      text run at (0,0) width 70: "Hello, world!"
+selection start: position 0 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
+selection end:   position 13 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png
new file mode 100644
index 0000000..603e24f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt
new file mode 100644
index 0000000..b7fff3f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/disable-spinvalidation/paint/selection/text-selection-with-composition-expected.txt
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x38
+  LayoutBlockFlow {HTML} at (0,0) size 800x38
+    LayoutBlockFlow {BODY} at (8,8) size 784x22
+      LayoutTextControl {INPUT} at (0,0) size 173x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
+      LayoutText {#text} at (0,0) size 0x0
+layer at (10,11) size 169x16
+  LayoutBlockFlow {DIV} at (2,3) size 169x16
+    LayoutText {#text} at (0,0) size 70x16
+      text run at (0,0) width 70: "Hello, world!"
+selection start: position 0 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
+selection end:   position 13 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValueFuzzer.cpp b/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValueFuzzer.cpp
index fe3e83e..e4ed1c8 100644
--- a/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValueFuzzer.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValueFuzzer.cpp
@@ -73,14 +73,14 @@
   SerializedScriptValue::DeserializeOptions options;
 
   // If message ports are requested, make some.
-  MessagePortArray* message_ports = nullptr;
   if (hash & kFuzzMessagePorts) {
-    options.message_ports = new MessagePortArray(3);
+    MessagePortArray* message_ports = new MessagePortArray(3);
     std::generate(message_ports->begin(), message_ports->end(), []() {
       MessagePort* port = MessagePort::Create(g_page_holder->GetDocument());
       port->Entangle(WTF::MakeUnique<WebMessagePortChannelImpl>());
       return port;
     });
+    options.message_ports = message_ports;
   }
 
   // If blobs are requested, supply blob info.
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index b4610d2f..e12dbf9 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -1207,6 +1207,7 @@
     "dom/ScriptedAnimationControllerTest.cpp",
     "dom/ScriptedIdleTaskControllerTest.cpp",
     "dom/SelectorQueryTest.cpp",
+    "dom/SpaceSplitStringTest.cpp",
     "dom/StaticRangeTest.cpp",
     "dom/StyleElementTest.cpp",
     "dom/StyleEngineTest.cpp",
diff --git a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
index 99afef7..c7e7630 100644
--- a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
+++ b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
@@ -1182,39 +1182,6 @@
 }
 
 template <>
-inline CSSIdentifierValue::CSSIdentifierValue(EUserModify e)
-    : CSSValue(kIdentifierClass) {
-  switch (e) {
-    case EUserModify::kReadOnly:
-      value_id_ = CSSValueReadOnly;
-      break;
-    case EUserModify::kReadWrite:
-      value_id_ = CSSValueReadWrite;
-      break;
-    case EUserModify::kReadWritePlaintextOnly:
-      value_id_ = CSSValueReadWritePlaintextOnly;
-      break;
-  }
-}
-
-template <>
-inline EUserModify CSSIdentifierValue::ConvertTo() const {
-  switch (value_id_) {
-    case CSSValueReadOnly:
-      return EUserModify::kReadOnly;
-    case CSSValueReadWrite:
-      return EUserModify::kReadWrite;
-    case CSSValueReadWritePlaintextOnly:
-      return EUserModify::kReadWritePlaintextOnly;
-    default:
-      break;
-  }
-
-  NOTREACHED();
-  return EUserModify::kReadOnly;
-}
-
-template <>
 inline CSSIdentifierValue::CSSIdentifierValue(EVerticalAlign a)
     : CSSValue(kIdentifierClass) {
   switch (a) {
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index f7342bc..1fc15f4 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -2690,10 +2690,9 @@
     {
       name: "-webkit-user-modify",
       inherited: true,
-      field_template: "storage_only",
-      type_name: "EUserModify",
-      default_value: "EUserModify::kReadOnly",
-      field_size: 2,
+      field_template: "keyword",
+      keywords: ["read-only", "read-write", "read-write-plaintext-only"],
+      default_value: "read-only",
       field_group: "rare-inherited",
     },
     {
diff --git a/third_party/WebKit/Source/core/dom/DOMTokenList.cpp b/third_party/WebKit/Source/core/dom/DOMTokenList.cpp
index 60e9c7f6f..2b8060f3 100644
--- a/third_party/WebKit/Source/core/dom/DOMTokenList.cpp
+++ b/third_party/WebKit/Source/core/dom/DOMTokenList.cpp
@@ -86,11 +86,8 @@
   return tokens_.Contains(token);
 }
 
-void DOMTokenList::add(const AtomicString& token,
-                       ExceptionState& exception_state) {
-  Vector<String> tokens;
-  tokens.push_back(token.GetString());
-  add(tokens, exception_state);
+void DOMTokenList::Add(const AtomicString& token) {
+  add(Vector<String>({token}), ASSERT_NO_EXCEPTION);
 }
 
 // https://dom.spec.whatwg.org/#dom-domtokenlist-add
@@ -104,11 +101,8 @@
   AddTokens(tokens);
 }
 
-void DOMTokenList::remove(const AtomicString& token,
-                          ExceptionState& exception_state) {
-  Vector<String> tokens;
-  tokens.push_back(token.GetString());
-  remove(tokens, exception_state);
+void DOMTokenList::Remove(const AtomicString& token) {
+  remove(Vector<String>({token}), ASSERT_NO_EXCEPTION);
 }
 
 // https://dom.spec.whatwg.org/#dom-domtokenlist-remove
diff --git a/third_party/WebKit/Source/core/dom/DOMTokenList.h b/third_party/WebKit/Source/core/dom/DOMTokenList.h
index ed19f01..f5eac95a 100644
--- a/third_party/WebKit/Source/core/dom/DOMTokenList.h
+++ b/third_party/WebKit/Source/core/dom/DOMTokenList.h
@@ -52,18 +52,15 @@
 
   unsigned length() const { return tokens_.size(); }
   const AtomicString item(unsigned index) const;
-
   bool contains(const AtomicString&) const;
   void add(const Vector<String>&, ExceptionState&);
-  void add(const AtomicString&, ExceptionState&);
   void remove(const Vector<String>&, ExceptionState&);
-  void remove(const AtomicString&, ExceptionState&);
   bool toggle(const AtomicString&, ExceptionState&);
   bool toggle(const AtomicString&, bool force, ExceptionState&);
   bool supports(const AtomicString&, ExceptionState&);
-
   const AtomicString& value() const { return value_; }
   void setValue(const AtomicString&);
+  const AtomicString& toString() const { return value(); }
 
   // This function should be called when the associated attribute value was
   // updated.
@@ -71,8 +68,9 @@
                                const AtomicString& new_value);
 
   const SpaceSplitString& Tokens() const { return tokens_; }
-
-  const AtomicString& toString() const { return value(); }
+  // Add() and Remove() have DCHECK for syntax of the specified token.
+  void Add(const AtomicString&);
+  void Remove(const AtomicString&);
 
  protected:
   DOMTokenList(Element& element, const QualifiedName& attr)
diff --git a/third_party/WebKit/Source/core/dom/SpaceSplitString.cpp b/third_party/WebKit/Source/core/dom/SpaceSplitString.cpp
index 3a68e4c..0a95059 100644
--- a/third_party/WebKit/Source/core/dom/SpaceSplitString.cpp
+++ b/third_party/WebKit/Source/core/dom/SpaceSplitString.cpp
@@ -29,8 +29,10 @@
 // https://dom.spec.whatwg.org/#concept-ordered-set-parser
 template <typename CharacterType>
 inline void SpaceSplitString::Data::CreateVector(
+    const AtomicString& source,
     const CharacterType* characters,
     unsigned length) {
+  DCHECK_EQ(0u, vector_.size());
   HashSet<AtomicString> token_set;
   unsigned start = 0;
   while (true) {
@@ -42,9 +44,24 @@
     while (end < length && IsNotHTMLSpace<CharacterType>(characters[end]))
       ++end;
 
+    if (start == 0 && end == length) {
+      vector_.push_back(source);
+      return;
+    }
+
     AtomicString token(characters + start, end - start);
-    if (!token_set.Contains(token)) {
-      token_set.insert(token);
+    // We skip adding |token| to |token_set| for the first token to reduce the
+    // cost of HashSet<>::insert(), and adjust |token_set| when the second
+    // unique token is found.
+    if (vector_.size() == 0) {
+      vector_.push_back(token);
+    } else if (vector_.size() == 1) {
+      if (vector_[0] != token) {
+        token_set.insert(vector_[0]);
+        token_set.insert(token);
+        vector_.push_back(token);
+      }
+    } else if (token_set.insert(token).is_new_entry) {
       vector_.push_back(token);
     }
 
@@ -52,15 +69,15 @@
   }
 }
 
-void SpaceSplitString::Data::CreateVector(const String& string) {
+void SpaceSplitString::Data::CreateVector(const AtomicString& string) {
   unsigned length = string.length();
 
   if (string.Is8Bit()) {
-    CreateVector(string.Characters8(), length);
+    CreateVector(string, string.Characters8(), length);
     return;
   }
 
-  CreateVector(string.Characters16(), length);
+  CreateVector(string, string.Characters16(), length);
 }
 
 bool SpaceSplitString::Data::ContainsAll(Data& other) {
diff --git a/third_party/WebKit/Source/core/dom/SpaceSplitString.h b/third_party/WebKit/Source/core/dom/SpaceSplitString.h
index f65e739f..01823799 100644
--- a/third_party/WebKit/Source/core/dom/SpaceSplitString.h
+++ b/third_party/WebKit/Source/core/dom/SpaceSplitString.h
@@ -21,6 +21,7 @@
 #ifndef SpaceSplitString_h
 #define SpaceSplitString_h
 
+#include "core/CoreExport.h"
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/RefCounted.h"
 #include "platform/wtf/Vector.h"
@@ -28,7 +29,7 @@
 
 namespace blink {
 
-class SpaceSplitString {
+class CORE_EXPORT SpaceSplitString {
   USING_FAST_MALLOC(SpaceSplitString);
 
  public:
@@ -84,9 +85,11 @@
     explicit Data(const AtomicString&);
     explicit Data(const Data&);
 
-    void CreateVector(const String&);
+    void CreateVector(const AtomicString&);
     template <typename CharacterType>
-    inline void CreateVector(const CharacterType*, unsigned);
+    inline void CreateVector(const AtomicString&,
+                             const CharacterType*,
+                             unsigned);
 
     AtomicString key_string_;
     Vector<AtomicString, 4> vector_;
diff --git a/third_party/WebKit/Source/core/dom/SpaceSplitStringTest.cpp b/third_party/WebKit/Source/core/dom/SpaceSplitStringTest.cpp
new file mode 100644
index 0000000..9b25e32
--- /dev/null
+++ b/third_party/WebKit/Source/core/dom/SpaceSplitStringTest.cpp
@@ -0,0 +1,35 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/dom/SpaceSplitString.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+TEST(SpaceSplitStringTest, Set) {
+  SpaceSplitString tokens;
+
+  tokens.Set("foo");
+  EXPECT_EQ(1u, tokens.size());
+  EXPECT_EQ(AtomicString("foo"), tokens[0]);
+
+  tokens.Set(" foo\t");
+  EXPECT_EQ(1u, tokens.size());
+  EXPECT_EQ(AtomicString("foo"), tokens[0]);
+
+  tokens.Set("foo foo\t");
+  EXPECT_EQ(1u, tokens.size());
+  EXPECT_EQ(AtomicString("foo"), tokens[0]);
+
+  tokens.Set("foo foo  foo");
+  EXPECT_EQ(1u, tokens.size());
+  EXPECT_EQ(AtomicString("foo"), tokens[0]);
+
+  tokens.Set("foo foo bar foo");
+  EXPECT_EQ(2u, tokens.size());
+  EXPECT_EQ(AtomicString("foo"), tokens[0]);
+  EXPECT_EQ(AtomicString("bar"), tokens[1]);
+}
+}
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp
index 4590346..fa0e682 100644
--- a/third_party/WebKit/Source/core/editing/Editor.cpp
+++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -655,15 +655,9 @@
                                           bool match_style,
                                           InputEvent::InputType input_type) {
   DCHECK(!GetFrame().GetDocument()->NeedsLayoutTreeUpdate());
-  if (GetFrame()
-          .Selection()
-          .ComputeVisibleSelectionInDOMTreeDeprecated()
-          .IsNone() ||
-      !GetFrame()
-           .Selection()
-           .ComputeVisibleSelectionInDOMTreeDeprecated()
-           .IsContentEditable() ||
-      !fragment)
+  const VisibleSelection& selection =
+      GetFrame().Selection().ComputeVisibleSelectionInDOMTree();
+  if (selection.IsNone() || !selection.IsContentEditable() || !fragment)
     return;
 
   ReplaceSelectionCommand::CommandOptions options =
diff --git a/third_party/WebKit/Source/core/editing/SelectionModifier.h b/third_party/WebKit/Source/core/editing/SelectionModifier.h
index 5e6488fb..5a00050e 100644
--- a/third_party/WebKit/Source/core/editing/SelectionModifier.h
+++ b/third_party/WebKit/Source/core/editing/SelectionModifier.h
@@ -82,6 +82,13 @@
   VisiblePosition ModifyMovingBackward(TextGranularity);
   VisiblePosition NextWordPositionForPlatform(const VisiblePosition&);
 
+  // TODO(editing-dev): We should handle |skips_spaces_when_moving_right| in
+  // another way, e.g. pass |EditingBehavior()|.
+  static VisiblePosition LeftWordPosition(const VisiblePosition&,
+                                          bool skips_space_when_moving_right);
+  static VisiblePosition RightWordPosition(const VisiblePosition&,
+                                           bool skips_space_when_moving_right);
+
   Member<LocalFrame> frame_;
   VisibleSelection selection_;
   LayoutUnit x_pos_for_vertical_arrow_navigation_;
diff --git a/third_party/WebKit/Source/core/editing/SelectionModifierWord.cpp b/third_party/WebKit/Source/core/editing/SelectionModifierWord.cpp
index 90f4e20..522a3ef5 100644
--- a/third_party/WebKit/Source/core/editing/SelectionModifierWord.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionModifierWord.cpp
@@ -23,6 +23,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+#include "core/editing/SelectionModifier.h"
 
 #include "core/editing/EditingUtilities.h"
 #include "core/editing/RenderedPosition.h"
@@ -387,10 +388,9 @@
 
 }  // namespace
 
-// TODO(yosin): Once we move |SelectionModifier::ModifyMovingLeft()| in this
-// file, we can make |LeftWordPosition()| as file local function.
-VisiblePosition LeftWordPosition(const VisiblePosition& visible_position,
-                                 bool skips_space_when_moving_right) {
+VisiblePosition SelectionModifier::LeftWordPosition(
+    const VisiblePosition& visible_position,
+    bool skips_space_when_moving_right) {
   DCHECK(visible_position.IsValid()) << visible_position;
   VisiblePosition left_word_break = VisualWordPosition(
       visible_position, kMoveLeft, skips_space_when_moving_right);
@@ -409,10 +409,9 @@
   return left_word_break;
 }
 
-// TODO(yosin): Once we move |SelectionModifier::ModifyMovingRight()| in this
-// file, we can make |RightWordPosition()| as file local function.
-VisiblePosition RightWordPosition(const VisiblePosition& visible_position,
-                                  bool skips_space_when_moving_right) {
+VisiblePosition SelectionModifier::RightWordPosition(
+    const VisiblePosition& visible_position,
+    bool skips_space_when_moving_right) {
   DCHECK(visible_position.IsValid()) << visible_position;
   VisiblePosition right_word_break = VisualWordPosition(
       visible_position, kMoveRight, skips_space_when_moving_right);
@@ -423,7 +422,7 @@
   if (right_word_break.IsNull() &&
       IsEditablePosition(visible_position.DeepEquivalent())) {
     TextDirection block_direction =
-        DirectionOfEnclosingBlockOf(visible_position.DeepEquivalent());
+        blink::DirectionOfEnclosingBlockOf(visible_position.DeepEquivalent());
     right_word_break = block_direction == TextDirection::kLtr
                            ? EndOfEditableContent(visible_position)
                            : StartOfEditableContent(visible_position);
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.h b/third_party/WebKit/Source/core/editing/VisibleUnits.h
index 101c9b8..26e5b98a2 100644
--- a/third_party/WebKit/Source/core/editing/VisibleUnits.h
+++ b/third_party/WebKit/Source/core/editing/VisibleUnits.h
@@ -183,14 +183,6 @@
 EndOfWord(const VisiblePositionInFlatTree&, EWordSide = kRightWordIfOnBoundary);
 VisiblePosition PreviousWordPosition(const VisiblePosition&);
 VisiblePosition NextWordPosition(const VisiblePosition&);
-// TODO(yosin): We'll move |RightPositionOf()| as file location function
-// for |SelectionModifier| class.
-VisiblePosition RightWordPosition(const VisiblePosition&,
-                                  bool skips_space_when_moving_right);
-// TODO(yosin): We'll move |LeftPositionOf()| as file location function
-// for |SelectionModifier| class.
-VisiblePosition LeftWordPosition(const VisiblePosition&,
-                                 bool skips_space_when_moving_right);
 
 // sentences
 CORE_EXPORT VisiblePosition StartOfSentence(const VisiblePosition&);
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
index b5389df..7f81c73 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
@@ -269,12 +269,6 @@
     return true;
   }
 
-  // TODO(xiaochengh): When multiple text runs should be emitted from a replaced
-  // element or non-text node, we should handle it directly from here, instead
-  // of going into the main iteration of Advance() for multiple times. In this
-  // way, we can also remove the return values of HandleReplaceElement() and
-  // HandleNonTextNode(), and make the control flow cleaner.
-
   if (needs_handle_replaced_element_) {
     HandleReplacedElement();
     if (text_state_.PositionNode())
@@ -361,12 +355,11 @@
 
       // Handle the current node according to its type.
       if (iteration_progress_ < kHandledNode) {
-        bool handled_node = false;
         if (layout_object->IsText() &&
             node_->getNodeType() ==
                 Node::kTextNode) {  // FIXME: What about kCdataSectionNode?
           if (!fully_clipped_stack_.Top() || IgnoresStyleVisibility())
-            handled_node = HandleTextNode();
+            HandleTextNode();
         } else if (layout_object &&
                    (layout_object->IsImage() || layout_object->IsLayoutPart() ||
                     (node_ && node_->IsHTMLElement() &&
@@ -375,12 +368,11 @@
                       isHTMLImageElement(ToHTMLElement(*node_)) ||
                       isHTMLMeterElement(ToHTMLElement(*node_)) ||
                       isHTMLProgressElement(ToHTMLElement(*node_)))))) {
-          handled_node = HandleReplacedElement();
+          HandleReplacedElement();
         } else {
-          handled_node = HandleNonTextNode();
+          HandleNonTextNode();
         }
-        if (handled_node)
-          iteration_progress_ = kHandledNode;
+        iteration_progress_ = kHandledNode;
         if (text_state_.PositionNode())
           return;
       }
@@ -481,19 +473,19 @@
 }
 
 template <typename Strategy>
-bool TextIteratorAlgorithm<Strategy>::HandleTextNode() {
+void TextIteratorAlgorithm<Strategy>::HandleTextNode() {
   if (ExcludesAutofilledValue()) {
     TextControlElement* control = EnclosingTextControl(node_);
     // For security reason, we don't expose suggested value if it is
     // auto-filled.
     if (control && control->IsAutofilled())
-      return true;
+      return;
   }
 
   DCHECK_NE(last_text_node_, node_)
       << "We should never call HandleTextNode on the same node twice";
   last_text_node_ = ToText(node_);
-  return text_node_handler_.HandleTextNode(ToText(node_));
+  text_node_handler_.HandleTextNode(ToText(node_));
 }
 
 template <typename Strategy>
@@ -512,21 +504,22 @@
 }
 
 template <typename Strategy>
-bool TextIteratorAlgorithm<Strategy>::HandleReplacedElement() {
+void TextIteratorAlgorithm<Strategy>::HandleReplacedElement() {
   needs_handle_replaced_element_ = false;
 
   if (fully_clipped_stack_.Top())
-    return false;
+    return;
 
   LayoutObject* layout_object = node_->GetLayoutObject();
   if (layout_object->Style()->Visibility() != EVisibility::kVisible &&
-      !IgnoresStyleVisibility())
-    return false;
+      !IgnoresStyleVisibility()) {
+    return;
+  }
 
   if (EmitsObjectReplacementCharacter()) {
     SpliceBuffer(kObjectReplacementCharacter, Strategy::Parent(*node_), node_,
                  0, 1);
-    return true;
+    return;
   }
 
   DCHECK_EQ(last_text_node_, text_node_handler_.GetNode());
@@ -534,13 +527,13 @@
     if (text_node_handler_.FixLeadingWhiteSpaceForReplacedElement(
             Strategy::Parent(*last_text_node_))) {
       needs_handle_replaced_element_ = true;
-      return true;
+      return;
     }
   }
 
   if (EntersTextControls() && layout_object->IsTextControl()) {
     // The shadow tree should be already visited.
-    return true;
+    return;
   }
 
   if (EmitsCharactersBetweenAllVisiblePositions()) {
@@ -548,7 +541,7 @@
     // finding, and to simply take up space for the selection preservation
     // code in moveParagraphs, so we use a comma.
     SpliceBuffer(',', Strategy::Parent(*node_), node_, 0, 1);
-    return true;
+    return;
   }
 
   text_state_.UpdateForReplacedElement(node_);
@@ -556,10 +549,8 @@
   if (EmitsImageAltText() && TextIterator::SupportsAltText(node_)) {
     text_state_.EmitAltText(node_);
     if (text_state_.length())
-      return true;
+      return;
   }
-
-  return true;
 }
 
 template <typename Strategy>
@@ -777,7 +768,7 @@
 }
 
 template <typename Strategy>
-bool TextIteratorAlgorithm<Strategy>::HandleNonTextNode() {
+void TextIteratorAlgorithm<Strategy>::HandleNonTextNode() {
   if (ShouldEmitNewlineForNode(node_, EmitsOriginalText()))
     SpliceBuffer('\n', Strategy::Parent(*node_), node_, 0, 1);
   else if (EmitsCharactersBetweenAllVisiblePositions() &&
@@ -785,8 +776,6 @@
     SpliceBuffer(kSpaceCharacter, Strategy::Parent(*node_), node_, 0, 1);
   else
     RepresentNodeOffsetZero();
-
-  return true;
 }
 
 template <typename Strategy>
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.h b/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
index 5b3167b..2b0290b 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.h
@@ -135,14 +135,9 @@
   // Returns true if text is emitted from the remembered progress (if any).
   bool HandleRememberedProgress();
 
-  // Return true if the iteration progress should advance to |kHandledNode|
-  // after calling a |HandleXXX| function.
-  // TODO(xiaochengh): The meaning of the return values is unclear, and they do
-  // not always clearly control the iteration progress. Should consider removing
-  // the return values and control the iteration in a cleaner way.
-  bool HandleTextNode();
-  bool HandleReplacedElement();
-  bool HandleNonTextNode();
+  void HandleTextNode();
+  void HandleReplacedElement();
+  void HandleNonTextNode();
   void SpliceBuffer(UChar,
                     Node* text_node,
                     Node* offset_base_node,
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp
index 4c6c9dd..395e6b2a 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp
@@ -134,7 +134,7 @@
   EmitText(text_node_, text_node_->GetLayoutObject(), run_start, run_end);
 }
 
-bool TextIteratorTextNodeHandler::HandleTextNode(Text* node) {
+void TextIteratorTextNodeHandler::HandleTextNode(Text* node) {
   text_node_ = node;
   offset_ = text_node_ == start_container_ ? start_offset_ : 0;
   handled_first_letter_ = false;
@@ -146,7 +146,7 @@
   // handle pre-formatted text
   if (!layout_object->Style()->CollapseWhiteSpace()) {
     HandlePreFormattedTextNode();
-    return true;
+    return;
   }
 
   if (layout_object->FirstTextBox())
@@ -159,12 +159,12 @@
 
   if (!layout_object->FirstTextBox() && str.length() > 0 &&
       !should_handle_first_letter) {
-    if (layout_object->Style()->Visibility() != EVisibility::kVisible &&
-        !IgnoresStyleVisibility())
-      return false;
-    last_text_node_ended_with_collapsed_space_ =
-        true;  // entire block is collapsed space
-    return true;
+    if (layout_object->Style()->Visibility() == EVisibility::kVisible ||
+        IgnoresStyleVisibility()) {
+      last_text_node_ended_with_collapsed_space_ =
+          true;  // entire block is collapsed space
+    }
+    return;
   }
 
   if (first_letter_text_)
@@ -184,7 +184,6 @@
   }
 
   HandleTextBox();
-  return true;
 }
 
 // Restore the collapsed space for copy & paste. See http://crbug.com/318925
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.h b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.h
index dc794df..adcd9ec 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.h
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.h
@@ -45,9 +45,7 @@
 
   void ResetCollapsedWhiteSpaceFixup();
 
-  // TODO(xiaochengh): Make the return type |void|. The current return value is
-  // not very meaningful.
-  bool HandleTextNode(Text*);
+  void HandleTextNode(Text*);
 
  private:
   void HandlePreFormattedTextNode();
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.cpp
index 44ab1f9..11c02f0 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.cpp
@@ -182,11 +182,6 @@
   start_offset_ += delta;
   end_offset_ += delta;
 }
-void DocumentMarker::SetIsActiveMatch(bool active) {
-  if (GetType() != DocumentMarker::kTextMatch)
-    return;
-  ToTextMatchMarker(this)->SetIsActiveMatch(active);
-}
 
 const String& DocumentMarker::Description() const {
   if (DocumentMarkerDescription* details =
@@ -195,12 +190,6 @@
   return g_empty_string;
 }
 
-bool DocumentMarker::IsActiveMatch() const {
-  if (GetType() != DocumentMarker::kTextMatch)
-    return false;
-  return ToTextMatchMarker(this)->IsActiveMatch();
-}
-
 Color DocumentMarker::UnderlineColor() const {
   if (TextCompositionMarkerDetails* details =
           ToTextCompositionMarkerDetails(details_.Get()))
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h
index 97a11558..c023c59 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h
@@ -36,9 +36,7 @@
 
 // A range of a node within a document that is "marked", such as the range of a
 // misspelled word. It optionally includes a description that could be displayed
-// in the user interface. It also optionally includes a flag specifying whether
-// the match is active, which is ignored for all types other than type
-// TextMatch.
+// in the user interface.
 class CORE_EXPORT DocumentMarker : public GarbageCollected<DocumentMarker> {
  public:
   enum MarkerTypeIndex {
@@ -147,13 +145,11 @@
   unsigned EndOffset() const { return end_offset_; }
 
   const String& Description() const;
-  bool IsActiveMatch() const;
   Color UnderlineColor() const;
   bool Thick() const;
   Color BackgroundColor() const;
   DocumentMarkerDetails* Details() const;
 
-  void SetIsActiveMatch(bool);
   void ClearDetails() { details_.Clear(); }
 
   struct MarkerOffsets {
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
index 73a528d..5f387eb 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
@@ -673,7 +673,9 @@
         builder.Append(":");
         builder.AppendNumber(marker->EndOffset());
         builder.Append("](");
-        builder.AppendNumber(marker->IsActiveMatch());
+        builder.AppendNumber(type == DocumentMarker::kTextMatch
+                                 ? ToTextMatchMarker(marker)->IsActiveMatch()
+                                 : 0);
         builder.Append(")");
       }
     }
diff --git a/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.h b/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.h
index 83cb212..2c24521 100644
--- a/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.h
+++ b/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.h
@@ -32,6 +32,10 @@
 
 namespace blink {
 
+// A subclass of DocumentMarker used to store information specific to TextMatch
+// markers. We store whether or not the match is active, a LayoutRect used for
+// rendering the marker, and whether or not the LayoutRect is currently
+// up-to-date.
 class TextMatchMarker final : public DocumentMarker {
  private:
   enum class State { kInvalid, kValidNull, kValidNotNull };
diff --git a/third_party/WebKit/Source/core/editing/markers/TextMatchMarkerListImpl.cpp b/third_party/WebKit/Source/core/editing/markers/TextMatchMarkerListImpl.cpp
index 18a5d75a..4dfaee9 100644
--- a/third_party/WebKit/Source/core/editing/markers/TextMatchMarkerListImpl.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/TextMatchMarkerListImpl.cpp
@@ -95,7 +95,7 @@
     // range.
     if (marker.StartOffset() >= end_offset)
       break;
-    marker.SetIsActiveMatch(active);
+    ToTextMatchMarker(marker).SetIsActiveMatch(active);
     doc_dirty = true;
   }
   return doc_dirty;
diff --git a/third_party/WebKit/Source/core/exported/BUILD.gn b/third_party/WebKit/Source/core/exported/BUILD.gn
index 75646bc..167b16c 100644
--- a/third_party/WebKit/Source/core/exported/BUILD.gn
+++ b/third_party/WebKit/Source/core/exported/BUILD.gn
@@ -46,6 +46,8 @@
     "WebSelection.cpp",
     "WebSelector.cpp",
     "WebSerializedScriptValue.cpp",
+    "WebSettingsImpl.cpp",
+    "WebSettingsImpl.h",
     "WebTextCheckingCompletionImpl.cpp",
     "WebTextCheckingCompletionImpl.h",
     "WebTextCheckingResult.cpp",
diff --git a/third_party/WebKit/Source/web/WebSettingsImpl.cpp b/third_party/WebKit/Source/core/exported/WebSettingsImpl.cpp
similarity index 99%
rename from third_party/WebKit/Source/web/WebSettingsImpl.cpp
rename to third_party/WebKit/Source/core/exported/WebSettingsImpl.cpp
index 61794c9..ade2c9c 100644
--- a/third_party/WebKit/Source/web/WebSettingsImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/WebSettingsImpl.cpp
@@ -28,7 +28,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "web/WebSettingsImpl.h"
+#include "core/exported/WebSettingsImpl.h"
 
 #include "core/frame/Settings.h"
 #include "platform/graphics/DeferredImageDecoder.h"
@@ -36,7 +36,6 @@
 #include "core/inspector/DevToolsEmulator.h"
 #include "public/platform/WebString.h"
 #include "public/platform/WebURL.h"
-#include "web/WebDevToolsAgentImpl.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/web/WebSettingsImpl.h b/third_party/WebKit/Source/core/exported/WebSettingsImpl.h
similarity index 98%
rename from third_party/WebKit/Source/web/WebSettingsImpl.h
rename to third_party/WebKit/Source/core/exported/WebSettingsImpl.h
index 9ee6e20..3510335 100644
--- a/third_party/WebKit/Source/web/WebSettingsImpl.h
+++ b/third_party/WebKit/Source/core/exported/WebSettingsImpl.h
@@ -31,17 +31,18 @@
 #ifndef WebSettingsImpl_h
 #define WebSettingsImpl_h
 
+#include "core/CoreExport.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Compiler.h"
 #include "public/web/WebSettings.h"
-#include "web/WebExport.h"
 
 namespace blink {
 
 class DevToolsEmulator;
 class Settings;
 
-class WEB_EXPORT WebSettingsImpl final : NON_EXPORTED_BASE(public WebSettings) {
+class CORE_EXPORT WebSettingsImpl final
+    : NON_EXPORTED_BASE(public WebSettings) {
  public:
   WebSettingsImpl(Settings*, DevToolsEmulator*);
   virtual ~WebSettingsImpl() {}
diff --git a/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.h b/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.h
index eecd3144..2abfa650 100644
--- a/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.h
+++ b/third_party/WebKit/Source/core/frame/WebFrameWidgetBase.h
@@ -38,6 +38,7 @@
   // Sets the root graphics layer. |GraphicsLayer| can be null when detaching
   // the root layer.
   virtual void SetRootGraphicsLayer(GraphicsLayer*) = 0;
+  virtual GraphicsLayer* RootGraphicsLayer() const = 0;
 
   // Sets the root layer. |WebLayer| can be null when detaching the root layer.
   virtual void SetRootLayer(WebLayer*) = 0;
diff --git a/third_party/WebKit/Source/core/frame/WebViewFrameWidget.cpp b/third_party/WebKit/Source/core/frame/WebViewFrameWidget.cpp
index 0314cb5a..aa88b008 100644
--- a/third_party/WebKit/Source/core/frame/WebViewFrameWidget.cpp
+++ b/third_party/WebKit/Source/core/frame/WebViewFrameWidget.cpp
@@ -233,6 +233,10 @@
   web_view_->SetRootGraphicsLayer(layer);
 }
 
+GraphicsLayer* WebViewFrameWidget::RootGraphicsLayer() const {
+  return web_view_->RootGraphicsLayer();
+}
+
 void WebViewFrameWidget::SetRootLayer(WebLayer* layer) {
   web_view_->SetRootLayer(layer);
 }
diff --git a/third_party/WebKit/Source/core/frame/WebViewFrameWidget.h b/third_party/WebKit/Source/core/frame/WebViewFrameWidget.h
index 990b81c6..100ca0e 100644
--- a/third_party/WebKit/Source/core/frame/WebViewFrameWidget.h
+++ b/third_party/WebKit/Source/core/frame/WebViewFrameWidget.h
@@ -100,6 +100,7 @@
   CompositorWorkerProxyClient* CreateCompositorWorkerProxyClient() override;
   AnimationWorkletProxyClient* CreateAnimationWorkletProxyClient() override;
   void SetRootGraphicsLayer(GraphicsLayer*) override;
+  GraphicsLayer* RootGraphicsLayer() const override;
   void SetRootLayer(WebLayer*) override;
   WebLayerTreeView* GetLayerTreeView() const override;
   CompositorAnimationHost* AnimationHost() const override;
diff --git a/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp b/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp
index e28f864e..6f0ec4f 100644
--- a/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLOptionElement.cpp
@@ -284,7 +284,7 @@
 }
 
 void HTMLOptionElement::SetDirty(bool value) {
-  is_dirty_ = true;
+  is_dirty_ = value;
 }
 
 void HTMLOptionElement::ChildrenChanged(const ChildrenChange& change) {
diff --git a/third_party/WebKit/Source/core/html/track/vtt/VTTRegion.cpp b/third_party/WebKit/Source/core/html/track/vtt/VTTRegion.cpp
index 8516ecb2..7c16eb50 100644
--- a/third_party/WebKit/Source/core/html/track/vtt/VTTRegion.cpp
+++ b/third_party/WebKit/Source/core/html/track/vtt/VTTRegion.cpp
@@ -288,8 +288,7 @@
 
   double box_height = box->getBoundingClientRect()->height();
 
-  cue_container_->classList().remove(TextTrackCueContainerScrollingClass(),
-                                     ASSERT_NO_EXCEPTION);
+  cue_container_->classList().Remove(TextTrackCueContainerScrollingClass());
 
   current_top_ += box_height;
   cue_container_->SetInlineStyleProperty(CSSPropertyTop, current_top_,
@@ -319,8 +318,7 @@
 
   // If it's a scrolling region, add the scrolling class.
   if (IsScrollingRegion())
-    cue_container_->classList().add(TextTrackCueContainerScrollingClass(),
-                                    ASSERT_NO_EXCEPTION);
+    cue_container_->classList().Add(TextTrackCueContainerScrollingClass());
 
   float region_bottom = region_display_tree_->getBoundingClientRect()->bottom();
 
diff --git a/third_party/WebKit/Source/core/inspector/BUILD.gn b/third_party/WebKit/Source/core/inspector/BUILD.gn
index 1d9705b..b186c15 100644
--- a/third_party/WebKit/Source/core/inspector/BUILD.gn
+++ b/third_party/WebKit/Source/core/inspector/BUILD.gn
@@ -39,6 +39,8 @@
     "InspectorDOMAgent.h",
     "InspectorDOMDebuggerAgent.cpp",
     "InspectorDOMDebuggerAgent.h",
+    "InspectorEmulationAgent.cpp",
+    "InspectorEmulationAgent.h",
     "InspectorFrontendClient.h",
     "InspectorHighlight.cpp",
     "InspectorHighlight.h",
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
index 77463d4..eddcc1c 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
@@ -757,6 +757,7 @@
   HeapVector<Member<Document>> documents = dom_agent_->Documents();
   for (Document* document : documents)
     UpdateActiveStyleSheets(document);
+  was_enabled_ = true;
 }
 
 Response InspectorCSSAgent::disable() {
@@ -764,6 +765,7 @@
   dom_agent_->SetDOMListener(nullptr);
   instrumenting_agents_->removeInspectorCSSAgent(this);
   state_->setBoolean(CSSAgentState::kCssAgentEnabled, false);
+  was_enabled_ = false;
   resource_content_loader_->Cancel(resource_content_loader_client_id_);
   state_->setBoolean(CSSAgentState::kRuleRecordingEnabled, false);
   SetCoverageEnabled(false);
@@ -915,8 +917,12 @@
         inherited_entries,
     Maybe<protocol::Array<protocol::CSS::CSSKeyframesRule>>*
         css_keyframes_rules) {
+  Response response = AssertEnabled();
+  if (!response.isSuccess())
+    return response;
+
   Element* element = nullptr;
-  Response response = dom_agent_->AssertElement(node_id, element);
+  response = dom_agent_->AssertElement(node_id, element);
   if (!response.isSuccess())
     return response;
 
@@ -1092,8 +1098,11 @@
     int node_id,
     Maybe<protocol::CSS::CSSStyle>* inline_style,
     Maybe<protocol::CSS::CSSStyle>* attributes_style) {
+  Response response = AssertEnabled();
+  if (!response.isSuccess())
+    return response;
   Element* element = nullptr;
-  Response response = dom_agent_->AssertElement(node_id, element);
+  response = dom_agent_->AssertElement(node_id, element);
   if (!response.isSuccess())
     return response;
 
@@ -1111,8 +1120,11 @@
     int node_id,
     std::unique_ptr<protocol::Array<protocol::CSS::CSSComputedStyleProperty>>*
         style) {
+  Response response = AssertEnabled();
+  if (!response.isSuccess())
+    return response;
   Node* node = nullptr;
-  Response response = dom_agent_->AssertNode(node_id, node);
+  response = dom_agent_->AssertNode(node_id, node);
   if (!response.isSuccess())
     return response;
 
@@ -1178,8 +1190,11 @@
     int node_id,
     std::unique_ptr<protocol::Array<protocol::CSS::PlatformFontUsage>>*
         platform_fonts) {
+  Response response = AssertEnabled();
+  if (!response.isSuccess())
+    return response;
   Node* node = nullptr;
-  Response response = dom_agent_->AssertNode(node_id, node);
+  response = dom_agent_->AssertNode(node_id, node);
   if (!response.isSuccess())
     return response;
 
@@ -1565,8 +1580,11 @@
 Response InspectorCSSAgent::forcePseudoState(
     int node_id,
     std::unique_ptr<protocol::Array<String>> forced_pseudo_classes) {
+  Response response = AssertEnabled();
+  if (!response.isSuccess())
+    return response;
   Element* element = nullptr;
-  Response response = dom_agent_->AssertElement(node_id, element);
+  response = dom_agent_->AssertElement(node_id, element);
   if (!response.isSuccess())
     return response;
 
@@ -1891,9 +1909,17 @@
   return css_style_sheet_to_inspector_style_sheet_.at(&inspector_sheet);
 }
 
+Response InspectorCSSAgent::AssertEnabled() {
+  return was_enabled_ ? Response::OK()
+                      : Response::Error("CSS agent was not enabled");
+}
+
 Response InspectorCSSAgent::AssertInspectorStyleSheetForId(
     const String& style_sheet_id,
     InspectorStyleSheet*& result) {
+  Response response = AssertEnabled();
+  if (!response.isSuccess())
+    return response;
   IdToInspectorStyleSheet::iterator it =
       id_to_inspector_style_sheet_.find(style_sheet_id);
   if (it == id_to_inspector_style_sheet_.end())
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h
index 6b381b2..81f8b8b5 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h
@@ -280,6 +280,8 @@
   InspectorStyleSheet* InspectorStyleSheetForRule(CSSStyleRule*);
 
   InspectorStyleSheet* ViaInspectorStyleSheet(Document*);
+
+  protocol::Response AssertEnabled();
   protocol::Response AssertInspectorStyleSheetForId(const String&,
                                                     InspectorStyleSheet*&);
   protocol::Response AssertStyleSheetForId(const String&,
@@ -352,6 +354,7 @@
   Member<CSSStyleSheet> inspector_user_agent_style_sheet_;
 
   int resource_content_loader_client_id_;
+  bool was_enabled_ = false;
 
   friend class InspectorResourceContentLoaderCallback;
   friend class StyleSheetBinder;
diff --git a/third_party/WebKit/Source/web/InspectorEmulationAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorEmulationAgent.cpp
similarity index 97%
rename from third_party/WebKit/Source/web/InspectorEmulationAgent.cpp
rename to third_party/WebKit/Source/core/inspector/InspectorEmulationAgent.cpp
index fdb8515..4b4ab41 100644
--- a/third_party/WebKit/Source/web/InspectorEmulationAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorEmulationAgent.cpp
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "web/InspectorEmulationAgent.h"
+#include "core/inspector/InspectorEmulationAgent.h"
 
 #include "core/exported/WebViewBase.h"
 #include "core/frame/LocalFrameView.h"
@@ -14,6 +14,7 @@
 #include "platform/geometry/DoubleRect.h"
 #include "platform/graphics/Color.h"
 #include "platform/scheduler/renderer/web_view_scheduler.h"
+#include "platform/wtf/Time.h"
 #include "public/platform/Platform.h"
 #include "public/platform/WebFloatPoint.h"
 #include "public/platform/WebThread.h"
@@ -169,8 +170,8 @@
   web_local_frame_->View()->Scheduler()->EnableVirtualTime();
 
   if (budget.isJust()) {
-    base::TimeDelta budget_amount =
-        base::TimeDelta::FromMilliseconds(budget.fromJust());
+    WTF::TimeDelta budget_amount =
+        WTF::TimeDelta::FromMilliseconds(budget.fromJust());
     web_local_frame_->View()->Scheduler()->GrantVirtualTimeBudget(
         budget_amount,
         WTF::Bind(&InspectorEmulationAgent::VirtualTimeBudgetExpired,
diff --git a/third_party/WebKit/Source/web/InspectorEmulationAgent.h b/third_party/WebKit/Source/core/inspector/InspectorEmulationAgent.h
similarity index 91%
rename from third_party/WebKit/Source/web/InspectorEmulationAgent.h
rename to third_party/WebKit/Source/core/inspector/InspectorEmulationAgent.h
index 1bed564..c9a7282 100644
--- a/third_party/WebKit/Source/web/InspectorEmulationAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorEmulationAgent.h
@@ -5,6 +5,7 @@
 #ifndef InspectorEmulationAgent_h
 #define InspectorEmulationAgent_h
 
+#include "core/CoreExport.h"
 #include "core/inspector/InspectorBaseAgent.h"
 #include "core/inspector/protocol/Emulation.h"
 
@@ -19,8 +20,9 @@
 }  // namespace DOM
 }  // namespace protocol
 
-class InspectorEmulationAgent final
-    : public InspectorBaseAgent<protocol::Emulation::Metainfo> {
+class CORE_EXPORT InspectorEmulationAgent final
+    : public NON_EXPORTED_BASE(
+          InspectorBaseAgent<protocol::Emulation::Metainfo>) {
   WTF_MAKE_NONCOPYABLE(InspectorEmulationAgent);
 
  public:
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObjectTest.cpp b/third_party/WebKit/Source/core/layout/LayoutBoxModelObjectTest.cpp
index ea4a068..00a895da 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObjectTest.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObjectTest.cpp
@@ -312,9 +312,7 @@
                 scrollable_area->GetStickyConstraintsMap().at(sticky->Layer()))
                 .Location()
                 .X());
-  ToHTMLElement(target->GetNode())
-      ->classList()
-      .add("hide", ASSERT_NO_EXCEPTION);
+  ToHTMLElement(target->GetNode())->classList().Add("hide");
   GetDocument().View()->UpdateLifecycleToLayoutClean();
   // Layout should invalidate the sticky constraints of the sticky element and
   // mark it as needing a compositing inputs update.
diff --git a/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp b/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp
index d450595..4115ba6 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp
+++ b/third_party/WebKit/Source/core/layout/line/InlineTextBox.cpp
@@ -553,7 +553,7 @@
 void InlineTextBox::PaintTextMatchMarkerForeground(
     const PaintInfo& paint_info,
     const LayoutPoint& box_origin,
-    const DocumentMarker& marker,
+    const TextMatchMarker& marker,
     const ComputedStyle& style,
     const Font& font) const {
   InlineTextBoxPainter(*this).PaintTextMatchMarkerForeground(
@@ -563,7 +563,7 @@
 void InlineTextBox::PaintTextMatchMarkerBackground(
     const PaintInfo& paint_info,
     const LayoutPoint& box_origin,
-    const DocumentMarker& marker,
+    const TextMatchMarker& marker,
     const ComputedStyle& style,
     const Font& font) const {
   InlineTextBoxPainter(*this).PaintTextMatchMarkerBackground(
diff --git a/third_party/WebKit/Source/core/layout/line/InlineTextBox.h b/third_party/WebKit/Source/core/layout/line/InlineTextBox.h
index 319a558..239e809 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineTextBox.h
+++ b/third_party/WebKit/Source/core/layout/line/InlineTextBox.h
@@ -35,6 +35,7 @@
 
 class DocumentMarker;
 class GraphicsContext;
+class TextMatchMarker;
 
 // The two truncation values below are used as tokens representing truncation
 // state for the text box, are intended to be relative to |m_start|, and are set
@@ -148,12 +149,12 @@
                                    bool grammar) const;
   virtual void PaintTextMatchMarkerForeground(const PaintInfo&,
                                               const LayoutPoint& box_origin,
-                                              const DocumentMarker&,
+                                              const TextMatchMarker&,
                                               const ComputedStyle&,
                                               const Font&) const;
   virtual void PaintTextMatchMarkerBackground(const PaintInfo&,
                                               const LayoutPoint& box_origin,
-                                              const DocumentMarker&,
+                                              const TextMatchMarker&,
                                               const ComputedStyle&,
                                               const Font&) const;
 
diff --git a/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.cpp b/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.cpp
index 9cfb2f6..6ebccb6 100644
--- a/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.cpp
@@ -242,7 +242,7 @@
 void SVGInlineTextBox::PaintTextMatchMarkerForeground(
     const PaintInfo& paint_info,
     const LayoutPoint& point,
-    const DocumentMarker& marker,
+    const TextMatchMarker& marker,
     const ComputedStyle& style,
     const Font& font) const {
   SVGInlineTextBoxPainter(*this).PaintTextMatchMarkerForeground(
@@ -252,7 +252,7 @@
 void SVGInlineTextBox::PaintTextMatchMarkerBackground(
     const PaintInfo& paint_info,
     const LayoutPoint& point,
-    const DocumentMarker& marker,
+    const TextMatchMarker& marker,
     const ComputedStyle& style,
     const Font& font) const {
   SVGInlineTextBoxPainter(*this).PaintTextMatchMarkerBackground(
diff --git a/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.h b/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.h
index c1a5603..d1fc236 100644
--- a/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.h
+++ b/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.h
@@ -27,6 +27,8 @@
 
 namespace blink {
 
+class TextMatchMarker;
+
 class SVGInlineTextBox final : public InlineTextBox {
  public:
   SVGInlineTextBox(LineLayoutItem, int start, unsigned short length);
@@ -85,12 +87,12 @@
                            bool) const final;
   void PaintTextMatchMarkerForeground(const PaintInfo&,
                                       const LayoutPoint&,
-                                      const DocumentMarker&,
+                                      const TextMatchMarker&,
                                       const ComputedStyle&,
                                       const Font&) const final;
   void PaintTextMatchMarkerBackground(const PaintInfo&,
                                       const LayoutPoint&,
-                                      const DocumentMarker&,
+                                      const TextMatchMarker&,
                                       const ComputedStyle&,
                                       const Font&) const final;
 
diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
index 2e4a3b602..0e103ea3 100644
--- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
@@ -7,6 +7,7 @@
 #include "core/editing/CompositionUnderline.h"
 #include "core/editing/Editor.h"
 #include "core/editing/markers/DocumentMarkerController.h"
+#include "core/editing/markers/TextMatchMarker.h"
 #include "core/frame/LocalFrame.h"
 #include "core/layout/LayoutTextCombine.h"
 #include "core/layout/LayoutTheme.h"
@@ -151,15 +152,6 @@
              layout_object.GetNode());
 }
 
-static bool PaintsCompositionMarkers(const LayoutObject& layout_object) {
-  return layout_object.GetNode() &&
-         layout_object.GetDocument()
-                 .Markers()
-                 .MarkersFor(layout_object.GetNode(),
-                             DocumentMarker::kComposition)
-                 .size() > 0;
-}
-
 static void PrepareContextForDecoration(
     GraphicsContext& context,
     GraphicsContextStateSaver& state_saver,
@@ -399,9 +391,7 @@
       paint_info.phase != kPaintPhaseTextClip && !is_printing) {
     PaintDocumentMarkers(paint_info, box_origin, style_to_use, font,
                          DocumentMarkerPaintPhase::kBackground);
-
-    const LayoutObject& text_box_layout_object = InlineLayoutObject();
-    if (have_selection && !PaintsCompositionMarkers(text_box_layout_object)) {
+    if (have_selection) {
       if (combined_text)
         PaintSelection<InlineTextBoxPainter::PaintOptions::kCombinedText>(
             context, box_rect, style_to_use, font, selection_style.fill_color,
@@ -677,12 +667,13 @@
                                              marker, style, font, true);
         break;
       case DocumentMarker::kTextMatch:
-        if (marker_paint_phase == DocumentMarkerPaintPhase::kBackground)
+        if (marker_paint_phase == DocumentMarkerPaintPhase::kBackground) {
           inline_text_box_.PaintTextMatchMarkerBackground(
-              paint_info, box_origin, marker, style, font);
-        else
+              paint_info, box_origin, ToTextMatchMarker(marker), style, font);
+        } else {
           inline_text_box_.PaintTextMatchMarkerForeground(
-              paint_info, box_origin, marker, style, font);
+              paint_info, box_origin, ToTextMatchMarker(marker), style, font);
+        }
         break;
       case DocumentMarker::kComposition: {
         CompositionUnderline underline(marker.StartOffset(), marker.EndOffset(),
@@ -1120,7 +1111,7 @@
 void InlineTextBoxPainter::PaintTextMatchMarkerForeground(
     const PaintInfo& paint_info,
     const LayoutPoint& box_origin,
-    const DocumentMarker& marker,
+    const TextMatchMarker& marker,
     const ComputedStyle& style,
     const Font& font) {
   if (!InlineLayoutObject()
@@ -1162,7 +1153,7 @@
 void InlineTextBoxPainter::PaintTextMatchMarkerBackground(
     const PaintInfo& paint_info,
     const LayoutPoint& box_origin,
-    const DocumentMarker& marker,
+    const TextMatchMarker& marker,
     const ComputedStyle& style,
     const Font& font) {
   if (!LineLayoutAPIShim::LayoutObjectFrom(inline_text_box_.GetLineLayoutItem())
diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.h b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.h
index b6560c1..5194d87 100644
--- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.h
+++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.h
@@ -23,6 +23,7 @@
 class LayoutObject;
 class LayoutPoint;
 class LayoutTextCombine;
+class TextMatchMarker;
 
 enum class DocumentMarkerPaintPhase { kForeground, kBackground };
 
@@ -47,12 +48,12 @@
                            bool grammar);
   void PaintTextMatchMarkerForeground(const PaintInfo&,
                                       const LayoutPoint& box_origin,
-                                      const DocumentMarker&,
+                                      const TextMatchMarker&,
                                       const ComputedStyle&,
                                       const Font&);
   void PaintTextMatchMarkerBackground(const PaintInfo&,
                                       const LayoutPoint& box_origin,
-                                      const DocumentMarker&,
+                                      const TextMatchMarker&,
                                       const ComputedStyle&,
                                       const Font&);
 
diff --git a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp
index 3d1c30e..1af0b67 100644
--- a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp
@@ -4,8 +4,10 @@
 
 #include "core/paint/SVGInlineTextBoxPainter.h"
 
+#include <memory>
 #include "core/editing/Editor.h"
 #include "core/editing/markers/DocumentMarkerController.h"
+#include "core/editing/markers/TextMatchMarker.h"
 #include "core/frame/LocalFrame.h"
 #include "core/layout/LayoutTheme.h"
 #include "core/layout/api/LineLayoutAPIShim.h"
@@ -22,7 +24,6 @@
 #include "core/style/AppliedTextDecoration.h"
 #include "core/style/ShadowList.h"
 #include "platform/graphics/GraphicsContextStateSaver.h"
-#include <memory>
 
 namespace blink {
 
@@ -592,7 +593,7 @@
 void SVGInlineTextBoxPainter::PaintTextMatchMarkerForeground(
     const PaintInfo& paint_info,
     const LayoutPoint& point,
-    const DocumentMarker& marker,
+    const TextMatchMarker& marker,
     const ComputedStyle& style,
     const Font& font) {
   const Vector<SVGTextFragmentWithRange> text_match_info_list =
@@ -634,7 +635,7 @@
 void SVGInlineTextBoxPainter::PaintTextMatchMarkerBackground(
     const PaintInfo& paint_info,
     const LayoutPoint& point,
-    const DocumentMarker& marker,
+    const TextMatchMarker& marker,
     const ComputedStyle& style,
     const Font& font) {
   const Vector<SVGTextFragmentWithRange> text_match_info_list =
diff --git a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.h b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.h
index 950fd85d..cea1799 100644
--- a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.h
+++ b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.h
@@ -11,6 +11,7 @@
 
 namespace blink {
 
+class DocumentMarker;
 class Font;
 struct PaintInfo;
 class LayoutPoint;
@@ -18,8 +19,8 @@
 class ComputedStyle;
 class SVGInlineTextBox;
 struct SVGTextFragment;
+class TextMatchMarker;
 class TextRun;
-class DocumentMarker;
 
 struct SVGTextFragmentWithRange {
   SVGTextFragmentWithRange(const SVGTextFragment& fragment,
@@ -43,12 +44,12 @@
   void PaintSelectionBackground(const PaintInfo&);
   void PaintTextMatchMarkerForeground(const PaintInfo&,
                                       const LayoutPoint&,
-                                      const DocumentMarker&,
+                                      const TextMatchMarker&,
                                       const ComputedStyle&,
                                       const Font&);
   void PaintTextMatchMarkerBackground(const PaintInfo&,
                                       const LayoutPoint&,
-                                      const DocumentMarker&,
+                                      const TextMatchMarker&,
                                       const ComputedStyle&,
                                       const Font&);
 
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index 2e37d8a..3c48cb7 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -1740,15 +1740,6 @@
     SET_VAR(rare_non_inherited_data_, user_drag_, d);
   }
 
-  // -webkit-user-modify
-  static EUserModify InitialUserModify() { return EUserModify::kReadOnly; }
-  EUserModify UserModify() const {
-    return static_cast<EUserModify>(rare_inherited_data_->user_modify_);
-  }
-  void SetUserModify(EUserModify u) {
-    SET_VAR(rare_inherited_data_, user_modify_, static_cast<unsigned>(u));
-  }
-
   // caret-color
   void SetCaretColor(const StyleAutoColor& color) {
     SET_VAR(rare_inherited_data_, caret_color_, color.Resolve(Color()));
diff --git a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
index d88b7e7d..be6ea14 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
@@ -171,10 +171,6 @@
 };
 enum EFlexWrap { kFlexNoWrap, kFlexWrap, kFlexWrapReverse };
 
-// CSS3 User Modify Properties
-
-enum class EUserModify { kReadOnly, kReadWrite, kReadWritePlaintextOnly };
-
 // CSS3 User Drag Values
 
 enum EUserDrag { DRAG_AUTO, DRAG_NONE, DRAG_ELEMENT };
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index 2ff584b..10f2767 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -65,6 +65,7 @@
 #include "core/editing/iterators/TextIterator.h"
 #include "core/editing/markers/DocumentMarker.h"
 #include "core/editing/markers/DocumentMarkerController.h"
+#include "core/editing/markers/TextMatchMarker.h"
 #include "core/editing/serializers/Serialization.h"
 #include "core/editing/spellcheck/IdleSpellCheckCallback.h"
 #include "core/editing/spellcheck/SpellCheckRequester.h"
@@ -964,7 +965,7 @@
 
   unsigned active_marker_count = 0;
   for (const auto& marker : markers) {
-    if (marker->IsActiveMatch())
+    if (ToTextMatchMarker(marker)->IsActiveMatch())
       active_marker_count++;
   }
 
diff --git a/third_party/WebKit/Source/devtools/BUILD.gn b/third_party/WebKit/Source/devtools/BUILD.gn
index 54af3f8..335b3f4 100644
--- a/third_party/WebKit/Source/devtools/BUILD.gn
+++ b/third_party/WebKit/Source/devtools/BUILD.gn
@@ -127,7 +127,6 @@
   "front_end/common/Worker.js",
   "front_end/components/breakpointsList.css",
   "front_end/components/BreakpointsSidebarPaneBase.js",
-  "front_end/components/CPUThrottlingManager.js",
   "front_end/components/DataSaverInfobar.js",
   "front_end/components/DockController.js",
   "front_end/components/DOMBreakpointsSidebarPane.js",
@@ -307,6 +306,11 @@
   "front_end/main/RequestAppBannerActionDelegate.js",
   "front_end/main/SimpleApp.js",
   "front_end/main/targetCrashedScreen.css",
+  "front_end/mobile_throttling/CPUThrottlingManager.js",
+  "front_end/mobile_throttling/module.json",
+  "front_end/mobile_throttling/NetworkConditionsSelector.js",
+  "front_end/mobile_throttling/networkConditionsSettingsTab.css",
+  "front_end/mobile_throttling/NetworkConditionsSettingsTab.js",
   "front_end/network/blockedURLsPane.css",
   "front_end/network/BlockedURLsPane.js",
   "front_end/network/eventSourceMessagesView.css",
@@ -346,12 +350,11 @@
   "front_end/network/xmlTree.css",
   "front_end/network/xmlView.css",
   "front_end/network/XMLView.js",
-  "front_end/network_conditions/module.json",
-  "front_end/network_conditions/NetworkConditionsSelector.js",
-  "front_end/network_conditions/networkConditionsSettingsTab.css",
   "front_end/network_log/HAREntry.js",
   "front_end/network_log/module.json",
   "front_end/network_log/NetworkLog.js",
+  "front_end/network_priorities/module.json",
+  "front_end/network_priorities/NetworkPriorities.js",
   "front_end/object_ui/customPreviewComponent.css",
   "front_end/object_ui/CustomPreviewComponent.js",
   "front_end/object_ui/JavaScriptAutocomplete.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/Tests.js b/third_party/WebKit/Source/devtools/front_end/Tests.js
index 69f72fd..5ce03ea 100644
--- a/third_party/WebKit/Source/devtools/front_end/Tests.js
+++ b/third_party/WebKit/Source/devtools/front_end/Tests.js
@@ -697,19 +697,19 @@
 
     function step1() {
       testPreset(
-          NetworkConditions.NetworkConditionsSelector.presets[0],
+          MobileThrottling.NetworkConditionsSelector.presets[0],
           ['offline event: online = false', 'connection change event: type = none; downlinkMax = 0'], step2);
     }
 
     function step2() {
       testPreset(
-          NetworkConditions.NetworkConditionsSelector.presets[1],
+          MobileThrottling.NetworkConditionsSelector.presets[1],
           ['online event: online = true', 'connection change event: type = cellular; downlinkMax = 0.390625'], step3);
     }
 
     function step3() {
       testPreset(
-          NetworkConditions.NetworkConditionsSelector.presets[2],
+          MobileThrottling.NetworkConditionsSelector.presets[2],
           ['connection change event: type = cellular; downlinkMax = 1.4400000000000002'],
           test.releaseControl.bind(test));
     }
diff --git a/third_party/WebKit/Source/devtools/front_end/components/module.json b/third_party/WebKit/Source/devtools/front_end/components/module.json
index 73db852..99999d2e 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/components/module.json
@@ -9,7 +9,9 @@
         },
         {
             "type": "@UI.ContextMenu.Provider",
-            "contextTypes": [ "SDK.DOMNode" ],
+            "contextTypes": [
+                "SDK.DOMNode"
+            ],
             "className": "Components.DOMBreakpointsSidebarPane.ContextMenuProvider"
         },
         {
@@ -46,7 +48,6 @@
     ],
     "scripts": [
         "BreakpointsSidebarPaneBase.js",
-        "CPUThrottlingManager.js",
         "DataSaverInfobar.js",
         "DOMBreakpointsSidebarPane.js",
         "DOMPresentationUtils.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeToolbar.js b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeToolbar.js
index 7ec9c67f..0aefce0 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeToolbar.js
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeToolbar.js
@@ -188,7 +188,7 @@
    * @param {!UI.Toolbar} toolbar
    */
   _fillOptionsToolbar(toolbar) {
-    this._networkConditionsItem = NetworkConditions.NetworkConditionsSelector.createToolbarMenuButton();
+    this._networkConditionsItem = MobileThrottling.NetworkConditionsSelector.createToolbarMenuButton();
     this._networkConditionsItem.setVisible(this._showNetworkConditionsSetting.get());
     this._networkConditionsItem.setTitle(Common.UIString('Network throttling'));
     this._networkConditionsItem.element.style.maxWidth = '140px';
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/module.json b/third_party/WebKit/Source/devtools/front_end/emulation/module.json
index 254857c..b480ea0f 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/module.json
@@ -150,7 +150,7 @@
         "components",
         "platform",
         "ui",
-        "network_conditions"
+        "mobile_throttling"
     ],
     "scripts": [
         "AdvancedApp.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/inspector.json b/third_party/WebKit/Source/devtools/front_end/inspector.json
index 21a943af..956b443e 100644
--- a/third_party/WebKit/Source/devtools/front_end/inspector.json
+++ b/third_party/WebKit/Source/devtools/front_end/inspector.json
@@ -52,7 +52,6 @@
         { "name": "color_picker" },
         { "name": "data_grid" },
         { "name": "heap_snapshot_model" },
-        { "name": "network_conditions", "type": "autostart"},
         { "name": "event_listeners" },
         { "name": "object_ui"},
         { "name": "help", "type": "autostart"},
@@ -60,7 +59,9 @@
         { "name": "console_model", "type": "autostart"},
         { "name": "network_log", "type": "autostart"},
         { "name": "text_utils", "type": "autostart"},
-        { "name": "changes"}
+        { "name": "changes"},
+        { "name": "mobile_throttling", "type": "autostart"},
+        { "name": "network_priorities"}
     ],
 
     "has_html": true
diff --git a/third_party/WebKit/Source/devtools/front_end/components/CPUThrottlingManager.js b/third_party/WebKit/Source/devtools/front_end/mobile_throttling/CPUThrottlingManager.js
similarity index 91%
rename from third_party/WebKit/Source/devtools/front_end/components/CPUThrottlingManager.js
rename to third_party/WebKit/Source/devtools/front_end/mobile_throttling/CPUThrottlingManager.js
index 40a9110..412e9e9fe 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/CPUThrottlingManager.js
+++ b/third_party/WebKit/Source/devtools/front_end/mobile_throttling/CPUThrottlingManager.js
@@ -5,7 +5,7 @@
 /**
  * @implements {SDK.SDKModelObserver<!SDK.EmulationModel>}
  */
-Components.CPUThrottlingManager = class extends Common.Object {
+MobileThrottling.CPUThrottlingManager = class extends Common.Object {
   constructor() {
     super();
     this._throttlingRate = 1;  // No throttling
@@ -31,7 +31,7 @@
     for (var control of this._controls)
       control.setSelectedIndex(index);
     UI.inspectorView.setPanelIcon('timeline', icon);
-    this.dispatchEventToListeners(Components.CPUThrottlingManager.Events.RateChanged);
+    this.dispatchEventToListeners(MobileThrottling.CPUThrottlingManager.Events.RateChanged);
   }
 
   /**
@@ -85,6 +85,6 @@
 };
 
 /** @enum {symbol} */
-Components.CPUThrottlingManager.Events = {
+MobileThrottling.CPUThrottlingManager.Events = {
   RateChanged: Symbol('RateChanged')
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/network_conditions/NetworkConditionsSelector.js b/third_party/WebKit/Source/devtools/front_end/mobile_throttling/NetworkConditionsSelector.js
similarity index 89%
rename from third_party/WebKit/Source/devtools/front_end/network_conditions/NetworkConditionsSelector.js
rename to third_party/WebKit/Source/devtools/front_end/mobile_throttling/NetworkConditionsSelector.js
index a99c6a2..3c25698 100644
--- a/third_party/WebKit/Source/devtools/front_end/network_conditions/NetworkConditionsSelector.js
+++ b/third_party/WebKit/Source/devtools/front_end/mobile_throttling/NetworkConditionsSelector.js
@@ -4,9 +4,9 @@
 /**
  * @unrestricted
  */
-NetworkConditions.NetworkConditionsSelector = class {
+MobileThrottling.NetworkConditionsSelector = class {
   /**
-   * @param {function(!Array<!NetworkConditions.NetworkConditionsGroup>):!Array<?SDK.NetworkManager.Conditions>} populateCallback
+   * @param {function(!Array<!MobileThrottling.NetworkConditionsGroup>):!Array<?SDK.NetworkManager.Conditions>} populateCallback
    * @param {function(number)} selectCallback
    */
   constructor(populateCallback, selectCallback) {
@@ -42,11 +42,11 @@
    */
   static decorateSelect(selectElement) {
     var options = [];
-    var selector = new NetworkConditions.NetworkConditionsSelector(populate, select);
+    var selector = new MobileThrottling.NetworkConditionsSelector(populate, select);
     selectElement.addEventListener('change', optionSelected, false);
 
     /**
-     * @param {!Array.<!NetworkConditions.NetworkConditionsGroup>} groups
+     * @param {!Array.<!MobileThrottling.NetworkConditionsGroup>} groups
      * @return {!Array<?SDK.NetworkManager.Conditions>}
      */
     function populate(groups) {
@@ -97,7 +97,7 @@
     /** @type {!Array<?SDK.NetworkManager.Conditions>} */
     var options = [];
     var selectedIndex = -1;
-    var selector = new NetworkConditions.NetworkConditionsSelector(populate, select);
+    var selector = new MobileThrottling.NetworkConditionsSelector(populate, select);
     return button;
 
     /**
@@ -118,7 +118,7 @@
     }
 
     /**
-     * @param {!Array.<!NetworkConditions.NetworkConditionsGroup>} groups
+     * @param {!Array.<!MobileThrottling.NetworkConditionsGroup>} groups
      * @return {!Array<?SDK.NetworkManager.Conditions>}
      */
     function populate(groups) {
@@ -152,12 +152,12 @@
 
     function forceOffline() {
       if (checkbox.checked()) {
-        NetworkConditions.NetworkConditionsSelector._lastNetworkConditions =
+        MobileThrottling.NetworkConditionsSelector._lastNetworkConditions =
             SDK.multitargetNetworkManager.networkConditions();
         SDK.multitargetNetworkManager.setNetworkConditions(SDK.NetworkManager.OfflineConditions);
       } else {
         SDK.multitargetNetworkManager.setNetworkConditions(
-            NetworkConditions.NetworkConditionsSelector._lastNetworkConditions);
+            MobileThrottling.NetworkConditionsSelector._lastNetworkConditions);
       }
     }
 
@@ -170,7 +170,7 @@
 
   _populateOptions() {
     var customGroup = {title: Common.UIString('Custom'), items: this._customSetting.get()};
-    var presetsGroup = {title: Common.UIString('Presets'), items: NetworkConditions.NetworkConditionsSelector.presets};
+    var presetsGroup = {title: Common.UIString('Presets'), items: MobileThrottling.NetworkConditionsSelector.presets};
     var disabledGroup = {title: Common.UIString('Disabled'), items: [SDK.NetworkManager.NoThrottlingConditions]};
     this._options = this._populateCallback([disabledGroup, presetsGroup, customGroup]);
     if (!this._conditionsChanged()) {
@@ -213,11 +213,11 @@
 };
 
 /** @typedef {!{title: string, items: !Array<!SDK.NetworkManager.Conditions>}} */
-NetworkConditions.NetworkConditionsGroup;
+MobileThrottling.NetworkConditionsGroup;
 
 
 /** @type {!Array.<!SDK.NetworkManager.Conditions>} */
-NetworkConditions.NetworkConditionsSelector.presets = [
+MobileThrottling.NetworkConditionsSelector.presets = [
   SDK.NetworkManager.OfflineConditions,
   {title: 'Slow 3G', download: 500 * 1024 / 8 * .8, upload: 500 * 1024 / 8 * .8, latency: 400 * 5},
   {title: 'Fast 3G', download: 1.6 * 1024 * 1024 / 8 * .9, upload: 750 * 1024 / 8 * .9, latency: 150 * 3.75}
@@ -227,7 +227,7 @@
  * @implements {UI.ActionDelegate}
  * @unrestricted
  */
-NetworkConditions.NetworkConditionsActionDelegate = class {
+MobileThrottling.NetworkConditionsActionDelegate = class {
   /**
    * @override
    * @param {!UI.Context} context
diff --git a/third_party/WebKit/Source/devtools/front_end/network_conditions/NetworkConditionsSettingsTab.js b/third_party/WebKit/Source/devtools/front_end/mobile_throttling/NetworkConditionsSettingsTab.js
similarity index 94%
rename from third_party/WebKit/Source/devtools/front_end/network_conditions/NetworkConditionsSettingsTab.js
rename to third_party/WebKit/Source/devtools/front_end/mobile_throttling/NetworkConditionsSettingsTab.js
index 350899f..a8a86fc1 100644
--- a/third_party/WebKit/Source/devtools/front_end/network_conditions/NetworkConditionsSettingsTab.js
+++ b/third_party/WebKit/Source/devtools/front_end/mobile_throttling/NetworkConditionsSettingsTab.js
@@ -6,10 +6,10 @@
  * @implements {UI.ListWidget.Delegate}
  * @unrestricted
  */
-NetworkConditions.NetworkConditionsSettingsTab = class extends UI.VBox {
+MobileThrottling.NetworkConditionsSettingsTab = class extends UI.VBox {
   constructor() {
     super(true);
-    this.registerRequiredCSS('network_conditions/networkConditionsSettingsTab.css');
+    this.registerRequiredCSS('mobile_throttling/networkConditionsSettingsTab.css');
 
     this.contentElement.createChild('div', 'header').textContent = Common.UIString('Network Throttling Profiles');
 
@@ -19,7 +19,7 @@
 
     this._list = new UI.ListWidget(this);
     this._list.element.classList.add('conditions-list');
-    this._list.registerRequiredCSS('network_conditions/networkConditionsSettingsTab.css');
+    this._list.registerRequiredCSS('mobile_throttling/networkConditionsSettingsTab.css');
     this._list.show(this.contentElement);
 
     this._customSetting = Common.moduleSetting('customNetworkConditions');
@@ -66,10 +66,10 @@
     titleText.title = conditions.title;
     element.createChild('div', 'conditions-list-separator');
     element.createChild('div', 'conditions-list-text').textContent =
-        NetworkConditions.NetworkConditionsSelector.throughputText(conditions.download);
+        MobileThrottling.NetworkConditionsSelector.throughputText(conditions.download);
     element.createChild('div', 'conditions-list-separator');
     element.createChild('div', 'conditions-list-text').textContent =
-        NetworkConditions.NetworkConditionsSelector.throughputText(conditions.upload);
+        MobileThrottling.NetworkConditionsSelector.throughputText(conditions.upload);
     element.createChild('div', 'conditions-list-separator');
     element.createChild('div', 'conditions-list-text').textContent = Common.UIString('%dms', conditions.latency);
     return element;
diff --git a/third_party/WebKit/Source/devtools/front_end/network_conditions/module.json b/third_party/WebKit/Source/devtools/front_end/mobile_throttling/module.json
similarity index 81%
rename from third_party/WebKit/Source/devtools/front_end/network_conditions/module.json
rename to third_party/WebKit/Source/devtools/front_end/mobile_throttling/module.json
index 2fcea456..3c83425 100644
--- a/third_party/WebKit/Source/devtools/front_end/network_conditions/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/mobile_throttling/module.json
@@ -11,7 +11,7 @@
             "actionId": "network-conditions.network-offline",
             "category": "Network",
             "title": "Go offline",
-            "className": "NetworkConditions.NetworkConditionsActionDelegate",
+            "className": "MobileThrottling.NetworkConditionsActionDelegate",
             "tags": "device"
         },
         {
@@ -19,7 +19,7 @@
             "actionId": "network-conditions.network-online",
             "category": "Network",
             "title": "Go online",
-            "className": "NetworkConditions.NetworkConditionsActionDelegate",
+            "className": "MobileThrottling.NetworkConditionsActionDelegate",
             "tags": "device"
         },
         {
@@ -28,7 +28,7 @@
             "id": "network-conditions",
             "title": "Throttling",
             "order": "35",
-            "className": "NetworkConditions.NetworkConditionsSettingsTab",
+            "className": "MobileThrottling.NetworkConditionsSettingsTab",
             "settings": [
                 "customNetworkConditions"
             ]
@@ -43,7 +43,7 @@
     "scripts": [
         "NetworkConditionsSelector.js",
         "NetworkConditionsSettingsTab.js",
-        "NetworkPriorities.js"
+        "CPUThrottlingManager.js"
     ],
     "resources": [
         "networkConditionsSettingsTab.css"
diff --git a/third_party/WebKit/Source/devtools/front_end/network_conditions/networkConditionsSettingsTab.css b/third_party/WebKit/Source/devtools/front_end/mobile_throttling/networkConditionsSettingsTab.css
similarity index 100%
rename from third_party/WebKit/Source/devtools/front_end/network_conditions/networkConditionsSettingsTab.css
rename to third_party/WebKit/Source/devtools/front_end/mobile_throttling/networkConditionsSettingsTab.css
diff --git a/third_party/WebKit/Source/devtools/front_end/network/FilterSuggestionBuilder.js b/third_party/WebKit/Source/devtools/front_end/network/FilterSuggestionBuilder.js
index 72cea82..cbda72f 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/FilterSuggestionBuilder.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/FilterSuggestionBuilder.js
@@ -89,11 +89,11 @@
       result = [];
       /** @type {!Map<number, !Protocol.Network.ResourcePriority>} */
       var numericToPriorityMap = new Map();
-      NetworkConditions.prioritySymbolToNumericMap().forEach((value, key) => numericToPriorityMap.set(value, key));
+      NetworkPriorities.prioritySymbolToNumericMap().forEach((value, key) => numericToPriorityMap.set(value, key));
       var sortedNumericPriorities = numericToPriorityMap.keysArray();
       sortedNumericPriorities.sortNumbers();
       var sortedPriorities = sortedNumericPriorities.map(value => numericToPriorityMap.get(value));
-      var sortedPriorityLabels = sortedPriorities.map(value => NetworkConditions.uiLabelForPriority(value));
+      var sortedPriorityLabels = sortedPriorities.map(value => NetworkPriorities.uiLabelForPriority(value));
 
       for (var value of sortedPriorityLabels) {
         if (!resultSet.has(value))
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkConfigView.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkConfigView.js
index 4aadd93f..ffe44a9 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkConfigView.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkConfigView.js
@@ -113,7 +113,7 @@
 
   _createNetworkThrottlingSection() {
     var section = this._createSection(Common.UIString('Network throttling'), 'network-config-throttling');
-    NetworkConditions.NetworkConditionsSelector.decorateSelect(
+    MobileThrottling.NetworkConditionsSelector.decorateSelect(
         /** @type {!HTMLSelectElement} */ (section.createChild('select', 'chrome-select')));
   }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkDataGridNode.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkDataGridNode.js
index 659c86b..48ce10c 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkDataGridNode.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkDataGridNode.js
@@ -487,7 +487,7 @@
     var bRequest = b.requestOrFirstKnownChildRequest();
     if (!aRequest || !bRequest)
       return !aRequest ? -1 : 1;
-    var priorityMap = NetworkConditions.prioritySymbolToNumericMap();
+    var priorityMap = NetworkPriorities.prioritySymbolToNumericMap();
     var aPriority = aRequest.initialPriority();
     var aScore = aPriority ? priorityMap.get(aPriority) : 0;
     aScore = aScore || 0;
@@ -765,7 +765,7 @@
         break;
       case 'priority':
         var priority = this._request.initialPriority();
-        this._setTextAndTitle(cell, priority ? NetworkConditions.uiLabelForPriority(priority) : '');
+        this._setTextAndTitle(cell, priority ? NetworkPriorities.uiLabelForPriority(priority) : '');
         break;
       case 'connectionid':
         this._setTextAndTitle(cell, this._request.connectionId);
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js
index 7fbfb92..953a544 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js
@@ -1007,7 +1007,7 @@
     var priority = request.initialPriority();
     if (priority) {
       this._suggestionBuilder.addItem(
-          Network.NetworkLogView.FilterType.Priority, NetworkConditions.uiLabelForPriority(priority));
+          Network.NetworkLogView.FilterType.Priority, NetworkPriorities.uiLabelForPriority(priority));
     }
 
     if (request.mixedContentType !== 'none') {
@@ -1543,7 +1543,7 @@
         return Network.NetworkLogView._requestSetCookieValueFilter.bind(null, value);
 
       case Network.NetworkLogView.FilterType.Priority:
-        return Network.NetworkLogView._requestPriorityFilter.bind(null, NetworkConditions.uiLabelToPriority(value));
+        return Network.NetworkLogView._requestPriorityFilter.bind(null, NetworkPriorities.uiLabelToPriority(value));
 
       case Network.NetworkLogView.FilterType.StatusCode:
         return Network.NetworkLogView._statusCodeFilter.bind(null, value);
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js
index 8e5b408..21e4f43 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js
@@ -185,7 +185,7 @@
     this._panelToolbar.appendToolbarItem(this._disableCacheCheckbox);
 
     this._panelToolbar.appendSeparator();
-    this._panelToolbar.appendToolbarItem(NetworkConditions.NetworkConditionsSelector.createOfflineToolbarCheckbox());
+    this._panelToolbar.appendToolbarItem(MobileThrottling.NetworkConditionsSelector.createOfflineToolbarCheckbox());
     this._panelToolbar.appendToolbarItem(this._createNetworkConditionsSelect());
 
     this._panelToolbar.appendToolbarItem(new UI.ToolbarItem(this._progressBarContainer));
@@ -197,7 +197,7 @@
   _createNetworkConditionsSelect() {
     var toolbarItem = new UI.ToolbarComboBox(null);
     toolbarItem.setMaxWidth(140);
-    NetworkConditions.NetworkConditionsSelector.decorateSelect(toolbarItem.selectElement());
+    MobileThrottling.NetworkConditionsSelector.decorateSelect(toolbarItem.selectElement());
     return toolbarItem;
   }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/network/module.json b/third_party/WebKit/Source/devtools/front_end/network/module.json
index 3fdbc06..711d4c4f 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/network/module.json
@@ -139,10 +139,11 @@
         "perf_ui",
         "cookie_table",
         "data_grid",
-        "network_conditions",
         "object_ui",
         "network_log",
-        "product_registry"
+        "product_registry",
+        "mobile_throttling",
+        "network_priorities"
     ],
     "scripts": [
         "BlockedURLsPane.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/network_conditions/NetworkPriorities.js b/third_party/WebKit/Source/devtools/front_end/network_priorities/NetworkPriorities.js
similarity index 71%
rename from third_party/WebKit/Source/devtools/front_end/network_conditions/NetworkPriorities.js
rename to third_party/WebKit/Source/devtools/front_end/network_priorities/NetworkPriorities.js
index 6f7a6702..8893f4b 100644
--- a/third_party/WebKit/Source/devtools/front_end/network_conditions/NetworkPriorities.js
+++ b/third_party/WebKit/Source/devtools/front_end/network_priorities/NetworkPriorities.js
@@ -6,8 +6,8 @@
  * @param {!Protocol.Network.ResourcePriority} priority
  * @return {string}
  */
-NetworkConditions.uiLabelForPriority = function(priority) {
-  var map = NetworkConditions.priorityUiLabelMap();
+NetworkPriorities.uiLabelForPriority = function(priority) {
+  var map = NetworkPriorities.priorityUiLabelMap();
   return map.get(priority) || '';
 };
 
@@ -15,25 +15,25 @@
  * @param {string} priorityLabel
  * @return {string}
  */
-NetworkConditions.uiLabelToPriority = function(priorityLabel) {
+NetworkPriorities.uiLabelToPriority = function(priorityLabel) {
   /** @type {!Map<string, !Protocol.Network.ResourcePriority>} */
-  var labelToPriorityMap = NetworkConditions.uiLabelToPriority._uiLabelToPriorityMap;
+  var labelToPriorityMap = NetworkPriorities.uiLabelToPriority._uiLabelToPriorityMap;
 
   if (labelToPriorityMap)
     return labelToPriorityMap.get(priorityLabel);
 
   labelToPriorityMap = new Map();
-  NetworkConditions.priorityUiLabelMap().forEach((value, key) => labelToPriorityMap.set(value, key));
-  NetworkConditions.uiLabelToPriority._uiLabelToPriorityMap = labelToPriorityMap;
+  NetworkPriorities.priorityUiLabelMap().forEach((value, key) => labelToPriorityMap.set(value, key));
+  NetworkPriorities.uiLabelToPriority._uiLabelToPriorityMap = labelToPriorityMap;
   return labelToPriorityMap.get(priorityLabel) || '';
 };
 
 /**
  * @return {!Map<!Protocol.Network.ResourcePriority, string>}
  */
-NetworkConditions.priorityUiLabelMap = function() {
+NetworkPriorities.priorityUiLabelMap = function() {
   /** @type {!Map<!Protocol.Network.ResourcePriority, string>} */
-  var map = NetworkConditions.priorityUiLabelMap._priorityUiLabelMap;
+  var map = NetworkPriorities.priorityUiLabelMap._priorityUiLabelMap;
 
   if (map)
     return map;
@@ -44,7 +44,7 @@
   map.set(Protocol.Network.ResourcePriority.Medium, Common.UIString('Medium'));
   map.set(Protocol.Network.ResourcePriority.High, Common.UIString('High'));
   map.set(Protocol.Network.ResourcePriority.VeryHigh, Common.UIString('Highest'));
-  NetworkConditions.priorityUiLabelMap._priorityUiLabelMap = map;
+  NetworkPriorities.priorityUiLabelMap._priorityUiLabelMap = map;
 
   return map;
 };
@@ -52,9 +52,9 @@
 /**
  * @return {!Map<!Protocol.Network.ResourcePriority, number>}
  */
-NetworkConditions.prioritySymbolToNumericMap = function() {
+NetworkPriorities.prioritySymbolToNumericMap = function() {
   /** @type {!Map<!Protocol.Network.ResourcePriority, number>} */
-  var priorityMap = NetworkConditions.prioritySymbolToNumericMap._symbolicToNumericPriorityMap;
+  var priorityMap = NetworkPriorities.prioritySymbolToNumericMap._symbolicToNumericPriorityMap;
 
   if (priorityMap)
     return priorityMap;
@@ -65,7 +65,7 @@
   priorityMap.set(Protocol.Network.ResourcePriority.Medium, 3);
   priorityMap.set(Protocol.Network.ResourcePriority.High, 4);
   priorityMap.set(Protocol.Network.ResourcePriority.VeryHigh, 5);
-  NetworkConditions.prioritySymbolToNumericMap._symbolicToNumericPriorityMap = priorityMap;
+  NetworkPriorities.prioritySymbolToNumericMap._symbolicToNumericPriorityMap = priorityMap;
 
   return priorityMap;
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/network_priorities/module.json b/third_party/WebKit/Source/devtools/front_end/network_priorities/module.json
new file mode 100644
index 0000000..2be531a
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/network_priorities/module.json
@@ -0,0 +1,9 @@
+{
+    "dependencies": [
+        "common",
+        "protocol"
+    ],
+    "scripts": [
+        "NetworkPriorities.js"
+    ]
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkersView.js b/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkersView.js
index bf07b15..1cc1c694 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkersView.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkersView.js
@@ -18,7 +18,7 @@
     /** @type {!Map<!SDK.ServiceWorkerRegistration, !Resources.ServiceWorkersView.Section>} */
     this._sections = new Map();
 
-    this._toolbar.appendToolbarItem(NetworkConditions.NetworkConditionsSelector.createOfflineToolbarCheckbox());
+    this._toolbar.appendToolbarItem(MobileThrottling.NetworkConditionsSelector.createOfflineToolbarCheckbox());
     var updateOnReloadSetting = Common.settings.createSetting('serviceWorkerUpdateOnReload', false);
     updateOnReloadSetting.setTitle(Common.UIString('Update on reload'));
     var forceUpdate = new UI.ToolbarSettingCheckbox(
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/module.json b/third_party/WebKit/Source/devtools/front_end/resources/module.json
index 99e22449..484ce12 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/resources/module.json
@@ -22,8 +22,8 @@
         "inline_editor",
         "data_grid",
         "components",
-        "network_conditions",
-        "object_ui"
+        "object_ui",
+        "mobile_throttling"
     ],
     "scripts": [
         "ApplicationCacheModel.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartNetworkDataProvider.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartNetworkDataProvider.js
index 60c966bd..36b2b4b 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartNetworkDataProvider.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartNetworkDataProvider.js
@@ -287,7 +287,7 @@
     if (typeof request.priority === 'string') {
       var div = contents.createChild('span');
       div.textContent =
-          NetworkConditions.uiLabelForPriority(/** @type {!Protocol.Network.ResourcePriority} */ (request.priority));
+          NetworkPriorities.uiLabelForPriority(/** @type {!Protocol.Network.ResourcePriority} */ (request.priority));
       div.style.color = this._colorForPriority(request.priority) || 'black';
     }
     contents.createChild('span').textContent = request.url.trimMiddle(maxURLChars);
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
index faa7317b..5a5dd7b9 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
@@ -71,7 +71,7 @@
     /** @type {?Timeline.PerformanceModel} */
     this._pendingPerformanceModel = null;
 
-    this._cpuThrottlingManager = new Components.CPUThrottlingManager();
+    this._cpuThrottlingManager = new MobileThrottling.CPUThrottlingManager();
 
     this._viewModeSetting =
         Common.settings.createSetting('timelineViewMode', Timeline.TimelinePanel.ViewMode.FlameChart);
@@ -260,7 +260,7 @@
     SDK.multitargetNetworkManager.addEventListener(
         SDK.MultitargetNetworkManager.Events.ConditionsChanged, this._updateShowSettingsToolbarButton, this);
     this._cpuThrottlingManager.addEventListener(
-        Components.CPUThrottlingManager.Events.RateChanged, this._updateShowSettingsToolbarButton, this);
+        MobileThrottling.CPUThrottlingManager.Events.RateChanged, this._updateShowSettingsToolbarButton, this);
     this._disableCaptureJSProfileSetting.addChangeListener(this._updateShowSettingsToolbarButton, this);
     this._captureLayersAndPicturesSetting.addChangeListener(this._updateShowSettingsToolbarButton, this);
 
@@ -324,7 +324,7 @@
   _createNetworkConditionsSelect() {
     var toolbarItem = new UI.ToolbarComboBox(null);
     toolbarItem.setMaxWidth(140);
-    NetworkConditions.NetworkConditionsSelector.decorateSelect(toolbarItem.selectElement());
+    MobileThrottling.NetworkConditionsSelector.decorateSelect(toolbarItem.selectElement());
     return toolbarItem;
   }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
index 51044fd..b475dd5 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
@@ -825,7 +825,7 @@
         if (eventData['mimeType'])
           contentHelper.appendTextRow(Common.UIString('MIME Type'), eventData['mimeType']);
         if ('priority' in eventData) {
-          var priority = NetworkConditions.uiLabelForPriority(eventData['priority']);
+          var priority = NetworkPriorities.uiLabelForPriority(eventData['priority']);
           contentHelper.appendTextRow(Common.UIString('Priority'), priority);
         }
         if (eventData['encodedDataLength']) {
@@ -1142,7 +1142,7 @@
       contentHelper.appendTextRow(Common.UIString('Request Method'), request.requestMethod);
     if (typeof request.priority === 'string') {
       const priority =
-          NetworkConditions.uiLabelForPriority(/** @type {!Protocol.Network.ResourcePriority} */ (request.priority));
+          NetworkPriorities.uiLabelForPriority(/** @type {!Protocol.Network.ResourcePriority} */ (request.priority));
       contentHelper.appendTextRow(Common.UIString('Priority'), priority);
     }
     if (request.mimeType)
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/module.json b/third_party/WebKit/Source/devtools/front_end/timeline/module.json
index eabd0a9..854d48c 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/module.json
@@ -179,8 +179,9 @@
         "perf_ui",
         "extensions",
         "data_grid",
-        "network_conditions",
-        "product_registry"
+        "product_registry",
+        "mobile_throttling",
+        "network_priorities"
     ],
     "scripts": [
         "CountersGraph.js",
diff --git a/third_party/WebKit/Source/devtools/package.json b/third_party/WebKit/Source/devtools/package.json
index e55dd255..39549c2 100644
--- a/third_party/WebKit/Source/devtools/package.json
+++ b/third_party/WebKit/Source/devtools/package.json
@@ -12,7 +12,8 @@
     "format": "git cl format --js .",
     "closure": "python scripts/compile_frontend.py",
     "setup-dtrun": "cd scripts/devtools_run && npm link",
-    "format-py": "yapf --exclude scripts/build/rjsmin.py -i --recursive scripts PRESUBMIT.py"
+    "format-py": "yapf --exclude scripts/build/rjsmin.py -i --recursive scripts PRESUBMIT.py",
+    "extract": "node scripts/extract_module/extract_module.js"
   },
   "repository": {
     "type": "git",
diff --git a/third_party/WebKit/Source/devtools/scripts/extract_module/extract_module.js b/third_party/WebKit/Source/devtools/scripts/extract_module/extract_module.js
index e48ad00..f63f40f 100644
--- a/third_party/WebKit/Source/devtools/scripts/extract_module/extract_module.js
+++ b/third_party/WebKit/Source/devtools/scripts/extract_module/extract_module.js
@@ -11,6 +11,12 @@
 const BUILD_GN_PATH = path.resolve(__dirname, '..', '..', 'BUILD.gn');
 const SPECIAL_CASE_NAMESPACES_PATH = path.resolve(__dirname, '..', 'special_case_namespaces.json');
 
+/*
+ * ==========================================
+ * START EDITING HERE - TRANSFORMATION INPUTS
+ * ==========================================
+ */
+
 const APPLICATION_DESCRIPTORS = [
   'inspector.json',
   'toolbox.json',
@@ -20,30 +26,61 @@
   'utility_shared_worker.json',
 ];
 
-// Replace based on specified transformation
+/*
+ * If the transformation removes all the files of a module:
+ * ['text_editor']
+ */
 const MODULES_TO_REMOVE = [];
 
+/**
+ * If moving to a new module:
+ * {file: 'common/Text.js', new: 'a_new_module'}
+ *
+ * If moving to an existing module:
+ * {file: 'ui/SomeFile.js', existing: 'common'}
+ */
 const JS_FILES_MAPPING = [
-  {file: 'common/Text.js', new: 'text_utils'},
-  {file: 'common/TextUtils.js', new: 'text_utils'},
-  {file: 'common/TextRange.js', new: 'text_utils'},
+  {file: 'mobile_throttling/NetworkPriorities.js', new: 'network_priorities'},
 ];
 
+/**
+ * List all new modules here:
+ * mobile_throttling: {
+ *   dependencies: ['sdk'],
+ *   dependents: ['console'],
+ *   applications: ['inspector.json'],
+ *   autostart: false,
+ * }
+ */
 const MODULE_MAPPING = {
-  text_utils: {
-    dependencies: [],
-    dependents: ['common'],
+  network_priorities: {
+    dependencies: ['protocol', 'common'],
+    dependents: ['network', 'timeline'],
     applications: ['inspector.json'],
-    autostart: true,  // set to autostart because of extensions
+    autostart: false,
   },
 };
 
+/**
+ * If an existing module will have a new dependency on an existing module:
+ * console: ['new_dependency']
+ */
 const NEW_DEPENDENCIES_BY_EXISTING_MODULES = {
     // resources: ['components'],
 };
 
+/**
+ * If an existing module will no longer have a dependency on a module:
+ * console: ['former_dependency']
+ */
 const REMOVE_DEPENDENCIES_BY_EXISTING_MODULES = {};
 
+/*
+ * ==========================================
+ * STOP EDITING HERE
+ * ==========================================
+ */
+
 const DEPENDENCIES_BY_MODULE = Object.keys(MODULE_MAPPING).reduce((acc, module) => {
   acc[module] = MODULE_MAPPING[module].dependencies;
   return acc;
@@ -636,7 +673,7 @@
         // Need spacing to preserve indentation
         let string;
         if (MODULE_MAPPING[m].autostart)
-          string = `        { "name": "${m}", "type": "autostart"}`;
+          string = `        { "name": "${m}", "type": "autostart" }`;
         else
           string = `        { "name": "${m}" }`;
         if (i !== newModules.length - 1)
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index bd93aa17..09af57c1 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -1555,6 +1555,7 @@
     "//net",
     "//services/service_manager/public/interfaces:interfaces_blink",
     "//skia",
+    "//storage/public/interfaces:interfaces_blink",
     "//third_party:jpeg",
     "//third_party/WebKit/Source/platform/wtf",
     "//third_party/WebKit/public:mojo_bindings_blink",
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
index 4175f08..407f3408 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
@@ -650,6 +650,9 @@
       status: "experimental",
     },
     {
+      name: "MojoBlobs",
+    },
+    {
       name: "MojoJS",
       status: "test",
     },
diff --git a/third_party/WebKit/Source/platform/blob/BlobData.cpp b/third_party/WebKit/Source/platform/blob/BlobData.cpp
index 2f3b3ba8..5b1ae9f 100644
--- a/third_party/WebKit/Source/platform/blob/BlobData.cpp
+++ b/third_party/WebKit/Source/platform/blob/BlobData.cpp
@@ -31,6 +31,7 @@
 #include "platform/blob/BlobData.h"
 
 #include <memory>
+#include "platform/RuntimeEnabledFeatures.h"
 #include "platform/UUID.h"
 #include "platform/blob/BlobRegistry.h"
 #include "platform/text/LineEnding.h"
@@ -40,6 +41,8 @@
 #include "platform/wtf/Vector.h"
 #include "platform/wtf/text/CString.h"
 #include "platform/wtf/text/TextEncoding.h"
+#include "public/platform/InterfaceProvider.h"
+#include "public/platform/Platform.h"
 
 namespace blink {
 
@@ -242,7 +245,17 @@
     : uuid_(CreateCanonicalUUIDString()),
       size_(0),
       is_single_unknown_size_file_(false) {
-  BlobRegistry::RegisterBlobData(uuid_, BlobData::Create());
+  if (RuntimeEnabledFeatures::mojoBlobsEnabled()) {
+    // TODO(mek): Going through InterfaceProvider to get a BlobRegistryPtr
+    // ends up going through the main thread. Ideally workers wouldn't need
+    // to do that.
+    storage::mojom::blink::BlobRegistryPtr registry;
+    Platform::Current()->GetInterfaceProvider()->GetInterface(
+        MakeRequest(&registry));
+    registry->Register(MakeRequest(&blob_), uuid_, "", "", {});
+  } else {
+    BlobRegistry::RegisterBlobData(uuid_, BlobData::Create());
+  }
 }
 
 BlobDataHandle::BlobDataHandle(std::unique_ptr<BlobData> data, long long size)
@@ -250,7 +263,19 @@
       type_(data->ContentType().IsolatedCopy()),
       size_(size),
       is_single_unknown_size_file_(data->IsSingleUnknownSizeFile()) {
-  BlobRegistry::RegisterBlobData(uuid_, std::move(data));
+  if (RuntimeEnabledFeatures::mojoBlobsEnabled()) {
+    // TODO(mek): Going through InterfaceProvider to get a BlobRegistryPtr
+    // ends up going through the main thread. Ideally workers wouldn't need
+    // to do that.
+    storage::mojom::blink::BlobRegistryPtr registry;
+    Platform::Current()->GetInterfaceProvider()->GetInterface(
+        MakeRequest(&registry));
+    // TODO(mek): Pass elements from |data| to Register.
+    registry->Register(MakeRequest(&blob_), uuid_, type_.IsNull() ? "" : type_,
+                       "", {});
+  } else {
+    BlobRegistry::RegisterBlobData(uuid_, std::move(data));
+  }
 }
 
 BlobDataHandle::BlobDataHandle(const String& uuid,
@@ -260,11 +285,22 @@
       type_(IsValidBlobType(type) ? type.IsolatedCopy() : ""),
       size_(size),
       is_single_unknown_size_file_(false) {
-  BlobRegistry::AddBlobDataRef(uuid_);
+  if (RuntimeEnabledFeatures::mojoBlobsEnabled()) {
+    // TODO(mek): Going through InterfaceProvider to get a BlobRegistryPtr
+    // ends up going through the main thread. Ideally workers wouldn't need
+    // to do that.
+    storage::mojom::blink::BlobRegistryPtr registry;
+    Platform::Current()->GetInterfaceProvider()->GetInterface(
+        MakeRequest(&registry));
+    registry->GetBlobFromUUID(MakeRequest(&blob_), uuid_);
+  } else {
+    BlobRegistry::AddBlobDataRef(uuid_);
+  }
 }
 
 BlobDataHandle::~BlobDataHandle() {
-  BlobRegistry::RemoveBlobDataRef(uuid_);
+  if (!RuntimeEnabledFeatures::mojoBlobsEnabled())
+    BlobRegistry::RemoveBlobDataRef(uuid_);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/blob/BlobData.h b/third_party/WebKit/Source/platform/blob/BlobData.h
index 5774181b..b63dd63 100644
--- a/third_party/WebKit/Source/platform/blob/BlobData.h
+++ b/third_party/WebKit/Source/platform/blob/BlobData.h
@@ -38,6 +38,7 @@
 #include "platform/wtf/Forward.h"
 #include "platform/wtf/ThreadSafeRefCounted.h"
 #include "platform/wtf/text/WTFString.h"
+#include "storage/public/interfaces/blobs.mojom-blink.h"
 
 namespace blink {
 
@@ -256,6 +257,7 @@
   const String type_;
   const long long size_;
   const bool is_single_unknown_size_file_;
+  storage::mojom::blink::BlobPtr blob_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/blob/BlobDataTest.cpp b/third_party/WebKit/Source/platform/blob/BlobDataTest.cpp
index 206f6618..90c471ab 100644
--- a/third_party/WebKit/Source/platform/blob/BlobDataTest.cpp
+++ b/third_party/WebKit/Source/platform/blob/BlobDataTest.cpp
@@ -5,7 +5,14 @@
 #include "platform/blob/BlobData.h"
 
 #include <memory>
+#include <utility>
+#include "base/test/scoped_task_environment.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "platform/UUID.h"
+#include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h"
+#include "platform/testing/TestingPlatformSupport.h"
 #include "platform/wtf/PtrUtil.h"
+#include "public/platform/InterfaceProvider.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -34,4 +41,151 @@
   EXPECT_EQ(kMaxConsolidatedItemSizeInBytes, data.items_[1].data->length());
 }
 
+namespace {
+
+class MockBlobRegistry : public storage::mojom::blink::BlobRegistry {
+ public:
+  void Register(storage::mojom::blink::BlobRequest blob,
+                const String& uuid,
+                const String& content_type,
+                const String& content_disposition,
+                Vector<storage::mojom::blink::DataElementPtr> elements,
+                RegisterCallback callback) override {
+    registrations.push_back(Registration{std::move(blob), uuid, content_type,
+                                         content_disposition,
+                                         std::move(elements)});
+    std::move(callback).Run();
+  }
+
+  void GetBlobFromUUID(storage::mojom::blink::BlobRequest blob,
+                       const String& uuid) override {
+    binding_requests.push_back(BindingRequest{std::move(blob), uuid});
+  }
+
+  struct Registration {
+    storage::mojom::blink::BlobRequest request;
+    String uuid;
+    String content_type;
+    String content_disposition;
+    Vector<storage::mojom::blink::DataElementPtr> elements;
+  };
+  Vector<Registration> registrations;
+
+  struct BindingRequest {
+    storage::mojom::blink::BlobRequest request;
+    String uuid;
+  };
+  Vector<BindingRequest> binding_requests;
+};
+
+class MojoBlobInterfaceProvider : public InterfaceProvider {
+ public:
+  explicit MojoBlobInterfaceProvider(
+      storage::mojom::blink::BlobRegistry* mock_registry)
+      : mock_registry_(mock_registry) {}
+
+  void GetInterface(const char* name,
+                    mojo::ScopedMessagePipeHandle handle) override {
+    if (std::string(name) == storage::mojom::blink::BlobRegistry::Name_) {
+      registry_bindings_.AddBinding(
+          mock_registry_,
+          storage::mojom::blink::BlobRegistryRequest(std::move(handle)));
+      return;
+    }
+  }
+
+  void Flush() { registry_bindings_.FlushForTesting(); }
+
+ private:
+  storage::mojom::blink::BlobRegistry* mock_registry_;
+  mojo::BindingSet<storage::mojom::blink::BlobRegistry> registry_bindings_;
+};
+
+class MojoBlobTestPlatform : public TestingPlatformSupport {
+ public:
+  explicit MojoBlobTestPlatform(
+      storage::mojom::blink::BlobRegistry* mock_registry)
+      : interface_provider_(
+            WTF::MakeUnique<MojoBlobInterfaceProvider>(mock_registry)) {}
+
+  InterfaceProvider* GetInterfaceProvider() override {
+    return interface_provider_.get();
+  }
+
+  void Flush() { interface_provider_->Flush(); }
+
+ private:
+  std::unique_ptr<MojoBlobInterfaceProvider> interface_provider_;
+};
+
+}  // namespace
+
+class BlobDataHandleTest : public testing::Test {
+ public:
+  BlobDataHandleTest()
+      : enable_mojo_blobs_(true), testing_platform_(&mock_blob_registry_) {}
+
+ protected:
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  ScopedMojoBlobsForTest enable_mojo_blobs_;
+  ScopedTestingPlatformSupport<MojoBlobTestPlatform,
+                               storage::mojom::blink::BlobRegistry*>
+      testing_platform_;
+  MockBlobRegistry mock_blob_registry_;
+};
+
+TEST_F(BlobDataHandleTest, CreateEmpty) {
+  RefPtr<BlobDataHandle> handle = BlobDataHandle::Create();
+  EXPECT_TRUE(handle->GetType().IsNull());
+  EXPECT_EQ(0u, handle->size());
+  EXPECT_FALSE(handle->IsSingleUnknownSizeFile());
+
+  testing_platform_->Flush();
+  EXPECT_EQ(0u, mock_blob_registry_.binding_requests.size());
+  ASSERT_EQ(1u, mock_blob_registry_.registrations.size());
+  const auto& reg = mock_blob_registry_.registrations[0];
+  EXPECT_EQ(handle->Uuid(), reg.uuid);
+  EXPECT_EQ("", reg.content_type);
+  EXPECT_EQ("", reg.content_disposition);
+  EXPECT_EQ(0u, reg.elements.size());
+}
+
+TEST_F(BlobDataHandleTest, CreateFromEmptyData) {
+  String kType = "content/type";
+
+  std::unique_ptr<BlobData> data = BlobData::Create();
+  data->SetContentType(kType);
+
+  RefPtr<BlobDataHandle> handle = BlobDataHandle::Create(std::move(data), 0);
+  EXPECT_EQ(kType, handle->GetType());
+  EXPECT_EQ(0u, handle->size());
+  EXPECT_FALSE(handle->IsSingleUnknownSizeFile());
+
+  testing_platform_->Flush();
+  EXPECT_EQ(0u, mock_blob_registry_.binding_requests.size());
+  ASSERT_EQ(1u, mock_blob_registry_.registrations.size());
+  const auto& reg = mock_blob_registry_.registrations[0];
+  EXPECT_EQ(handle->Uuid(), reg.uuid);
+  EXPECT_EQ(kType, reg.content_type);
+  EXPECT_EQ("", reg.content_disposition);
+  EXPECT_EQ(0u, reg.elements.size());
+}
+
+TEST_F(BlobDataHandleTest, CreateFromUUID) {
+  String kUuid = CreateCanonicalUUIDString();
+  String kType = "content/type";
+  uint64_t kSize = 1234;
+
+  RefPtr<BlobDataHandle> handle = BlobDataHandle::Create(kUuid, kType, kSize);
+  EXPECT_EQ(kUuid, handle->Uuid());
+  EXPECT_EQ(kType, handle->GetType());
+  EXPECT_EQ(kSize, handle->size());
+  EXPECT_FALSE(handle->IsSingleUnknownSizeFile());
+
+  testing_platform_->Flush();
+  EXPECT_EQ(0u, mock_blob_registry_.registrations.size());
+  ASSERT_EQ(1u, mock_blob_registry_.binding_requests.size());
+  EXPECT_EQ(kUuid, mock_blob_registry_.binding_requests[0].uuid);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/blob/DEPS b/third_party/WebKit/Source/platform/blob/DEPS
new file mode 100644
index 0000000..241c1ce
--- /dev/null
+++ b/third_party/WebKit/Source/platform/blob/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+    "+storage/public/interfaces",
+]
\ No newline at end of file
diff --git a/third_party/WebKit/Source/platform/exported/WebRuntimeFeatures.cpp b/third_party/WebKit/Source/platform/exported/WebRuntimeFeatures.cpp
index 2c46ea8..54c5d82 100644
--- a/third_party/WebKit/Source/platform/exported/WebRuntimeFeatures.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebRuntimeFeatures.cpp
@@ -168,6 +168,10 @@
   RuntimeEnabledFeatures::setMediaSessionEnabled(enable);
 }
 
+void WebRuntimeFeatures::EnableMojoBlobs(bool enable) {
+  RuntimeEnabledFeatures::setMojoBlobsEnabled(enable);
+}
+
 void WebRuntimeFeatures::EnableNotificationConstructor(bool enable) {
   RuntimeEnabledFeatures::setNotificationConstructorEnabled(enable);
 }
diff --git a/third_party/WebKit/Source/platform/loader/BUILD.gn b/third_party/WebKit/Source/platform/loader/BUILD.gn
index 2c35b06..62e39ebc 100644
--- a/third_party/WebKit/Source/platform/loader/BUILD.gn
+++ b/third_party/WebKit/Source/platform/loader/BUILD.gn
@@ -89,6 +89,7 @@
   deps = [
     ":make_platform_loader_generated_fetch_initiator_type_names",
     "//components/link_header_util:link_header_util",
+    "//storage/public/interfaces:interfaces_blink__generator",
   ]
 
   public_deps = [
diff --git a/third_party/WebKit/Source/platform/testing/RuntimeEnabledFeaturesTestHelpers.h b/third_party/WebKit/Source/platform/testing/RuntimeEnabledFeaturesTestHelpers.h
index 3927c71d..afe954f6 100644
--- a/third_party/WebKit/Source/platform/testing/RuntimeEnabledFeaturesTestHelpers.h
+++ b/third_party/WebKit/Source/platform/testing/RuntimeEnabledFeaturesTestHelpers.h
@@ -60,6 +60,10 @@
     RuntimeEnabledFeatures::accessibilityObjectModelEnabled,
     RuntimeEnabledFeatures::setAccessibilityObjectModelEnabled>
     ScopedAccessibilityObjectModelForTest;
+typedef ScopedRuntimeEnabledFeatureForTest<
+    RuntimeEnabledFeatures::mojoBlobsEnabled,
+    RuntimeEnabledFeatures::setMojoBlobsEnabled>
+    ScopedMojoBlobsForTest;
 
 }  // namespace blink
 
diff --git a/third_party/WebKit/Source/web/BUILD.gn b/third_party/WebKit/Source/web/BUILD.gn
index 8f5004f7..6b92b6a 100644
--- a/third_party/WebKit/Source/web/BUILD.gn
+++ b/third_party/WebKit/Source/web/BUILD.gn
@@ -65,8 +65,6 @@
     "FullscreenController.h",
     "IndexedDBClientImpl.cpp",
     "IndexedDBClientImpl.h",
-    "InspectorEmulationAgent.cpp",
-    "InspectorEmulationAgent.h",
     "InspectorOverlayAgent.cpp",
     "InspectorOverlayAgent.h",
     "LinkHighlightImpl.cpp",
@@ -160,8 +158,6 @@
     "WebScopedWindowFocusAllowedIndicator.cpp",
     "WebSearchableFormData.cpp",
     "WebSelectElement.cpp",
-    "WebSettingsImpl.cpp",
-    "WebSettingsImpl.h",
     "WebSharedWorkerImpl.cpp",
     "WebSharedWorkerImpl.h",
     "WebSharedWorkerReportingProxyImpl.cpp",
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.cpp b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
index ea57c9a..6a01332 100644
--- a/third_party/WebKit/Source/web/ChromeClientImpl.cpp
+++ b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
@@ -42,6 +42,7 @@
 #include "core/events/WebInputEventConversion.h"
 #include "core/exported/WebFileChooserCompletionImpl.h"
 #include "core/exported/WebPluginContainerBase.h"
+#include "core/exported/WebSettingsImpl.h"
 #include "core/exported/WebViewBase.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/Settings.h"
@@ -126,7 +127,6 @@
 #include "web/WebFrameWidgetImpl.h"
 #include "web/WebLocalFrameImpl.h"
 #include "web/WebRemoteFrameImpl.h"
-#include "web/WebSettingsImpl.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/web/LinkHighlightImpl.cpp b/third_party/WebKit/Source/web/LinkHighlightImpl.cpp
index fab3849..c003d23 100644
--- a/third_party/WebKit/Source/web/LinkHighlightImpl.cpp
+++ b/third_party/WebKit/Source/web/LinkHighlightImpl.cpp
@@ -29,6 +29,7 @@
 #include "core/dom/DOMNodeIds.h"
 #include "core/dom/LayoutTreeBuilderTraversal.h"
 #include "core/dom/Node.h"
+#include "core/exported/WebSettingsImpl.h"
 #include "core/exported/WebViewBase.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/LocalFrameView.h"
@@ -64,7 +65,6 @@
 #include "public/web/WebKit.h"
 #include "third_party/skia/include/core/SkMatrix44.h"
 #include "ui/gfx/geometry/rect.h"
-#include "web/WebSettingsImpl.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/web/PageOverlay.cpp b/third_party/WebKit/Source/web/PageOverlay.cpp
index dd43c7a..c25ba67 100644
--- a/third_party/WebKit/Source/web/PageOverlay.cpp
+++ b/third_party/WebKit/Source/web/PageOverlay.cpp
@@ -31,6 +31,8 @@
 #include <memory>
 #include "core/frame/LocalFrame.h"
 #include "core/frame/VisualViewport.h"
+#include "core/frame/WebFrameWidgetBase.h"
+#include "core/frame/WebLocalFrameBase.h"
 #include "core/page/Page.h"
 #include "core/page/scrolling/ScrollingCoordinator.h"
 #include "platform/graphics/GraphicsContext.h"
@@ -41,7 +43,6 @@
 #include "public/platform/WebLayer.h"
 #include "public/web/WebViewClient.h"
 #include "web/WebDevToolsAgentImpl.h"
-#include "web/WebFrameWidgetImpl.h"
 
 namespace blink {
 
@@ -89,9 +90,7 @@
       frame->GetPage()->GetVisualViewport().ContainerLayer()->AddChild(
           layer_.get());
     } else {
-      ToWebFrameWidgetImpl(frame_impl_->FrameWidget())
-          ->RootGraphicsLayer()
-          ->AddChild(layer_.get());
+      frame_impl_->FrameWidget()->RootGraphicsLayer()->AddChild(layer_.get());
     }
   }
 
diff --git a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
index 32b956d..3a276ad 100644
--- a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
+++ b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
@@ -37,6 +37,7 @@
 #include "bindings/core/v8/V8BindingForCore.h"
 #include "core/CoreProbeSink.h"
 #include "core/events/WebInputEventConversion.h"
+#include "core/exported/WebSettingsImpl.h"
 #include "core/exported/WebViewBase.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/LocalFrameView.h"
@@ -49,6 +50,7 @@
 #include "core/inspector/InspectorCSSAgent.h"
 #include "core/inspector/InspectorDOMAgent.h"
 #include "core/inspector/InspectorDOMDebuggerAgent.h"
+#include "core/inspector/InspectorEmulationAgent.h"
 #include "core/inspector/InspectorInputAgent.h"
 #include "core/inspector/InspectorLayerTreeAgent.h"
 #include "core/inspector/InspectorLogAgent.h"
@@ -86,10 +88,8 @@
 #include "public/platform/WebString.h"
 #include "public/web/WebDevToolsAgentClient.h"
 #include "public/web/WebSettings.h"
-#include "web/InspectorEmulationAgent.h"
 #include "web/InspectorOverlayAgent.h"
 #include "web/WebFrameWidgetImpl.h"
-#include "web/WebSettingsImpl.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h
index e5fb5f2..3d04b7b 100644
--- a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h
+++ b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h
@@ -33,6 +33,7 @@
 
 #include <memory>
 
+#include "core/inspector/InspectorEmulationAgent.h"
 #include "core/inspector/InspectorPageAgent.h"
 #include "core/inspector/InspectorSession.h"
 #include "core/inspector/InspectorTracingAgent.h"
@@ -42,7 +43,6 @@
 #include "public/platform/WebSize.h"
 #include "public/platform/WebThread.h"
 #include "public/web/WebDevToolsAgent.h"
-#include "web/InspectorEmulationAgent.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/web/WebFrameWidgetImpl.h b/third_party/WebKit/Source/web/WebFrameWidgetImpl.h
index 66fb6b68..f542cd51 100644
--- a/third_party/WebKit/Source/web/WebFrameWidgetImpl.h
+++ b/third_party/WebKit/Source/web/WebFrameWidgetImpl.h
@@ -149,7 +149,9 @@
   void MouseContextMenu(const WebMouseEvent&);
 
   WebLayerTreeView* LayerTreeView() const { return layer_tree_view_; }
-  GraphicsLayer* RootGraphicsLayer() const { return root_graphics_layer_; };
+  GraphicsLayer* RootGraphicsLayer() const override {
+    return root_graphics_layer_;
+  };
 
   Color BaseBackgroundColor() const;
 
diff --git a/third_party/WebKit/Source/web/WebPagePopupImpl.cpp b/third_party/WebKit/Source/web/WebPagePopupImpl.cpp
index e7aa9b1..6a3e3e1 100644
--- a/third_party/WebKit/Source/web/WebPagePopupImpl.cpp
+++ b/third_party/WebKit/Source/web/WebPagePopupImpl.cpp
@@ -33,6 +33,7 @@
 #include "core/dom/ContextFeatures.h"
 #include "core/events/MessageEvent.h"
 #include "core/events/WebInputEventConversion.h"
+#include "core/exported/WebSettingsImpl.h"
 #include "core/exported/WebViewBase.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/LocalFrameClient.h"
@@ -66,7 +67,6 @@
 #include "public/web/WebViewClient.h"
 #include "public/web/WebWidgetClient.h"
 #include "web/WebLocalFrameImpl.h"
-#include "web/WebSettingsImpl.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp
index f7013a5d..e1f737d7 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -54,6 +54,7 @@
 #include "core/events/WheelEvent.h"
 #include "core/exported/WebFactory.h"
 #include "core/exported/WebPluginContainerBase.h"
+#include "core/exported/WebSettingsImpl.h"
 #include "core/frame/BrowserControls.h"
 #include "core/frame/EventHandlerRegistry.h"
 #include "core/frame/LocalFrame.h"
@@ -173,7 +174,6 @@
 #include "web/StorageQuotaClientImpl.h"
 #include "web/WebDevToolsAgentImpl.h"
 #include "web/WebRemoteFrameImpl.h"
-#include "web/WebSettingsImpl.h"
 
 #if USE(DEFAULT_RENDER_THEME)
 #include "core/layout/LayoutThemeDefault.h"
diff --git a/third_party/WebKit/Source/web/tests/WebViewTest.cpp b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
index 1c33978..44b6555 100644
--- a/third_party/WebKit/Source/web/tests/WebViewTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
@@ -41,6 +41,7 @@
 #include "core/editing/FrameSelection.h"
 #include "core/editing/InputMethodController.h"
 #include "core/editing/markers/DocumentMarkerController.h"
+#include "core/exported/WebSettingsImpl.h"
 #include "core/exported/WebViewBase.h"
 #include "core/frame/EventHandlerRegistry.h"
 #include "core/frame/LocalFrame.h"
@@ -107,7 +108,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkCanvas.h"
-#include "web/WebSettingsImpl.h"
 #include "web/tests/FrameTestHelpers.h"
 
 #if OS(MACOSX)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py
index 4e609df4..f82824f 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py
@@ -27,6 +27,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
+import hashlib
 import logging
 import re
 
@@ -178,23 +179,23 @@
                                              self._test_name, driver_output, None, failures)
         # FIXME: It the test crashed or timed out, it might be better to avoid
         # to write new baselines.
-        self._overwrite_baselines(driver_output)
+        self._update_or_add_new_baselines(driver_output)
         return TestResult(self._test_name, failures, driver_output.test_time, driver_output.has_stderr(),
                           pid=driver_output.pid)
 
     _render_tree_dump_pattern = re.compile(r"^layer at \(\d+,\d+\) size \d+x\d+\n")
 
     def _add_missing_baselines(self, test_result, driver_output):
-        missingImage = test_result.has_failure_matching_types(
+        missing_image = test_result.has_failure_matching_types(
             test_failures.FailureMissingImage, test_failures.FailureMissingImageHash)
         if test_result.has_failure_matching_types(test_failures.FailureMissingResult):
-            self._save_baseline_data(driver_output.text, '.txt', self._location_for_new_baseline(driver_output.text, '.txt'))
+            self._save_baseline_data(driver_output.text, '.txt', self._location_for_missing_baseline(driver_output.text, '.txt'))
         if test_result.has_failure_matching_types(test_failures.FailureMissingAudio):
-            self._save_baseline_data(driver_output.audio, '.wav', self._location_for_new_baseline(driver_output.audio, '.wav'))
-        if missingImage:
-            self._save_baseline_data(driver_output.image, '.png', self._location_for_new_baseline(driver_output.image, '.png'))
+            self._save_baseline_data(driver_output.audio, '.wav', self._location_for_missing_baseline(driver_output.audio, '.wav'))
+        if missing_image:
+            self._save_baseline_data(driver_output.image, '.png', self._location_for_missing_baseline(driver_output.image, '.png'))
 
-    def _location_for_new_baseline(self, data, extension):
+    def _location_for_missing_baseline(self, data, extension):
         if self._options.add_platform_exceptions:
             return self.VERSION_DIR
         if extension == '.png':
@@ -205,7 +206,7 @@
             return self.PLATFORM_DIR
         return self.ALONGSIDE_TEST
 
-    def _overwrite_baselines(self, driver_output):
+    def _update_or_add_new_baselines(self, driver_output):
         location = self.VERSION_DIR if self._options.add_platform_exceptions else self.UPDATE
         self._save_baseline_data(driver_output.text, '.txt', location)
         self._save_baseline_data(driver_output.audio, '.wav', location)
@@ -217,6 +218,7 @@
             return
         port = self._port
         fs = self._filesystem
+
         if location == self.ALONGSIDE_TEST:
             output_dir = fs.dirname(port.abspath_for_test(self._test_name))
         elif location == self.VERSION_DIR:
@@ -231,6 +233,14 @@
         fs.maybe_make_directory(output_dir)
         output_basename = fs.basename(fs.splitext(self._test_name)[0] + '-expected' + extension)
         output_path = fs.join(output_dir, output_basename)
+
+        if location == self.VERSION_DIR:
+            fallback_path = port.expected_filename(self._test_name, extension)
+            if fallback_path != output_path and fs.sha1(fallback_path) == hashlib.sha1(data).hexdigest():
+                _log.info('Not writing new expected result "%s" because it is the same as "%s"',
+                          port.relative_test_filename(output_path), port.relative_test_filename(fallback_path))
+                return
+
         _log.info('Writing new expected result "%s"', port.relative_test_filename(output_path))
         port.update_baseline(output_path, data)
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
index 7e1af3c..9a81b7d8 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
@@ -1133,13 +1133,33 @@
         # for both existing and new baselines.
         host = MockHost()
         details, err, _ = logging_run(
-            ['--pixel-tests', '--new-baseline', 'passes/image.html'],
+            ['--pixel-tests', '--new-baseline', 'failures/unexpected/text-image-checksum.html'],
             tests_included=True, host=host, new_results=True)
         file_list = host.filesystem.written_files.keys()
         self.assertEqual(details.exit_code, 0)
         self.assertEqual(len(file_list), 8)
         self.assert_baselines(file_list,
-                              'platform/test-mac-mac10.10/passes/image', ['.txt', '.png'], err)
+                              'platform/test-mac-mac10.10/failures/unexpected/text-image-checksum',
+                              ['.txt', '.png'], err)
+
+    def test_new_baseline_same_as_fallback(self):
+        # Test that we update the platform expectations in the version-specific directories
+        # if the new baseline is different from the fallback baseline.
+        host = MockHost()
+        host.filesystem.write_text_file(
+            test.LAYOUT_TEST_DIR + '/failures/unexpected/text-image-checksum-expected.txt',
+            # Make the fallback baseline the same as the actual result of the test.
+            # The value is the same as actual_result of the test defined in test.py.
+            'text-image-checksum_fail-txt')
+        details, err, _ = logging_run(
+            ['--pixel-tests', '--new-baseline', 'failures/unexpected/text-image-checksum.html'],
+            tests_included=True, host=host, new_results=True)
+        file_list = host.filesystem.written_files.keys()
+        self.assertEqual(details.exit_code, 0)
+        self.assertEqual(len(file_list), 8)
+        self.assert_baselines(file_list,
+                              'platform/test-mac-mac10.10/failures/unexpected/text-image-checksum',
+                              ['.png'], err)
 
     def test_reftest_reset_results(self):
         # Test rebaseline of reftests.
diff --git a/third_party/WebKit/public/platform/WebRuntimeFeatures.h b/third_party/WebKit/public/platform/WebRuntimeFeatures.h
index f8206ac..8fec638 100644
--- a/third_party/WebKit/public/platform/WebRuntimeFeatures.h
+++ b/third_party/WebKit/public/platform/WebRuntimeFeatures.h
@@ -90,6 +90,7 @@
   BLINK_PLATFORM_EXPORT static void EnableMediaDocumentDownloadButton(bool);
   BLINK_PLATFORM_EXPORT static void EnableMediaSession(bool);
   BLINK_PLATFORM_EXPORT static void EnableMiddleClickAutoscroll(bool);
+  BLINK_PLATFORM_EXPORT static void EnableMojoBlobs(bool);
   BLINK_PLATFORM_EXPORT static void EnableNavigatorContentUtils(bool);
   BLINK_PLATFORM_EXPORT static void EnableNetworkInformation(bool);
   BLINK_PLATFORM_EXPORT static void EnableNotificationConstructor(bool);
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index db43539..b9e363234 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -26237,10 +26237,6 @@
     Save operation failed because an interstitial page (i.e. page warning of
     expired certificates or improper dev signatures) was detected.
   </int>
-  <int value="11" label="Archive folder missing">
-    Save operation failed because there's no available archive folder for the
-    page and the attemp to create the archive folder also failed.
-  </int>
 </enum>
 
 <enum name="OfflinePagesSharedPageWasOffline" type="int">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index f9d012fc..e4580c7 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -9739,6 +9739,23 @@
   </summary>
 </histogram>
 
+<histogram name="Cryptohome.DircryptoMigrationTotalByteCountInMb" units="MB">
+  <owner>hashimoto@chromium.org</owner>
+  <summary>
+    The total byte count (MB) of the data in a user's home directory which is
+    being migrated from ecryptfs to ext4-crypto.  This is logged once when a new
+    migration starts.
+  </summary>
+</histogram>
+
+<histogram name="Cryptohome.DircryptoMigrationTotalFileCount">
+  <owner>hashimoto@chromium.org</owner>
+  <summary>
+    The total file count in a user's home directory which is being migrated from
+    ecryptfs to ext4-crypto.  This is logged once when a new migration starts.
+  </summary>
+</histogram>
+
 <histogram name="Cryptohome.Errors" enum="CryptohomeError">
   <owner>dkrahn@chromium.org</owner>
   <summary>Cryptohome errors.</summary>
@@ -28663,6 +28680,14 @@
   </summary>
 </histogram>
 
+<histogram name="Media.MeanTimeBetweenRebuffers" units="ms">
+  <owner>dalecurtis@chromium.org</owner>
+  <summary>
+    The total watch time (see Media.WatchTime) of a given playback divided by
+    the number of rebuffering events that occured during that playback.
+  </summary>
+</histogram>
+
 <histogram name="Media.MediaElement.ContentTypeParseable"
     enum="ContentTypeParseableResult">
   <owner>jrummell@chromium.org</owner>
@@ -35388,6 +35413,17 @@
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
 </histogram>
 
+<histogram name="Net.DNSNameCompliantIfValid" enum="Boolean">
+  <owner>palmer@chromium.org</owner>
+  <summary>
+    True if |net::IsCanonicalizedHostCompliant| returns true. Used to see if
+    IsCanonicalizedHostCompliant() runs afoul of real websites. This histogram
+    is recorded when converting dotted DNS names into DNS query form, in
+    preparation for issuing a DNS request. This histogram is only recorded if
+    Net.ValidDNSName is true.
+  </summary>
+</histogram>
+
 <histogram name="Net.DoubleGetExperiment_InitialResponseMethod"
     enum="DoubleGetExperimentMethods">
   <obsolete>
@@ -57175,6 +57211,22 @@
   </summary>
 </histogram>
 
+<histogram name="Printing.CUPS.PrinterAdded" enum="PrinterProtocol">
+  <owner>skau@chromium.org</owner>
+  <summary>
+    The protocol for a printer that was added.  Used to track printer churn by
+    protocol.  Only on Chrome OS.
+  </summary>
+</histogram>
+
+<histogram name="Printing.CUPS.PrinterRemoved" enum="PrinterProtocol">
+  <owner>skau@chromium.org</owner>
+  <summary>
+    The protocol for a printer that was removed.  Used to track printer churn by
+    protocol.  Only on Chrome OS.
+  </summary>
+</histogram>
+
 <histogram name="Printing.CUPS.PrintersDiscovered" units="printers">
   <owner>skau@chromium.org</owner>
   <summary>
@@ -88599,6 +88651,19 @@
   <affected-histogram name="Media.Timeline.Width"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="MediaMtbrCategories" separator=".">
+  <suffix name="Audio.MSE" label="MTBR for MSE media with an audio track."/>
+  <suffix name="Audio.SRC" label="MTBR for SRC media with an audio track."/>
+  <suffix name="Audio.EME" label="MTBR for EME media with an audio track."/>
+  <suffix name="AudioVideo.MSE"
+      label="MTBR for MSE media with both an audio and video track."/>
+  <suffix name="AudioVideo.SRC"
+      label="MTBR for SRC media with both an audio and video track."/>
+  <suffix name="AudioVideo.EME"
+      label="MTBR for EME media with both an audio and video track."/>
+  <affected-histogram name="Media.MeanTimeBetweenRebuffers"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="MediaPipelineStatusForStreams" separator=".">
   <suffix name="AudioVideo.Other"
       label="PipelineStatus for the codecs that dont have an explicit metric."/>
diff --git a/tools/perf/benchmarks/dromaeo.py b/tools/perf/benchmarks/dromaeo.py
index a5847799..a9a5fbbb 100644
--- a/tools/perf/benchmarks/dromaeo.py
+++ b/tools/perf/benchmarks/dromaeo.py
@@ -118,10 +118,11 @@
     ps = story.StorySet(
         archive_data_file=archive_data_file,
         base_dir=os.path.dirname(os.path.abspath(__file__)),
-        cloud_storage_bucket=story.PUBLIC_BUCKET)
+        cloud_storage_bucket=story.PUBLIC_BUCKET,
+        verify_names=True)
     url = 'http://dromaeo.com?%s' % self.query_param
     ps.AddStory(page_module.Page(
-        url, ps, ps.base_dir, make_javascript_deterministic=False))
+        url, ps, ps.base_dir, make_javascript_deterministic=False, name=url))
     return ps
 
 
diff --git a/tools/web_dev_style/PRESUBMIT.py b/tools/web_dev_style/PRESUBMIT.py
index d808f851..c2d69e3 100644
--- a/tools/web_dev_style/PRESUBMIT.py
+++ b/tools/web_dev_style/PRESUBMIT.py
@@ -27,6 +27,7 @@
 
   if utils_changed or any(f for f in files if f.startswith('js_checker')):
     tests.append(path.join(cwd, 'js_checker_test.py'))
+    tests.append(path.join(cwd, 'js_checker_eslint_test.py'))
 
   if utils_changed or any(f for f in files if f.startswith('resource_checker')):
     tests.append(path.join(cwd, 'resource_checker_test.py'))
diff --git a/tools/web_dev_style/js_checker.py b/tools/web_dev_style/js_checker.py
index 79e0895..00a16e32 100644
--- a/tools/web_dev_style/js_checker.py
+++ b/tools/web_dev_style/js_checker.py
@@ -95,13 +95,6 @@
 
     return [self.output_api.PresubmitError(output)] if output else []
 
-  def WrapperTypeCheck(self, i, line):
-    """Check for wrappers (new String()) instead of builtins (string)."""
-    return self.RegexCheck(i, line,
-        r"(?:/\*)?\*.*?@(?:param|return|type) ?"     # /** @param/@return/@type
-        r"{[^}]*\b(String|Boolean|Number)\b[^}]*}",  # {(Boolean|Number|String)}
-        "Don't use wrapper types (i.e. new String() or @type {String})")
-
   def VarNameCheck(self, i, line):
     """See the style guide. http://goo.gl/eQiXVW"""
     return self.RegexCheck(i, line,
@@ -140,7 +133,6 @@
             self.ExtraDotInGenericCheck(i, line),
             self.InheritDocCheck(i, line),
             self.PolymerLocalIdCheck(i, line),
-            self.WrapperTypeCheck(i, line),
             self.VarNameCheck(i, line),
         ])
 
diff --git a/tools/web_dev_style/js_checker_eslint_test.py b/tools/web_dev_style/js_checker_eslint_test.py
index 1309c06..8eb4c42 100755
--- a/tools/web_dev_style/js_checker_eslint_test.py
+++ b/tools/web_dev_style/js_checker_eslint_test.py
@@ -21,28 +21,35 @@
   def tearDown(self):
     os.remove(self._tmp_file)
 
-  def testGetElementByIdCheck(self):
+  def _runChecks(self, file_contents):
     tmp_args = {'suffix': '.js', 'dir': _HERE_PATH, 'delete': False}
     with tempfile.NamedTemporaryFile(**tmp_args) as f:
       self._tmp_file = f.name
-      f.write('var a = document.getElementById(\'foo\');')
+      f.write(file_contents)
 
     input_api = MockInputApi()
     input_api.files = [MockFile(os.path.abspath(self._tmp_file), '')]
     input_api.presubmit_local_path = _HERE_PATH
 
     checker = js_checker.JSChecker(input_api, MockOutputApi())
-    results_json = checker.RunEsLintChecks(
-        input_api.AffectedFiles(), format='json')
-    self.assertEqual(1, len(results_json))
+    return checker.RunEsLintChecks(input_api.AffectedFiles(), format='json')
 
+  def _assertError(self, results_json, rule_id, line):
+    self.assertEqual(1, len(results_json))
     results = json.loads(results_json[0].message)
     self.assertEqual(1, len(results))
-
     self.assertEqual(1, len(results[0].get('messages')))
     message = results[0].get('messages')[0]
-    self.assertEqual('no-restricted-properties', message.get('ruleId'))
-    self.assertEqual(1, message.get('line'))
+    self.assertEqual(rule_id, message.get('ruleId'))
+    self.assertEqual(line, message.get('line'))
+
+  def testGetElementByIdCheck(self):
+    results_json = self._runChecks('var a = document.getElementById(\'foo\');')
+    self._assertError(results_json, 'no-restricted-properties', 1)
+
+  def testPrimitiveWrappersCheck(self):
+    results_json = self._runChecks('var a = new Number(1);')
+    self._assertError(results_json, 'no-new-wrappers', 1)
 
 
 if __name__ == '__main__':
diff --git a/tools/web_dev_style/js_checker_test.py b/tools/web_dev_style/js_checker_test.py
index 428c7824..887ed60 100755
--- a/tools/web_dev_style/js_checker_test.py
+++ b/tools/web_dev_style/js_checker_test.py
@@ -267,50 +267,6 @@
     for line in lines:
       self.ShouldPassPolymerLocalIdCheck(line)
 
-  def ShouldFailWrapperTypeCheck(self, line):
-    """Checks that the use of wrapper types (i.e. new Number(), @type {Number})
-       is a style error.
-    """
-    error = self.checker.WrapperTypeCheck(1, line)
-    self.assertNotEqual('', error,
-        msg='Should be flagged as style error: ' + line)
-    highlight = test_util.GetHighlight(line, error)
-    self.assertTrue(highlight in ('Boolean', 'Number', 'String'))
-
-  def ShouldPassWrapperTypeCheck(self, line):
-    """Checks that the wrapper type checker doesn't flag |line| as a style
-       error.
-    """
-    self.assertEqual('', self.checker.WrapperTypeCheck(1, line),
-        msg='Should not be flagged as style error: ' + line)
-
-  def testWrapperTypePasses(self):
-    lines = [
-        "/** @param {!ComplexType} */",
-        "  * @type {Object}",
-        "   * @param {Function=} opt_callback",
-        "    * @param {} num Number of things to add to {blah}.",
-        "   *  @return {!print_preview.PageNumberSet}",
-        " /* @returns {Number} */",  # Should be /** @return {Number} */
-        "* @param {!LocalStrings}"
-        " Your type of Boolean is false!",
-        "  Then I parameterized a Number from my friend!",
-        "   A String of Pearls",
-        "    types.params.aBoolean.typeString(someNumber)",
-    ]
-    for line in lines:
-      self.ShouldPassWrapperTypeCheck(line)
-
-  def testWrapperTypeFails(self):
-    lines = [
-        "  /**@type {String}*/(string)",
-        "   * @param{Number=} opt_blah A number",
-        "/** @private @return {!Boolean} */",
-        " * @param {number|String}",
-    ]
-    for line in lines:
-      self.ShouldFailWrapperTypeCheck(line)
-
   def ShouldFailVarNameCheck(self, line):
     """Checks that var unix_hacker, $dollar are style errors."""
     error = self.checker.VarNameCheck(1, line)
diff --git a/ui/aura/mus/client_surface_embedder.cc b/ui/aura/mus/client_surface_embedder.cc
index 4458206..426059b 100644
--- a/ui/aura/mus/client_surface_embedder.cc
+++ b/ui/aura/mus/client_surface_embedder.cc
@@ -76,7 +76,8 @@
         fallback_device_scale_factor, fallback_surface_info->size_in_pixels());
   }
   gfx::Rect window_bounds(window_->bounds());
-  if (fallback_surface_size_in_dip.width() < window_bounds.width()) {
+  if (!window_->transparent() &&
+      fallback_surface_size_in_dip.width() < window_bounds.width()) {
     right_gutter_ = base::MakeUnique<ui::Layer>(ui::LAYER_SOLID_COLOR);
     // TODO(fsamuel): Use the embedded client's background color.
     right_gutter_->SetColor(SK_ColorWHITE);
@@ -93,7 +94,7 @@
 
   // Only create a bottom gutter if a fallback surface is available. Otherwise,
   // the right gutter will fill the whole window until a fallback is available.
-  if (!fallback_surface_size_in_dip.IsEmpty() &&
+  if (!window_->transparent() && !fallback_surface_size_in_dip.IsEmpty() &&
       fallback_surface_size_in_dip.height() < window_bounds.height()) {
     bottom_gutter_ = base::MakeUnique<ui::Layer>(ui::LAYER_SOLID_COLOR);
     // TODO(fsamuel): Use the embedded client's background color.
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 05cb33ba..741d856 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -686,13 +686,6 @@
     sources += [ "test/user_interactive_test_case.cc" ]
   }
 
-  if (is_chromeos) {
-    sources += [
-      "ime/chromeos/mock_input_method_manager.cc",
-      "ime/chromeos/mock_input_method_manager.h",
-    ]
-  }
-
   public_deps = [
     ":base",
   ]
@@ -722,6 +715,19 @@
     ]
   }
 
+  if (is_chromeos) {
+    sources += [
+      "ime/chromeos/input_method_whitelist.cc",
+      "ime/chromeos/input_method_whitelist.h",
+      "ime/chromeos/mock_input_method_manager.cc",
+      "ime/chromeos/mock_input_method_manager.h",
+    ]
+    deps += [
+      # Generates a header used by input_method_whitelist.cc
+      "//chromeos/ime:gencode",
+    ]
+  }
+
   if (!use_aura) {
     sources -= [
       "test/ui_controls_aura.cc",
@@ -835,6 +841,7 @@
     sources += [
       "ime/candidate_window_unittest.cc",
       "ime/chromeos/character_composer_unittest.cc",
+      "ime/chromeos/input_method_util_unittest.cc",
       "ime/composition_text_unittest.cc",
       "ime/input_method_base_unittest.cc",
       "ime/input_method_chromeos_unittest.cc",
diff --git a/ui/base/ime/BUILD.gn b/ui/base/ime/BUILD.gn
index 0eb784c..2a64844 100644
--- a/ui/base/ime/BUILD.gn
+++ b/ui/base/ime/BUILD.gn
@@ -42,6 +42,8 @@
     "chromeos/input_method_descriptor.h",
     "chromeos/input_method_manager.cc",
     "chromeos/input_method_manager.h",
+    "chromeos/input_method_util.cc",
+    "chromeos/input_method_util.h",
     "chromeos/mock_component_extension_ime_manager.cc",
     "chromeos/mock_component_extension_ime_manager.h",
     "chromeos/mock_component_extension_ime_manager_delegate.cc",
@@ -161,6 +163,7 @@
   if (is_chromeos) {
     deps += [
       "//chromeos",
+      "//ui/chromeos/strings",
       "//ui/events:dom_keycode_converter",
     ]
     if (!use_ozone) {
diff --git a/ui/base/ime/chromeos/DEPS b/ui/base/ime/chromeos/DEPS
index 2207eb7..1f5487c 100644
--- a/ui/base/ime/chromeos/DEPS
+++ b/ui/base/ime/chromeos/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   "+chromeos/chromeos_switches.h",
   "+chromeos/ime",
+  "+ui/chromeos/strings",
 ]
diff --git a/ui/base/ime/chromeos/extension_ime_util.cc b/ui/base/ime/chromeos/extension_ime_util.cc
index 71440a1..bc02ce8 100644
--- a/ui/base/ime/chromeos/extension_ime_util.cc
+++ b/ui/base/ime/chromeos/extension_ime_util.cc
@@ -23,6 +23,11 @@
 
 namespace extension_ime_util {
 
+const char kBrailleImeExtensionId[] = "jddehjeebkoimngcbdkaahpobgicbffp";
+const char kBrailleImeExtensionPath[] = "chromeos/braille_ime";
+const char kBrailleImeEngineId[] =
+    "_comp_ime_jddehjeebkoimngcbdkaahpobgicbffpbraille";
+
 std::string GetInputMethodID(const std::string& extension_id,
                              const std::string& engine_id) {
   DCHECK(!extension_id.empty());
diff --git a/ui/base/ime/chromeos/extension_ime_util.h b/ui/base/ime/chromeos/extension_ime_util.h
index 0fa3eafb..09f28b85 100644
--- a/ui/base/ime/chromeos/extension_ime_util.h
+++ b/ui/base/ime/chromeos/extension_ime_util.h
@@ -35,6 +35,12 @@
 const char kChineseCangjieExtensionId[] = "aeebooiibjahgpgmhkeocbeekccfknbj";
 #endif
 
+// Extension id, path (relative to |chrome::DIR_RESOURCES|) and IME engine
+// id for the builtin-in Braille IME extension.
+UI_BASE_IME_EXPORT extern const char kBrailleImeExtensionId[];
+UI_BASE_IME_EXPORT extern const char kBrailleImeExtensionPath[];
+UI_BASE_IME_EXPORT extern const char kBrailleImeEngineId[];
+
 // Returns InputMethodID for |engine_id| in |extension_id| of extension IME.
 // This function does not check |extension_id| is installed extension IME nor
 // |engine_id| is really a member of |extension_id|.
diff --git a/chrome/browser/chromeos/input_method/input_method_util.cc b/ui/base/ime/chromeos/input_method_util.cc
similarity index 97%
rename from chrome/browser/chromeos/input_method/input_method_util.cc
rename to ui/base/ime/chromeos/input_method_util.cc
index 48085cf..81ae3e7 100644
--- a/chrome/browser/chromeos/input_method/input_method_util.cc
+++ b/ui/base/ime/chromeos/input_method_util.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 
 #include <stddef.h>
 
@@ -17,16 +17,13 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/common/extensions/extension_constants.h"
-// TODO(nona): move this header from this file.
-#include "chrome/grit/generated_resources.h"
-#include "components/prefs/pref_service.h"
 #include "ui/base/ime/chromeos/component_extension_ime_manager.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 // For SetHardwareKeyboardLayoutForTesting.
 #include "ui/base/ime/chromeos/fake_input_method_delegate.h"
 #include "ui/base/ime/chromeos/input_method_delegate.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/chromeos/strings/grit/ui_chromeos_strings.h"
 
 namespace {
 
@@ -51,7 +48,7 @@
     IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_TRADITIONAL },
   { "zh-hant-t-i0-cangjie-1987-x-m0-simplified",
     IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_TRADITIONAL },
-  { extension_misc::kBrailleImeEngineId,
+  { chromeos::extension_ime_util::kBrailleImeEngineId,
     IDS_LANGUAGES_MEDIUM_LEN_NAME_BRAILLE },
 };
 const size_t kMappingImeIdToMediumLenNameResourceIdLen =
@@ -388,8 +385,7 @@
   }
 }
 
-InputMethodUtil::~InputMethodUtil() {
-}
+InputMethodUtil::~InputMethodUtil() {}
 
 std::string InputMethodUtil::GetLocalizedDisplayName(
     const InputMethodDescriptor& descriptor) const {
@@ -529,7 +525,6 @@
   return text;
 }
 
-
 base::string16 InputMethodUtil::GetInputMethodLongNameStripped(
     const InputMethodDescriptor& input_method) const {
   return GetInputMethodLongNameInternal(input_method, true /* short_name */);
@@ -594,13 +589,12 @@
   // screen or set in UserContext when starting a public session).
   out_input_method_ids->push_back(preferred_input_method.id());
 
-  const std::string current_layout
-      = preferred_input_method.GetPreferredKeyboardLayout();
-  for (size_t i = 0; i < arraysize(kDefaultInputMethodRecommendation);
-       ++i) {
-    if (kDefaultInputMethodRecommendation[i].locale == language_code && (
-        !kDefaultInputMethodRecommendation[i].layout[0] ||
-        kDefaultInputMethodRecommendation[i].layout == current_layout)) {
+  const std::string current_layout =
+      preferred_input_method.GetPreferredKeyboardLayout();
+  for (size_t i = 0; i < arraysize(kDefaultInputMethodRecommendation); ++i) {
+    if (kDefaultInputMethodRecommendation[i].locale == language_code &&
+        (!kDefaultInputMethodRecommendation[i].layout[0] ||
+         kDefaultInputMethodRecommendation[i].layout == current_layout)) {
       out_input_method_ids->push_back(
           extension_ime_util::GetInputMethodIDByEngineID(
               kDefaultInputMethodRecommendation[i].engine_id));
@@ -666,8 +660,7 @@
     }
   }
   // Migrates the extension IDs.
-  std::string id =
-      extension_ime_util::GetInputMethodIDByEngineID(engine_id);
+  std::string id = extension_ime_util::GetInputMethodIDByEngineID(engine_id);
   if (extension_ime_util::IsComponentExtensionIME(id)) {
     std::string id_new = extension_ime_util::GetInputMethodIDByEngineID(
         extension_ime_util::GetComponentIDByInputMethodID(id));
@@ -753,15 +746,14 @@
   UpdateHardwareLayoutCache();
 }
 
-const std::vector<std::string>&
-    InputMethodUtil::GetHardwareInputMethodIds() {
+const std::vector<std::string>& InputMethodUtil::GetHardwareInputMethodIds() {
   DCHECK(thread_checker_.CalledOnValidThread());
   UpdateHardwareLayoutCache();
   return hardware_layouts_;
 }
 
 const std::vector<std::string>&
-    InputMethodUtil::GetHardwareLoginInputMethodIds() {
+InputMethodUtil::GetHardwareLoginInputMethodIds() {
   DCHECK(thread_checker_.CalledOnValidThread());
   UpdateHardwareLayoutCache();
   return hardware_login_layouts_;
diff --git a/chrome/browser/chromeos/input_method/input_method_util.h b/ui/base/ime/chromeos/input_method_util.h
similarity index 96%
rename from chrome/browser/chromeos/input_method/input_method_util.h
rename to ui/base/ime/chromeos/input_method_util.h
index fea1448f..06f886f 100644
--- a/chrome/browser/chromeos/input_method/input_method_util.h
+++ b/ui/base/ime/chromeos/input_method_util.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_INPUT_METHOD_INPUT_METHOD_UTIL_H_
-#define CHROME_BROWSER_CHROMEOS_INPUT_METHOD_INPUT_METHOD_UTIL_H_
+#ifndef UI_BASE_IME_CHROMEOS_INPUT_METHOD_UTIL_H_
+#define UI_BASE_IME_CHROMEOS_INPUT_METHOD_UTIL_H_
 
 #include <cstddef>
 #include <map>
@@ -16,6 +16,7 @@
 #include "base/strings/string16.h"
 #include "base/threading/thread_checker.h"
 #include "ui/base/ime/chromeos/input_method_descriptor.h"
+#include "ui/base/ime/ui_base_ime_export.h"
 
 namespace chromeos {
 namespace input_method {
@@ -28,7 +29,7 @@
 };
 
 // A class which provides miscellaneous input method utility functions.
-class InputMethodUtil {
+class UI_BASE_IME_EXPORT InputMethodUtil {
  public:
   explicit InputMethodUtil(InputMethodDelegate* delegate);
   ~InputMethodUtil();
@@ -221,4 +222,4 @@
 }  // namespace input_method
 }  // namespace chromeos
 
-#endif  // CHROME_BROWSER_CHROMEOS_INPUT_METHOD_INPUT_METHOD_UTIL_H_
+#endif  // UI_BASE_IME_CHROMEOS_INPUT_METHOD_UTIL_H_
diff --git a/chrome/browser/chromeos/input_method/input_method_util_unittest.cc b/ui/base/ime/chromeos/input_method_util_unittest.cc
similarity index 96%
rename from chrome/browser/chromeos/input_method/input_method_util_unittest.cc
rename to ui/base/ime/chromeos/input_method_util_unittest.cc
index 0489f50..cc132e1 100644
--- a/chrome/browser/chromeos/input_method/input_method_util_unittest.cc
+++ b/ui/base/ime/chromeos/input_method_util_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/input_method/input_method_util.h"
+#include "ui/base/ime/chromeos/input_method_util.h"
 
 #include <stddef.h>
 
@@ -210,20 +210,17 @@
   // See below for exceptions.
   {
     InputMethodDescriptor desc = GetDesc("xkb:jp::jpn", "jp", "ja", "");
-    EXPECT_EQ(ASCIIToUTF16("Japanese"),
-              util_.GetInputMethodLongName(desc));
+    EXPECT_EQ(ASCIIToUTF16("Japanese"), util_.GetInputMethodLongName(desc));
   }
   {
     InputMethodDescriptor desc =
         GetDesc("xkb:us:dvorak:eng", "us(dvorak)", "en-US", "");
-    EXPECT_EQ(ASCIIToUTF16("US Dvorak"),
-              util_.GetInputMethodLongName(desc));
+    EXPECT_EQ(ASCIIToUTF16("US Dvorak"), util_.GetInputMethodLongName(desc));
   }
   {
     InputMethodDescriptor desc =
         GetDesc("xkb:gb:dvorak:eng", "gb(dvorak)", "en-US", "");
-    EXPECT_EQ(ASCIIToUTF16("UK Dvorak"),
-              util_.GetInputMethodLongName(desc));
+    EXPECT_EQ(ASCIIToUTF16("UK Dvorak"), util_.GetInputMethodLongName(desc));
   }
 
   // For Dutch, French, German and Hindi,
@@ -258,8 +255,7 @@
     InputMethodDescriptor desc = GetDesc("invalid-id", "us", "xx", "");
     // You can safely ignore the "Resouce ID is not found for: invalid-id"
     // error.
-    EXPECT_EQ(ASCIIToUTF16("invalid-id"),
-              util_.GetInputMethodLongName(desc));
+    EXPECT_EQ(ASCIIToUTF16("invalid-id"), util_.GetInputMethodLongName(desc));
   }
 }
 
@@ -291,8 +287,7 @@
 }
 
 TEST_F(InputMethodUtilTest, TestGetInputMethodDisplayNameFromId) {
-  EXPECT_EQ("US",
-            util_.GetInputMethodDisplayNameFromId("xkb:us::eng"));
+  EXPECT_EQ("US", util_.GetInputMethodDisplayNameFromId("xkb:us::eng"));
   EXPECT_EQ("", util_.GetInputMethodDisplayNameFromId("nonexistent"));
 }
 
@@ -526,11 +521,11 @@
   EXPECT_EQ(1U, login_input_method_ids.size());
 
   EXPECT_EQ("xkb:us::eng", extension_ime_util::GetComponentIDByInputMethodID(
-      input_method_ids[0]));
+                               input_method_ids[0]));
   EXPECT_EQ("xkb:ru::rus", extension_ime_util::GetComponentIDByInputMethodID(
-      input_method_ids[1]));
+                               input_method_ids[1]));
   EXPECT_EQ("xkb:us::eng", extension_ime_util::GetComponentIDByInputMethodID(
-      login_input_method_ids[0]));
+                               login_input_method_ids[0]));
 }
 
 }  // namespace input_method
diff --git a/ui/chromeos/ui_chromeos_strings.grd b/ui/chromeos/ui_chromeos_strings.grd
index 8765816..33e91423 100644
--- a/ui/chromeos/ui_chromeos_strings.grd
+++ b/ui/chromeos/ui_chromeos_strings.grd
@@ -336,9 +336,624 @@
       <message translateable="false" name="IDS_LOGIN_DEFAULT_USER_WEBSITE_33">
       </message>
 
+      <!-- Input method strings. -->
       <message name="IDS_CHROMEOS_IME_INFOLIST_WINDOW_TITLE" desc="The title of the infolist window where the meanings and the usages of words are displayed.">
         Information
       </message>
+      <message name="IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_SIMPLIFIED" desc="Medium length name for the input method for simplified Chinese which is shown following the text: Your input method has changed to...">
+        Simplified Chinese
+      </message>
+      <message name="IDS_LANGUAGES_MEDIUM_LEN_NAME_CHINESE_TRADITIONAL" desc="Medium length name for the input method for traditional Chinese which is show following the text: Your input method has changed to...">
+       Traditional Chinese
+      </message>
+      <message name="IDS_LANGUAGES_MEDIUM_LEN_NAME_KOREAN" desc="Medium length name for the input method for Korean which is show following the text: Your input method has changed to...">
+        Korean
+      </message>
+      <message name="IDS_LANGUAGES_MEDIUM_LEN_NAME_BRAILLE" desc="Medium length name for the input method for the hardware keyboard on a braille display. Shown after the text: Your input method has changed to...">
+        Braille
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_JAPAN" desc="In the language menu button, this shows the input mode [Japanese keyboard].">
+        Japanese
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_SLOVENIA" desc="In the language menu button, this shows the input mode [Slovenian keyboard].">
+        Slovenian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_GERMANY" desc="In the language menu button, this shows the input mode [German keyboard].">
+        German
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_GERMANY_NEO2" desc="In the language menu button, this shows the input mode [German Neo 2 keyboard].">
+        German Neo 2
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_ITALY" desc="In the language menu button, this shows the input mode [Italian keyboard].">
+        Italian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_ESTONIA" desc="In the language menu button, this shows the input mode [Estonian keyboard].">
+        Estonian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_FAROESE" desc="In the language menu button, this shows the input mode [Faroese keyboard].">
+        Faroese
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_HUNGARY" desc="In the language menu button, this shows the input mode [Hungarian keyboard].">
+        Hungarian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_HUNGARY_QWERTY" desc="In the language menu button, this shows the input mode [Hungarian QWERTY keyboard].">
+        Hungarian QWERTY
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_POLAND" desc="In the language menu button, this shows the input mode [Polish keyboard].">
+        Polish
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_DENMARK" desc="In the language menu button, this shows the input mode [Danish keyboard].">
+        Danish
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_CROATIA" desc="In the language menu button, this shows the input mode [Croatian keyboard].">
+        Croatian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_BRAZIL" desc="In the language menu button, this shows the input mode [Brazilian keyboard].">
+        Brazilian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_SERBIA" desc="In the language menu button, this shows the input mode [Serbian keyboard].">
+        Serbian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_CZECHIA" desc="In the language menu button, this shows the input mode [Czech keyboard].">
+        Czech
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_CZECHIA_QWERTY" desc="In the language menu button, this shows the input mode [Czech QWERTY keyboard].">
+        Czech QWERTY
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_USA_DVORAK" desc="In the language menu button, this shows the input mode [US Dvorak keyboard].">
+        US Dvorak
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_USA_DVP" desc="In the language menu button, this shows the input mode [US Programmer Dvorak keyboard].">
+        US Programmer Dvorak
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_USA_COLEMAK" desc="In the language menu button, this shows the input mode [US Colemak keyboard].">
+        US Colemak
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_ROMANIA" desc="In the language menu button, this shows the input mode [Romanian keyboard].">
+        Romanian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_USA" desc="In the language menu button, this shows the input mode [US keyboard].">
+        US
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_USA_EXTENDED" desc="In the language menu button, this shows the input mode [US extended keyboard].">
+        US extended
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_USA_INTERNATIONAL" desc="In the language menu button, this shows the input mode [US international keyboard].">
+        US international
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_USA_WORKMAN" desc="In the language menu button, this shows the input mode [US Workman keyboard].">
+        US Workman
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_USA_WORKMAN_INTERNATIONAL" desc="In the language menu button, this shows the input mode [US Workman international keyboard].">
+        US Workman international
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_LITHUANIA" desc="In the language menu button, this shows the input mode [Lithuanian keyboard].">
+        Lithuanian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_UNITED_KINGDOM" desc="In the language menu button, this shows the input mode [UK keyboard].">
+        UK
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_UNITED_KINGDOM_DVORAK" desc="In the language menu button, this shows the input mode [UK Dvorak keyboard].">
+        UK Dvorak
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_SLOVAKIA" desc="In the language menu button, this shows the input mode [Slovak keyboard].">
+        Slovak
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_RUSSIA" desc="In the language menu button, this shows the input mode [Russian keyboard].">
+        Russian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_RUSSIA_PHONETIC" desc="In the language menu button, this shows the input mode [Russian phonetic keyboard].">
+        Russian phonetic
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_GREECE" desc="In the language menu button, this shows the input mode [Greek keyboard].">
+        Greek
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_BELGIUM" desc="In the language menu button, this shows the input mode [Belgian keyboard].">
+        Belgian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_BULGARIA" desc="In the language menu button, this shows the input mode [Bulgarian keyboard].">
+        Bulgarian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_BULGARIA_PHONETIC" desc="In the language menu button, this shows the input mode [Bulgarian phonetic keyboard].">
+        Bulgarian phonetic
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_SWITZERLAND" desc="In the language menu button, this shows the input mode [Swiss keyboard].">
+        Swiss
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_SWITZERLAND_FRENCH" desc="In the language menu button, this shows the input mode [Swiss French keyboard].">
+        Swiss French
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_TURKEY" desc="In the language menu button, this shows the input mode [Turkish keyboard].">
+        Turkish
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_TURKEY_F" desc="In the language menu button, this shows the input mode [Turkish-F keyboard].">
+        Turkish-F
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_PORTUGAL" desc="In the language menu button, this shows the input mode [Portuguese keyboard].">
+        Portuguese
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_SPAIN" desc="In the language menu button, this shows the input mode [Spanish keyboard].">
+        Spanish
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_FINLAND" desc="In the language menu button, this shows the input mode [Finnish keyboard].">
+        Finnish
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_UKRAINE" desc="In the language menu button, this shows the input mode [Ukrainian keyboard].">
+        Ukrainian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_SPAIN_CATALAN" desc="In the language menu button, this shows the input mode [Catalan keyboard].">
+        Catalan
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_FRANCE_BEPO" desc="In the language menu button, this shows the input mode [French BÉPO keyboard].">
+        French BÉPO
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_FRANCE" desc="In the language menu button, this shows the input mode [French keyboard].">
+        French
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_NORWAY" desc="In the language menu button, this shows the input mode [Norwegian keyboard].">
+        Norwegian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_SWEDEN" desc="In the language menu button, this shows the input mode [Swedish keyboard].">
+        Swedish
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_NETHERLANDS" desc="In the language menu button, this shows the input mode [Dutch keyboard].">
+        Dutch
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_LATIN_AMERICAN" desc="In the language menu button, this shows the input mode [Latin American keyboard].">
+        Latin American
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_LATVIA" desc="In the language menu button, this shows the input mode [Latvian keyboard].">
+        Latvian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_CANADA" desc="In the language menu button, this shows the input mode [Canadian French keyboard].">
+        Canadian French
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_CANADA_ENGLISH" desc="In the language menu button, this shows the input mode [Canadian English keyboard].">
+        Canadian English
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_ISRAEL" desc="In the language menu button, this shows the input mode [Hebrew keyboard].">
+        Hebrew
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_KOREA_104" desc="In the language menu button, this shows the input mode [Korean keyboard].">
+        Korean
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_ICELANDIC" desc="In the language menu button, this shows the input mode [Icelandic keyboard].">
+        Icelandic
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_CANADIAN_MULTILINGUAL" desc="In the language menu button, this shows the input mode [Canadian Multilingual keyboard].">
+        Canadian Multilingual
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_GEORGIAN" desc="In the language menu button, this shows the input mode [Georgian keyboard].">
+        Georgian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_BELARUSIAN" desc="In the language menu button, this shows the input mode [Belarusian keyboard].">
+        Belarusian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_ARMENIAN_PHONETIC" desc="In the language menu button, this shows the input mode [Armenian Phonetic keyboard].">
+        Armenian Phonetic
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_MONGOLIAN" desc="In the language menu button, this shows the input mode [Mongolian keyboard].">
+        Mongolian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_IRISH" desc="In the language menu button, this shows the input mode [Irish keyboard].">
+        Irish
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_MACEDONIAN" desc="In the language menu button, this shows the input mode [Macedonian keyboard].">
+        Macedonian
+      </message>
+      <message name="IDS_STATUSBAR_LAYOUT_KAZAKH" desc="In the language menu button, this shows the input mode [Kazakh keyboard].">
+        Kazakh
+      </message>
+
+      <message name="IDS_IME_NAME_KEYBOARD_ARMENIAN_PHONETIC" desc="The input method name shows in system tray menu, this shows [Armenian Phonetic keyboard].">
+        Armenian Phonetic keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_BELARUSIAN" desc="The input method name shows in system tray menu, this shows [Belarusian keyboard].">
+        Belarusian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_BELGIAN" desc="The input method name shows in system tray menu, this shows [Belgian keyboard].">
+        Belgian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_BRAZILIAN" desc="The input method name shows in system tray menu, this shows [Brazilian keyboard].">
+        Brazilian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_BULGARIAN" desc="The input method name shows in system tray menu, this shows [Bulgarian keyboard].">
+        Bulgarian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_BULGARIAN_PHONETIC" desc="The input method name shows in system tray menu, this shows [Bulgarian Phonetic keyboard].">
+        Bulgarian Phonetic keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_CANADIAN_ENGLISH" desc="The input method name shows in system tray menu, this shows [Canadian English keyboard].">
+        Canadian English keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_CANADIAN_FRENCH" desc="The input method name shows in system tray menu, this shows [Canadian French keyboard].">
+        Canadian French keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_CANADIAN_MULTILINGUAL" desc="The input method name shows in system tray menu, this shows [Canadian Multilingual keyboard].">
+        Canadian Multilingual keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_CATALAN" desc="The input method name shows in system tray menu, this shows [Catalan keyboard].">
+        Catalan keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_CROATIAN" desc="The input method name shows in system tray menu, this shows [Croatian keyboard].">
+        Croatian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_CZECH" desc="The input method name shows in system tray menu, this shows [Czech keyboard].">
+        Czech keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_CZECH_QWERTY" desc="The input method name shows in system tray menu, this shows [Czech QWERTY keyboard].">
+        Czech QWERTY keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_DANISH" desc="The input method name shows in system tray menu, this shows [Danish keyboard].">
+        Danish keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_ESTONIAN" desc="The input method name shows in system tray menu, this shows [Estonian keyboard].">
+        Estonian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_FAROESE" desc="The input method name shows in system tray menu, this shows [Faroese keyboard].">
+        Faroese keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_FINNISH" desc="The input method name shows in system tray menu, this shows [Finnish keyboard].">
+        Finnish keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_FRENCH_BEPO" desc="The input method name shows in system tray menu, this shows [French BÉPO keyboard].">
+        French BÉPO keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_FRENCH" desc="The input method name shows in system tray menu, this shows [French keyboard].">
+        French keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_GEORGIAN" desc="The input method name shows in system tray menu, this shows [Georgian keyboard].">
+        Georgian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_GERMAN" desc="The input method name shows in system tray menu, this shows [German keyboard].">
+        German keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_GERMAN_NEO_2" desc="The input method name shows in system tray menu, this shows [German NEO 2 keyboard].">
+        German NEO 2 keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_GREEK" desc="The input method name shows in system tray menu, this shows [Greek keyboard].">
+        Greek keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_HEBREW" desc="The input method name shows in system tray menu, this shows [Hebrew keyboard].">
+        Hebrew keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_HUNGARIAN" desc="The input method name shows in system tray menu, this shows [Hungarian keyboard].">
+        Hungarian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_HUNGARIAN_QWERTY" desc="The input method name shows in system tray menu, this shows [Hungarian QWERTY keyboard].">
+        Hungarian QWERTY keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_ICELANDIC" desc="The input method name shows in system tray menu, this shows [Icelandic keyboard].">
+        Icelandic keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_IRISH" desc="The input method name shows in system tray menu, this shows [Irish keyboard].">
+        Irish keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_ITALIAN" desc="The input method name shows in system tray menu, this shows [Italian keyboard].">
+        Italian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_JAPANESE" desc="The input method name shows in system tray menu, this shows [Japanese keyboard].">
+        Japanese keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_KAZAKH" desc="The input method name shows in system tray menu, this shows [Kazakh keyboard].">
+        Kazakh keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_LATIN_AMERICAN" desc="The input method name shows in system tray menu, this shows [Latin American keyboard].">
+        Latin American keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_LATVIAN" desc="The input method name shows in system tray menu, this shows [Latvian keyboard].">
+        Latvian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_LITHUANIAN" desc="The input method name shows in system tray menu, this shows [Lithuanian keyboard].">
+        Lithuanian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_MACEDONIAN" desc="The input method name shows in system tray menu, this shows [Macedonian keyboard].">
+        Macedonian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_MALTESE" desc="The input method name shows in system tray menu, this shows [Maltese keyboard].">
+        Maltese keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_MONGOLIAN" desc="The input method name shows in system tray menu, this shows [Mongolian keyboard].">
+        Mongolian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_NETHERLANDS" desc="The input method name shows in system tray menu, this shows [Netherlands keyboard].">
+        Netherlands keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_NORWEGIAN" desc="The input method name shows in system tray menu, this shows [Norwegian keyboard].">
+        Norwegian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_POLISH" desc="The input method name shows in system tray menu, this shows [Polish keyboard].">
+        Polish keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_PORTUGUESE" desc="The input method name shows in system tray menu, this shows [Portuguese keyboard].">
+        Portuguese keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_ROMANIAN" desc="The input method name shows in system tray menu, this shows [Romanian keyboard].">
+        Romanian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_ROMANIAN_STANDARD" desc="The input method name shows in system tray menu, this shows [Romanian standard keyboard].">
+        Romanian standard keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_RUSSIAN" desc="The input method name shows in system tray menu, this shows [Russian keyboard].">
+        Russian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_RUSSIAN_PHONETIC" desc="The input method name shows in system tray menu, this shows [Russian Phonetic keyboard].">
+        Russian Phonetic keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_RUSSIAN_PHONETIC_AATSEEL" desc="The input method name shows in system tray menu, this shows [Russian Phonetic (AATSEEL) keyboard].">
+        Russian Phonetic (AATSEEL) keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_RUSSIAN_PHONETIC_YAZHERT" desc="The input method name shows in system tray menu, this shows [Russian Phonetic (YaZHert) keyboard].">
+        Russian Phonetic (YaZHert) keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_SERBIAN" desc="The input method name shows in system tray menu, this shows [Serbian keyboard].">
+        Serbian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_SLOVAK" desc="The input method name shows in system tray menu, this shows [Slovak keyboard].">
+        Slovak keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_SLOVENIAN" desc="The input method name shows in system tray menu, this shows [Slovenian keyboard].">
+        Slovenian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_SPANISH" desc="The input method name shows in system tray menu, this shows [Spanish keyboard].">
+        Spanish keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_SWEDISH" desc="The input method name shows in system tray menu, this shows [Swedish keyboard].">
+        Swedish keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_SWISS_FRENCH" desc="The input method name shows in system tray menu, this shows [Swiss French keyboard].">
+        Swiss French keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_SWISS" desc="The input method name shows in system tray menu, this shows [Swiss keyboard].">
+        Swiss keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_TURKISH" desc="The input method name shows in system tray menu, this shows [Turkish keyboard].">
+        Turkish keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_TURKISH_F" desc="The input method name shows in system tray menu, this shows [Turkish-F keyboard].">
+        Turkish-F keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_UK_DVORAK" desc="The input method name shows in system tray menu, this shows [UK Dvorak keyboard].">
+        UK Dvorak keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_UK" desc="The input method name shows in system tray menu, this shows [UK keyboard].">
+        UK keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_UKRAINIAN" desc="The input method name shows in system tray menu, this shows [Ukrainian keyboard].">
+        Ukrainian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_US_COLEMAK" desc="The input method name shows in system tray menu, this shows [US Colemak keyboard].">
+        US Colemak keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_US_DVORAK" desc="The input method name shows in system tray menu, this shows [US Dvorak keyboard].">
+        US Dvorak keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_US_DVP" desc="The input method name shows in system tray menu, this shows [US Programmer Dvorak keyboard].">
+        US Programmer Dvorak keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_US_EXTENDED" desc="The input method name shows in system tray menu, this shows [US Extended keyboard].">
+        US Extended keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_US_INTERNATIONAL" desc="The input method name shows in system tray menu, this shows [US International keyboard].">
+        US International keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_US_WORKMAN" desc="The input method name shows in system tray menu, this shows [US Workman keyboard].">
+        US Workman keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_US_WORKMAN_INTERNATIONAL" desc="The input method name shows in system tray menu, this shows [US Workman international keyboard].">
+        US Workman international keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_US" desc="The input method name shows in system tray menu, this shows [US keyboard].">
+        US keyboard
+      </message>
+
+      <message name="IDS_IME_NAME_INPUTMETHOD_ARRAY" desc="The input method name shows in system tray menu, this is Array (\u884c\u5217) input method for Traditional Chinese.">
+        Array input method
+      </message>
+      <message name="IDS_IME_NAME_INPUTMETHOD_CANGJIE" desc="The input method name shows in system tray menu, this is Cangjie input method for Tradition Chinese.">
+        Cangjie input method
+      </message>
+      <message name="IDS_IME_NAME_INPUTMETHOD_DAYI" desc="The input method name shows in system tray menu, this is Dayi (\u5927\u6613) input method for Traditional Chinese.">
+        Dayi input method
+      </message>
+      <message name="IDS_IME_NAME_INPUTMETHOD_MOZC_JP" desc="The input method name shows in system tray menu, this is Japanese input method for Japanese keyboard.">
+        Google Japanese Input (for Japanese keyboard)
+      </message>
+      <message name="IDS_IME_NAME_INPUTMETHOD_MOZC_US" desc="The input method name shows in system tray menu, this is Japanese input method for US keyboard.">
+        Google Japanese Input (for US keyboard)
+      </message>
+      <message name="IDS_IME_NAME_INPUTMETHOD_PINYIN" desc="The input method name shows in system tray menu, this is Pinyin input method for Simplified Chinese.">
+        Pinyin input method
+      </message>
+      <message name="IDS_IME_NAME_INPUTMETHOD_QUICK" desc="The input method name shows in system tray menu, this is Quick input method for Traditional Chinese.">
+        Quick input method
+      </message>
+      <message name="IDS_IME_NAME_INPUTMETHOD_TRADITIONAL_PINYIN" desc="The input method name shows in system tray menu, this is Pinyin input method for Traditional Chinese.">
+        Traditional Pinyin input method
+      </message>
+      <message name="IDS_IME_NAME_INPUTMETHOD_WUBI" desc="The input method name shows in system tray menu, this is Wubi input method for Simplified Chinese.">
+        Wubi input method
+      </message>
+      <message name="IDS_IME_NAME_INPUTMETHOD_ZHUYIN" desc="The input method name shows in system tray menu, this is Zhuyin input method for Traditional Chinese.">
+        Zhuyin input method
+      </message>
+      <message name="IDS_IME_NAME_INPUTMETHOD_CANTONESE" desc="The input method name shows in system tray menu, this is Cantonese input method for Traditional Chinese.">
+        Cantonese input method
+      </message>
+      <message name="IDS_IME_NAME_INPUTMETHOD_HANGUL" desc="The input method name shows in system tray menu, this is Korean Hangul input method.">
+        Korean input method
+      </message>
+      <message name="IDS_IME_NAME_INPUTMETHOD_HANGUL_2_SET" desc="The input method name shows in system tray menu, this is Korean Hangul input method, 2 Set mode.">
+        Hangul 2 Set
+      </message>
+      <message name="IDS_IME_NAME_INPUTMETHOD_HANGUL_3_SET_390" desc="The input method name shows in system tray menu, this is Korean Hangul input method, 3 Set (390) mode.">
+        Hangul 3 Set (390)
+      </message>
+      <message name="IDS_IME_NAME_INPUTMETHOD_HANGUL_3_SET_FINAL" desc="The input method name shows in system tray menu, this is Korean Hangul input method, 3 Set (Final) mode.">
+        Hangul 3 Set (Final)
+      </message>
+      <message name="IDS_IME_NAME_INPUTMETHOD_HANGUL_3_SET_NO_SHIFT" desc="The input method name shows in system tray menu, this is Korean Hangul input method, 3 Set (No Shift) mode.">
+        Hangul 3 Set (No Shift)
+      </message>
+      <message name="IDS_IME_NAME_INPUTMETHOD_HANGUL_ROMAJA" desc="The input method name shows in system tray menu, this is Korean Hangul input method, Romaja mode.">
+        Hangul Romaja
+      </message>
+      <message name="IDS_IME_NAME_INPUTMETHOD_HANGUL_AHNMATAE" desc="The input method name shows in system tray menu, this is Korean Hangul input method, Ahnmatae mode.">
+        Hangul Ahnmatae
+      </message>
+
+      <message name="IDS_IME_NAME_KEYBOARD_ARABIC" desc="The input method name shows in system tray menu.">
+        Arabic keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_BENGALI_PHONETIC" desc="The input method name shows in system tray menu.">
+        Bengali keyboard (Phonetic)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_DEVANAGARI_PHONETIC" desc="The input method name shows in system tray menu.">
+        Devanagari keyboard (Phonetic)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_ETHIOPIC" desc="The input method name shows in system tray menu.">
+        Ethiopic keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_GUJARATI_PHONETIC" desc="The input method name shows in system tray menu.">
+        Gujarati keyboard (Phonetic)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_KANNADA_PHONETIC" desc="The input method name shows in system tray menu.">
+        Kannada keyboard (Phonetic)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_KHMER" desc="The input method name shows in system tray menu.">
+        Khmer keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_LAO" desc="The input method name shows in system tray menu.">
+        Lao keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_MALAYALAM_PHONETIC" desc="The input method name shows in system tray menu.">
+        Malayalam keyboard (Phonetic)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_MYANMAR" desc="The input method name shows in system tray menu.">
+        Myanmar keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_MYANMAR_MYANSAN" desc="The input method name shows in system tray menu.">
+        Myanmar Myansan keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_NEPALI_INSCRIPT" desc="The input method name shows in system tray menu.">
+        Nepali keyboard (InScript)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_NEPALI_PHONETIC" desc="The input method name shows in system tray menu.">
+        Nepali keyboard (Phonetic)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_PERSIAN" desc="The input method name shows in system tray menu.">
+        Persian keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_SINHALA" desc="The input method name shows in system tray menu.">
+        Sinhala keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_SORANIKURDISH_AR" desc="The input method name shows in system tray menu.">
+        Sorani Kurdish Arabic-based keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_SORANIKURDISH_EN" desc="The input method name shows in system tray menu.">
+        Sorani Kurdish English-based keyboard
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_TAMIL_INSCRIPT" desc="The input method name shows in system tray menu.">
+        Tamil keyboard (InScript)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_TAMIL_ITRANS" desc="The input method name shows in system tray menu.">
+        Tamil keyboard (itrans)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_TAMIL_PHONETIC" desc="The input method name shows in system tray menu.">
+        Tamil keyboard (Phonetic)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_TAMIL_TAMIL99" desc="The input method name shows in system tray menu.">
+        Tamil keyboard (Tamil99)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_TAMIL_TYPEWRITER" desc="The input method name shows in system tray menu.">
+        Tamil keyboard (Typewriter)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_TELUGU_PHONETIC" desc="The input method name shows in system tray menu.">
+        Telugu keyboard (Phonetic)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_THAI_KEDMANEE" desc="The input method name shows in system tray menu.">
+        Thai keyboard (Kedmanee)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_THAI_PATTACHOTE" desc="The input method name shows in system tray menu.">
+        Thai keyboard (Pattachote)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_THAI_TIS" desc="The input method name shows in system tray menu.">
+        Thai keyboard (TIS 820-2531)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_VIETNAMESE_TCVN" desc="The input method name shows in system tray menu.">
+        Vietnamese keyboard (TCVN)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_VIETNAMESE_TELEX" desc="The input method name shows in system tray menu.">
+        Vietnamese keyboard (Telex)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_VIETNAMESE_VIQR" desc="The input method name shows in system tray menu.">
+        Vietnamese keyboard (VIQR)
+      </message>
+      <message name="IDS_IME_NAME_KEYBOARD_VIETNAMESE_VNI" desc="The input method name shows in system tray menu.">
+        Vietnamese keyboard (VNI)
+      </message>
+
+      <message name="IDS_IME_NAME_TRANSLITERATION_AM" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (salam &#x2192; &#x1230;&#x120b;&#x121d;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_AR" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (marhaban &#x2190; &#x0645;&#x0631;&#x062d;&#x0628;&#x0627;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_BN" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (namaskar &#x2192; &#x09a8;&#x09ae;&#x09b8;&#x09cd;&#x0995;&#x09be;&#x09b0;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_EL" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (geia &#x2192; &#x03b3;&#x03b5;&#x03b9;&#x03b1;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_FA" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (salam &#x2190; &#x0633;&#x0644;&#x0627;&#x0645;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_GU" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (namaste &#x2192; &#x0aa8;&#x0aae;&#x0ab8;&#x0acd;&#x0aa4;&#x0ac7;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_HE" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (shalom &#x2190; &#x05e9;&#x05dc;&#x05d5;&#x05dd;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_HI" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (namaste &#x2192; &#x0928;&#x092e;&#x0938;&#x094d;&#x0924;&#x0947;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_KN" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (namaskaram &#x2192; &#x0ca8;&#x0cae;&#x0cb8;&#x0ccd;&#x0c95;&#x0cbe;&#x0cb0;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_ML" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (namaskar &#x2192; &#x0d28;&#x0d2e;&#x0d38;&#x0d4d;&#x0d15;&#x0d3e;&#x0d30;&#x0d02;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_MR" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (namaste &#x2192; &#x0928;&#x092e;&#x0938;&#x094d;&#x0915;&#x093e;&#x0930;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_NE" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (namaste &#x2192; &#x0928;&#x092e;&#x0938;&#x094d;&#x0924;&#x0947;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_OR" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (mausam &#x2192; &#x0b28;&#x0b2e;&#x0b38;&#x0b4d;&#x0b24;&#x0b47;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_PA" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (mausam &#x2192; &#x0a2e;&#x0a4c;&#x0a38;&#x0a2e;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_SA" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (namaste &#x2192; &#x0928;&#x092e;&#x0938;&#x094d;&#x0924;&#x0947;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_SR" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (zdravo &#x2192; &#x0437;&#x0434;&#x0440;&#x0430;&#x0432;&#x043e;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_TA" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (vanakkam &#x2192; &#x0bb5;&#x0ba3;&#x0b95;&#x0bcd;&#x0b95;&#x0bae;&#x0bcd;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_TE" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (emandi &#x2192; &#x0c0f;&#x0c2e;&#x0c02;&#x0c21;&#x0c40;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_TI" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (selam &#x2192; &#x1230;&#x120b;&#x121d;)
+      </message>
+      <message name="IDS_IME_NAME_TRANSLITERATION_UR" desc="The input method name shows in system tray menu. Please translate only for 'transliteration'.">
+        Transliteration (salam &#x2190; &#x0633;&#x0644;&#x0627;&#x0645;)
+      </message>
+
     </messages>
   </release>
 </grit>
diff --git a/ui/gl/init/gl_factory.cc b/ui/gl/init/gl_factory.cc
index 20da613..744b430 100644
--- a/ui/gl/init/gl_factory.cc
+++ b/ui/gl/init/gl_factory.cc
@@ -37,12 +37,12 @@
         cmd->GetSwitchValueASCII(switches::kUseGL);
     if (requested_implementation_name == "any") {
       fallback_to_software_gl = true;
-    } else if (requested_implementation_name ==
-               kGLImplementationSwiftShaderName) {
+    } else if ((requested_implementation_name ==
+                kGLImplementationSwiftShaderName) ||
+               (requested_implementation_name ==
+                kGLImplementationSwiftShaderForWebGLName)) {
       impl = kGLImplementationSwiftShaderGL;
-    } else if (requested_implementation_name ==
-                   kGLImplementationSwiftShaderForWebGLName ||
-               requested_implementation_name == kGLImplementationANGLEName) {
+    } else if (requested_implementation_name == kGLImplementationANGLEName) {
       impl = kGLImplementationEGLGLES2;
     } else {
       impl = GetNamedGLImplementation(requested_implementation_name);
diff --git a/ui/gl/init/gl_initializer_win.cc b/ui/gl/init/gl_initializer_win.cc
index e3b67c5..09d9d6f0 100644
--- a/ui/gl/init/gl_initializer_win.cc
+++ b/ui/gl/init/gl_initializer_win.cc
@@ -9,7 +9,6 @@
 #include "base/at_exit.h"
 #include "base/base_paths.h"
 #include "base/bind.h"
-#include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/native_library.h"
@@ -84,7 +83,7 @@
   return true;
 }
 
-bool InitializeStaticEGLInternal() {
+bool InitializeStaticEGLInternal(GLImplementation implementation) {
   base::FilePath module_path;
   if (!PathService::Get(base::DIR_MODULE, &module_path))
     return false;
@@ -96,14 +95,7 @@
   LoadD3DXLibrary(module_path, kD3DCompiler);
 
   base::FilePath gles_path;
-  const base::CommandLine* command_line =
-      base::CommandLine::ForCurrentProcess();
-  const std::string use_gl =
-      command_line->GetSwitchValueASCII(switches::kUseGL);
-  bool using_swift_shader =
-      (use_gl == kGLImplementationSwiftShaderName) ||
-      (use_gl == kGLImplementationSwiftShaderForWebGLName);
-  if (using_swift_shader) {
+  if (implementation == kGLImplementationSwiftShaderGL) {
 #if BUILDFLAG(ENABLE_SWIFTSHADER)
     gles_path = module_path.Append(L"swiftshader/");
     // Preload library
@@ -268,7 +260,7 @@
       return InitializeStaticOSMesaInternal();
     case kGLImplementationSwiftShaderGL:
     case kGLImplementationEGLGLES2:
-      return InitializeStaticEGLInternal();
+      return InitializeStaticEGLInternal(implementation);
     case kGLImplementationDesktopGL:
       return InitializeStaticWGLInternal();
     case kGLImplementationMockGL:
diff --git a/ui/gl/init/gl_initializer_x11.cc b/ui/gl/init/gl_initializer_x11.cc
index a8e3d42..b7dbcba 100644
--- a/ui/gl/init/gl_initializer_x11.cc
+++ b/ui/gl/init/gl_initializer_x11.cc
@@ -81,23 +81,11 @@
   return true;
 }
 
-bool InitializeStaticEGLInternal() {
+bool InitializeStaticEGLInternal(GLImplementation implementation) {
   base::FilePath glesv2_path(kGLESv2LibraryName);
   base::FilePath egl_path(kEGLLibraryName);
 
-  const base::CommandLine* command_line =
-      base::CommandLine::ForCurrentProcess();
-  const std::string use_gl =
-      command_line->GetSwitchValueASCII(switches::kUseGL);
-  if (use_gl == kGLImplementationANGLEName) {
-    base::FilePath module_path;
-    if (!PathService::Get(base::DIR_MODULE, &module_path))
-      return false;
-
-    glesv2_path = module_path.Append(kGLESv2ANGLELibraryName);
-    egl_path = module_path.Append(kEGLANGLELibraryName);
-  } else if ((use_gl == kGLImplementationSwiftShaderName) ||
-             (use_gl == kGLImplementationSwiftShaderForWebGLName)) {
+  if (implementation == kGLImplementationSwiftShaderGL) {
 #if BUILDFLAG(ENABLE_SWIFTSHADER)
     base::FilePath module_path;
     if (!PathService::Get(base::DIR_MODULE, &module_path))
@@ -109,6 +97,13 @@
 #else
     return false;
 #endif
+  } else {
+    base::FilePath module_path;
+    if (!PathService::Get(base::DIR_MODULE, &module_path))
+      return false;
+
+    glesv2_path = module_path.Append(kGLESv2ANGLELibraryName);
+    egl_path = module_path.Append(kEGLANGLELibraryName);
   }
 
   base::NativeLibrary gles_library = LoadLibraryAndPrintError(glesv2_path);
@@ -194,7 +189,7 @@
       return InitializeStaticGLXInternal();
     case kGLImplementationSwiftShaderGL:
     case kGLImplementationEGLGLES2:
-      return InitializeStaticEGLInternal();
+      return InitializeStaticEGLInternal(implementation);
     case kGLImplementationMockGL:
     case kGLImplementationStubGL:
       SetGLImplementation(implementation);
diff --git a/ui/login/account_picker/md_screen_account_picker.css b/ui/login/account_picker/md_screen_account_picker.css
index bc80ef2..bfb64369 100644
--- a/ui/login/account_picker/md_screen_account_picker.css
+++ b/ui/login/account_picker/md_screen_account_picker.css
@@ -8,24 +8,20 @@
 }
 
 #bubble {
+  margin-top: 16px;
   z-index: 1;
 }
 
 #signin-banner-container1 {
-  bottom: 100%;
-  margin-bottom: 10px;
+  height: 64px;
   position: absolute;
-  width: 100%;
-}
-
-html[screen=login] #signin-banner-container1 {
-  margin-bottom: 6px;
+  width: 520px;
+  z-index: 3;
 }
 
 #signin-banner-container2 {
   display: inline-block;
   position: relative;
-  right: -50%;
 }
 
 html[dir=rtl] #signin-banner-container2 {
@@ -36,14 +32,12 @@
 #signin-banner {
   background-color: rgba(0, 0, 0, 0.75);
   border-radius: 4px;
-  color: whitesmoke;
+  color: #FFF;
   display: none;
-  left: -50%;
-  max-width: 722px;
-  padding: 20px;
+  font-family: "Roboto";
+  font-size: 13px;
   position: relative;
   text-align: center;
-  width: max-content;
 }
 
 html[dir=rtl] #signin-banner {
@@ -68,7 +62,7 @@
 
 html[screen=login] #signin-banner.message-set,
 html[screen=lock] #signin-banner.message-set {
-  opacity: 1;
+  opacity: 0.8;
   transition: opacity 1s;
   visibility: visible;
 }
@@ -76,4 +70,33 @@
 .small-pod-container {
   overflow: scroll;
   position: absolute;
+}
+
+.small-pod-container::-webkit-scrollbar {
+   width: 0;
+}
+
+.small-pod-container.scroll {
+  background-color: rgba(20, 29, 40, .2);
+}
+
+.small-pod-container.scroll::-webkit-scrollbar {
+   width: 9px;
+}
+
+.small-pod-container.scroll::-webkit-scrollbar-thumb {
+   background-color: rgba(255, 255, 255, .17);
+   border-radius: 8px;
+}
+
+.small-pod-container-mask {
+  background: linear-gradient(#4FC3F7, transparent);
+  height: 112px;
+  position: absolute;
+  width: 100%;
+  z-index: 2;
+}
+
+.small-pod-container-mask.rotate {
+  transform: rotate(180deg);
 }
\ No newline at end of file
diff --git a/ui/login/account_picker/md_screen_account_picker.js b/ui/login/account_picker/md_screen_account_picker.js
index e7830ec..88ca673 100644
--- a/ui/login/account_picker/md_screen_account_picker.js
+++ b/ui/login/account_picker/md_screen_account_picker.js
@@ -71,12 +71,6 @@
     /** @override */
     onWindowResize: function() {
       $('pod-row').onWindowResize();
-
-      // Reposition the error bubble, if it is showing. Since we are just
-      // moving the bubble, the number of login attempts tried doesn't matter.
-      var errorBubble = $('bubble');
-      if (errorBubble && !errorBubble.hidden)
-        this.showErrorBubble(0, undefined  /* Reuses the existing message. */);
     },
 
     /**
@@ -362,9 +356,7 @@
      * @param {string} message Text to be displayed or empty to hide the banner.
      */
     showBannerMessage: function(message) {
-      var banner = $('signin-banner');
-      banner.textContent = message;
-      banner.classList.toggle('message-set', !!message);
+      $('pod-row').showBannerMessage(message);
     },
 
     /**
diff --git a/ui/login/account_picker/md_user_pod_row.css b/ui/login/account_picker/md_user_pod_row.css
index ae7e826..1fc9f13c 100644
--- a/ui/login/account_picker/md_user_pod_row.css
+++ b/ui/login/account_picker/md_user_pod_row.css
@@ -32,7 +32,7 @@
 }
 
 .account-picker.flying-pods .pod {
-  transition: all 180ms;
+  transition: all 300ms;
 }
 
 .pod.pin-enabled {
@@ -95,10 +95,15 @@
 
 .user-image {
   border-radius: 50%;
+  box-shadow: 0 0 2px rgba(255, 255, 255, .34);
   height: 100%;
   width: 100%;
 }
 
+.user-image.switch-image-animation {
+  animation: switch-image 300ms;
+}
+
 .pod .user-image {
   flex: none;
 }
@@ -139,7 +144,6 @@
   display: flex;
   height: 40px;
   left: 51px;
-  padding-bottom: 16px;
   position: absolute;
   top: 244px;
 /* On chromeos we extend the width to cover the padding on the user pods. This
@@ -201,7 +205,7 @@
   opacity: 0.34;
   position: absolute;
   stroke: #FFFFFF;
-  stroke-width: 1;
+  stroke-width: 1px;
   top: 40px;
 }
 
@@ -489,6 +493,25 @@
   width: 24px;
 }
 
+.action-box-button.ripple-circle {
+  background: #FFF;
+  border-radius: 50%;
+  opacity: .08;
+  position: absolute;
+  transform: scale(0);
+}
+
+.action-box-area.active .action-box-button.ripple-circle {
+  animation: ripple 360ms;
+  transform: scale(1);
+}
+
+@keyframes ripple {
+  0% { transform: scale(0); }
+  30% { transform: scale(1); }
+  100% { transform: scale(1); }
+}
+
 .action-box-area .action-box-icon {
   /* overriden in chrome/browser/resources/md_user_manager/user_manager.css */
   display: none;
@@ -572,11 +595,12 @@
 
 .action-box-menu {
   display: none;
+  position: absolute;
   z-index: 6;
 }
 
 .action-box-area.active ~ .action-box-menu {
-  background-color: rgba(0, 0, 0, .34);
+  background-color: rgba(0, 0, 0, 0.8);
   border-radius: 2px;
   display: flex;
   flex-direction: column;
@@ -1048,12 +1072,6 @@
   width: 60px;
 }
 
-.small-pod-image {
-  border-radius: 50%;
-  height: 100%;
-  width: 100%;
-}
-
 .small-pod-name {
   color: #FFFFFF;
   flex: auto;
@@ -1077,19 +1095,7 @@
   width: 190px;
 }
 
-.small-pod-container.scroll {
-  background-color: rgba(20, 29, 40, .2);
+@keyframes switch-image {
+  from { transform: rotate3d(0, 1, 0, 90deg); }
+  to { transform: none; }
 }
-
-.small-pod-container-mask {
-  background: linear-gradient(#00B0FF, transparent);
-  height: 112px;
-  opacity: 0.6;
-  position: absolute;
-  width: 100%;
-  z-index: 2;
-}
-
-.small-pod-container-mask.rotate {
-  transform: rotate(180deg);
-}
\ No newline at end of file
diff --git a/ui/login/account_picker/md_user_pod_row.js b/ui/login/account_picker/md_user_pod_row.js
index 8a03bd9..5ba3286 100644
--- a/ui/login/account_picker/md_user_pod_row.js
+++ b/ui/login/account_picker/md_user_pod_row.js
@@ -8,43 +8,6 @@
 
 cr.define('login', function() {
   /**
-   * Number of displayed columns depending on user pod count.
-   * @type {Array<number>}
-   * @const
-   */
-  var COLUMNS = [0, 1, 2, 3, 4, 5, 4, 4, 4, 5, 5, 6, 6, 5, 5, 6, 6, 6, 6];
-
-  /**
-   * Mapping between number of columns in pod-row and margin between user pods
-   * for such layout.
-   * @type {Array<number>}
-   * @const
-   */
-  var MARGIN_BY_COLUMNS = [undefined, 40, 40, 40, 40, 40, 12];
-
-  /**
-   * Mapping between number of columns in the desktop pod-row and margin
-   * between user pods for such layout.
-   * @type {Array<number>}
-   * @const
-   */
-  var DESKTOP_MARGIN_BY_COLUMNS = [undefined, 32, 32, 32, 32, 32, 32];
-
-  /**
-   * Maximal number of columns currently supported by pod-row.
-   * @type {number}
-   * @const
-   */
-  var MAX_NUMBER_OF_COLUMNS = 6;
-
-  /**
-   * Maximal number of rows if sign-in banner is displayed alonside.
-   * @type {number}
-   * @const
-   */
-  var MAX_NUMBER_OF_ROWS_UNDER_SIGNIN_BANNER = 2;
-
-  /**
    * Variables used for pod placement processing. Width and height should be
    * synced with computed CSS sizes of pods.
    */
@@ -65,6 +28,7 @@
   var CUSTOM_ICON_CONTAINER_SIZE = 40;
   var CROS_PIN_POD_HEIGHT = 417;
   var SCROLL_MASK_HEIGHT = 112;
+  var BANNER_MESSAGE_WIDTH = 520;
 
   /**
    * The maximum number of users that each pod placement method can handle.
@@ -984,7 +948,7 @@
      * @type {!HTMLImageElement}
      */
     get smallPodImageElement() {
-      return this.querySelector('.small-pod-image');
+      return this.querySelector('.user-image.small-pod-image');
     },
 
     /**
@@ -1221,7 +1185,7 @@
         return UserPod.Style.LARGE;
       if (this.querySelector('.small-pod').classList.contains('extra-small'))
         return UserPod.Style.EXTRA_SMALL;
-      return UserPod.Style.SMALL; 
+      return UserPod.Style.SMALL;
     },
 
     /**
@@ -1416,19 +1380,6 @@
         // Invisible focus causes ChromeVox to read user name and email.
         this.actionBoxMenuTitleElement.tabIndex = UserPodTabOrder.POD_MENU_ITEM;
         this.actionBoxMenuTitleElement.focus();
-
-        // If the user pod is on either edge of the screen, then the menu
-        // could be displayed partially ofscreen.
-        this.actionBoxMenu.classList.remove('left-edge-offset');
-        this.actionBoxMenu.classList.remove('right-edge-offset');
-
-        var offsetLeft =
-            cr.ui.login.DisplayManager.getOffset(this.actionBoxMenu).left;
-        var menuWidth = this.actionBoxMenu.offsetWidth;
-        if (offsetLeft < 0)
-          this.actionBoxMenu.classList.add('left-edge-offset');
-        else if (offsetLeft + menuWidth > window.innerWidth)
-          this.actionBoxMenu.classList.add('right-edge-offset');
       } else {
         this.actionBoxAreaElement.classList.remove('active');
         this.actionBoxAreaElement.classList.remove('menu-moved-up');
@@ -2135,6 +2086,7 @@
         $('pod-row').switchMainPod(this);
         return;
       }
+      Oobe.clearErrors();
 
       if (!this.isActionBoxMenuActive) {
         if (this.isAuthTypeOnlineSignIn) {
@@ -2407,6 +2359,7 @@
         $('pod-row').switchMainPod(this);
         return;
       }
+      Oobe.clearErrors();
 
       this.parentNode.focusPod(this);
       this.parentNode.setActivatedPod(this, e);
@@ -2868,6 +2821,9 @@
     // If we're in Touch View mode.
     touchViewEnabled_: false,
 
+    // If testing mode is enabled.
+    testingModeEnabled_: false,
+
     /** @override */
     decorate: function() {
       // Event listeners that are installed for the time period during which
@@ -3503,88 +3459,10 @@
      * screen orientation and showing the virtual keyboard.
      */
     onWindowResize: function() {
-      var screen = document.querySelector('#scroll-container');
-      var clientArea = document.querySelector('#inner-container');
-      if (Oobe.getInstance().virtualKeyboardShown) {
-        // Edge case: when virtual keyboard is shown, although the screen size
-        // is reduced properly, the size of the outer container remains the
-        // same because its min-height is applied. Users can scroll the screen
-        // upward and see empty areas beyond the pod row and the scroll bar,
-        // which should be avoided.
-        // This is a hacky solution: we can make the scroll container hide
-        // the overflow area and manully position the client area. 
-        screen.style.overflowY = "hidden";
-        clientArea.style.position = "absolute";
-        clientArea.style.left = cr.ui.toCssPx(0);
-        clientArea.style.top = cr.ui.toCssPx(0);
-      } else {
-        // Sets the values to default when virtual keyboard is not shown. 
-        screen.style.overflowY = "auto";
-        clientArea.style.position = "relative";
-      }
       this.placePods_();
     },
 
     /**
-     * Returns width of podrow having |columns| number of columns.
-     * @private
-     */
-    columnsToWidth_: function(columns) {
-      var isDesktopUserManager = Oobe.getInstance().displayType ==
-          DISPLAY_TYPE.DESKTOP_USER_MANAGER;
-      var margin = isDesktopUserManager ? DESKTOP_MARGIN_BY_COLUMNS[columns] :
-                                          MARGIN_BY_COLUMNS[columns];
-      var rowPadding = isDesktopUserManager ? DESKTOP_ROW_PADDING :
-                                              POD_ROW_PADDING;
-      return 2 * rowPadding + columns * this.userPodWidth_ +
-          (columns - 1) * margin;
-    },
-
-    /**
-     * Returns height of podrow having |rows| number of rows.
-     * @private
-     */
-    rowsToHeight_: function(rows) {
-      var isDesktopUserManager = Oobe.getInstance().displayType ==
-          DISPLAY_TYPE.DESKTOP_USER_MANAGER;
-      var rowPadding = isDesktopUserManager ? DESKTOP_ROW_PADDING :
-                                              POD_ROW_PADDING;
-      return 2 * rowPadding + rows * this.userPodHeight_;
-    },
-
-    /**
-     * Calculates number of columns and rows that podrow should have in order to
-     * hold as much its pods as possible for current screen size. Also it tries
-     * to choose layout that looks good.
-     * @return {{columns: number, rows: number}}
-     */
-    calculateLayout_: function() {
-      var preferredColumns = this.pods.length < COLUMNS.length ?
-          COLUMNS[this.pods.length] : COLUMNS[COLUMNS.length - 1];
-      var maxWidth = Oobe.getInstance().clientAreaSize.width;
-      var columns = preferredColumns;
-      while (maxWidth < this.columnsToWidth_(columns) && columns > 1)
-        --columns;
-      var rows = Math.floor((this.pods.length - 1) / columns) + 1;
-      if (getComputedStyle(
-          $('signin-banner'), null).getPropertyValue('display') != 'none') {
-        rows = Math.min(rows, MAX_NUMBER_OF_ROWS_UNDER_SIGNIN_BANNER);
-      }
-      if (!Oobe.getInstance().newDesktopUserManager) {
-        var maxHeigth = Oobe.getInstance().clientAreaSize.height;
-        while (maxHeigth < this.rowsToHeight_(rows) && rows > 1)
-          --rows;
-      }
-      // One more iteration if it's not enough cells to place all pods.
-      while (maxWidth >= this.columnsToWidth_(columns + 1) &&
-             columns * rows < this.pods.length &&
-             columns < MAX_NUMBER_OF_COLUMNS) {
-        ++columns;
-      }
-      return {columns: columns, rows: rows};
-    },
-
-    /**
      * Places pods onto their positions in pod grid matching the new design.
      * @private
      */
@@ -3594,7 +3472,7 @@
         console.error('Attempt to place pods for an empty pod list.');
         return;
       }
-      // Append all pods to their proper parents. Small pods have parent other
+      // Appends all pods to their proper parents. Small pods have parent other
       // than the pod row. The pods were all initialized with the pow row as a
       // temporary parent, which is intended to ensure that all event listeners
       // work properly. If the main pod already exists, it means we are in the
@@ -3602,16 +3480,21 @@
       // of any pod.
       if (!this.mainPod_) {
         this.mainPod_ = this.preselectedPod;
-        this.appendPodsToParents();
+        this.appendPodsToParents_();
       }
       this.restoreInitialStates_();
-      if (Oobe.getInstance().virtualKeyboardShown) {
+      this.hideEmptyArea_();
+      // Clear error bubbles whenever pod placement is happening, i.e., after
+      // orientation change, showing or hiding virtual keyboard, and user
+      // removal.
+      Oobe.clearErrors();
+
+      if (this.isScreenShrinked_()) {
         // When virtual keyboard is shown, the account picker should occupy
         // all the remaining screen. Screen size was already updated to exclude
         // the virtual keyboard.
         this.parentNode.setPreferredSize(
-          this.screenSize.width,
-          this.screenSize.height);
+            this.screenSize.width, this.screenSize.height);
       } else {
         // Make sure not to block the header bar when virtual keyboard is absent.
         this.parentNode.setPreferredSize(
@@ -3627,14 +3510,14 @@
         this.placePodsOnContainer_();
       }
       Oobe.getInstance().updateScreenSize(this.parentNode);
-      this.updatePodNameArea();
+      this.updatePodNameArea_();
     },
 
     /**
-     * Append pods to proper parents. Called each time before pod placement.
+     * Appends pods to proper parents. Called each time before pod placement.
      * @private
      */
-    appendPodsToParents: function() {
+    appendPodsToParents_: function() {
       var pods = this.pods;
       // Pod count may have changed, so the placement method may change
       // accordingly. Therefore, always remove all pods from their current
@@ -3651,16 +3534,42 @@
         // main pod still has pow row as parent, all other pods should be
         // appended to the container with scroll bar. 
         for (var pod of pods) {
-          if (pod == this.mainPod_) {
+          if (pod == this.mainPod_)
             this.appendChild(pod);
-          } else {
+          else
             this.smallPodsContainer.appendChild(pod);
-          }
         }
       }
     },
 
     /**
+     * Makes inner container unscrollable and hides the bottom empty area
+     * when virtual keyboard is shown.
+     * @private
+     */
+    hideEmptyArea_: function() {
+      var screen = document.querySelector('#scroll-container');
+      var clientArea = document.querySelector('#inner-container');
+      if (this.isScreenShrinked_()) {
+        // When virtual keyboard is shown, although the screen size
+        // is reduced properly, the size of the outer container remains the
+        // same because its min-height is applied. Users can scroll the screen
+        // upward and see empty areas beyond the pod row and the scroll bar,
+        // which should be avoided.
+        // This is a hacky solution: we can make the scroll container hide
+        // the overflow area and manully position the client area.
+        screen.style.overflowY = 'hidden';
+        clientArea.style.position = 'absolute';
+        clientArea.style.left = cr.ui.toCssPx(0);
+        clientArea.style.top = cr.ui.toCssPx(0);
+      } else {
+        // Sets the values to default when virtual keyboard is not shown.
+        screen.style.overflowY = 'auto';
+        clientArea.style.position = 'relative';
+      }
+    },
+
+    /**
      * Called when there is one user pod.
      * @private
      */
@@ -3681,8 +3590,10 @@
       this.mainPod_.setPodStyle(UserPod.Style.LARGE);
       secondPod.setPodStyle(UserPod.Style.LARGE);
 
-      var DOUBLE_PODS_PADDING = this.isPortraitMode() ? 32 : 118;
-      var leftPadding = (this.screenSize.width - (CROS_POD_WIDTH * 2 + DOUBLE_PODS_PADDING)) / 2;  
+      var DOUBLE_PODS_PADDING = this.isPortraitMode_() ? 32 : 118;
+      var leftPadding =
+          (this.screenSize.width - (CROS_POD_WIDTH * 2 + DOUBLE_PODS_PADDING)) /
+          2;
       // Start actual positioning.
       this.mainPod_.left = leftPadding;
       this.mainPod_.top = (this.screenSize.height - CROS_POD_HEIGHT) / 2;
@@ -3697,8 +3608,8 @@
     placePodsOnContainer_: function() {
       this.smallPodsContainer.hidden = false;
       var pods = this.pods;
-      if ((pods.length > LANDSCAPE_MODE_LIMIT && !this.isPortraitMode()) ||
-          (pods.length > PORTRAIT_MODE_LIMIT && this.isPortraitMode())) {
+      if ((pods.length > LANDSCAPE_MODE_LIMIT && !this.isPortraitMode_()) ||
+          (pods.length > PORTRAIT_MODE_LIMIT && this.isPortraitMode_())) {
         // If the pod count exceeds limits, they should be in extra small size
         // and the container will become scrollable.
         this.placePodsOnScrollableContainer_();
@@ -3711,31 +3622,46 @@
           pod.setPodStyle(UserPod.Style.SMALL);
         }
       }
-      // The size of the smallPodsContainer must be updated to avoid overflow,
-      // otherwise unnecessary scroll bar will show up.
+      // The size of the smallPodsContainer must be updated to avoid overflow.
       this.smallPodsContainer.style.height =
           cr.ui.toCssPx(this.screenSize.height);
       this.smallPodsContainer.style.width = cr.ui.toCssPx(CROS_SMALL_POD_WIDTH);
 
-      var LEFT_PADDING = this.isPortraitMode() ? 0 : 98;
-      var MIDDLE_PADDING = this.isPortraitMode() ? 84 : 220;
+      var LEFT_PADDING = this.isPortraitMode_() ? 0 : 98;
+      var MIDDLE_PADDING = this.isPortraitMode_() ? 84 : 220;
       var contentsWidth = LEFT_PADDING +
           CROS_POD_WIDTH + MIDDLE_PADDING + CROS_SMALL_POD_WIDTH;
       var blankWidth = this.screenSize.width - contentsWidth;   
       var actualLeftPadding = LEFT_PADDING;
-      actualLeftPadding += this.isPortraitMode() ? blankWidth * 2 / 3:
-                                                   blankWidth / 2;
+      actualLeftPadding +=
+          this.isPortraitMode_() ? blankWidth * 2 / 3 : blankWidth / 2;
       var SMALL_POD_PADDING = 54;
       var actualSmallPodPadding = SMALL_POD_PADDING;
       var smallPodsTotalHeight = (pods.length - 1) * CROS_SMALL_POD_HEIGHT +
           (pods.length - 2) * actualSmallPodPadding;
-      if (smallPodsTotalHeight > this.screenSize.height) {
-        // Edge case: when the virtual keyboard is present, the total height of
-        // the smallPodsContainer may exceed the screen height. Decrease the
-        // padding among small pods according to the design spec.
-        actualSmallPodPadding = 32;
-        smallPodsTotalHeight = (pods.length - 1) * CROS_SMALL_POD_HEIGHT +
-          (pods.length - 2) * actualSmallPodPadding;
+
+      var SCROLL_TOP_PADDING = this.isPortraitMode_() ? 66 : 72;
+      if (smallPodsTotalHeight + SCROLL_TOP_PADDING * 2 >
+          this.screenSize.height) {
+        // Edge case: the design spec assumes that the screen height is large
+        // enough if the pod count limits set above are not exceeded, but for
+        // smaller screens the contents may still overflow.
+        // SCROLL_TOP_PADDING denotes the smallest top padding we can tolerate
+        // before allowing the container to overflow and show the scroll bar.
+        // If virtual keyboard is shown, we will first try a smaller padding
+        // and recalculate the total height.
+        if (this.isScreenShrinked_()) {
+          actualSmallPodPadding = 32;
+          smallPodsTotalHeight = (pods.length - 1) * CROS_SMALL_POD_HEIGHT +
+              (pods.length - 2) * actualSmallPodPadding;
+        }
+        // If virtual keyboard is not shown, or the updated total height still
+        // exceeds screen height, fall to the scrollable container case.
+        if (smallPodsTotalHeight + SCROLL_TOP_PADDING * 2 >
+            this.screenSize.height) {
+          this.placePodsOnScrollableContainer_();
+          return;
+        }
       }
       
       // Start positioning of the main pod and the smallPodsContainer.
@@ -3745,7 +3671,8 @@
           cr.ui.toCssPx(actualLeftPadding + CROS_POD_WIDTH + MIDDLE_PADDING);
       this.smallPodsContainer.style.top = cr.ui.toCssPx(0);
       // Start positioning of the small pods inside the smallPodsContainer.
-      var smallPodsTopPadding = (this.screenSize.height - smallPodsTotalHeight) / 2;
+      var smallPodsTopPadding =
+          (this.screenSize.height - smallPodsTotalHeight) / 2;
       for (var pod of pods) {
         if (pod == this.mainPod_) {
           continue;
@@ -3774,14 +3701,14 @@
         }
       }
 
-      var SCROLL_LEFT_PADDING = this.isPortraitMode() ? 46 : 72;
-      var SCROLL_RIGHT_PADDING = this.isPortraitMode() ? 12 : 72;
+      var SCROLL_LEFT_PADDING = this.isPortraitMode_() ? 46 : 72;
+      var SCROLL_RIGHT_PADDING = this.isPortraitMode_() ? 12 : 72;
       // The offsetWidth of the smallPodsContainer.
       var scrollAreaWidth = SCROLL_LEFT_PADDING + CROS_EXTRA_SMALL_POD_WIDTH +
           SCROLL_RIGHT_PADDING;
       var mainPodPadding = (this.screenSize.width -
                             scrollAreaWidth - CROS_POD_WIDTH) / 2;
-      var SCROLL_TOP_PADDING = this.isPortraitMode() ? 66 : 72;
+      var SCROLL_TOP_PADDING = this.isPortraitMode_() ? 66 : 72;
       var EXTRA_SMALL_POD_PADDING = 32;
       // Start positioning of the main pod and the smallPodsContainer.
       this.mainPod_.left = mainPodPadding;
@@ -3801,7 +3728,8 @@
       }
       scrollHeight -= EXTRA_SMALL_POD_PADDING;
       // The smallPodsContainer should occupy the full screen vertically.
-      this.smallPodsContainer.style.height = cr.ui.toCssPx(this.screenSize.height);
+      this.smallPodsContainer.style.height =
+          cr.ui.toCssPx(this.screenSize.height);
       this.smallPodsContainer.style.width = cr.ui.toCssPx(
           SCROLL_LEFT_PADDING + CROS_EXTRA_SMALL_POD_WIDTH +
           SCROLL_RIGHT_PADDING);
@@ -3817,13 +3745,13 @@
         // the overlay, but the top and bottom padding should be adjusted
         // to ensure a symmetric layout.
         actualTopPadding = (this.screenSize.height - scrollHeight) / 2;
-      } else if (!Oobe.getInstance().virtualKeyboardShown) {
+      } else if (!this.isScreenShrinked_()) {
         // The scroll bar will definitely be shown if we reach here. A gradient
         // mask is applied to avoid blocking the header bar if the virtual
         // keyboard is not shown. When the keyboard is shown, there's no need
         // to add the mask and the original top padding value should be kept. 
         actualTopPadding = SCROLL_MASK_HEIGHT;
-        this.showScrollMask();
+        this.showScrollMask_();
       } 
 
       // Start positioning of the small pods inside the smallPodsContainer.
@@ -3862,23 +3790,36 @@
         // the last position in the scrollable container, a bottom padding
         // was added to ensure a symmetric layout.
         pod.style.paddingBottom = cr.ui.toCssPx(0);
+        // Remove the switch animation that might be added earlier.
+        pod.imageElement.classList.remove('switch-image-animation');
+        pod.smallPodImageElement.classList.remove('switch-image-animation');
       }
     },
 
     /**
-     * Check if the screen is in portrait mode.
+     * Checks if the screen is in portrait mode.
      * @return {boolean} True if in portrait mode.
      */
-    isPortraitMode: function() {
-      return this.screenSize.width <
-          this.screenSize.height;
+    isPortraitMode_: function() {
+      return this.screenSize.width < this.screenSize.height;
+    },
+
+    /**
+     * Checks if the screen is shrinked, i.e., when showing virtual keyboard.
+     * We used to check Oobe.getInstance().virtualKeyboardShown directly
+     * but there were occasional bugs because that value may not be updated yet
+     * during pod placement.
+     * @return {boolean} True if the screen is shrinked.
+     */
+    isScreenShrinked_: function() {
+      return this.screenSize.height <= Oobe.getInstance().clientAreaSize.height;
     },
 
     /**
      * Called when scroll bar is shown and we need a mask for the header bar.
      * @private
      */
-    showScrollMask: function() {
+    showScrollMask_: function() {
       var topMask = document.querySelector('.small-pod-container-mask');
       topMask.hidden = false;
       topMask.style.left = this.smallPodsContainer.style.left;
@@ -3891,26 +3832,55 @@
       bottomMask.style.width = this.smallPodsContainer.style.width;
       // The bottom mask should overlap with the header bar, and its z-index
       // is chosen to ensure it does not block users from using the header bar.
-      bottomMask.style.top = cr.ui.toCssPx(
-          this.screenSize.height -
-          SCROLL_MASK_HEIGHT);
+      bottomMask.style.top =
+          cr.ui.toCssPx(this.screenSize.height - SCROLL_MASK_HEIGHT);
     },
 
     /**
-     * Makes sure that user name on each large pod is centered and extra long
-     * name does not exceed max width. Names on small pods do not need to be
-     * dynamically updated.
+     * Makes sure that:
+     * 1) User name on each large pod is centered.
+     * 2) Extra long names don't exceed maximum pod width.
+     * 3) Action box menus are either left-aligned or right-aligned with
+     * the drop down button.
      * @private
      */
-    updatePodNameArea: function() {
-      this.querySelectorAll('.name-container').forEach(function(nameArea) {
-        var nameElement = nameArea.querySelector('.name');
-        var leftMargin = (CROS_POD_WIDTH - nameElement.offsetWidth) / 2;
+    updatePodNameArea_: function() {
+      var pods = this.pods;
+      for (var pod of pods) {
+        if (pods.length > POD_ROW_LIMIT && pod != this.mainPod_)
+          continue;
+        var nameArea = pod.querySelector('.name-container');
+        var leftMargin = (CROS_POD_WIDTH - pod.nameElement.offsetWidth) / 2;
         if (leftMargin > 0)
           nameArea.style.left = cr.ui.toCssPx(leftMargin);
-        else
-          nameElement.style.width = cr.ui.toCssPx(CROS_POD_WIDTH);
-      });
+        else {
+          pod.nameElement.style.width = cr.ui.toCssPx(CROS_POD_WIDTH);
+          nameArea.style.left = cr.ui.toCssPx(0);
+        }
+        // Update action box menu position to ensure it doesn't overlap with
+        // elements outside the pod.
+        var actionBoxMenu = pod.querySelector('.action-box-menu');
+        var actionBoxButton = pod.querySelector('.action-box-button');
+        var MENU_TOP_PADDING = 7;
+        actionBoxMenu.style.top =
+            cr.ui.toCssPx(actionBoxButton.offsetHeight + MENU_TOP_PADDING);
+        if (this.isPortraitMode_() && pods.length > 1) {
+          // Confine the menu inside the pod when it may overlap with outside
+          // elements.
+          actionBoxMenu.style.left = 'auto';
+          actionBoxMenu.style.right = cr.ui.toCssPx(0);
+        } else {
+          actionBoxMenu.style.left = cr.ui.toCssPx(
+              pod.nameElement.offsetWidth + actionBoxButton.style.marginLeft);
+          actionBoxMenu.style.right = 'auto';
+        }
+        // Add ripple animation.
+        var actionBoxRippleEffect =
+            pod.querySelector('.action-box-button.ripple-circle');
+        actionBoxRippleEffect.style.left = actionBoxMenu.style.left;
+        actionBoxRippleEffect.style.top =
+            cr.ui.toCssPx(actionBoxButton.style.marginTop);
+      }
     },
 
     /**
@@ -3938,6 +3908,10 @@
       // Switch style of the two pods.
       this.mainPod_.setPodStyle(pod.getPodStyle());
       pod.setPodStyle(UserPod.Style.LARGE);
+      // Add switch animation.
+      this.mainPod_.smallPodImageElement.classList.add(
+          'switch-image-animation');
+      pod.imageElement.classList.add('switch-image-animation');
 
       // Switch parent and position of the two pods.
       var left = pod.left;
@@ -3962,9 +3936,10 @@
       this.mainPod_.top = top;
       this.mainPod_.style.paddingBottom = paddingBottom;
       this.mainPod_ = pod;
-      // Focus the new main pod.
-      this.focusPod(this.mainPod_);
-      this.updatePodNameArea();
+      // The new main pod should already be focused but we need a focus update
+      // in order to focus on the input box.
+      this.focusPod(this.mainPod_, true /* force */);
+      this.updatePodNameArea_();
     },
 
     /**
@@ -3977,27 +3952,26 @@
     },
 
     /**
-     * Number of columns.
-     * @type {?number}
+     * Displays a banner containing |message|. If the banner is already present
+     * this function updates the message in the banner.
+     * @param {string} message Text to be displayed or empty to hide the banner.
      */
-    set columns(columns) {
-      // Cannot use 'columns' here.
-      this.setAttribute('ncolumns', columns);
-    },
-    get columns() {
-      return parseInt(this.getAttribute('ncolumns'));
-    },
-
-    /**
-     * Number of rows.
-     * @type {?number}
-     */
-    set rows(rows) {
-      // Cannot use 'rows' here.
-      this.setAttribute('nrows', rows);
-    },
-    get rows() {
-      return parseInt(this.getAttribute('nrows'));
+    showBannerMessage: function(message) {
+      var banner = $('signin-banner');
+      banner.textContent = message;
+      banner.classList.toggle('message-set', !!message);
+      var bannerContainer = $('signin-banner-container1');
+      var BANNER_TOP_PADDING = this.isScreenShrinked_() ? 0 : 38;
+      bannerContainer.style.top = cr.ui.toCssPx(
+          this.mainPod_.top + CROS_POD_HEIGHT + BANNER_TOP_PADDING);
+      if (this.pods.length <= POD_ROW_LIMIT)
+        bannerContainer.style.left =
+            cr.ui.toCssPx((this.screenSize.width - BANNER_MESSAGE_WIDTH) / 2);
+      else {
+        var leftPadding =
+            this.mainPod_.left - (BANNER_MESSAGE_WIDTH - CROS_POD_WIDTH) / 2;
+        bannerContainer.style.left = cr.ui.toCssPx(Math.max(leftPadding, 0));
+      }
     },
 
     /**
@@ -4079,7 +4053,6 @@
           chrome.send('focusPod', [podToFocus.user.username]);
         this.firstShown_ = false;
         this.lastFocusedPod_ = podToFocus;
-        this.scrollFocusedPodIntoView();
         this.setUserPodFingerprintIcon(
             podToFocus.user.username, FINGERPRINT_STATES.DEFAULT);
       } else {
@@ -4114,11 +4087,42 @@
         console.error('Cannot activate pod while sign-in UI is disabled.');
         return;
       }
+      // If testing mode is enabled and a positive integer was entered, abort
+      // the activation process and start testing mode.
+      if (pod && this.testingModeEnabled_) {
+        var userCount = pod.passwordElement.value;
+        if (parseInt(userCount) == userCount && userCount > 0) {
+          this.showDummyUsersForTesting(userCount);
+          return;
+        }
+      }
       if (pod && pod.activate(e))
         this.activatedPod_ = pod;
     },
 
     /**
+     * Used for testing only. Create the specified number of dummy users and
+     * conveniently test the behaviors under different number of pods.
+     * @param {number} count The number of users we want to test for.
+     */
+    showDummyUsersForTesting: function(count) {
+      if (!this.testingModeEnabled_) {
+        console.error(
+            'Attempt to create dummy users when testing mode is disabled.');
+        return;
+      }
+      var pods = this.pods;
+      for (var pod of pods)
+        pod.parentNode.removeChild(pod);
+      var sampleUser = this.users_[0];
+      var users = [];
+      for (var i = 0; i < count; i++)
+        users.push(sampleUser);
+
+      this.loadPods(users);
+    },
+
+    /**
      * The pod of the signed-in user, if any; null otherwise.
      * @type {?UserPod}
      */
@@ -4235,14 +4239,18 @@
         this.focusPod();
       }
 
-      if (pod)
+      if (pod && pod.getPodStyle() == UserPod.Style.LARGE)
         pod.isActionBoxMenuHovered = true;
 
       // Return focus back to single pod.
       if (this.alwaysFocusSinglePod && !pod) {
         if ($('login-header-bar').contains(e.target))
           return;
-        this.focusPod(this.focusedPod_, true /* force */);
+        // If the click is outside the single pod, still focus on that pod
+        // but do not focus on input box any more. This makes virtual keyboard
+        // (if present) disappear.
+        this.focusPod(
+            this.focusedPod_, true /* force */, true /* opt_skipInputFocus */);
         this.focusedPod_.userTypeBubbleElement.classList.remove('bubble-shown');
         this.focusedPod_.isActionBoxMenuHovered = false;
       }
@@ -4286,8 +4294,12 @@
       if (this.disabled)
         return;
       if (e.target.parentNode == this) {
-        // Focus on a pod
+        // Handles focus event on a large pod.
         if (e.target.classList.contains('focused')) {
+          // Edge case: prevent input box from receiving unncessary focus
+          // (thus hiding virtual keyboard) when remove user is clicked.
+          if (e.target.isActionBoxMenuActive)
+            return;
           if (!e.target.multiProfilesPolicyApplied)
             e.target.focusInput();
           else
@@ -4433,7 +4445,7 @@
         this.maybePreselectPod();
       }
 
-      this.updatePodNameArea();
+      this.updatePodNameArea_();
     },
 
     /**
diff --git a/ui/login/account_picker/md_user_pod_template.html b/ui/login/account_picker/md_user_pod_template.html
index fc647d3..5023323 100644
--- a/ui/login/account_picker/md_user_pod_template.html
+++ b/ui/login/account_picker/md_user_pod_template.html
@@ -51,6 +51,7 @@
           <paper-icon-button class="action-box-button" disabled
                              icon="user-pod:dropdown">
           </paper-icon-button>
+          <div class="action-box-button ripple-circle"></div>
           <iron-icon icon="cr:more-vert" class="action-box-icon"></iron-icon>
         </div>
         <div class="action-box-menu">
@@ -172,7 +173,7 @@
   </div>
   <div class="small-pod" hidden>
     <div class="small-user-image-container">
-      <img class="small-pod-image" alt>
+      <img class="user-image small-pod-image" alt>
     </div>
     <div class="small-pod-name"></div>
   </div>
diff --git a/ui/views/mus/mus_client.cc b/ui/views/mus/mus_client.cc
index 03093279..eb48bd2 100644
--- a/ui/views/mus/mus_client.cc
+++ b/ui/views/mus/mus_client.cc
@@ -171,6 +171,10 @@
   properties[WindowManager::kFocusable_InitProperty] =
       mojo::ConvertTo<TransportType>(init_params.CanActivate());
 
+  properties[WindowManager::kTranslucent_InitProperty] =
+      mojo::ConvertTo<TransportType>(init_params.opacity ==
+                                     Widget::InitParams::TRANSLUCENT_WINDOW);
+
   if (!init_params.bounds.IsEmpty()) {
     properties[WindowManager::kBounds_InitProperty] =
         mojo::ConvertTo<TransportType>(init_params.bounds);