diff --git a/AUTHORS b/AUTHORS
index c191f2e..c3382cc 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -481,6 +481,7 @@
 Paweł Hajdan jr <phajdan.jr@gmail.com>
 Pawel Forysiuk <p.forysiuk@samsung.com>
 Peng Jiang <leiyi.jp@gmail.com>
+Peng Xinchao <pxinchao@gmail.com>
 Petar Jovanovic <petarj@mips.com>
 Peter Beverloo <peter@chromium.org>
 Peter Bright <drpizza@quiscalusmexicanus.org>
diff --git a/DEPS b/DEPS
index 15ea04a..1fc4361b 100644
--- a/DEPS
+++ b/DEPS
@@ -39,11 +39,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': 'ed330c8755044822ec536ce8eb0a98a8627302bd',
+  'skia_revision': '063ece71848fadc963cbac5c978cd48262138131',
   # 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': '09c6e1a2fe05b24e34ba8829a760a90c085fe59e',
+  'v8_revision': '9e87a245fce674a540231fba9a5ebba64269cd42',
   # 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.
@@ -59,7 +59,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '47bcd4c5c56cdc2d63a0c2ed4e7f68e6ccf523f6',
+  'pdfium_revision': '2fad11a8d9d2704cd9ee28b02373ad7ce19c65e3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -220,7 +220,7 @@
    Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '896b6c55361f898df240e684a1820b0cb457d62e', # commit position 13176
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'b3f05f40409ca9cfa7986b6b5eb98fb826623939', # commit position 13192
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc
index 23fa5d27..6b29ad4 100644
--- a/ash/accelerators/accelerator_controller.cc
+++ b/ash/accelerators/accelerator_controller.cc
@@ -16,6 +16,7 @@
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/shelf/shelf_model.h"
 #include "ash/common/shell_window_ids.h"
+#include "ash/common/system/system_notifier.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
 #include "ash/common/system/volume_control_delegate.h"
 #include "ash/common/wm/mru_window_tracker.h"
@@ -44,7 +45,6 @@
 #include "ash/system/brightness_control_delegate.h"
 #include "ash/system/keyboard_brightness/keyboard_brightness_control_delegate.h"
 #include "ash/system/status_area_widget.h"
-#include "ash/system/system_notifier.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/system/web_notification/web_notification_tray.h"
diff --git a/ash/ash.gyp b/ash/ash.gyp
index ec9a855..988ed0d9 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -96,6 +96,20 @@
       'common/shelf/wm_shelf_util.h',
       'common/shell_window_ids.cc',
       'common/shell_window_ids.h',
+      'common/system/chromeos/devicetype_utils.cc',
+      'common/system/chromeos/devicetype_utils.h',
+      'common/system/chromeos/power/battery_notification.cc',
+      'common/system/chromeos/power/battery_notification.h',
+      'common/system/chromeos/power/dual_role_notification.cc',
+      'common/system/chromeos/power/dual_role_notification.h',
+      'common/system/chromeos/power/power_status.cc',
+      'common/system/chromeos/power/power_status.h',
+      'common/system/chromeos/power/power_status_view.cc',
+      'common/system/chromeos/power/power_status_view.h',
+      'common/system/chromeos/power/tray_power.cc',
+      'common/system/chromeos/power/tray_power.h',
+      'common/system/chromeos/settings/tray_settings.cc',
+      'common/system/chromeos/settings/tray_settings.h',
       'common/system/chromeos/shutdown_policy_observer.h',
       'common/system/chromeos/system_clock_observer.cc',
       'common/system/chromeos/system_clock_observer.h',
@@ -108,6 +122,8 @@
       'common/system/date/tray_date.h',
       'common/system/networking_config_delegate.cc',
       'common/system/networking_config_delegate.h',
+      'common/system/system_notifier.cc',
+      'common/system/system_notifier.h',
       'common/system/tray/actionable_view.cc',
       'common/system/tray/actionable_view.h',
       'common/system/tray/default_system_tray_delegate.cc',
@@ -486,8 +502,6 @@
       'system/chromeos/brightness/brightness_controller_chromeos.h',
       'system/chromeos/brightness/tray_brightness.cc',
       'system/chromeos/brightness/tray_brightness.h',
-      'system/chromeos/devicetype_utils.cc',
-      'system/chromeos/devicetype_utils.h',
       'system/chromeos/enterprise/enterprise_domain_observer.h',
       'system/chromeos/enterprise/tray_enterprise.cc',
       'system/chromeos/enterprise/tray_enterprise.h',
@@ -514,18 +528,8 @@
       'system/chromeos/network/vpn_delegate.h',
       'system/chromeos/network/vpn_list_view.cc',
       'system/chromeos/network/vpn_list_view.h',
-      'system/chromeos/power/battery_notification.cc',
-      'system/chromeos/power/battery_notification.h',
-      'system/chromeos/power/dual_role_notification.cc',
-      'system/chromeos/power/dual_role_notification.h',
       'system/chromeos/power/power_event_observer.cc',
       'system/chromeos/power/power_event_observer.h',
-      'system/chromeos/power/power_status.cc',
-      'system/chromeos/power/power_status.h',
-      'system/chromeos/power/power_status_view.cc',
-      'system/chromeos/power/power_status_view.h',
-      'system/chromeos/power/tray_power.cc',
-      'system/chromeos/power/tray_power.h',
       'system/chromeos/power/video_activity_notifier.cc',
       'system/chromeos/power/video_activity_notifier.h',
       'system/chromeos/rotation/tray_rotation_lock.cc',
@@ -551,8 +555,6 @@
       'system/chromeos/session/session_length_limit_observer.h',
       'system/chromeos/session/tray_session_length_limit.cc',
       'system/chromeos/session/tray_session_length_limit.h',
-      'system/chromeos/settings/tray_settings.cc',
-      'system/chromeos/settings/tray_settings.h',
       'system/chromeos/supervised/custodian_info_tray_observer.h',
       'system/chromeos/supervised/tray_supervised_user.cc',
       'system/chromeos/supervised/tray_supervised_user.h',
@@ -577,8 +579,6 @@
       'system/status_area_widget.h',
       'system/status_area_widget_delegate.cc',
       'system/status_area_widget_delegate.h',
-      'system/system_notifier.cc',
-      'system/system_notifier.h',
       'system/toast/toast_data.cc',
       'system/toast/toast_data.h',
       'system/toast/toast_manager.cc',
@@ -895,6 +895,9 @@
       'autoclick/autoclick_unittest.cc',
       'common/material_design/material_design_controller_unittest.cc',
       'common/shelf/shelf_model_unittest.cc',
+      'common/system/chromeos/power/power_status_unittest.cc',
+      'common/system/chromeos/power/power_status_view_unittest.cc',
+      'common/system/chromeos/power/tray_power_unittest.cc',
       'common/system/date/date_view_unittest.cc',
       'common/system/update/tray_update_unittest.cc',
       'content/display/screen_orientation_controller_chromeos_unittest.cc',
@@ -954,9 +957,6 @@
       'system/chromeos/brightness/tray_brightness_unittest.cc',
       'system/chromeos/multi_user/user_switch_util_unittest.cc',
       'system/chromeos/power/power_event_observer_unittest.cc',
-      'system/chromeos/power/power_status_unittest.cc',
-      'system/chromeos/power/power_status_view_unittest.cc',
-      'system/chromeos/power/tray_power_unittest.cc',
       'system/chromeos/rotation/tray_rotation_lock_unittest.cc',
       'system/chromeos/screen_security/screen_tray_item_unittest.cc',
       'system/chromeos/session/logout_confirmation_controller_unittest.cc',
diff --git a/ash/common/DEPS b/ash/common/DEPS
index 1412c1f7..8d45fdc 100644
--- a/ash/common/DEPS
+++ b/ash/common/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "-ash",
   "+ash/ash_export.h",
+  "+ash/ash_switches.h",
   "+ash/common",
   "+ui",
   "-ui/aura",
diff --git a/ash/common/material_design/material_design_controller.cc b/ash/common/material_design/material_design_controller.cc
index f458402..711aafa2 100644
--- a/ash/common/material_design/material_design_controller.cc
+++ b/ash/common/material_design/material_design_controller.cc
@@ -52,16 +52,6 @@
 }
 
 // static
-bool MaterialDesignController::IsMaterial() {
-  return IsMaterialExperimental() || GetMode() == Mode::MATERIAL_NORMAL;
-}
-
-// static
-bool MaterialDesignController::IsMaterialExperimental() {
-  return GetMode() == Mode::MATERIAL_EXPERIMENTAL;
-}
-
-// static
 MaterialDesignController::Mode MaterialDesignController::GetMode() {
   DCHECK_NE(mode_, Mode::UNINITIALIZED);
   return mode_;
@@ -69,7 +59,7 @@
 
 // static
 bool MaterialDesignController::IsOverviewMaterial() {
-  return MaterialDesignController::IsMaterialExperimental();
+  return MaterialDesignController::IsMaterial();
 }
 
 // static
@@ -88,8 +78,23 @@
 }
 
 // static
+bool MaterialDesignController::IsMaterial() {
+  return IsMaterialExperimental() || IsMaterialNormal();
+}
+
+// static
+bool MaterialDesignController::IsMaterialNormal() {
+  return GetMode() == Mode::MATERIAL_NORMAL;
+}
+
+// static
+bool MaterialDesignController::IsMaterialExperimental() {
+  return GetMode() == Mode::MATERIAL_EXPERIMENTAL;
+}
+
+// static
 MaterialDesignController::Mode MaterialDesignController::DefaultMode() {
-  return Mode::NON_MATERIAL;
+  return Mode::MATERIAL_NORMAL;
 }
 
 // static
diff --git a/ash/common/material_design/material_design_controller.h b/ash/common/material_design/material_design_controller.h
index 98f8c44..803b671 100644
--- a/ash/common/material_design/material_design_controller.h
+++ b/ash/common/material_design/material_design_controller.h
@@ -30,18 +30,9 @@
   };
 
   // Initializes |mode_|. Must be called before calling IsMaterial(),
-  // IsMaterialExperimental(), or GetMode().
+  // IsMaterialExperimental(), IsMaterialNormal(), or GetMode().
   static void Initialize();
 
-  // Returns true if Material Design is enabled in Chrome OS system UI.
-  // Maps to "ash-md" flag "enabled" or "experimental" values.
-  static bool IsMaterial();
-
-  // Returns true if Material Design experimental features are enabled in
-  // Chrome OS system UI.
-  // Maps to "--ash-md=experimental" command line switch value.
-  static bool IsMaterialExperimental();
-
   // Returns the currently initialized MaterialDesignController::Mode type for
   // Chrome OS system UI.
   static Mode GetMode();
@@ -66,6 +57,19 @@
   // Material Design |Mode| for Chrome OS system UI. Used only by tests.
   static Mode mode();
 
+  // Returns true if Material Design is enabled in Chrome OS system UI.
+  // Maps to "ash-md" flag "enabled" or "experimental" values.
+  static bool IsMaterial();
+
+  // Returns true if Material Design normal features are enabled in Chrome OS
+  // system UI. Maps to "--ash-md=enabled" command line switch value.
+  static bool IsMaterialNormal();
+
+  // Returns true if Material Design experimental features are enabled in
+  // Chrome OS system UI. Maps to "--ash-md=experimental" command line switch
+  // value.
+  static bool IsMaterialExperimental();
+
   // Returns the per-platform default material design variant.
   static Mode DefaultMode();
 
diff --git a/ash/common/material_design/material_design_controller_unittest.cc b/ash/common/material_design/material_design_controller_unittest.cc
index b9a6772..5935b264 100644
--- a/ash/common/material_design/material_design_controller_unittest.cc
+++ b/ash/common/material_design/material_design_controller_unittest.cc
@@ -99,28 +99,28 @@
                     MaterialDesignController::Mode::MATERIAL_NORMAL ||
                 test::MaterialDesignControllerTestAPI::DefaultMode() ==
                     MaterialDesignController::Mode::MATERIAL_EXPERIMENTAL,
-            MaterialDesignController::IsMaterial());
+            test::MaterialDesignControllerTestAPI::IsMaterial());
 }
 
 // Verify that MaterialDesignController::IsMaterial() will be false when
 // initialized with command line flag "disabled".
 TEST_F(MaterialDesignControllerTestNonMaterial, CommandLineValue) {
-  EXPECT_FALSE(MaterialDesignController::IsMaterial());
-  EXPECT_FALSE(MaterialDesignController::IsMaterialExperimental());
+  EXPECT_FALSE(test::MaterialDesignControllerTestAPI::IsMaterial());
+  EXPECT_FALSE(test::MaterialDesignControllerTestAPI::IsMaterialExperimental());
 }
 
 // Verify that MaterialDesignController::IsMaterial() will be true when
 // initialized with command line flag "enabled".
 TEST_F(MaterialDesignControllerTestMaterial, CommandLineValue) {
-  EXPECT_TRUE(MaterialDesignController::IsMaterial());
-  EXPECT_FALSE(MaterialDesignController::IsMaterialExperimental());
+  EXPECT_TRUE(test::MaterialDesignControllerTestAPI::IsMaterial());
+  EXPECT_FALSE(test::MaterialDesignControllerTestAPI::IsMaterialExperimental());
 }
 
 // Verify that MaterialDesignController::IsMaterialexperimental() will be true
 // when initialized with command line flag "experimental".
 TEST_F(MaterialDesignControllerTestExperimental, CommandLineValue) {
-  EXPECT_TRUE(MaterialDesignController::IsMaterial());
-  EXPECT_TRUE(MaterialDesignController::IsMaterialExperimental());
+  EXPECT_TRUE(test::MaterialDesignControllerTestAPI::IsMaterial());
+  EXPECT_TRUE(test::MaterialDesignControllerTestAPI::IsMaterialExperimental());
 }
 
 // Verify an invalid command line value uses the default mode.
@@ -129,7 +129,7 @@
                     MaterialDesignController::Mode::MATERIAL_NORMAL ||
                 test::MaterialDesignControllerTestAPI::DefaultMode() ==
                     MaterialDesignController::Mode::MATERIAL_EXPERIMENTAL,
-            MaterialDesignController::IsMaterial());
+            test::MaterialDesignControllerTestAPI::IsMaterial());
 }
 
 }  // namespace ash
diff --git a/ash/common/shelf/shelf_constants.cc b/ash/common/shelf/shelf_constants.cc
index e9aa5c2..b2819f2 100644
--- a/ash/common/shelf/shelf_constants.cc
+++ b/ash/common/shelf/shelf_constants.cc
@@ -22,10 +22,10 @@
 const SkColor kShelfIconColor = SK_ColorWHITE;
 
 int GetShelfConstant(ShelfConstant shelf_constant) {
-  const int kShelfBackgroundAlpha[] = {204, 153, 153};
-  const int kShelfSize[] = {47, 48, 48};
-  const int kShelfButtonSpacing[] = {10, 16, 16};
-  const int kShelfButtonSize[] = {44, 48, 48};
+  const int kShelfBackgroundAlpha[] = {204, 204, 153};
+  const int kShelfSize[] = {47, 47, 48};
+  const int kShelfButtonSpacing[] = {10, 10, 16};
+  const int kShelfButtonSize[] = {44, 44, 48};
 
   const int mode = MaterialDesignController::GetMode();
   DCHECK(mode >= MaterialDesignController::NON_MATERIAL &&
diff --git a/ash/system/chromeos/devicetype_utils.cc b/ash/common/system/chromeos/devicetype_utils.cc
similarity index 94%
rename from ash/system/chromeos/devicetype_utils.cc
rename to ash/common/system/chromeos/devicetype_utils.cc
index 7f31a388..920b50d 100644
--- a/ash/system/chromeos/devicetype_utils.cc
+++ b/ash/common/system/chromeos/devicetype_utils.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 "ash/system/chromeos/devicetype_utils.h"
+#include "ash/common/system/chromeos/devicetype_utils.h"
 
 #include "chromeos/system/devicetype.h"
 #include "grit/ash_strings.h"
diff --git a/ash/system/chromeos/devicetype_utils.h b/ash/common/system/chromeos/devicetype_utils.h
similarity index 82%
rename from ash/system/chromeos/devicetype_utils.h
rename to ash/common/system/chromeos/devicetype_utils.h
index bcdc04f..a84fd87 100644
--- a/ash/system/chromeos/devicetype_utils.h
+++ b/ash/common/system/chromeos/devicetype_utils.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 ASH_SYSTEM_CHROMEOS_DEVICETYPE_UTILS_H_
-#define ASH_SYSTEM_CHROMEOS_DEVICETYPE_UTILS_H_
+#ifndef ASH_COMMON_SYSTEM_CHROMEOS_DEVICETYPE_UTILS_H_
+#define ASH_COMMON_SYSTEM_CHROMEOS_DEVICETYPE_UTILS_H_
 
 #include "ash/ash_export.h"
 #include "base/strings/string16.h"
@@ -23,4 +23,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_SYSTEM_CHROMEOS_DEVICETYPE_UTILS_H_
+#endif  // ASH_COMMON_SYSTEM_CHROMEOS_DEVICETYPE_UTILS_H_
diff --git a/ash/system/chromeos/power/battery_notification.cc b/ash/common/system/chromeos/power/battery_notification.cc
similarity index 95%
rename from ash/system/chromeos/power/battery_notification.cc
rename to ash/common/system/chromeos/power/battery_notification.cc
index ba522453..67cf3959 100644
--- a/ash/system/chromeos/power/battery_notification.cc
+++ b/ash/common/system/chromeos/power/battery_notification.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 "ash/system/chromeos/power/battery_notification.h"
+#include "ash/common/system/chromeos/power/battery_notification.h"
 
-#include "ash/system/chromeos/power/power_status.h"
-#include "ash/system/system_notifier.h"
+#include "ash/common/system/chromeos/power/power_status.h"
+#include "ash/common/system/system_notifier.h"
 #include "base/i18n/message_formatter.h"
 #include "base/i18n/time_formatting.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ash/system/chromeos/power/battery_notification.h b/ash/common/system/chromeos/power/battery_notification.h
similarity index 76%
rename from ash/system/chromeos/power/battery_notification.h
rename to ash/common/system/chromeos/power/battery_notification.h
index 24284d19..fa698320 100644
--- a/ash/system/chromeos/power/battery_notification.h
+++ b/ash/common/system/chromeos/power/battery_notification.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SYSTEM_CHROMEOS_POWER_BATTERY_NOTIFICATION_H_
-#define ASH_SYSTEM_CHROMEOS_POWER_BATTERY_NOTIFICATION_H_
+#ifndef ASH_COMMON_SYSTEM_CHROMEOS_POWER_BATTERY_NOTIFICATION_H_
+#define ASH_COMMON_SYSTEM_CHROMEOS_POWER_BATTERY_NOTIFICATION_H_
 
 #include "ash/ash_export.h"
-#include "ash/system/chromeos/power/tray_power.h"
+#include "ash/common/system/chromeos/power/tray_power.h"
 #include "base/macros.h"
 
 namespace message_center {
@@ -33,4 +33,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_SYSTEM_CHROMEOS_POWER_BATTERY_NOTIFICATION_H_
+#endif  // ASH_COMMON_SYSTEM_CHROMEOS_POWER_BATTERY_NOTIFICATION_H_
diff --git a/ash/system/chromeos/power/dual_role_notification.cc b/ash/common/system/chromeos/power/dual_role_notification.cc
similarity index 96%
rename from ash/system/chromeos/power/dual_role_notification.cc
rename to ash/common/system/chromeos/power/dual_role_notification.cc
index 58e6aec..1b90278 100644
--- a/ash/system/chromeos/power/dual_role_notification.cc
+++ b/ash/common/system/chromeos/power/dual_role_notification.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/system/chromeos/power/dual_role_notification.h"
+#include "ash/common/system/chromeos/power/dual_role_notification.h"
 
 #include <set>
 
+#include "ash/common/system/chromeos/power/power_status.h"
+#include "ash/common/system/system_notifier.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
 #include "ash/common/wm_shell.h"
-#include "ash/system/chromeos/power/power_status.h"
-#include "ash/system/system_notifier.h"
 #include "base/strings/utf_string_conversions.h"
 #include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
diff --git a/ash/system/chromeos/power/dual_role_notification.h b/ash/common/system/chromeos/power/dual_role_notification.h
similarity index 80%
rename from ash/system/chromeos/power/dual_role_notification.h
rename to ash/common/system/chromeos/power/dual_role_notification.h
index d990093..a648783 100644
--- a/ash/system/chromeos/power/dual_role_notification.h
+++ b/ash/common/system/chromeos/power/dual_role_notification.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SYSTEM_CHROMEOS_POWER_DUAL_ROLE_NOTIFICATION_H_
-#define ASH_SYSTEM_CHROMEOS_POWER_DUAL_ROLE_NOTIFICATION_H_
+#ifndef ASH_COMMON_SYSTEM_CHROMEOS_POWER_DUAL_ROLE_NOTIFICATION_H_
+#define ASH_COMMON_SYSTEM_CHROMEOS_POWER_DUAL_ROLE_NOTIFICATION_H_
 
 #include <stddef.h>
 
 #include <memory>
 
 #include "ash/ash_export.h"
-#include "ash/system/chromeos/power/power_status.h"
+#include "ash/common/system/chromeos/power/power_status.h"
 #include "base/macros.h"
 
 namespace message_center {
@@ -45,4 +45,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_SYSTEM_CHROMEOS_POWER_DUAL_ROLE_NOTIFICATION_H_
+#endif  // ASH_COMMON_SYSTEM_CHROMEOS_POWER_DUAL_ROLE_NOTIFICATION_H_
diff --git a/ash/system/chromeos/power/power_status.cc b/ash/common/system/chromeos/power/power_status.cc
similarity index 98%
rename from ash/system/chromeos/power/power_status.cc
rename to ash/common/system/chromeos/power/power_status.cc
index 5b2a0ad..806db34 100644
--- a/ash/system/chromeos/power/power_status.cc
+++ b/ash/common/system/chromeos/power/power_status.cc
@@ -2,13 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/system/chromeos/power/power_status.h"
+#include "ash/common/system/chromeos/power/power_status.h"
 
 #include <algorithm>
 #include <cmath>
 
-#include "ash/shell.h"
-#include "ash/shell_delegate.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ash/system/chromeos/power/power_status.h b/ash/common/system/chromeos/power/power_status.h
similarity index 97%
rename from ash/system/chromeos/power/power_status.h
rename to ash/common/system/chromeos/power/power_status.h
index 7fb94d72..26c4b19 100644
--- a/ash/system/chromeos/power/power_status.h
+++ b/ash/common/system/chromeos/power/power_status.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 ASH_SYSTEM_CHROMEOS_POWER_POWER_STATUS_H_
-#define ASH_SYSTEM_CHROMEOS_POWER_POWER_STATUS_H_
+#ifndef ASH_COMMON_SYSTEM_CHROMEOS_POWER_POWER_STATUS_H_
+#define ASH_COMMON_SYSTEM_CHROMEOS_POWER_POWER_STATUS_H_
 
 #include <string>
 #include <vector>
@@ -220,4 +220,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_SYSTEM_CHROMEOS_POWER_POWER_STATUS_H_
+#endif  // ASH_COMMON_SYSTEM_CHROMEOS_POWER_POWER_STATUS_H_
diff --git a/ash/system/chromeos/power/power_status_unittest.cc b/ash/common/system/chromeos/power/power_status_unittest.cc
similarity index 98%
rename from ash/system/chromeos/power/power_status_unittest.cc
rename to ash/common/system/chromeos/power/power_status_unittest.cc
index a747e5d..5115828f 100644
--- a/ash/system/chromeos/power/power_status_unittest.cc
+++ b/ash/common/system/chromeos/power/power_status_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 "ash/system/chromeos/power/power_status.h"
+#include "ash/common/system/chromeos/power/power_status.h"
 
 #include <memory>
 
diff --git a/ash/system/chromeos/power/power_status_view.cc b/ash/common/system/chromeos/power/power_status_view.cc
similarity index 95%
rename from ash/system/chromeos/power/power_status_view.cc
rename to ash/common/system/chromeos/power/power_status_view.cc
index ec472cc..a30ce2c4 100644
--- a/ash/system/chromeos/power/power_status_view.cc
+++ b/ash/common/system/chromeos/power/power_status_view.cc
@@ -2,14 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/system/chromeos/power/power_status_view.h"
+#include "ash/common/system/chromeos/power/power_status_view.h"
 
+#include "ash/common/system/chromeos/power/power_status.h"
+#include "ash/common/system/chromeos/power/tray_power.h"
 #include "ash/common/system/tray/fixed_sized_image_view.h"
 #include "ash/common/system/tray/tray_constants.h"
-#include "ash/shell.h"
-#include "ash/shell_delegate.h"
-#include "ash/system/chromeos/power/power_status.h"
-#include "ash/system/chromeos/power/tray_power.h"
 #include "base/i18n/message_formatter.h"
 #include "base/i18n/time_formatting.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ash/system/chromeos/power/power_status_view.h b/ash/common/system/chromeos/power/power_status_view.h
similarity index 86%
rename from ash/system/chromeos/power/power_status_view.h
rename to ash/common/system/chromeos/power/power_status_view.h
index c050d4d..5d92e1e 100644
--- a/ash/system/chromeos/power/power_status_view.h
+++ b/ash/common/system/chromeos/power/power_status_view.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SYSTEM_CHROMEOS_POWER_POWER_STATUS_VIEW_H_
-#define ASH_SYSTEM_CHROMEOS_POWER_POWER_STATUS_VIEW_H_
+#ifndef ASH_COMMON_SYSTEM_CHROMEOS_POWER_POWER_STATUS_VIEW_H_
+#define ASH_COMMON_SYSTEM_CHROMEOS_POWER_POWER_STATUS_VIEW_H_
 
 #include "ash/ash_export.h"
-#include "ash/system/chromeos/power/power_status.h"
+#include "ash/common/system/chromeos/power/power_status.h"
 #include "base/macros.h"
 #include "ui/views/view.h"
 
@@ -60,4 +60,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_SYSTEM_CHROMEOS_POWER_POWER_STATUS_VIEW_H_
+#endif  // ASH_COMMON_SYSTEM_CHROMEOS_POWER_POWER_STATUS_VIEW_H_
diff --git a/ash/system/chromeos/power/power_status_view_unittest.cc b/ash/common/system/chromeos/power/power_status_view_unittest.cc
similarity index 97%
rename from ash/system/chromeos/power/power_status_view_unittest.cc
rename to ash/common/system/chromeos/power/power_status_view_unittest.cc
index 67b9941..c2d4964 100644
--- a/ash/system/chromeos/power/power_status_view_unittest.cc
+++ b/ash/common/system/chromeos/power/power_status_view_unittest.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/system/chromeos/power/power_status_view.h"
+#include "ash/common/system/chromeos/power/power_status_view.h"
 
-#include "ash/system/chromeos/power/power_status.h"
+#include "ash/common/system/chromeos/power/power_status.h"
 #include "ash/test/ash_test_base.h"
 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
 #include "grit/ash_strings.h"
diff --git a/ash/system/chromeos/power/tray_power.cc b/ash/common/system/chromeos/power/tray_power.cc
similarity index 97%
rename from ash/system/chromeos/power/tray_power.cc
rename to ash/common/system/chromeos/power/tray_power.cc
index ecfaa85..22e8ec1 100644
--- a/ash/system/chromeos/power/tray_power.cc
+++ b/ash/common/system/chromeos/power/tray_power.cc
@@ -2,21 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/system/chromeos/power/tray_power.h"
+#include "ash/common/system/chromeos/power/tray_power.h"
 
 #include <utility>
 
 #include "ash/ash_switches.h"
 #include "ash/common/accessibility_delegate.h"
+#include "ash/common/system/chromeos/devicetype_utils.h"
+#include "ash/common/system/chromeos/power/battery_notification.h"
+#include "ash/common/system/chromeos/power/dual_role_notification.h"
 #include "ash/common/system/date/date_view.h"
+#include "ash/common/system/system_notifier.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
 #include "ash/common/system/tray/tray_constants.h"
 #include "ash/common/system/tray/tray_utils.h"
-#include "ash/shell.h"
-#include "ash/system/chromeos/devicetype_utils.h"
-#include "ash/system/chromeos/power/battery_notification.h"
-#include "ash/system/chromeos/power/dual_role_notification.h"
-#include "ash/system/system_notifier.h"
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
diff --git a/ash/system/chromeos/power/tray_power.h b/ash/common/system/chromeos/power/tray_power.h
similarity index 93%
rename from ash/system/chromeos/power/tray_power.h
rename to ash/common/system/chromeos/power/tray_power.h
index 4f47be8..9ad7516 100644
--- a/ash/system/chromeos/power/tray_power.h
+++ b/ash/common/system/chromeos/power/tray_power.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SYSTEM_CHROMEOS_POWER_TRAY_POWER_H_
-#define ASH_SYSTEM_CHROMEOS_POWER_TRAY_POWER_H_
+#ifndef ASH_COMMON_SYSTEM_CHROMEOS_POWER_TRAY_POWER_H_
+#define ASH_COMMON_SYSTEM_CHROMEOS_POWER_TRAY_POWER_H_
 
 #include <memory>
 
+#include "ash/common/system/chromeos/power/power_status.h"
 #include "ash/common/system/tray/system_tray_item.h"
-#include "ash/system/chromeos/power/power_status.h"
 #include "base/macros.h"
 
 class SkBitmap;
@@ -121,4 +121,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_SYSTEM_CHROMEOS_POWER_TRAY_POWER_H_
+#endif  // ASH_COMMON_SYSTEM_CHROMEOS_POWER_TRAY_POWER_H_
diff --git a/ash/system/chromeos/power/tray_power_unittest.cc b/ash/common/system/chromeos/power/tray_power_unittest.cc
similarity index 99%
rename from ash/system/chromeos/power/tray_power_unittest.cc
rename to ash/common/system/chromeos/power/tray_power_unittest.cc
index 5423631..d2d102f 100644
--- a/ash/system/chromeos/power/tray_power_unittest.cc
+++ b/ash/common/system/chromeos/power/tray_power_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 "ash/system/chromeos/power/tray_power.h"
+#include "ash/common/system/chromeos/power/tray_power.h"
 
 #include <map>
 #include <memory>
diff --git a/ash/system/chromeos/settings/tray_settings.cc b/ash/common/system/chromeos/settings/tray_settings.cc
similarity index 86%
rename from ash/system/chromeos/settings/tray_settings.cc
rename to ash/common/system/chromeos/settings/tray_settings.cc
index 5c1ce9b7..33cf711 100644
--- a/ash/system/chromeos/settings/tray_settings.cc
+++ b/ash/common/system/chromeos/settings/tray_settings.cc
@@ -2,17 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/system/chromeos/settings/tray_settings.h"
+#include "ash/common/system/chromeos/settings/tray_settings.h"
 
 #include "ash/common/session/session_state_delegate.h"
+#include "ash/common/system/chromeos/power/power_status.h"
+#include "ash/common/system/chromeos/power/power_status_view.h"
 #include "ash/common/system/tray/actionable_view.h"
 #include "ash/common/system/tray/fixed_sized_image_view.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
 #include "ash/common/system/tray/tray_constants.h"
 #include "ash/common/wm_shell.h"
-#include "ash/shell.h"
-#include "ash/system/chromeos/power/power_status.h"
-#include "ash/system/chromeos/power/power_status_view.h"
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
 #include "grit/ash_resources.h"
@@ -40,12 +39,11 @@
         ash::kTrayPopupPaddingBetweenItems));
 
     bool power_view_right_align = false;
-    bool userAddingRunning = ash::Shell::GetInstance()
-                                 ->session_state_delegate()
-                                 ->IsInSecondaryLoginScreen();
-
     if (login_status_ != LoginStatus::NOT_LOGGED_IN &&
-        login_status_ != LoginStatus::LOCKED && !userAddingRunning) {
+        login_status_ != LoginStatus::LOCKED &&
+        !WmShell::Get()
+             ->GetSessionStateDelegate()
+             ->IsInSecondaryLoginScreen()) {
       ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
       views::ImageView* icon =
           new ash::FixedSizedImageView(0, ash::kTrayPopupItemHeight);
@@ -73,12 +71,9 @@
 
   // Overridden from ash::ActionableView.
   bool PerformAction(const ui::Event& event) override {
-    bool adding_user = Shell::GetInstance()
-                           ->session_state_delegate()
-                           ->IsInSecondaryLoginScreen();
-
     if (login_status_ == LoginStatus::NOT_LOGGED_IN ||
-        login_status_ == LoginStatus::LOCKED || adding_user) {
+        login_status_ == LoginStatus::LOCKED ||
+        WmShell::Get()->GetSessionStateDelegate()->IsInSecondaryLoginScreen()) {
       return false;
     }
 
@@ -157,15 +152,13 @@
   return NULL;
 }
 
-void TraySettings::DestroyTrayView() {
-}
+void TraySettings::DestroyTrayView() {}
 
 void TraySettings::DestroyDefaultView() {
   default_view_ = NULL;
 }
 
-void TraySettings::DestroyDetailedView() {
-}
+void TraySettings::DestroyDetailedView() {}
 
 void TraySettings::UpdateAfterLoginStatusChange(LoginStatus status) {}
 
diff --git a/ash/system/chromeos/settings/tray_settings.h b/ash/common/system/chromeos/settings/tray_settings.h
similarity index 83%
rename from ash/system/chromeos/settings/tray_settings.h
rename to ash/common/system/chromeos/settings/tray_settings.h
index 5f5e0f891..2a46942b 100644
--- a/ash/system/chromeos/settings/tray_settings.h
+++ b/ash/common/system/chromeos/settings/tray_settings.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 ASH_SYSTEM_CHROMEOS_SETTINGS_TRAY_SETTINGS_H_
-#define ASH_SYSTEM_CHROMEOS_SETTINGS_TRAY_SETTINGS_H_
+#ifndef ASH_COMMON_SYSTEM_CHROMEOS_SETTINGS_TRAY_SETTINGS_H_
+#define ASH_COMMON_SYSTEM_CHROMEOS_SETTINGS_TRAY_SETTINGS_H_
 
 #include "ash/common/system/tray/system_tray_item.h"
 #include "base/macros.h"
@@ -35,4 +35,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_SYSTEM_CHROMEOS_SETTINGS_TRAY_SETTINGS_H_
+#endif  // ASH_COMMON_SYSTEM_CHROMEOS_SETTINGS_TRAY_SETTINGS_H_
diff --git a/ash/system/system_notifier.cc b/ash/common/system/system_notifier.cc
similarity index 98%
rename from ash/system/system_notifier.cc
rename to ash/common/system/system_notifier.cc
index 76875de..1d35d4f 100644
--- a/ash/system/system_notifier.cc
+++ b/ash/common/system/system_notifier.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 "ash/system/system_notifier.h"
+#include "ash/common/system/system_notifier.h"
 
 #include "base/logging.h"
 
diff --git a/ash/system/system_notifier.h b/ash/common/system/system_notifier.h
similarity index 93%
rename from ash/system/system_notifier.h
rename to ash/common/system/system_notifier.h
index 8febc9f..a43484b 100644
--- a/ash/system/system_notifier.h
+++ b/ash/common/system/system_notifier.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 ASH_SYSTEM_SYSTEM_NOTIFIER_H_
-#define ASH_SYSTEM_SYSTEM_NOTIFIER_H_
+#ifndef ASH_COMMON_SYSTEM_SYSTEM_NOTIFIER_H_
+#define ASH_COMMON_SYSTEM_SYSTEM_NOTIFIER_H_
 
 #include <string>
 
@@ -48,4 +48,4 @@
 }  // namespace system_notifier
 }  // namespace ash
 
-#endif  // ASH_SYSTEM_SYSTEM_NOTIFIER_H_
+#endif  // ASH_COMMON_SYSTEM_SYSTEM_NOTIFIER_H_
diff --git a/ash/common/system/tray/tray_constants.cc b/ash/common/system/tray/tray_constants.cc
index 4c719ad..667e952 100644
--- a/ash/common/system/tray/tray_constants.cc
+++ b/ash/common/system/tray/tray_constants.cc
@@ -90,8 +90,8 @@
 const int kShelfItemSizeMD = 32;
 
 int GetTrayConstant(TrayConstant constant) {
-  const int kTraySpacing[] = {4, 8, 8};
-  const int kTrayPaddingFromEdgeOfShelf[] = {3, 8, 8};
+  const int kTraySpacing[] = {4, 4, 8};
+  const int kTrayPaddingFromEdgeOfShelf[] = {3, 3, 8};
 
   const int mode = MaterialDesignController::GetMode();
   DCHECK(mode >= MaterialDesignController::NON_MATERIAL &&
diff --git a/ash/display/display_util.cc b/ash/display/display_util.cc
index ec36ab2..dd62d4b4 100644
--- a/ash/display/display_util.cc
+++ b/ash/display/display_util.cc
@@ -6,12 +6,12 @@
 
 #include <algorithm>
 
+#include "ash/common/system/system_notifier.h"
 #include "ash/display/display_info.h"
 #include "ash/display/display_manager.h"
 #include "ash/host/ash_window_tree_host.h"
 #include "ash/new_window_delegate.h"
 #include "ash/shell.h"
-#include "ash/system/system_notifier.h"
 #include "base/strings/string_number_conversions.h"
 #include "grit/ash_resources.h"
 #include "ui/aura/env.h"
diff --git a/ash/display/resolution_notification_controller.cc b/ash/display/resolution_notification_controller.cc
index f740ea4..9d66bc80 100644
--- a/ash/display/resolution_notification_controller.cc
+++ b/ash/display/resolution_notification_controller.cc
@@ -6,10 +6,10 @@
 
 #include <utility>
 
+#include "ash/common/system/system_notifier.h"
 #include "ash/display/display_info.h"
 #include "ash/display/display_manager.h"
 #include "ash/shell.h"
-#include "ash/system/system_notifier.h"
 #include "base/strings/utf_string_conversions.h"
 #include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
diff --git a/ash/shell.cc b/ash/shell.cc
index e17a8da..e1260682 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -127,6 +127,7 @@
 #include "ash/accelerators/magnifier_key_scroller.h"
 #include "ash/accelerators/spoken_feedback_toggler.h"
 #include "ash/common/ash_constants.h"
+#include "ash/common/system/chromeos/power/power_status.h"
 #include "ash/display/display_change_observer_chromeos.h"
 #include "ash/display/display_color_manager_chromeos.h"
 #include "ash/display/display_error_observer_chromeos.h"
@@ -137,7 +138,6 @@
 #include "ash/system/chromeos/bluetooth/bluetooth_notification_controller.h"
 #include "ash/system/chromeos/brightness/brightness_controller_chromeos.h"
 #include "ash/system/chromeos/power/power_event_observer.h"
-#include "ash/system/chromeos/power/power_status.h"
 #include "ash/system/chromeos/power/video_activity_notifier.h"
 #include "ash/system/chromeos/session/last_window_closed_logout_reminder.h"
 #include "ash/system/chromeos/session/logout_confirmation_controller.h"
diff --git a/ash/system/chromeos/bluetooth/bluetooth_notification_controller.cc b/ash/system/chromeos/bluetooth/bluetooth_notification_controller.cc
index 1864a1cf..d4985d9 100644
--- a/ash/system/chromeos/bluetooth/bluetooth_notification_controller.cc
+++ b/ash/system/chromeos/bluetooth/bluetooth_notification_controller.cc
@@ -7,7 +7,7 @@
 #include <memory>
 #include <utility>
 
-#include "ash/system/system_notifier.h"
+#include "ash/common/system/system_notifier.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/logging.h"
diff --git a/ash/system/chromeos/screen_security/screen_capture_tray_item.cc b/ash/system/chromeos/screen_security/screen_capture_tray_item.cc
index cfa538b..fe0dc5ad 100644
--- a/ash/system/chromeos/screen_security/screen_capture_tray_item.cc
+++ b/ash/system/chromeos/screen_security/screen_capture_tray_item.cc
@@ -6,9 +6,9 @@
 
 #include <utility>
 
+#include "ash/common/system/system_notifier.h"
 #include "ash/common/wm_shell.h"
 #include "ash/shell.h"
-#include "ash/system/system_notifier.h"
 #include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/ash/system/chromeos/screen_security/screen_share_tray_item.cc b/ash/system/chromeos/screen_security/screen_share_tray_item.cc
index d04a04fc..2c8bd67 100644
--- a/ash/system/chromeos/screen_security/screen_share_tray_item.cc
+++ b/ash/system/chromeos/screen_security/screen_share_tray_item.cc
@@ -6,8 +6,8 @@
 
 #include <utility>
 
+#include "ash/common/system/system_notifier.h"
 #include "ash/shell.h"
-#include "ash/system/system_notifier.h"
 #include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/ash/system/chromeos/session/tray_session_length_limit.cc b/ash/system/chromeos/session/tray_session_length_limit.cc
index 5588718..0dec056 100644
--- a/ash/system/chromeos/session/tray_session_length_limit.cc
+++ b/ash/system/chromeos/session/tray_session_length_limit.cc
@@ -8,11 +8,11 @@
 #include <memory>
 #include <utility>
 
+#include "ash/common/system/system_notifier.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
 #include "ash/common/wm_shell.h"
 #include "ash/shell.h"
 #include "ash/system/chromeos/label_tray_view.h"
-#include "ash/system/system_notifier.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "base/logging.h"
diff --git a/ash/system/chromeos/supervised/tray_supervised_user.cc b/ash/system/chromeos/supervised/tray_supervised_user.cc
index df6e92b..c694c7f5 100644
--- a/ash/system/chromeos/supervised/tray_supervised_user.cc
+++ b/ash/system/chromeos/supervised/tray_supervised_user.cc
@@ -6,11 +6,11 @@
 
 #include <utility>
 
+#include "ash/common/system/system_notifier.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
 #include "ash/common/system/tray/tray_notification_view.h"
 #include "ash/common/wm_shell.h"
 #include "ash/system/chromeos/label_tray_view.h"
-#include "ash/system/system_notifier.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/system/user/login_status.h"
 #include "base/callback.h"
diff --git a/ash/system/chromeos/tray_display.cc b/ash/system/chromeos/tray_display.cc
index 9462d513..d2eba2a 100644
--- a/ash/system/chromeos/tray_display.cc
+++ b/ash/system/chromeos/tray_display.cc
@@ -8,6 +8,8 @@
 #include <utility>
 #include <vector>
 
+#include "ash/common/system/chromeos/devicetype_utils.h"
+#include "ash/common/system/system_notifier.h"
 #include "ash/common/system/tray/actionable_view.h"
 #include "ash/common/system/tray/fixed_sized_image_view.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
@@ -18,8 +20,6 @@
 #include "ash/display/screen_orientation_controller_chromeos.h"
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/shell.h"
-#include "ash/system/chromeos/devicetype_utils.h"
-#include "ash/system/system_notifier.h"
 #include "ash/system/tray/system_tray.h"
 #include "base/bind.h"
 #include "base/strings/string_util.h"
diff --git a/ash/system/chromeos/tray_display_unittest.cc b/ash/system/chromeos/tray_display_unittest.cc
index ce5a878..374d9d3 100644
--- a/ash/system/chromeos/tray_display_unittest.cc
+++ b/ash/system/chromeos/tray_display_unittest.cc
@@ -4,11 +4,11 @@
 
 #include "ash/system/chromeos/tray_display.h"
 
+#include "ash/common/system/chromeos/devicetype_utils.h"
 #include "ash/display/display_manager.h"
 #include "ash/root_window_controller.h"
 #include "ash/screen_util.h"
 #include "ash/shell.h"
-#include "ash/system/chromeos/devicetype_utils.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/display_manager_test_api.h"
diff --git a/ash/system/locale/locale_notification_controller.cc b/ash/system/locale/locale_notification_controller.cc
index 174a662c..bc514d58 100644
--- a/ash/system/locale/locale_notification_controller.cc
+++ b/ash/system/locale/locale_notification_controller.cc
@@ -6,8 +6,8 @@
 
 #include <utility>
 
+#include "ash/common/system/system_notifier.h"
 #include "ash/shell.h"
-#include "ash/system/system_notifier.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "base/strings/string16.h"
 #include "grit/ash_resources.h"
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc
index eec513c..1fe6be7 100644
--- a/ash/system/tray/system_tray.cc
+++ b/ash/system/tray/system_tray.cc
@@ -46,6 +46,9 @@
 #include "ui/views/view.h"
 
 #if defined(OS_CHROMEOS)
+#include "ash/common/system/chromeos/power/power_status.h"
+#include "ash/common/system/chromeos/power/tray_power.h"
+#include "ash/common/system/chromeos/settings/tray_settings.h"
 #include "ash/system/chromeos/audio/tray_audio_chromeos.h"
 #include "ash/system/chromeos/bluetooth/tray_bluetooth.h"
 #include "ash/system/chromeos/brightness/tray_brightness.h"
@@ -53,13 +56,10 @@
 #include "ash/system/chromeos/network/tray_network.h"
 #include "ash/system/chromeos/network/tray_sms.h"
 #include "ash/system/chromeos/network/tray_vpn.h"
-#include "ash/system/chromeos/power/power_status.h"
-#include "ash/system/chromeos/power/tray_power.h"
 #include "ash/system/chromeos/rotation/tray_rotation_lock.h"
 #include "ash/system/chromeos/screen_security/screen_capture_tray_item.h"
 #include "ash/system/chromeos/screen_security/screen_share_tray_item.h"
 #include "ash/system/chromeos/session/tray_session_length_limit.h"
-#include "ash/system/chromeos/settings/tray_settings.h"
 #include "ash/system/chromeos/supervised/tray_supervised_user.h"
 #include "ash/system/chromeos/tray_caps_lock.h"
 #include "ash/system/chromeos/tray_display.h"
diff --git a/ash/test/material_design_controller_test_api.cc b/ash/test/material_design_controller_test_api.cc
index be221e7..7ce735ac 100644
--- a/ash/test/material_design_controller_test_api.cc
+++ b/ash/test/material_design_controller_test_api.cc
@@ -18,6 +18,21 @@
 }
 
 // static
+bool MaterialDesignControllerTestAPI::IsMaterial() {
+  return MaterialDesignController::IsMaterial();
+}
+
+// static
+bool MaterialDesignControllerTestAPI::IsMaterialNormal() {
+  return MaterialDesignController::IsMaterialNormal();
+}
+
+// static
+bool MaterialDesignControllerTestAPI::IsMaterialExperimental() {
+  return MaterialDesignController::IsMaterialExperimental();
+}
+
+// static
 MaterialDesignController::Mode MaterialDesignControllerTestAPI::DefaultMode() {
   return MaterialDesignController::DefaultMode();
 }
diff --git a/ash/test/material_design_controller_test_api.h b/ash/test/material_design_controller_test_api.h
index c5603b0..109dd76 100644
--- a/ash/test/material_design_controller_test_api.h
+++ b/ash/test/material_design_controller_test_api.h
@@ -20,6 +20,9 @@
   ~MaterialDesignControllerTestAPI();
 
   // Wrapper functions for MaterialDesignController internal functions.
+  static bool IsMaterial();
+  static bool IsMaterialNormal();
+  static bool IsMaterialExperimental();
   static MaterialDesignController::Mode DefaultMode();
   static void Uninitialize();
 
diff --git a/build/android/pylib/local/device/local_device_test_run.py b/build/android/pylib/local/device/local_device_test_run.py
index a1ad7ef..544fbf0e 100644
--- a/build/android/pylib/local/device/local_device_test_run.py
+++ b/build/android/pylib/local/device/local_device_test_run.py
@@ -6,9 +6,13 @@
 import functools
 import imp
 import logging
+import signal
+import thread
+import threading
 
 from devil import base_error
 from devil.android import device_errors
+from devil.utils import signal_handler
 from pylib import valgrind_tools
 from pylib.base import base_test_result
 from pylib.base import test_run
@@ -67,8 +71,10 @@
       except device_errors.DeviceUnreachableError:
         logging.exception('Shard died: %s(%s)', f.__name__, str(dev))
       except base_error.BaseError:
-        logging.exception('Shard failed: %s(%s)', f.__name__,
-                          str(dev))
+        logging.exception('Shard failed: %s(%s)', f.__name__, str(dev))
+      except SystemExit:
+        logging.exception('Shard killed: %s(%s)', f.__name__, str(dev))
+        raise
       if on_failure:
         on_failure(dev, f.__name__)
       return None
@@ -88,9 +94,14 @@
   def RunTests(self):
     tests = self._GetTests()
 
+    exit_now = threading.Event()
+
     @handle_shard_failures
     def run_tests_on_device(dev, tests, results):
       for test in tests:
+        if exit_now.isSet():
+          thread.exit()
+
         result = None
         try:
           result = self._RunTest(dev, test)
@@ -112,34 +123,38 @@
 
       logging.info('Finished running tests on this device.')
 
-    tries = 0
-    results = []
-    while tries < self._env.max_tries and tests:
-      logging.info('STARTING TRY #%d/%d', tries + 1, self._env.max_tries)
-      logging.info('Will run %d tests on %d devices: %s',
-                   len(tests), len(self._env.devices),
-                   ', '.join(str(d) for d in self._env.devices))
-      for t in tests:
-        logging.debug('  %s', t)
+    def stop_tests(_signum, _frame):
+      exit_now.set()
 
-      try_results = base_test_result.TestRunResults()
-      if self._ShouldShard():
-        tc = test_collection.TestCollection(self._CreateShards(tests))
-        self._env.parallel_devices.pMap(
-            run_tests_on_device, tc, try_results).pGet(None)
-      else:
-        self._env.parallel_devices.pMap(
-            run_tests_on_device, tests, try_results).pGet(None)
+    with signal_handler.AddSignalHandler(signal.SIGTERM, stop_tests):
+      tries = 0
+      results = []
+      while tries < self._env.max_tries and tests:
+        logging.info('STARTING TRY #%d/%d', tries + 1, self._env.max_tries)
+        logging.info('Will run %d tests on %d devices: %s',
+                     len(tests), len(self._env.devices),
+                     ', '.join(str(d) for d in self._env.devices))
+        for t in tests:
+          logging.debug('  %s', t)
 
-      results.append(try_results)
-      tries += 1
-      tests = self._GetTestsToRetry(tests, try_results)
+        try_results = base_test_result.TestRunResults()
+        if self._ShouldShard():
+          tc = test_collection.TestCollection(self._CreateShards(tests))
+          self._env.parallel_devices.pMap(
+              run_tests_on_device, tc, try_results).pGet(None)
+        else:
+          self._env.parallel_devices.pMap(
+              run_tests_on_device, tests, try_results).pGet(None)
 
-      logging.info('FINISHED TRY #%d/%d', tries, self._env.max_tries)
-      if tests:
-        logging.info('%d failed tests remain.', len(tests))
-      else:
-        logging.info('All tests completed.')
+        results.append(try_results)
+        tries += 1
+        tests = self._GetTestsToRetry(tests, try_results)
+
+        logging.info('FINISHED TRY #%d/%d', tries, self._env.max_tries)
+        if tests:
+          logging.info('%d failed tests remain.', len(tests))
+        else:
+          logging.info('All tests completed.')
 
     return results
 
diff --git a/build/android/test_runner.pydeps b/build/android/test_runner.pydeps
index f21b815..ea75edb 100644
--- a/build/android/test_runner.pydeps
+++ b/build/android/test_runner.pydeps
@@ -60,6 +60,7 @@
 ../../third_party/catapult/devil/devil/utils/parallelizer.py
 ../../third_party/catapult/devil/devil/utils/reraiser_thread.py
 ../../third_party/catapult/devil/devil/utils/run_tests_helper.py
+../../third_party/catapult/devil/devil/utils/signal_handler.py
 ../../third_party/catapult/devil/devil/utils/timeout_retry.py
 ../../third_party/catapult/devil/devil/utils/watchdog_timer.py
 ../../third_party/catapult/devil/devil/utils/zip_utils.py
diff --git a/chrome/android/java/res/layout/most_visited_item.xml b/chrome/android/java/res/layout/most_visited_item.xml
index cb036156..56e5ec9f 100644
--- a/chrome/android/java/res/layout/most_visited_item.xml
+++ b/chrome/android/java/res/layout/most_visited_item.xml
@@ -29,7 +29,7 @@
         android:visibility="gone"
         android:background="@drawable/offline_badge_background"
         android:contentDescription="@null"
-        chrome:tint="#4285f4"
+        chrome:tint="@color/most_visited_offline_badge_tint"
         android:src="@drawable/offline_bolt" />
 
     <View
@@ -49,7 +49,7 @@
         android:gravity="center_horizontal"
         android:lines="2"
         android:lineSpacingMultiplier="1.17"
-        android:textColor="#787878"
+        android:textColor="@color/most_visited_text"
         android:textSize="12sp" />
 
 </org.chromium.chrome.browser.ntp.MostVisitedItemView>
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index ecdd61e..bb238f4d 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -112,6 +112,10 @@
     <color name="snippets_list_header_text_color">#646464</color>
     <color name="snippets_headline_text_color">#333333</color>
 
+    <!-- Most Visited colors. -->
+    <color name="most_visited_text">#6f6f6f</color>
+    <color name="most_visited_offline_badge_tint">#4285f4</color>
+
     <!-- Contextual Search colors -->
     <color name="contextual_search_promo_text_color">#333333</color>
     <color name="contextual_search_promo_background_color">#EEEEEE</color>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index f42bb67..09988fb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -30,6 +30,7 @@
 import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.mojo.system.MojoException;
+import org.chromium.mojom.payments.PaymentComplete;
 import org.chromium.mojom.payments.PaymentDetails;
 import org.chromium.mojom.payments.PaymentItem;
 import org.chromium.mojom.payments.PaymentMethodData;
@@ -605,8 +606,8 @@
      * Called when the merchant website has processed the payment.
      */
     @Override
-    public void complete(boolean success) {
-        closeUI(success);
+    public void complete(int result) {
+        closeUI(PaymentComplete.FAIL != result);
     }
 
     /**
@@ -699,9 +700,9 @@
     /**
      * Closes the UI. If the client is still connected, then it's notified of UI hiding.
      */
-    private void closeUI(boolean paymentSuccess) {
+    private void closeUI(boolean immediateClose) {
         if (mUI != null) {
-            mUI.close(paymentSuccess, new Runnable() {
+            mUI.close(immediateClose, new Runnable() {
                 @Override
                 public void run() {
                     if (mClient != null) mClient.onComplete();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
index ef8b5cb..8a972b23 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
@@ -398,12 +398,13 @@
      *
      * Should not be called multiple times.
      *
-     * @param paymentSuccess Whether the payment (if any) was successful.
+     * @param shouldCloseImmediately If true, this function will immediately dismiss the dialog
+     *        without describing the error.
      * @param callback The callback to notify of finished animations.
      */
-    public void close(boolean paymentSuccess, final Runnable callback) {
+    public void close(boolean shouldCloseImmediately, final Runnable callback) {
         mIsClientClosing = true;
-        mResultView.update(paymentSuccess, new Runnable() {
+        mResultView.update(shouldCloseImmediately, new Runnable() {
             @Override
             public void run() {
                 dismissDialog(false);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentResultUIManager.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentResultUIManager.java
index ebb171d..2ec9a11 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentResultUIManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentResultUIManager.java
@@ -63,12 +63,15 @@
     /**
      * Updates the UI to display whether or not the payment request was successful.
      *
-     * @param paymentSuccess Whether or not the payment request was successful.
-     * @param callback       Callback to run upon dismissal.
+     * @param shouldCloseImmediately If true, this function will immediately dismiss the dialog
+     *        without describing the error.
+     * @param callback Callback to run upon dismissal.
      */
-    public void update(boolean paymentSuccess, final Runnable callback) {
-        if (mResultLayout.getParent() == null || paymentSuccess) {
-            // Dismiss the dialog immediately.
+    public void update(boolean shouldCloseImmediately, final Runnable callback) {
+        if (mResultLayout.getParent() == null || shouldCloseImmediately) {
+            // The shouldCloseImmediately boolean is true when the merchant calls
+            // instrumentResponse.complete("success") or instrumentResponse.complete("")
+            // in JavaScript.
             callback.run();
         } else {
             // Describe the error.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/ConfirmImportSyncDataDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/ConfirmImportSyncDataDialog.java
index 50c850c..24d2336a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/ConfirmImportSyncDataDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/ConfirmImportSyncDataDialog.java
@@ -106,6 +106,11 @@
 
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
+        // If the dialog is being recreated it won't have the listener set and so won't be
+        // functional. Therefore we dismiss, and the user will need to open the dialog again.
+        if (savedInstanceState != null) {
+            dismiss();
+        }
         String oldAccountName = getArguments().getString(KEY_OLD_ACCOUNT_NAME);
         String newAccountName = getArguments().getString(KEY_NEW_ACCOUNT_NAME);
         ImportSyncType importSyncType =
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 45de8fe..e966ebd 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2008,6 +2008,12 @@
       switches::kDisableFeatures);
 }
 
+void RegisterAllFeatureVariationParameters(
+    flags_ui::FlagsStorage* flags_storage) {
+  FlagsStateSingleton::GetFlagsState()->RegisterAllFeatureVariationParameters(
+      flags_storage);
+}
+
 bool AreSwitchesIdenticalToCurrentCommandLine(
     const base::CommandLine& new_cmdline,
     const base::CommandLine& active_cmdline,
diff --git a/chrome/browser/about_flags.h b/chrome/browser/about_flags.h
index c7d6a8e..91917421 100644
--- a/chrome/browser/about_flags.h
+++ b/chrome/browser/about_flags.h
@@ -34,6 +34,11 @@
                             base::CommandLine* command_line,
                             flags_ui::SentinelsMode sentinels);
 
+// Registers variations parameter values stored in |flags_storage| (previously
+// selected in about:flags).
+void RegisterAllFeatureVariationParameters(
+    flags_ui::FlagsStorage* flags_storage);
+
 // Compares a set of switches of the two provided command line objects and
 // returns true if they are the same and false otherwise.
 // If |out_difference| is not NULL, it's filled with set_symmetric_difference
diff --git a/chrome/browser/about_flags_unittest.cc b/chrome/browser/about_flags_unittest.cc
index 416c01f..3863e6c1 100644
--- a/chrome/browser/about_flags_unittest.cc
+++ b/chrome/browser/about_flags_unittest.cc
@@ -168,7 +168,8 @@
 }
 
 // Get all associated switches corresponding to defined about_flags.cc entries.
-// Does not include information about FEATURE_VALUE entries.
+// Does not include information about FEATURE_VALUE or
+// FEATURE_WITH_VARIATIOSN_VALUE entries.
 std::set<std::string> GetAllSwitchesForTesting() {
   std::set<std::string> result;
 
@@ -184,8 +185,8 @@
         result.insert(entry.command_line_switch);
         break;
       case flags_ui::FeatureEntry::MULTI_VALUE:
-        for (int j = 0; j < entry.num_choices; ++j) {
-          result.insert(entry.choices[j].command_line_switch);
+        for (int j = 0; j < entry.num_options; ++j) {
+          result.insert(entry.ChoiceForOption(j).command_line_switch);
         }
         break;
       case flags_ui::FeatureEntry::ENABLE_DISABLE_VALUE:
@@ -193,6 +194,7 @@
         result.insert(entry.disable_command_line_switch);
         break;
       case flags_ui::FeatureEntry::FEATURE_VALUE:
+      case flags_ui::FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
         break;
     }
   }
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 3d200cec..c64ee2e1 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -720,6 +720,11 @@
     metrics->AddSyntheticTrialObserver(provider);
   }
 
+  // Associate parameters chosen in about:flags and create trial/group for them.
+  flags_ui::PrefServiceFlagsStorage flags_storage(
+      g_browser_process->local_state());
+  about_flags::RegisterAllFeatureVariationParameters(&flags_storage);
+
   std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
   feature_list->InitializeFromCommandLine(
       command_line->GetSwitchValueASCII(switches::kEnableFeatures),
@@ -972,9 +977,9 @@
   {
     TRACE_EVENT0("startup",
         "ChromeBrowserMainParts::PreCreateThreadsImpl:ConvertFlags");
-    flags_ui::PrefServiceFlagsStorage flags_storage_(
+    flags_ui::PrefServiceFlagsStorage flags_storage(
         g_browser_process->local_state());
-    about_flags::ConvertFlagsToSwitches(&flags_storage_,
+    about_flags::ConvertFlagsToSwitches(&flags_storage,
                                         base::CommandLine::ForCurrentProcess(),
                                         flags_ui::kAddSentinels);
   }
diff --git a/chrome/browser/chrome_webusb_browser_client.cc b/chrome/browser/chrome_webusb_browser_client.cc
index b966ace..187cd71 100644
--- a/chrome/browser/chrome_webusb_browser_client.cc
+++ b/chrome/browser/chrome_webusb_browser_client.cc
@@ -6,7 +6,7 @@
 
 #include <utility>
 
-#include "ash/system/system_notifier.h"
+#include "ash/common/system/system_notifier.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/chromeos/arc/OWNERS b/chrome/browser/chromeos/arc/OWNERS
index 2797e0d..d7d81e7 100644
--- a/chrome/browser/chromeos/arc/OWNERS
+++ b/chrome/browser/chromeos/arc/OWNERS
@@ -1,3 +1,4 @@
-yusukes@chromium.org
+elijahtaylor@chromium.org
 hidehiko@chromium.org
 lhchavez@chromium.org
+yusukes@chromium.org
diff --git a/chrome/browser/chromeos/arc/arc_auth_notification.cc b/chrome/browser/chromeos/arc/arc_auth_notification.cc
index 98e7135..1617cf4 100644
--- a/chrome/browser/chromeos/arc/arc_auth_notification.cc
+++ b/chrome/browser/chromeos/arc/arc_auth_notification.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/chromeos/arc/arc_auth_notification.h"
 
-#include "ash/system/chromeos/devicetype_utils.h"
+#include "ash/common/system/chromeos/devicetype_utils.h"
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/arc/arc_auth_service.h"
diff --git a/chrome/browser/chromeos/arc/arc_navigation_throttle.cc b/chrome/browser/chromeos/arc/arc_navigation_throttle.cc
new file mode 100644
index 0000000..1ed4915
--- /dev/null
+++ b/chrome/browser/chromeos/arc/arc_navigation_throttle.cc
@@ -0,0 +1,192 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/arc/arc_navigation_throttle.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "components/arc/arc_bridge_service.h"
+#include "components/arc/arc_service_manager.h"
+#include "components/arc/intent_helper/arc_intent_helper_bridge.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_handle.h"
+
+namespace arc {
+
+namespace {
+
+constexpr int kMinInstanceVersion = 7;
+
+scoped_refptr<ActivityIconLoader> GetIconLoader() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  ArcServiceManager* arc_service_manager = ArcServiceManager::Get();
+  if (!arc_service_manager)
+    return nullptr;
+  return arc_service_manager->icon_loader();
+}
+
+mojom::IntentHelperInstance* GetIntentHelper() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  ArcBridgeService* bridge_service = ArcBridgeService::Get();
+  if (!bridge_service) {
+    VLOG(1) << "ARC bridge is not ready.";
+    return nullptr;
+  }
+  mojom::IntentHelperInstance* intent_helper_instance =
+      bridge_service->intent_helper_instance();
+  if (!intent_helper_instance) {
+    VLOG(1) << "ARC intent helper instance is not ready.";
+    return nullptr;
+  }
+  if (bridge_service->intent_helper_version() < kMinInstanceVersion) {
+    VLOG(1) << "ARC intent helper instance is too old.";
+    return nullptr;
+  }
+  return intent_helper_instance;
+}
+
+}  // namespace
+
+ArcNavigationThrottle::ArcNavigationThrottle(
+    content::NavigationHandle* navigation_handle,
+    const ShowDisambigDialogCallback& show_disambig_dialog_cb)
+    : content::NavigationThrottle(navigation_handle),
+      show_disambig_dialog_callback_(show_disambig_dialog_cb),
+      weak_ptr_factory_(this) {}
+
+ArcNavigationThrottle::~ArcNavigationThrottle() = default;
+
+content::NavigationThrottle::ThrottleCheckResult
+ArcNavigationThrottle::WillStartRequest() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (!navigation_handle()->HasUserGesture())
+    return content::NavigationThrottle::PROCEED;
+
+  const GURL& url = navigation_handle()->GetURL();
+  mojom::IntentHelperInstance* bridge_instance = GetIntentHelper();
+  if (!bridge_instance)
+    return content::NavigationThrottle::PROCEED;
+  bridge_instance->RequestUrlHandlerList(
+      url.spec(), base::Bind(&ArcNavigationThrottle::OnAppCandidatesReceived,
+                             weak_ptr_factory_.GetWeakPtr()));
+  return content::NavigationThrottle::DEFER;
+}
+
+content::NavigationThrottle::ThrottleCheckResult
+ArcNavigationThrottle::WillRedirectRequest() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  return content::NavigationThrottle::PROCEED;
+}
+
+// We received the array of app candidates to handle this URL (even the Chrome
+// app is included).
+void ArcNavigationThrottle::OnAppCandidatesReceived(
+    mojo::Array<mojom::UrlHandlerInfoPtr> handlers) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if ((handlers.size() == 1 && ArcIntentHelperBridge::IsIntentHelperPackage(
+                                   handlers[0]->package_name)) ||
+      handlers.size() == 0) {
+    // This scenario shouldn't be accesed as ArcNavigationThrottle is created
+    // iff there are ARC apps which can actually handle the given URL.
+    DVLOG(1) << "There are no app candidates for this URL: "
+             << navigation_handle()->GetURL().spec();
+    navigation_handle()->Resume();
+    return;
+  }
+
+  // If one of the apps is marked as preferred, use it right away without
+  // showing the UI.
+  for (size_t i = 0; i < handlers.size(); ++i) {
+    if (!handlers[i]->is_preferred)
+      continue;
+    if (ArcIntentHelperBridge::IsIntentHelperPackage(
+            handlers[i]->package_name)) {
+      // If Chrome browser was selected as the preferred app, we should't
+      // create a throttle.
+      DVLOG(1)
+          << "Chrome browser is selected as the preferred app for this URL: "
+          << navigation_handle()->GetURL().spec();
+    }
+    OnDisambigDialogClosed(std::move(handlers), i, false);
+    return;
+  }
+
+  scoped_refptr<ActivityIconLoader> icon_loader = GetIconLoader();
+  if (!icon_loader) {
+    LOG(ERROR) << "Cannot get an instance of ActivityIconLoader";
+    navigation_handle()->Resume();
+    return;
+  }
+  std::vector<ActivityIconLoader::ActivityName> activities;
+  for (const auto& handler : handlers) {
+    activities.emplace_back(handler->package_name, handler->activity_name);
+  }
+  icon_loader->GetActivityIcons(
+      activities,
+      base::Bind(&ArcNavigationThrottle::OnAppIconsReceived,
+                 weak_ptr_factory_.GetWeakPtr(), base::Passed(&handlers)));
+}
+
+void ArcNavigationThrottle::OnAppIconsReceived(
+    mojo::Array<mojom::UrlHandlerInfoPtr> handlers,
+    std::unique_ptr<ActivityIconLoader::ActivityToIconsMap> icons) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  std::vector<NameAndIcon> app_info;
+
+  for (const auto& handler : handlers) {
+    gfx::Image icon;
+    const ActivityIconLoader::ActivityName activity(handler->package_name,
+                                                    handler->activity_name);
+    const auto it = icons->find(activity);
+
+    if (it != icons->end()) {
+      app_info.emplace_back(handler->name, it->second.icon20);
+    } else {
+      app_info.emplace_back(handler->name, gfx::Image());
+    }
+  }
+
+  show_disambig_dialog_callback_.Run(
+      navigation_handle(), app_info,
+      base::Bind(&ArcNavigationThrottle::OnDisambigDialogClosed,
+                 weak_ptr_factory_.GetWeakPtr(), base::Passed(&handlers)));
+}
+
+void ArcNavigationThrottle::OnDisambigDialogClosed(
+    mojo::Array<mojom::UrlHandlerInfoPtr> handlers,
+    size_t selected_app_index,
+    bool always) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  const GURL& url = navigation_handle()->GetURL();
+  content::NavigationHandle* handle = navigation_handle();
+
+  // TODO(djacobo): Record UMA
+  // If the user fails to select an option from the list then resume the
+  // navigation in Chrome. Otherwise check if the selected app was selected as
+  // "ALWAYS" so we can record this decision.
+  if (selected_app_index >= handlers.size()) {
+    DVLOG(1) << "User didn't select a valid option, resuming navigation.";
+    handle->Resume();
+    return;
+  }
+  mojom::IntentHelperInstance* bridge = GetIntentHelper();
+  if (!bridge) {
+    handle->Resume();
+    return;
+  }
+  if (always) {
+    bridge->AddPreferredPackage(handlers[selected_app_index]->package_name);
+  }
+  if (ArcIntentHelperBridge::IsIntentHelperPackage(
+          handlers[selected_app_index]->package_name)) {
+    handle->Resume();
+    return;
+  }
+  bridge->HandleUrl(url.spec(), handlers[selected_app_index]->package_name);
+  handle->CancelDeferredNavigation(
+      content::NavigationThrottle::CANCEL_AND_IGNORE);
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/arc/arc_navigation_throttle.h b/chrome/browser/chromeos/arc/arc_navigation_throttle.h
new file mode 100644
index 0000000..b2ab0cb
--- /dev/null
+++ b/chrome/browser/chromeos/arc/arc_navigation_throttle.h
@@ -0,0 +1,64 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_ARC_ARC_NAVIGATION_THROTTLE_H_
+#define CHROME_BROWSER_CHROMEOS_ARC_ARC_NAVIGATION_THROTTLE_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/arc/intent_helper/activity_icon_loader.h"
+#include "content/public/browser/navigation_throttle.h"
+#include "ui/gfx/image/image.h"
+
+namespace content {
+class NavigationHandle;
+}  // namespace content
+
+namespace arc {
+
+// A class that allow us to retrieve ARC app's information and handle URL
+// traffic initiated on Chrome browser, either on Chrome or an ARC's app.
+class ArcNavigationThrottle : public content::NavigationThrottle {
+ public:
+  using NameAndIcon = std::pair<std::string, gfx::Image>;
+  using ShowDisambigDialogCallback =
+      base::Callback<void(content::NavigationHandle* handle,
+                          const std::vector<NameAndIcon>& app_info,
+                          const base::Callback<void(size_t, bool)>& cb)>;
+  ArcNavigationThrottle(
+      content::NavigationHandle* navigation_handle,
+      const ShowDisambigDialogCallback& show_disambig_dialog_cb);
+  ~ArcNavigationThrottle() override;
+
+ private:
+  // content::Navigation implementation:
+  NavigationThrottle::ThrottleCheckResult WillStartRequest() override;
+  NavigationThrottle::ThrottleCheckResult WillRedirectRequest() override;
+
+  void OnAppCandidatesReceived(mojo::Array<mojom::UrlHandlerInfoPtr> handlers);
+  void OnAppIconsReceived(
+      mojo::Array<mojom::UrlHandlerInfoPtr> handlers,
+      std::unique_ptr<ActivityIconLoader::ActivityToIconsMap> icons);
+  void OnDisambigDialogClosed(mojo::Array<mojom::UrlHandlerInfoPtr> handlers,
+                              size_t selected_app_index,
+                              bool always);
+
+  // A callback object that allow us to display an IntentPicker when Run() is
+  // executed, it also allow us to report the user's selection back to
+  // OnDisambigDialogClosed().
+  ShowDisambigDialogCallback show_disambig_dialog_callback_;
+
+  base::WeakPtrFactory<ArcNavigationThrottle> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcNavigationThrottle);
+};
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_CHROMEOS_ARC_ARC_NAVIGATION_THROTTLE_H_
diff --git a/chrome/browser/chromeos/arc/arc_support_host.cc b/chrome/browser/chromeos/arc/arc_support_host.cc
index 68c02fe..25c8cc01 100644
--- a/chrome/browser/chromeos/arc/arc_support_host.cc
+++ b/chrome/browser/chromeos/arc/arc_support_host.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
 
-#include "ash/system/chromeos/devicetype_utils.h"
+#include "ash/common/system/chromeos/devicetype_utils.h"
 #include "base/i18n/timezone.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
diff --git a/chrome/browser/chromeos/hats/hats_notification_controller.cc b/chrome/browser/chromeos/hats/hats_notification_controller.cc
index edf6000e2..fc2dc29 100644
--- a/chrome/browser/chromeos/hats/hats_notification_controller.cc
+++ b/chrome/browser/chromeos/hats/hats_notification_controller.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/chromeos/hats/hats_notification_controller.h"
 
-#include "ash/system/system_notifier.h"
+#include "ash/common/system/system_notifier.h"
 #include "base/feature_list.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/chromeos/net/network_portal_notification_controller.cc b/chrome/browser/chromeos/net/network_portal_notification_controller.cc
index 0080161..f90253f4 100644
--- a/chrome/browser/chromeos/net/network_portal_notification_controller.cc
+++ b/chrome/browser/chromeos/net/network_portal_notification_controller.cc
@@ -9,8 +9,8 @@
 #include <memory>
 #include <vector>
 
+#include "ash/common/system/system_notifier.h"
 #include "ash/shell.h"
-#include "ash/system/system_notifier.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
diff --git a/chrome/browser/chromeos/status/data_promo_notification.cc b/chrome/browser/chromeos/status/data_promo_notification.cc
index 8b177bc..c50a0ed 100644
--- a/chrome/browser/chromeos/status/data_promo_notification.cc
+++ b/chrome/browser/chromeos/status/data_promo_notification.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/chromeos/status/data_promo_notification.h"
 
-#include "ash/system/system_notifier.h"
+#include "ash/common/system/system_notifier.h"
 #include "base/command_line.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
index 37a0da2..f00088f 100644
--- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
+++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
@@ -53,7 +53,7 @@
 #include "ui/gfx/range/range.h"
 
 #if defined(OS_CHROMEOS)
-#include "ash/system/chromeos/devicetype_utils.h"
+#include "ash/common/system/chromeos/devicetype_utils.h"
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.h"
 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.h"
 #include "components/user_manager/user.h"
diff --git a/chrome/browser/extensions/api/hotword_private/hotword_private_api.cc b/chrome/browser/extensions/api/hotword_private/hotword_private_api.cc
index ac98050..6b87899 100644
--- a/chrome/browser/extensions/api/hotword_private/hotword_private_api.cc
+++ b/chrome/browser/extensions/api/hotword_private/hotword_private_api.cc
@@ -30,7 +30,7 @@
 #include "ui/base/webui/web_ui_util.h"
 
 #if defined(OS_CHROMEOS)
-#include "ash/system/chromeos/devicetype_utils.h"
+#include "ash/common/system/chromeos/devicetype_utils.h"
 #endif
 
 namespace extensions {
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index 5fbc12ec6..2a6c428 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -47,7 +47,7 @@
 #include "ui/base/resource/resource_bundle.h"
 
 #if defined(OS_CHROMEOS)
-#include "ash/system/chromeos/devicetype_utils.h"
+#include "ash/common/system/chromeos/devicetype_utils.h"
 #include "components/chrome_apps/grit/chrome_apps_resources.h"
 #include "components/user_manager/user_manager.h"
 #include "grit/keyboard_resources.h"
diff --git a/chrome/browser/extensions/extension_fullscreen_apitest.cc b/chrome/browser/extensions/extension_fullscreen_apitest.cc
index 84de0a4f..57b2d428 100644
--- a/chrome/browser/extensions/extension_fullscreen_apitest.cc
+++ b/chrome/browser/extensions/extension_fullscreen_apitest.cc
@@ -30,8 +30,7 @@
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest,
                        FocusWindowDoesNotExitFullscreen) {
   browser()->exclusive_access_manager()->context()->EnterFullscreen(
-      GURL(), EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION,
-      false);
+      GURL(), EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION);
   ASSERT_TRUE(browser()->window()->IsFullscreen());
   ASSERT_TRUE(RunExtensionTest("window_update/focus")) << message_;
   ASSERT_TRUE(browser()->window()->IsFullscreen());
@@ -47,8 +46,7 @@
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest,
                        MAYBE_UpdateWindowSizeExitsFullscreen) {
   browser()->exclusive_access_manager()->context()->EnterFullscreen(
-      GURL(), EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION,
-      false);
+      GURL(), EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION);
   ASSERT_TRUE(RunExtensionTest("window_update/sizing")) << message_;
   ASSERT_FALSE(browser()->window()->IsFullscreen());
 }
diff --git a/chrome/browser/google/google_update_win.cc b/chrome/browser/google/google_update_win.cc
index 238ce58b..02706b0 100644
--- a/chrome/browser/google/google_update_win.cc
+++ b/chrome/browser/google/google_update_win.cc
@@ -234,7 +234,9 @@
   void BeginUpdateCheck();
 
   // Returns the result of initiating an update check. Sets |error_code| if the
-  // result is any kind of failure.
+  // result is any kind of failure. On failure, the instance is left in a
+  // consistent state so that this method can be invoked later to retry the
+  // steps that failed.
   HRESULT BeginUpdateCheckInternal(GoogleUpdateErrorCode* error_code);
 
   // Sets status_ to UPGRADE_ERROR, error_code_ to |error_code|, hresult_ to
@@ -448,85 +450,125 @@
     task_runner_->PostTask(FROM_HERE,
                            base::Bind(&UpdateCheckDriver::PollGoogleUpdate,
                                       base::Unretained(this)));
-  } else {
-    // Return results immediately since the driver is not polling Google Update.
-    OnUpgradeError(error_code, hresult, -1, base::string16());
-    result_runner_->DeleteSoon(FROM_HERE, this);
+    return;
   }
+  if (hresult == GOOPDATE_E_APP_USING_EXTERNAL_UPDATER) {
+    // This particular transient error is worth retrying.
+    if (allowed_retries_) {
+      --allowed_retries_;
+      task_runner_->PostDelayedTask(
+          FROM_HERE, base::Bind(&UpdateCheckDriver::BeginUpdateCheck,
+                                base::Unretained(this)),
+          base::TimeDelta::FromSeconds(kGoogleRetryIntervalSeconds));
+      return;
+    }
+  }
+
+  DCHECK(FAILED(hresult));
+  // Return results immediately since the driver is not polling Google Update.
+  OnUpgradeError(error_code, hresult, -1, base::string16());
+  result_runner_->DeleteSoon(FROM_HERE, this);
 }
 
 HRESULT UpdateCheckDriver::BeginUpdateCheckInternal(
     GoogleUpdateErrorCode* error_code) {
-  base::FilePath chrome_exe;
-  if (!PathService::Get(base::DIR_EXE, &chrome_exe))
-    NOTREACHED();
+  HRESULT hresult = S_OK;
+  // Instantiate GoogleUpdate3Web{Machine,User}Class.
+  if (!google_update_) {
+    base::FilePath chrome_exe;
+    if (!PathService::Get(base::DIR_EXE, &chrome_exe))
+      NOTREACHED();
 
-  system_level_install_ = !InstallUtil::IsPerUserInstall(chrome_exe);
+    system_level_install_ = !InstallUtil::IsPerUserInstall(chrome_exe);
 
-  // Make sure ATL is initialized in this module.
-  ui::win::CreateATLModuleIfNeeded();
+    // Make sure ATL is initialized in this module.
+    ui::win::CreateATLModuleIfNeeded();
 
-  *error_code = CanUpdateCurrentChrome(chrome_exe, system_level_install_);
-  if (*error_code != GOOGLE_UPDATE_NO_ERROR)
-    return E_FAIL;
+    *error_code = CanUpdateCurrentChrome(chrome_exe, system_level_install_);
+    if (*error_code != GOOGLE_UPDATE_NO_ERROR)
+      return E_FAIL;
 
-  HRESULT hresult = CreateGoogleUpdate3WebClass(
-      system_level_install_, install_update_if_possible_, elevation_window_,
-      &google_update_);
-  if (FAILED(hresult)) {
-    *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND;
-    return hresult;
+    hresult = CreateGoogleUpdate3WebClass(system_level_install_,
+                                          install_update_if_possible_,
+                                          elevation_window_, &google_update_);
+    if (FAILED(hresult)) {
+      *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND;
+      return hresult;
+    }
+
+    ConfigureProxyBlanket(google_update_.get());
   }
 
-  ConfigureProxyBlanket(google_update_.get());
-
   // The class was created, so all subsequent errors are reported as:
   *error_code = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
-  base::string16 app_guid =
-      installer::GetAppGuidForUpdates(system_level_install_);
-  DCHECK(!app_guid.empty());
 
-  {
+  // Create an app bundle.
+  if (!app_bundle_) {
+    base::win::ScopedComPtr<IAppBundleWeb> app_bundle;
     base::win::ScopedComPtr<IDispatch> dispatch;
     hresult = google_update_->createAppBundleWeb(dispatch.Receive());
     if (FAILED(hresult))
       return hresult;
-    hresult = dispatch.QueryInterface(app_bundle_.Receive());
+    hresult = dispatch.QueryInterface(app_bundle.Receive());
     if (FAILED(hresult))
       return hresult;
-  }
-  ConfigureProxyBlanket(app_bundle_.get());
+    dispatch.Release();
 
-  if (!locale_.empty()) {
-    // Ignore the result of this since, while setting the display language is
-    // nice to have, a failure to do so does not affect the likelihood that the
-    // update check and/or install will succeed.
-    app_bundle_->put_displayLanguage(
-        base::win::ScopedBstr(base::UTF8ToUTF16(locale_).c_str()));
+    ConfigureProxyBlanket(app_bundle.get());
+
+    if (!locale_.empty()) {
+      // Ignore the result of this since, while setting the display language is
+      // nice to have, a failure to do so does not affect the likelihood that
+      // the update check and/or install will succeed.
+      app_bundle->put_displayLanguage(
+          base::win::ScopedBstr(base::UTF8ToUTF16(locale_).c_str()));
+    }
+
+    hresult = app_bundle->initialize();
+    if (FAILED(hresult))
+      return hresult;
+    if (elevation_window_) {
+      // Likewise, a failure to set the parent window need not block an update
+      // check.
+      app_bundle->put_parentHWND(
+          reinterpret_cast<ULONG_PTR>(elevation_window_));
+    }
+    app_bundle_.swap(app_bundle);
   }
 
-  hresult = app_bundle_->initialize();
-  if (FAILED(hresult))
-    return hresult;
-  if (elevation_window_) {
-    // Likewise, a failure to set the parent window need not block an update
-    // check.
-    app_bundle_->put_parentHWND(reinterpret_cast<ULONG_PTR>(elevation_window_));
+  // Get a reference to the Chrome app in the bundle.
+  if (!app_) {
+    base::string16 app_guid =
+        installer::GetAppGuidForUpdates(system_level_install_);
+    DCHECK(!app_guid.empty());
+
+    base::win::ScopedComPtr<IDispatch> dispatch;
+    // It is common for this call to fail with APP_USING_EXTERNAL_UPDATER if
+    // an auto update is in progress.
+    hresult = app_bundle_->createInstalledApp(
+        base::win::ScopedBstr(app_guid.c_str()));
+    if (FAILED(hresult))
+      return hresult;
+    // Move the IAppBundleWeb reference into a local now so that failures from
+    // this point onward result in it being released.
+    base::win::ScopedComPtr<IAppBundleWeb> app_bundle;
+    app_bundle.swap(app_bundle_);
+    hresult = app_bundle->get_appWeb(0, dispatch.Receive());
+    if (FAILED(hresult))
+      return hresult;
+    base::win::ScopedComPtr<IAppWeb> app;
+    hresult = dispatch.QueryInterface(app.Receive());
+    if (FAILED(hresult))
+      return hresult;
+    ConfigureProxyBlanket(app.get());
+    hresult = app_bundle->checkForUpdate();
+    if (FAILED(hresult))
+      return hresult;
+    app_bundle_.swap(app_bundle);
+    app_.swap(app);
   }
 
-  base::win::ScopedComPtr<IDispatch> dispatch;
-  hresult =
-      app_bundle_->createInstalledApp(base::win::ScopedBstr(app_guid.c_str()));
-  if (FAILED(hresult))
-    return hresult;
-  hresult = app_bundle_->get_appWeb(0, dispatch.Receive());
-  if (FAILED(hresult))
-    return hresult;
-  hresult = dispatch.QueryInterface(app_.Receive());
-  if (FAILED(hresult))
-    return hresult;
-  ConfigureProxyBlanket(app_.get());
-  return app_bundle_->checkForUpdate();
+  return hresult;
 }
 
 bool UpdateCheckDriver::GetCurrentState(
@@ -722,19 +764,6 @@
                    base::string16());
   } else if (IsErrorState(state, state_value, &error_code, &hresult,
                           &installer_exit_code, &error_string)) {
-    // Some errors can be transient.  Retry them after a short delay.
-    if (hresult == GOOPDATE_E_APP_USING_EXTERNAL_UPDATER) {
-      if (allowed_retries_ > 0) {
-        --allowed_retries_;
-        app_bundle_.Release();
-        google_update_.Release();
-        task_runner_->PostDelayedTask(
-            FROM_HERE, base::Bind(&UpdateCheckDriver::BeginUpdateCheck,
-                                  base::Unretained(this)),
-            base::TimeDelta::FromSeconds(kGoogleRetryIntervalSeconds));
-        return;
-      }
-    }
     OnUpgradeError(error_code, hresult, installer_exit_code, error_string);
   } else if (IsFinalState(state, state_value, &upgrade_status, &new_version)) {
     status_ = upgrade_status;
diff --git a/chrome/browser/google/google_update_win_unittest.cc b/chrome/browser/google/google_update_win_unittest.cc
index 5bbe4b7..325a634f0 100644
--- a/chrome/browser/google/google_update_win_unittest.cc
+++ b/chrome/browser/google/google_update_win_unittest.cc
@@ -914,40 +914,36 @@
 TEST_P(GoogleUpdateWinTest, RetryAfterExternalUpdaterError) {
   static const HRESULT GOOPDATE_E_APP_USING_EXTERNAL_UPDATER = 0xa043081d;
 
-  CComObject<MockAppBundle>* mock_app_bundle1 =
+  CComObject<MockAppBundle>* mock_app_bundle =
       mock_google_update_factory_.MakeServerMock()->MakeAppBundle();
 
   // The first attempt will fail in createInstalledApp indicating that an update
   // is already in progress.
-  EXPECT_CALL(*mock_app_bundle1, createInstalledApp(StrEq(kChromeBinariesGuid)))
+  Sequence bundle_seq;
+  EXPECT_CALL(*mock_app_bundle, createInstalledApp(StrEq(kChromeBinariesGuid)))
+      .InSequence(bundle_seq)
       .WillOnce(Return(GOOPDATE_E_APP_USING_EXTERNAL_UPDATER));
 
-  // Retry with a second instance.
-  CComObject<MockAppBundle>* mock_app_bundle2 = nullptr;
+  // Expect a retry on the same instance.
+  EXPECT_CALL(*mock_app_bundle, createInstalledApp(StrEq(kChromeBinariesGuid)))
+      .InSequence(bundle_seq)
+      .WillOnce(Return(S_OK));
+
+  // See MakeApp() for an explanation of this:
   CComObject<MockApp>* mock_app = nullptr;
-  MakeGoogleUpdateMocks(&mock_app_bundle2, &mock_app);
+  EXPECT_EQ(S_OK, CComObject<MockApp>::CreateInstance(&mock_app));
+  mock_app->AddRef();
+  EXPECT_CALL(*mock_app_bundle, get_appWeb(0, _))
+      .WillOnce(DoAll(SetArgPointee<1>(mock_app), Return(S_OK)));
 
   // Expect the bundle to be called on to start the update.
-  EXPECT_CALL(*mock_app_bundle2, checkForUpdate())
-      .WillOnce(Return(S_OK));
+  EXPECT_CALL(*mock_app_bundle, checkForUpdate()).WillOnce(Return(S_OK));
 
   mock_app->PushState(STATE_INIT);
   mock_app->PushState(STATE_CHECKING_FOR_UPDATE);
   mock_app->PushState(STATE_NO_UPDATE);
 
-  // Until http://crbug.com/504516 is fixed, we expect the first update check
-  // to fail.
-  EXPECT_CALL(mock_update_check_delegate_,
-              OnError(GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, _, _));
-
-  // Run the first update check. When http://crbug.com/504516 is fixed, this
-  // update check will be subsumed in the one below.
-  BeginUpdateCheck(task_runner_, std::string(), true, 0,
-                   mock_update_check_delegate_.AsWeakPtr());
-  task_runner_->RunUntilIdle();
-
-  // Expect a second update check to succeed. When http://crbug.com/504516 is
-  // fixed, this will be the one and only update check.
+  // Expect the update check to succeed.
   EXPECT_CALL(mock_update_check_delegate_,
               OnUpdateCheckComplete(IsEmpty()));  // new_version
   BeginUpdateCheck(task_runner_, std::string(), false, 0,
diff --git a/chrome/browser/media/DEPS b/chrome/browser/media/DEPS
index 30abf7d6..dcd73c70 100644
--- a/chrome/browser/media/DEPS
+++ b/chrome/browser/media/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+device/power_save_blocker",
   "+media/audio",
   "+media/base",
   "+media/cast",
diff --git a/chrome/browser/media/cast_transport_host_filter.cc b/chrome/browser/media/cast_transport_host_filter.cc
index 49d8fd1..87080587 100644
--- a/chrome/browser/media/cast_transport_host_filter.cc
+++ b/chrome/browser/media/cast_transport_host_filter.cc
@@ -9,7 +9,8 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/common/cast_messages.h"
 #include "components/net_log/chrome_net_log.h"
-#include "content/public/browser/power_save_blocker_factory.h"
+#include "content/public/browser/browser_thread.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 #include "media/cast/net/cast_transport.h"
 
 namespace {
@@ -148,10 +149,14 @@
   if (!power_save_blocker_) {
     DVLOG(1) << ("Preventing the application from being suspended while one or "
                  "more transports are active for Cast Streaming.");
-    power_save_blocker_ = content::CreatePowerSaveBlocker(
-        content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
-        content::PowerSaveBlocker::kReasonOther,
-        "Cast is streaming content to a remote receiver");
+    power_save_blocker_ = device::PowerSaveBlocker::CreateWithTaskRunners(
+        device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
+        device::PowerSaveBlocker::kReasonOther,
+        "Cast is streaming content to a remote receiver",
+        content::BrowserThread::GetMessageLoopProxyForThread(
+            content::BrowserThread::UI),
+        content::BrowserThread::GetMessageLoopProxyForThread(
+            content::BrowserThread::FILE));
   }
 
   if (id_map_.Lookup(channel_id)) {
diff --git a/chrome/browser/media/cast_transport_host_filter.h b/chrome/browser/media/cast_transport_host_filter.h
index ad9818e0..fefde8b 100644
--- a/chrome/browser/media/cast_transport_host_filter.h
+++ b/chrome/browser/media/cast_transport_host_filter.h
@@ -19,9 +19,9 @@
 #include "media/cast/net/cast_transport.h"
 #include "media/cast/net/udp_transport.h"
 
-namespace content {
+namespace device {
 class PowerSaveBlocker;
-}  // namespace content
+}  // namespace device
 
 namespace cast {
 
@@ -91,9 +91,9 @@
   base::DefaultTickClock clock_;
 
   // While |id_map_| is non-empty, hold an instance of
-  // content::PowerSaveBlocker.  This prevents Chrome from being suspended while
+  // device::PowerSaveBlocker.  This prevents Chrome from being suspended while
   // remoting content.
-  std::unique_ptr<content::PowerSaveBlocker> power_save_blocker_;
+  std::unique_ptr<device::PowerSaveBlocker> power_save_blocker_;
 
   base::WeakPtrFactory<CastTransportHostFilter> weak_factory_;
 
diff --git a/chrome/browser/notifications/fullscreen_notification_blocker.cc b/chrome/browser/notifications/fullscreen_notification_blocker.cc
index c9831fc..a0c0a7b 100644
--- a/chrome/browser/notifications/fullscreen_notification_blocker.cc
+++ b/chrome/browser/notifications/fullscreen_notification_blocker.cc
@@ -10,10 +10,10 @@
 #include "content/public/browser/notification_service.h"
 
 #if defined(USE_ASH)
+#include "ash/common/system/system_notifier.h"
 #include "ash/common/wm/window_state.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
-#include "ash/system/system_notifier.h"
 #include "ash/wm/window_state_aura.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher.h"
diff --git a/chrome/browser/notifications/login_state_notification_blocker_chromeos.cc b/chrome/browser/notifications/login_state_notification_blocker_chromeos.cc
index 6cd5fdb8..1caad4b 100644
--- a/chrome/browser/notifications/login_state_notification_blocker_chromeos.cc
+++ b/chrome/browser/notifications/login_state_notification_blocker_chromeos.cc
@@ -4,9 +4,9 @@
 
 #include "chrome/browser/notifications/login_state_notification_blocker_chromeos.h"
 
+#include "ash/common/system/system_notifier.h"
 #include "ash/common/wm_shell.h"
 #include "ash/root_window_controller.h"
-#include "ash/system/system_notifier.h"
 #include "ash/wm/window_properties.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/notifications/login_state_notification_blocker_chromeos_browsertest.cc b/chrome/browser/notifications/login_state_notification_blocker_chromeos_browsertest.cc
index 92cc81f..bd7b90d 100644
--- a/chrome/browser/notifications/login_state_notification_blocker_chromeos_browsertest.cc
+++ b/chrome/browser/notifications/login_state_notification_blocker_chromeos_browsertest.cc
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "ash/common/system/system_notifier.h"
 #include "ash/shell.h"
-#include "ash/system/system_notifier.h"
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
diff --git a/chrome/browser/notifications/login_state_notification_blocker_chromeos_unittest.cc b/chrome/browser/notifications/login_state_notification_blocker_chromeos_unittest.cc
index dd52c0c..b5d3a1f 100644
--- a/chrome/browser/notifications/login_state_notification_blocker_chromeos_unittest.cc
+++ b/chrome/browser/notifications/login_state_notification_blocker_chromeos_unittest.cc
@@ -6,8 +6,8 @@
 
 #include <memory>
 
+#include "ash/common/system/system_notifier.h"
 #include "ash/shell.h"
-#include "ash/system/system_notifier.h"
 #include "ash/test/ash_test_base.h"
 #include "base/command_line.h"
 #include "base/macros.h"
diff --git a/chrome/browser/notifications/message_center_settings_controller.cc b/chrome/browser/notifications/message_center_settings_controller.cc
index 1e0dc01..8de630e 100644
--- a/chrome/browser/notifications/message_center_settings_controller.cc
+++ b/chrome/browser/notifications/message_center_settings_controller.cc
@@ -47,7 +47,7 @@
 #include "ui/strings/grit/ui_strings.h"
 
 #if defined(OS_CHROMEOS)
-#include "ash/system/system_notifier.h"
+#include "ash/common/system/system_notifier.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/notifications/arc_notifier_manager.h"
 #include "components/arc/arc_bridge_service.h"
diff --git a/chrome/browser/notifications/message_center_settings_controller_unittest.cc b/chrome/browser/notifications/message_center_settings_controller_unittest.cc
index aed37ce..ea47722 100644
--- a/chrome/browser/notifications/message_center_settings_controller_unittest.cc
+++ b/chrome/browser/notifications/message_center_settings_controller_unittest.cc
@@ -26,7 +26,7 @@
 #include "ui/message_center/notifier_settings.h"
 
 #if defined(OS_CHROMEOS)
-#include "ash/system/system_notifier.h"
+#include "ash/common/system/system_notifier.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #endif
diff --git a/chrome/browser/ntp_snippets/ntp_snippets_service_factory.cc b/chrome/browser/ntp_snippets/ntp_snippets_service_factory.cc
index ad28739..0783595 100644
--- a/chrome/browser/ntp_snippets/ntp_snippets_service_factory.cc
+++ b/chrome/browser/ntp_snippets/ntp_snippets_service_factory.cc
@@ -10,6 +10,7 @@
 #include "base/memory/singleton.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search/suggestions/image_decoder_impl.h"
 #include "chrome/browser/search/suggestions/image_fetcher_impl.h"
 #include "chrome/browser/search/suggestions/suggestions_service_factory.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
@@ -18,6 +19,7 @@
 #include "chrome/common/channel_info.h"
 #include "chrome/common/pref_names.h"
 #include "components/browser_sync/browser/profile_sync_service.h"
+#include "components/image_fetcher/image_decoder.h"
 #include "components/image_fetcher/image_fetcher.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/ntp_snippets/ntp_snippets_constants.h"
@@ -41,6 +43,7 @@
 #endif  // OS_ANDROID
 
 using content::BrowserThread;
+using suggestions::ImageDecoderImpl;
 using suggestions::ImageFetcherImpl;
 using suggestions::SuggestionsService;
 using suggestions::SuggestionsServiceFactory;
@@ -115,6 +118,7 @@
           base::Bind(&safe_json::SafeJsonParser::Parse),
           chrome::GetChannel() == version_info::Channel::STABLE)),
       base::WrapUnique(new ImageFetcherImpl(request_context.get())),
+      base::WrapUnique(new ImageDecoderImpl()),
       base::WrapUnique(
           new ntp_snippets::NTPSnippetsDatabase(database_dir, task_runner)));
 }
diff --git a/chrome/browser/resources/chromeos/arc_support/background.js b/chrome/browser/resources/chromeos/arc_support/background.js
index 4b6e9ad..29ca078 100644
--- a/chrome/browser/resources/chromeos/arc_support/background.js
+++ b/chrome/browser/resources/chromeos/arc_support/background.js
@@ -127,7 +127,7 @@
   };
 
   var onLearnMore = function(event) {
-    var url = 'https://support.google.com/chrome/answer/96817';
+    var url = 'https://support.google.com/chromebook?p=playapps';
     chrome.browser.openTab({'url': url}, function() {});
     event.preventDefault();
   };
diff --git a/chrome/browser/search/suggestions/image_fetcher_impl.cc b/chrome/browser/search/suggestions/image_fetcher_impl.cc
index f2173a1..9d046f0a 100644
--- a/chrome/browser/search/suggestions/image_fetcher_impl.cc
+++ b/chrome/browser/search/suggestions/image_fetcher_impl.cc
@@ -63,8 +63,13 @@
 
 void ImageFetcherImpl::OnImageURLFetched(const GURL& image_url,
                                          const std::string& image_data) {
-  // TODO(markusheintz): Add a method OnImageDataFetched on the delegate and
-  // call that here.
+  // Inform the ImageFetcherDelegate.
+  if (delegate_) {
+    auto it = pending_net_requests_.find(image_url);
+    DCHECK(it != pending_net_requests_.end());
+    delegate_->OnImageDataFetched(it->second.id, image_data);
+  }
+
   image_decoder_->DecodeImage(
       image_data,
       base::Bind(&ImageFetcherImpl::OnImageDecoded,
diff --git a/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc b/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc
index ed7eee6..b632fab8 100644
--- a/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc
+++ b/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc
@@ -15,7 +15,7 @@
 #include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_CHROMEOS)
-#include "ash/system/chromeos/devicetype_utils.h"
+#include "ash/common/system/chromeos/devicetype_utils.h"
 #endif
 
 using proximity_auth::ScreenlockState;
diff --git a/chrome/browser/signin/signin_error_notifier_ash.cc b/chrome/browser/signin/signin_error_notifier_ash.cc
index 85e1b94..bb17d7f 100644
--- a/chrome/browser/signin/signin_error_notifier_ash.cc
+++ b/chrome/browser/signin/signin_error_notifier_ash.cc
@@ -4,9 +4,9 @@
 
 #include "chrome/browser/signin/signin_error_notifier_ash.h"
 
+#include "ash/common/system/system_notifier.h"
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
-#include "ash/system/system_notifier.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
diff --git a/chrome/browser/sync/sync_error_notifier_ash.cc b/chrome/browser/sync/sync_error_notifier_ash.cc
index 4e4f3e2..02ca4d3 100644
--- a/chrome/browser/sync/sync_error_notifier_ash.cc
+++ b/chrome/browser/sync/sync_error_notifier_ash.cc
@@ -4,9 +4,9 @@
 
 #include "chrome/browser/sync/sync_error_notifier_ash.h"
 
+#include "ash/common/system/system_notifier.h"
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
-#include "ash/system/system_notifier.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/ui/ash/chrome_screenshot_grabber.cc b/chrome/browser/ui/ash/chrome_screenshot_grabber.cc
index 861251a..a1078e6b 100644
--- a/chrome/browser/ui/ash/chrome_screenshot_grabber.cc
+++ b/chrome/browser/ui/ash/chrome_screenshot_grabber.cc
@@ -6,8 +6,8 @@
 
 #include <stddef.h>
 
+#include "ash/common/system/system_notifier.h"
 #include "ash/shell.h"
-#include "ash/system/system_notifier.h"
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/callback.h"
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc
index c89b3ebd..b36a5df2 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h"
 
-#include "ash/system/system_notifier.h"
+#include "ash/common/system/system_notifier.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
 #include "components/signin/core/account_id/account_id.h"
 #include "ui/message_center/message_center.h"
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
index 6eac3f3..2015efea9 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #include "ash/common/session/session_state_delegate.h"
+#include "ash/common/system/system_notifier.h"
 #include "ash/shell.h"
-#include "ash/system/system_notifier.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/test_session_state_delegate.h"
 #include "ash/test/test_shell_delegate.h"
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
index 8e5bfa4..32fed2c 100644
--- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
@@ -16,6 +16,7 @@
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/session/session_state_observer.h"
 #include "ash/common/shell_window_ids.h"
+#include "ash/common/system/chromeos/power/power_status.h"
 #include "ash/common/system/chromeos/shutdown_policy_observer.h"
 #include "ash/common/system/date/clock_observer.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
@@ -28,7 +29,6 @@
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
 #include "ash/system/chromeos/bluetooth/bluetooth_observer.h"
-#include "ash/system/chromeos/power/power_status.h"
 #include "ash/system/chromeos/session/logout_button_observer.h"
 #include "ash/system/ime/ime_observer.h"
 #include "ash/system/tray/system_tray.h"
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 66004f92..959963b2 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -2749,8 +2749,7 @@
   CheckDisplayModeMQ(ASCIIToUTF16("standalone"), app_contents);
 
   app_browser->exclusive_access_manager()->context()->EnterFullscreen(
-      GURL(), EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION,
-      false);
+      GURL(), EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION);
 
   // Sync navigation just to make sure IPC has passed (updated
   // display mode is delivered to RP).
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index 605d5457..d0d1d43a 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -415,11 +415,7 @@
       ConvertPopupToTabbedBrowser(browser_);
       break;
     case IDC_FULLSCREEN:
-#if defined(OS_MACOSX)
-      chrome::ToggleFullscreenWithToolbarOrFallback(browser_);
-#else
       chrome::ToggleFullscreenMode(browser_);
-#endif
       break;
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/browser_command_controller_unittest.cc b/chrome/browser/ui/browser_command_controller_unittest.cc
index 0a5532d..4e6c5d58 100644
--- a/chrome/browser/ui/browser_command_controller_unittest.cc
+++ b/chrome/browser/ui/browser_command_controller_unittest.cc
@@ -260,8 +260,7 @@
   bool ShouldHideUIForFullscreen() const override { return fullscreen_; }
   bool IsFullscreen() const override { return fullscreen_; }
   void EnterFullscreen(const GURL& url,
-                       ExclusiveAccessBubbleType type,
-                       bool with_toolbar) override {
+                       ExclusiveAccessBubbleType type) override {
     fullscreen_ = true;
   }
   void ExitFullscreen() override { fullscreen_ = false; }
diff --git a/chrome/browser/ui/browser_commands_mac.cc b/chrome/browser/ui/browser_commands_mac.cc
index d286aa9..9c160b5 100644
--- a/chrome/browser/ui/browser_commands_mac.cc
+++ b/chrome/browser/ui/browser_commands_mac.cc
@@ -14,16 +14,6 @@
 
 namespace chrome {
 
-void ToggleFullscreenWithToolbarOrFallback(Browser* browser) {
-  DCHECK(browser);
-  if (mac::SupportsSystemFullscreen())
-    browser->exclusive_access_manager()
-        ->fullscreen_controller()
-        ->ToggleBrowserFullscreenWithToolbar();
-  else
-    ToggleFullscreenMode(browser);
-}
-
 void ToggleFullscreenToolbar(Browser* browser) {
   DCHECK(browser);
 
diff --git a/chrome/browser/ui/browser_commands_mac.h b/chrome/browser/ui/browser_commands_mac.h
index 5fac3c62..7e66d7a3 100644
--- a/chrome/browser/ui/browser_commands_mac.h
+++ b/chrome/browser/ui/browser_commands_mac.h
@@ -9,10 +9,6 @@
 
 namespace chrome {
 
-// Enters Mac OSX 10.7 Lion Fullscreen mode, with browser chrome displayed.
-// On earlier OSX versions, falls back to presentation mode.
-void ToggleFullscreenWithToolbarOrFallback(Browser* browser);
-
 // Toggles the visibility of the toolbar in fullscreen mode.
 void ToggleFullscreenToolbar(Browser* browser);
 
diff --git a/chrome/browser/ui/cocoa/applescript/scripting.sdef b/chrome/browser/ui/cocoa/applescript/scripting.sdef
index 854330b..661890f 100644
--- a/chrome/browser/ui/cocoa/applescript/scripting.sdef
+++ b/chrome/browser/ui/cocoa/applescript/scripting.sdef
@@ -263,17 +263,6 @@
 			<property name="URL" code="URL " description="The URL of the bookmark." type="text"/>
 			<property name="index" code="indx" description="Returns the index with respect to its parent bookmark folder" type="number" access="r"/>
 		</class>
-		<class-extension extends="window">
-			<property name="presenting" code="pres" description="Whether the window is in presentation mode." type="boolean" access="r">
-				<cocoa key="presenting"/>
-			</property>
-			<responds-to command="enter presentation mode">
-				<cocoa method="handlesEnterPresentationMode:"/>
-			</responds-to>
-			<responds-to command="exit presentation mode">
-				<cocoa method="handlesExitPresentationMode:"/>
-			</responds-to>
-		</class-extension>
 		<command name="reload" code="CrSuRlod" description="Reload a tab.">
 			<direct-parameter description="The tab to execute the command in." type="specifier"/>
 		</command>
@@ -314,11 +303,5 @@
 			</parameter>
 			<result type="any"/>
 		</command>
-		<command name="enter presentation mode" code="CrSuEnPM" description="Enter presentation mode in window.">
-			<direct-parameter description="The window to enter presentation mode." type="specifier"/>
-		</command>
-		<command name="exit presentation mode" code="CrSuExPM" description="Exit presentation mode in window.">
-			<direct-parameter description="The window to exit presentation mode." type="specifier"/>
-		</command>
 	</suite>
 </dictionary>
\ No newline at end of file
diff --git a/chrome/browser/ui/cocoa/applescript/window_applescript.h b/chrome/browser/ui/cocoa/applescript/window_applescript.h
index 9cfa5617..d1c28de 100644
--- a/chrome/browser/ui/cocoa/applescript/window_applescript.h
+++ b/chrome/browser/ui/cocoa/applescript/window_applescript.h
@@ -76,15 +76,6 @@
 // The index of the window, windows are ordered front to back.
 - (NSNumber*)orderedIndex;
 
-// Used to see if the windows is in presentation mode.
-- (NSNumber*)presenting;
-
-// Used to enter presentation mode.
-- (void)handlesEnterPresentationMode:(NSScriptCommand*)command;
-
-// Used to exit presentation mode.
-- (void)handlesExitPresentationMode:(NSScriptCommand*)command;
-
 @end
 
 #endif  // CHROME_BROWSER_UI_COCOA_APPLESCRIPT_WINDOW_APPLESCRIPT_H_
diff --git a/chrome/browser/ui/cocoa/applescript/window_applescript.mm b/chrome/browser/ui/cocoa/applescript/window_applescript.mm
index 216c0e3..66fd7c55 100644
--- a/chrome/browser/ui/cocoa/applescript/window_applescript.mm
+++ b/chrome/browser/ui/cocoa/applescript/window_applescript.mm
@@ -259,26 +259,4 @@
     browser_->window()->Close();
 }
 
-- (NSNumber*)presenting {
-  BOOL presentingValue = browser_->window() &&
-                         browser_->window()->IsFullscreen() &&
-                         !browser_->window()
-                              ->GetExclusiveAccessContext()
-                              ->IsFullscreenWithToolbar();
-  return [NSNumber numberWithBool:presentingValue];
-}
-
-- (void)handlesEnterPresentationMode:(NSScriptCommand*)command {
-  AppleScript::LogAppleScriptUMA(
-      AppleScript::AppleScriptCommand::WINDOW_ENTER_PRESENTATION_MODE);
-  browser_->exclusive_access_manager()->context()->EnterFullscreen(
-      GURL(), EXCLUSIVE_ACCESS_BUBBLE_TYPE_FULLSCREEN_EXIT_INSTRUCTION, false);
-}
-
-- (void)handlesExitPresentationMode:(NSScriptCommand*)command {
-  AppleScript::LogAppleScriptUMA(
-      AppleScript::AppleScriptCommand::WINDOW_EXIT_PRESENTATION_MODE);
-  browser_->exclusive_access_manager()->context()->ExitFullscreen();
-}
-
 @end
diff --git a/chrome/browser/ui/cocoa/browser/exclusive_access_controller_views.h b/chrome/browser/ui/cocoa/browser/exclusive_access_controller_views.h
index 1ba1e7f..e82f167 100644
--- a/chrome/browser/ui/cocoa/browser/exclusive_access_controller_views.h
+++ b/chrome/browser/ui/cocoa/browser/exclusive_access_controller_views.h
@@ -62,8 +62,7 @@
   void UpdateFullscreenToolbar() override;
   bool IsFullscreenWithToolbar() const override;
   void EnterFullscreen(const GURL& url,
-                       ExclusiveAccessBubbleType type,
-                       bool with_toolbar) override;
+                       ExclusiveAccessBubbleType type) override;
   void ExitFullscreen() override;
   void UpdateExclusiveAccessExitBubbleContent(
       const GURL& url,
diff --git a/chrome/browser/ui/cocoa/browser/exclusive_access_controller_views.mm b/chrome/browser/ui/cocoa/browser/exclusive_access_controller_views.mm
index de52365..7fd122ad 100644
--- a/chrome/browser/ui/cocoa/browser/exclusive_access_controller_views.mm
+++ b/chrome/browser/ui/cocoa/browser/exclusive_access_controller_views.mm
@@ -109,7 +109,7 @@
 }
 
 bool ExclusiveAccessController::IsFullscreenWithToolbar() const {
-  return IsFullscreen() && ![controller_ inPresentationMode];
+  return IsFullscreen();
 }
 
 // See the Fullscreen terminology section and the (Fullscreen) interface
@@ -117,18 +117,15 @@
 // logic in this method.
 void ExclusiveAccessController::EnterFullscreen(
     const GURL& url,
-    ExclusiveAccessBubbleType bubble_type,
-    bool with_toolbar) {
+    ExclusiveAccessBubbleType bubble_type) {
   url_ = url;
   bubble_type_ = bubble_type;
   if (browser_->exclusive_access_manager()
           ->fullscreen_controller()
           ->IsWindowFullscreenForTabOrPending())
     [controller_ enterWebContentFullscreen];
-  else if (!url.is_empty())
-    [controller_ enterExtensionFullscreen];
   else
-    [controller_ enterBrowserFullscreenWithToolbar:with_toolbar];
+    [controller_ enterBrowserFullscreen];
 }
 
 void ExclusiveAccessController::ExitFullscreen() {
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
index 365df2e0..1fc240f 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -23,7 +23,7 @@
 #include "chrome/browser/translate/chrome_translate_client.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_command_controller.h"
-#include "chrome/browser/ui/browser_commands_mac.h"
+#include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window_state.h"
 #import "chrome/browser/ui/cocoa/autofill/save_card_bubble_view_bridge.h"
@@ -186,7 +186,7 @@
     [window() orderOut:controller_];
     [window() miniaturize:controller_];
   } else if (initial_show_state_ == ui::SHOW_STATE_FULLSCREEN) {
-    chrome::ToggleFullscreenWithToolbarOrFallback(browser_);
+    chrome::ToggleFullscreenMode(browser_);
   }
   initial_show_state_ = ui::SHOW_STATE_DEFAULT;
 
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h
index 3e7ab18..2a6f092 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.h
+++ b/chrome/browser/ui/cocoa/browser_window_controller.h
@@ -149,11 +149,6 @@
   // AppKit fullscreen mode.
   BOOL enteringImmersiveFullscreen_;
 
-  // True between |-setPresentationMode:url:bubbleType:| and
-  // |-windowDidEnterFullScreen:| to indicate that the window is in the process
-  // of transitioning into fullscreen presentation mode.
-  BOOL enteringPresentationMode_;
-
   // When the window is in the process of entering AppKit Fullscreen, this
   // property indicates whether the window is being fullscreened on the
   // primary screen.
@@ -441,6 +436,10 @@
 // Returns the size of the original (non-fullscreen) window.
 - (NSRect)savedRegularWindowFrame;
 
+// Returns true if the browser is in the process of entering/exiting
+// fullscreen.
+- (BOOL)isFullscreenTransitionInProgress;
+
 @end  // @interface BrowserWindowController(WindowType)
 
 // Fullscreen terminology:
@@ -534,10 +533,8 @@
 // or exit Lion fullscreen mode.  Must not be called on Snow Leopard or earlier.
 - (void)handleLionToggleFullscreen;
 
-// Enters Browser/Appkit Fullscreen.
-// If |withToolbar| is NO, the tab strip and toolbar are hidden
-// (aka Presentation Mode).
-- (void)enterBrowserFullscreenWithToolbar:(BOOL)withToolbar;
+// Enters Browser AppKit Fullscreen.
+- (void)enterBrowserFullscreen;
 
 // Adds or removes the tab strip and toolbar from the current window. The
 // window must be in immersive or AppKit Fullscreen.
@@ -565,22 +562,12 @@
 // the AppKit Fullscreen API.
 - (BOOL)isInAppKitFullscreen;
 
-// Enter fullscreen for an extension.
-- (void)enterExtensionFullscreen;
-
 // Enters Immersive Fullscreen for the given URL.
 - (void)enterWebContentFullscreen;
 
 // Exits the current fullscreen mode.
 - (void)exitAnyFullscreen;
 
-// Whether the system is in the very specific fullscreen mode: Presentation
-// Mode.
-- (BOOL)inPresentationMode;
-
-// Whether the toolbar should be shown in fullscreen.
-- (BOOL)shouldShowFullscreenToolbar;
-
 // Called by BrowserWindowFullscreenTransition when the exit animation is
 // finished.
 - (void)exitFullscreenAnimationFinished;
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index 065825b..4a9c4e7 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -1851,21 +1851,8 @@
   chrome::ExecuteCommand(browser_.get(), IDC_FULLSCREEN);
 }
 
-- (void)enterBrowserFullscreenWithToolbar:(BOOL)withToolbar {
-  if (!chrome::mac::SupportsSystemFullscreen()) {
-    if (![self isInImmersiveFullscreen])
-      [self enterImmersiveFullscreen];
-    return;
-  }
-
-  if ([self isInAppKitFullscreen]) {
-    [self updateFullscreenWithToolbar:withToolbar];
-  } else {
-    // Need to invoke AppKit Fullscreen API. Presentation mode (if set) will
-    // automatically be enabled in |-windowWillEnterFullScreen:|.
-    enteringPresentationMode_ = !withToolbar;
-    [self enterAppKitFullscreen];
-  }
+- (void)enterBrowserFullscreen {
+  [self enterAppKitFullscreen];
 }
 
 - (void)updateFullscreenWithToolbar:(BOOL)withToolbar {
@@ -1918,16 +1905,6 @@
   return [presentationModeController_ menubarOffset];
 }
 
-- (void)enterExtensionFullscreen {
-  if (chrome::mac::SupportsSystemFullscreen()) {
-    [self enterBrowserFullscreenWithToolbar:NO];
-  } else {
-    [self enterImmersiveFullscreen];
-    DCHECK(!exclusiveAccessController_->url().is_empty());
-    [self updateFullscreenExitBubble];
-  }
-}
-
 - (void)enterWebContentFullscreen {
   // HTML5 Fullscreen should only use AppKit fullscreen in 10.10+.
   // However, if the user is using multiple monitors and turned off
@@ -1935,8 +1912,7 @@
   // that the other monitors won't blank out.
   display::Screen* screen = display::Screen::GetScreen();
   BOOL hasMultipleMonitors = screen && screen->GetNumDisplays() > 1;
-  if (chrome::mac::SupportsSystemFullscreen() &&
-      base::mac::IsOSYosemiteOrLater() &&
+  if (base::mac::IsOSYosemiteOrLater() &&
       !(hasMultipleMonitors && ![NSScreen screensHaveSeparateSpaces])) {
     [self enterAppKitFullscreen];
   } else {
@@ -1956,17 +1932,6 @@
     [self exitImmersiveFullscreen];
 }
 
-- (BOOL)inPresentationMode {
-  return presentationModeController_.get() &&
-         [presentationModeController_ inPresentationMode] &&
-         presentationModeController_.get().slidingStyle ==
-             fullscreen_mac::OMNIBOX_TABS_HIDDEN;
-}
-
-- (BOOL)shouldShowFullscreenToolbar {
-  return shouldShowFullscreenToolbar_;
-}
-
 - (void)exitFullscreenAnimationFinished {
   if (appKitDidExitFullscreen_) {
     [self windowDidExitFullScreen:nil];
@@ -2062,4 +2027,8 @@
   return savedRegularWindowFrame_;
 }
 
+- (BOOL)isFullscreenTransitionInProgress {
+  return enteringAppKitFullscreen_ || exitingAppKitFullscreen_;
+}
+
 @end  // @implementation BrowserWindowController(WindowType)
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm b/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm
index f886a0d..4021a49 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm
@@ -380,7 +380,7 @@
     browser()
         ->exclusive_access_manager()
         ->fullscreen_controller()
-        ->ToggleBrowserFullscreenWithToolbar();
+        ->ToggleBrowserFullscreenMode();
     waiter->Wait();
   }
 
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
index 883c3b30..937409c7 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -71,11 +71,10 @@
 };
 
 // There are 2 mechanisms for invoking fullscreen: AppKit and Immersive.
-// There are 2 types of AppKit Fullscreen: Presentation Mode and Canonical
-// Fullscreen.
+// PRESENTATION_MODE = 1 had been removed, but the enums aren't renumbered
+// since they are associated with a histogram.
 enum FullscreenStyle {
   IMMERSIVE_FULLSCREEN = 0,
-  PRESENTATION_MODE = 1,
   CANONICAL_FULLSCREEN = 2,
   FULLSCREEN_STYLE_COUNT = 3
 };
@@ -684,8 +683,7 @@
 
 - (void)windowWillEnterFullScreen:(NSNotification*)notification {
   RecordFullscreenWindowLocation([self window]);
-  RecordFullscreenStyle(enteringPresentationMode_ ? PRESENTATION_MODE
-                                                  : CANONICAL_FULLSCREEN);
+  RecordFullscreenStyle(CANONICAL_FULLSCREEN);
 
   if (notification)  // For System Fullscreen when non-nil.
     [self registerForContentViewResizeNotifications];
@@ -755,7 +753,6 @@
     [self deregisterForContentViewResizeNotifications];
 
   enteringImmersiveFullscreen_ = NO;
-  enteringPresentationMode_ = NO;
 
   [self resetCustomAppKitFullscreenVariables];
   [[tabStripController_ activeTabContentsController]
@@ -867,7 +864,7 @@
   fullscreen_mac::SlidingStyle style;
   if ([self isFullscreenForTabContentOrExtension]) {
     style = fullscreen_mac::OMNIBOX_TABS_NONE;
-  } else if (enteringPresentationMode_ || ![self shouldShowFullscreenToolbar]) {
+  } else if (!shouldShowFullscreenToolbar_) {
     style = fullscreen_mac::OMNIBOX_TABS_HIDDEN;
   } else {
     style = fullscreen_mac::OMNIBOX_TABS_PRESENT;
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
index a0650c6..c6a79eb2 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
@@ -768,7 +768,7 @@
   [controller_ showWindow:nil];
   EXPECT_FALSE([controller_ isInAnyFullscreenMode]);
 
-  [controller_ enterBrowserFullscreenWithToolbar:YES];
+  [controller_ enterBrowserFullscreen];
   WaitForFullScreenTransition();
   EXPECT_TRUE([controller_ isInAnyFullscreenMode]);
 
@@ -792,7 +792,7 @@
   chrome::testing::NSRunLoopRunAllPending();
   EXPECT_TRUE(IsFrontWindow([controller_ window]));
 
-  [controller_ enterBrowserFullscreenWithToolbar:YES];
+  [controller_ enterBrowserFullscreen];
   WaitForFullScreenTransition();
   [controller_ activate];
   chrome::testing::NSRunLoopRunAllPending();
diff --git a/chrome/browser/ui/cocoa/presentation_mode_controller.h b/chrome/browser/ui/cocoa/presentation_mode_controller.h
index 3ee4319..56bb6f0 100644
--- a/chrome/browser/ui/cocoa/presentation_mode_controller.h
+++ b/chrome/browser/ui/cocoa/presentation_mode_controller.h
@@ -145,6 +145,10 @@
 // Returns true if the window is the main window.
 - (BOOL)isMainWindow;
 
+// Returns true if the browser is in the process of entering/exiting
+// fullscreen.
+- (BOOL)isFullscreenTransitionInProgress;
+
 @end
 
 // Private methods exposed for testing.
diff --git a/chrome/browser/ui/cocoa/presentation_mode_controller.mm b/chrome/browser/ui/cocoa/presentation_mode_controller.mm
index 51504cd8..a3d63f5 100644
--- a/chrome/browser/ui/cocoa/presentation_mode_controller.mm
+++ b/chrome/browser/ui/cocoa/presentation_mode_controller.mm
@@ -52,7 +52,7 @@
   // As such, we should ignore the kMenuBarRevealEventKind event if it gives
   // us a fraction of 0.0 or 1.0, and rely on kEventMenuBarShown and
   // kEventMenuBarHidden to set these values.
-  if ([self isMainWindow]) {
+  if ([self isMainWindow] && ![self isFullscreenTransitionInProgress]) {
     if (GetEventKind(event) == kMenuBarRevealEventKind) {
       CGFloat revealFraction = 0;
       GetEventParameter(event, FOUR_CHAR_CODE('rvlf'), typeCGFloat, NULL,
@@ -426,6 +426,10 @@
              : 0;
 }
 
+- (BOOL)isFullscreenTransitionInProgress {
+  return [browserController_ isFullscreenTransitionInProgress];
+}
+
 - (BOOL)isMainWindow {
   return [browserController_ window].isMainWindow;
 }
diff --git a/chrome/browser/ui/cocoa/view_id_util_browsertest.mm b/chrome/browser/ui/cocoa/view_id_util_browsertest.mm
index 91de2236..73827e4c 100644
--- a/chrome/browser/ui/cocoa/view_id_util_browsertest.mm
+++ b/chrome/browser/ui/cocoa/view_id_util_browsertest.mm
@@ -104,8 +104,7 @@
 // Flaky on Mac: http://crbug.com/90557.
 IN_PROC_BROWSER_TEST_F(ViewIDTest, DISABLED_Fullscreen) {
   browser()->exclusive_access_manager()->context()->EnterFullscreen(
-      GURL(), EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION,
-      false);
+      GURL(), EXCLUSIVE_ACCESS_BUBBLE_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION);
   ASSERT_NO_FATAL_FAILURE(DoTest());
 }
 
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_context.h b/chrome/browser/ui/exclusive_access/exclusive_access_context.h
index a897357..4ba3c47d 100644
--- a/chrome/browser/ui/exclusive_access/exclusive_access_context.h
+++ b/chrome/browser/ui/exclusive_access/exclusive_access_context.h
@@ -30,11 +30,13 @@
   virtual bool IsFullscreen() const = 0;
 
   // Returns true if fullscreen with toolbar is supported.
+  // TODO (spqchan): Deprecate this method. crbug.com/579259
   virtual bool SupportsFullscreenWithToolbar() const;
 
   // Shows or hides the tab strip, toolbar and bookmark bar with in browser
   // fullscreen.
   // Currently only supported on Mac.
+  // TODO (spqchan): Deprecate this method. crbug.com/579259
   virtual void UpdateFullscreenWithToolbar(bool with_toolbar);
 
   // Updates the toolbar state to be hidden or shown in fullscreen according to
@@ -43,14 +45,12 @@
 
   // Returns true if the window is fullscreen with additional UI elements. See
   // EnterFullscreen |with_toolbar|.
+   // TODO (spqchan): Deprecate this method. crbug.com/579259
   virtual bool IsFullscreenWithToolbar() const;
 
   // Enters fullscreen and update exit bubble.
-  // On Mac, the tab strip and toolbar will be shown if |with_toolbar| is true,
-  // |with_toolbar| is ignored on other platforms.
   virtual void EnterFullscreen(const GURL& url,
-                               ExclusiveAccessBubbleType bubble_type,
-                               bool with_toolbar) = 0;
+                               ExclusiveAccessBubbleType bubble_type) = 0;
 
   // Exits fullscreen and update exit bubble.
   virtual void ExitFullscreen() = 0;
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
index 7038dcb..a114fdd 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
@@ -71,10 +71,6 @@
   ToggleFullscreenModeInternal(BROWSER);
 }
 
-void FullscreenController::ToggleBrowserFullscreenWithToolbar() {
-  ToggleFullscreenModeInternal(BROWSER_WITH_TOOLBAR);
-}
-
 void FullscreenController::ToggleBrowserFullscreenModeWithExtension(
     const GURL& extension_url) {
   // |extension_caused_fullscreen_| will be reset if this causes fullscreen to
@@ -347,13 +343,8 @@
       !IsWindowFullscreenForTabOrPending() &&
       exclusive_access_context->SupportsFullscreenWithToolbar() &&
       IsExtensionFullscreenOrPending()) {
-    if (option == BROWSER_WITH_TOOLBAR) {
-      enter_fullscreen = enter_fullscreen ||
-                         !exclusive_access_context->IsFullscreenWithToolbar();
-    } else {
-      enter_fullscreen = enter_fullscreen ||
-                         exclusive_access_context->IsFullscreenWithToolbar();
-    }
+    enter_fullscreen = enter_fullscreen ||
+        exclusive_access_context->IsFullscreenWithToolbar();
   }
 
   // In kiosk mode, we always want to be fullscreen. When the browser first
@@ -396,8 +387,7 @@
   // from tab fullscreen out to browser with toolbar.
 
   exclusive_access_manager()->context()->EnterFullscreen(
-      url, exclusive_access_manager()->GetExclusiveAccessExitBubbleType(),
-      option == BROWSER_WITH_TOOLBAR);
+      url, exclusive_access_manager()->GetExclusiveAccessExitBubbleType());
 
   exclusive_access_manager()->UpdateExclusiveAccessExitBubbleContent();
 
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.h b/chrome/browser/ui/exclusive_access/fullscreen_controller.h
index fcd01da..82a8a95 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller.h
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.h
@@ -65,10 +65,6 @@
 
   void ToggleBrowserFullscreenMode();
 
-  // Fullscreen mode with tab strip and toolbar shown.
-  // Currently only supported on Mac.
-  void ToggleBrowserFullscreenWithToolbar();
-
   // Extension API implementation uses this method to toggle fullscreen mode.
   // The extension's name is displayed in the full screen bubble UI to attribute
   // the cause of the full screen state change.
@@ -135,7 +131,6 @@
 
   enum FullscreenInternalOption {
     BROWSER,
-    BROWSER_WITH_TOOLBAR,
     TAB
   };
 
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc
index 99b43f8f..16a3489 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_state_unittest.cc
@@ -62,8 +62,7 @@
   void HideDownloadShelf() override;
   void UnhideDownloadShelf() override;
   void EnterFullscreen(const GURL& url,
-                       ExclusiveAccessBubbleType type,
-                       bool with_toolbar) override;
+                       ExclusiveAccessBubbleType type) override;
   void ExitFullscreen() override;
   void UpdateExclusiveAccessExitBubbleContent(
       const GURL& url,
@@ -74,8 +73,6 @@
   void ChangeWindowFullscreenState();
 
  private:
-  // TODO(spqchan): Remove the with_toolbar param in EnterFullscreen() since
-  // it is now deprecated. See crbug.com/579259.
   void EnterFullscreen();
 
   // Returns true if ChangeWindowFullscreenState() should be called as a result
@@ -93,8 +90,7 @@
 
 void FullscreenControllerTestWindow::EnterFullscreen(
     const GURL& url,
-    ExclusiveAccessBubbleType type,
-    bool with_toolbar) {
+    ExclusiveAccessBubbleType type) {
   EnterFullscreen();
 }
 
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc
index 3670921..c37d34c1 100644
--- a/chrome/browser/ui/extensions/application_launch.cc
+++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -289,11 +289,7 @@
   // this case?
   if (launch_type == extensions::LAUNCH_TYPE_FULLSCREEN &&
       !browser->window()->IsFullscreen()) {
-#if defined(OS_MACOSX)
-    chrome::ToggleFullscreenWithToolbarOrFallback(browser);
-#else
     chrome::ToggleFullscreenMode(browser);
-#endif
   }
 #endif  // USE_ASH
   return contents;
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 2e51b4b..c33095dfe 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -931,8 +931,7 @@
 }
 
 void BrowserView::EnterFullscreen(const GURL& url,
-                                  ExclusiveAccessBubbleType bubble_type,
-                                  bool with_toolbar) {
+                                  ExclusiveAccessBubbleType bubble_type) {
   if (IsFullscreen())
     return;  // Nothing to do.
 
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 18792a1..f25e171 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -278,8 +278,7 @@
   void Minimize() override;
   void Restore() override;
   void EnterFullscreen(const GURL& url,
-                       ExclusiveAccessBubbleType bubble_type,
-                       bool with_toolbar) override;
+                       ExclusiveAccessBubbleType bubble_type) override;
   void ExitFullscreen() override;
   void UpdateExclusiveAccessExitBubbleContent(
       const GURL& url,
diff --git a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
index 53cb6b5d..a3ab879 100644
--- a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
 
-#include "ash/system/chromeos/devicetype_utils.h"
+#include "ash/common/system/chromeos/devicetype_utils.h"
 #include "base/message_loop/message_loop.h"
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/login/screens/network_error_model.h"
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 f8795e98..188ffd2 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
 
-#include "ash/system/chromeos/devicetype_utils.h"
+#include "ash/common/system/chromeos/devicetype_utils.h"
 #include "base/bind.h"
 #include "base/guid.h"
 #include "base/logging.h"
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 d738494..88971ea 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -9,8 +9,8 @@
 #include <algorithm>
 #include <vector>
 
+#include "ash/common/system/chromeos/devicetype_utils.h"
 #include "ash/shell.h"
-#include "ash/system/chromeos/devicetype_utils.h"
 #include "ash/wm/lock_state_controller.h"
 #include "base/bind.h"
 #include "base/location.h"
diff --git a/chrome/browser/ui/webui/help/help_handler.cc b/chrome/browser/ui/webui/help/help_handler.cc
index 3fd9934..423444a 100644
--- a/chrome/browser/ui/webui/help/help_handler.cc
+++ b/chrome/browser/ui/webui/help/help_handler.cc
@@ -8,7 +8,7 @@
 
 #include <string>
 
-#include "ash/system/chromeos/devicetype_utils.h"
+#include "ash/common/system/chromeos/devicetype_utils.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index 7c2be992..0d435e05 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -112,9 +112,9 @@
 
 #if defined(OS_CHROMEOS)
 #include "ash/ash_switches.h"
+#include "ash/common/system/chromeos/devicetype_utils.h"
 #include "ash/desktop_background/user_wallpaper_delegate.h"
 #include "ash/shell.h"
-#include "ash/system/chromeos/devicetype_utils.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_util.h"
 #include "chrome/browser/chromeos/arc/arc_auth_service.h"
diff --git a/chrome/browser/ui/webui/options/chromeos/consumer_management_handler.cc b/chrome/browser/ui/webui/options/chromeos/consumer_management_handler.cc
index ea72850..7acbd03 100644
--- a/chrome/browser/ui/webui/options/chromeos/consumer_management_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/consumer_management_handler.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/webui/options/chromeos/consumer_management_handler.h"
 
-#include "ash/system/chromeos/devicetype_utils.h"
+#include "ash/common/system/chromeos/devicetype_utils.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/logging.h"
diff --git a/chrome/browser/ui/webui/options/chromeos/power_handler.h b/chrome/browser/ui/webui/options/chromeos/power_handler.h
index 68667c8..b5045e6 100644
--- a/chrome/browser/ui/webui/options/chromeos/power_handler.h
+++ b/chrome/browser/ui/webui/options/chromeos/power_handler.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS_CHROMEOS_POWER_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_OPTIONS_CHROMEOS_POWER_HANDLER_H_
 
-#include "ash/system/chromeos/power/power_status.h"
+#include "ash/common/system/chromeos/power/power_status.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/ui/webui/options/options_ui.h"
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc
index 6f9ca5d..50db13d 100644
--- a/chrome/browser/ui/webui/settings/about_handler.cc
+++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -8,7 +8,7 @@
 
 #include <string>
 
-#include "ash/system/chromeos/devicetype_utils.h"
+#include "ash/common/system/chromeos/devicetype_utils.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 1f8269c..20cb4885 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -28,7 +28,7 @@
 #include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_CHROMEOS)
-#include "ash/system/chromeos/devicetype_utils.h"
+#include "ash/common/system/chromeos/devicetype_utils.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/ui/webui/chromeos/ui_account_tweaks.h"
 #include "chromeos/chromeos_switches.h"
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi
index 0c4590ef..7b6f035 100644
--- a/chrome/chrome_browser_chromeos.gypi
+++ b/chrome/chrome_browser_chromeos.gypi
@@ -62,6 +62,8 @@
         'browser/chromeos/arc/arc_auth_service.h',
         'browser/chromeos/arc/arc_downloads_watcher_service.cc',
         'browser/chromeos/arc/arc_downloads_watcher_service.h',
+        'browser/chromeos/arc/arc_navigation_throttle.cc',
+        'browser/chromeos/arc/arc_navigation_throttle.h',
         'browser/chromeos/arc/arc_service_launcher.cc',
         'browser/chromeos/arc/arc_service_launcher.h',
         'browser/chromeos/arc/arc_support_host.cc',
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_provider.cc b/chrome/common/extensions/permissions/chrome_permission_message_provider.cc
index 49db418..ecaaf2d3 100644
--- a/chrome/common/extensions/permissions/chrome_permission_message_provider.cc
+++ b/chrome/common/extensions/permissions/chrome_permission_message_provider.cc
@@ -44,6 +44,15 @@
 };
 using ComparablePermissions = std::vector<ComparablePermission>;
 
+void DropPermissionParameter(APIPermission::ID id,
+                             PermissionIDSet* permissions) {
+  if (permissions->ContainsID(id)) {
+    // Erase the permission, and insert it again without a parameter.
+    permissions->erase(id);
+    permissions->insert(id);
+  }
+}
+
 }  // namespace
 
 typedef std::set<PermissionMessage> PermissionMsgSet;
@@ -176,6 +185,20 @@
   AddAPIPermissions(new_permissions, &new_ids);
   AddManifestPermissions(new_permissions, &new_ids);
 
+  // Ugly hack: Before M46 beta, we didn't store the parameter for settings
+  // override permissions in prefs (which is where |old_permissions| is coming
+  // from). To avoid a spurious permission increase warning, drop the parameter.
+  // See crbug.com/533086 and crbug.com/619759.
+  // TODO(treib,devlin): Remove this for M56, when hopefully all users will have
+  // updated prefs.
+  const APIPermission::ID kSettingsOverrideIDs[] = {
+      APIPermission::kHomepage, APIPermission::kSearchProvider,
+      APIPermission::kStartupPages};
+  for (auto id : kSettingsOverrideIDs) {
+    DropPermissionParameter(id, &old_ids);
+    DropPermissionParameter(id, &new_ids);
+  }
+
   // If all the IDs were already there, it's not a privilege increase.
   if (old_ids.Includes(new_ids))
     return false;
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_provider_unittest.cc b/chrome/common/extensions/permissions/chrome_permission_message_provider_unittest.cc
index 606218ab..c6d69aef 100644
--- a/chrome/common/extensions/permissions/chrome_permission_message_provider_unittest.cc
+++ b/chrome/common/extensions/permissions/chrome_permission_message_provider_unittest.cc
@@ -129,4 +129,30 @@
   EXPECT_FALSE(message1.submessages().empty());
 }
 
+// Anti-test: Check that adding a parameter to a SettingsOverridePermission
+// doesn't trigger a privilege increase. This is because prior to M46 beta, we
+// failed to store the parameter in the granted_permissions pref. Now we do, and
+// we don't want to bother every user with a spurious permissions warning.
+// See crbug.com/533086 and crbug.com/619759.
+// TODO(treib,devlin): Remove this for M56, when hopefully all users will have
+// updated prefs.
+TEST_F(ChromePermissionMessageProviderUnittest,
+       EvilHackToSuppressSettingsOverrideParameter) {
+  const APIPermissionInfo* info =
+      PermissionsInfo::GetInstance()->GetByID(APIPermission::kSearchProvider);
+
+  APIPermissionSet granted_permissions;
+  granted_permissions.insert(new SettingsOverrideAPIPermission(info));
+
+  APIPermissionSet actual_permissions;
+  actual_permissions.insert(new SettingsOverrideAPIPermission(info, "a.com"));
+
+  EXPECT_FALSE(IsPrivilegeIncrease(granted_permissions, actual_permissions));
+
+  // Just to be safe: Adding the permission (with or without parameter) should
+  // still be considered a privilege escalation.
+  EXPECT_TRUE(IsPrivilegeIncrease(APIPermissionSet(), granted_permissions));
+  EXPECT_TRUE(IsPrivilegeIncrease(APIPermissionSet(), actual_permissions));
+}
+
 }  // namespace extensions
diff --git a/chrome/test/data/android/payments/dynamic_shipping.js b/chrome/test/data/android/payments/dynamic_shipping.js
index 0b55e07..ede7b7f 100644
--- a/chrome/test/data/android/payments/dynamic_shipping.js
+++ b/chrome/test/data/android/payments/dynamic_shipping.js
@@ -30,7 +30,7 @@
 
     request.show()
         .then(function(resp) {
-          resp.complete(true)
+          resp.complete("success")
               .then(function() {
                 print(
                     JSON.stringify(resp.totalAmount, undefined, 2) + '<br>' +
diff --git a/chrome/test/data/android/payments/free_shipping.js b/chrome/test/data/android/payments/free_shipping.js
index 217ea93..d7ee2132 100644
--- a/chrome/test/data/android/payments/free_shipping.js
+++ b/chrome/test/data/android/payments/free_shipping.js
@@ -25,7 +25,7 @@
         {requestShipping: true});
     request.show()
         .then(function(resp) {
-          resp.complete(true)
+          resp.complete("success")
               .then(function() {
                 print(
                     JSON.stringify(resp.totalAmount, undefined, 2) + '<br>' +
diff --git a/chrome/test/data/android/payments/no_shipping.js b/chrome/test/data/android/payments/no_shipping.js
index 9df7a46..060a11b9 100644
--- a/chrome/test/data/android/payments/no_shipping.js
+++ b/chrome/test/data/android/payments/no_shipping.js
@@ -16,7 +16,7 @@
         {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}})
         .show()
         .then(function(resp) {
-          resp.complete(true)
+          resp.complete("success")
               .then(function() {
                 print(
                     JSON.stringify(resp.totalAmount, undefined, 2) + '<br>' +
diff --git a/chromeos/dbus/session_manager_client.cc b/chromeos/dbus/session_manager_client.cc
index 9b2bacad..fa193b12 100644
--- a/chromeos/dbus/session_manager_client.cc
+++ b/chromeos/dbus/session_manager_client.cc
@@ -429,6 +429,13 @@
                    weak_ptr_factory_.GetWeakPtr()),
         base::Bind(&SessionManagerClientImpl::SignalConnected,
                    weak_ptr_factory_.GetWeakPtr()));
+    session_manager_proxy_->ConnectToSignal(
+        login_manager::kSessionManagerInterface,
+        login_manager::kArcInstanceStopped,
+        base::Bind(&SessionManagerClientImpl::ArcInstanceStoppedReceived,
+                   weak_ptr_factory_.GetWeakPtr()),
+        base::Bind(&SessionManagerClientImpl::SignalConnected,
+                   weak_ptr_factory_.GetWeakPtr()));
   }
 
  private:
@@ -654,6 +661,16 @@
     FOR_EACH_OBSERVER(Observer, observers_, ScreenIsUnlocked());
   }
 
+  void ArcInstanceStoppedReceived(dbus::Signal* signal) {
+    dbus::MessageReader reader(signal);
+    bool clean = false;
+    if (!reader.PopBool(&clean)) {
+      LOG(ERROR) << "Invalid signal: " << signal->ToString();
+      return;
+    }
+    FOR_EACH_OBSERVER(Observer, observers_, ArcInstanceStopped(clean));
+  }
+
   // Called when the object is connected to the signal.
   void SignalConnected(const std::string& interface_name,
                        const std::string& signal_name,
diff --git a/chromeos/dbus/session_manager_client.h b/chromeos/dbus/session_manager_client.h
index 7b51f25..13818d5 100644
--- a/chromeos/dbus/session_manager_client.h
+++ b/chromeos/dbus/session_manager_client.h
@@ -47,6 +47,11 @@
 
     // Called after EmitLoginPromptVisible is called.
     virtual void EmitLoginPromptVisibleCalled() {}
+
+    // Called when the ARC instance is stopped after it had already started.
+    // |clean| is true if the instance was stopped as a result of an explicit
+    // request, false if it died unexpectedly.
+    virtual void ArcInstanceStopped(bool clean) {}
   };
 
   // Interface for performing actions on behalf of the stub implementation.
diff --git a/components/arc/OWNERS b/components/arc/OWNERS
index f068aeb..d7d81e7 100644
--- a/components/arc/OWNERS
+++ b/components/arc/OWNERS
@@ -1,3 +1,4 @@
 elijahtaylor@chromium.org
 hidehiko@chromium.org
 lhchavez@chromium.org
+yusukes@chromium.org
diff --git a/components/arc/arc_bridge_bootstrap.cc b/components/arc/arc_bridge_bootstrap.cc
index 33b04cd..930282e 100644
--- a/components/arc/arc_bridge_bootstrap.cc
+++ b/components/arc/arc_bridge_bootstrap.cc
@@ -42,7 +42,23 @@
 
 const char kArcBridgeSocketGroup[] = "arc-bridge";
 
-class ArcBridgeBootstrapImpl : public ArcBridgeBootstrap {
+// This is called when StopArcInstance D-Bus method completes. Since we have the
+// ArcInstanceStopped() callback and are notified if StartArcInstance fails, we
+// don't need to do anything when StopArcInstance completes.
+void DoNothingInstanceStopped(bool) {}
+
+chromeos::SessionManagerClient* GetSessionManagerClient() {
+  // If the DBusThreadManager or the SessionManagerClient aren't available,
+  // there isn't much we can do. This should only happen when running tests.
+  if (!chromeos::DBusThreadManager::IsInitialized() ||
+      !chromeos::DBusThreadManager::Get() ||
+      !chromeos::DBusThreadManager::Get()->GetSessionManagerClient())
+    return nullptr;
+  return chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
+}
+
+class ArcBridgeBootstrapImpl : public ArcBridgeBootstrap,
+                               public chromeos::SessionManagerClient::Observer {
  public:
   // The possible states of the bootstrap connection.  In the normal flow,
   // the state changes in the following sequence:
@@ -112,7 +128,9 @@
 
   // DBus callbacks.
   void OnInstanceStarted(base::ScopedFD socket_fd, bool success);
-  void OnInstanceStopped(bool success);
+
+  // chromeos::SessionManagerClient::Observer:
+  void ArcInstanceStopped(bool clean) override;
 
   // The state of the bootstrap connection.
   State state_ = State::STOPPED;
@@ -126,11 +144,21 @@
   DISALLOW_COPY_AND_ASSIGN(ArcBridgeBootstrapImpl);
 };
 
-ArcBridgeBootstrapImpl::ArcBridgeBootstrapImpl() : weak_factory_(this) {}
+ArcBridgeBootstrapImpl::ArcBridgeBootstrapImpl()
+    : weak_factory_(this) {
+  chromeos::SessionManagerClient* client = GetSessionManagerClient();
+  if (client == nullptr)
+    return;
+  client->AddObserver(this);
+}
 
 ArcBridgeBootstrapImpl::~ArcBridgeBootstrapImpl() {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(state_ == State::STOPPED || state_ == State::STOPPING);
+  chromeos::SessionManagerClient* client = GetSessionManagerClient();
+  if (client == nullptr)
+    return;
+  client->RemoveObserver(this);
 }
 
 void ArcBridgeBootstrapImpl::Start() {
@@ -228,10 +256,6 @@
 void ArcBridgeBootstrapImpl::OnInstanceStarted(base::ScopedFD socket_fd,
                                                bool success) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  if (state_ != State::STARTING) {
-    VLOG(1) << "Stop() called when ARC is not running";
-    return;
-  }
   if (!success) {
     LOG(ERROR) << "Failed to start ARC instance";
     // Roll back the state to SOCKET_CREATING to avoid sending the D-Bus signal
@@ -240,6 +264,10 @@
     Stop();
     return;
   }
+  if (state_ != State::STARTING) {
+    VLOG(1) << "Stop() called when ARC is not running";
+    return;
+  }
   SetState(State::STARTED);
 
   base::PostTaskAndReplyWithResult(
@@ -315,21 +343,21 @@
     // This was stopped before the D-Bus command to start the instance. Skip
     // the D-Bus command to stop it.
     SetState(State::STOPPING);
-    OnInstanceStopped(true);
+    ArcInstanceStopped(true);
     return;
   }
   SetState(State::STOPPING);
+  // Notification will arrive through ArcInstanceStopped().
   chromeos::SessionManagerClient* session_manager_client =
       chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
-  session_manager_client->StopArcInstance(base::Bind(
-      &ArcBridgeBootstrapImpl::OnInstanceStopped, weak_factory_.GetWeakPtr()));
+  session_manager_client->StopArcInstance(
+      base::Bind(&DoNothingInstanceStopped));
 }
 
-void ArcBridgeBootstrapImpl::OnInstanceStopped(bool success) {
+void ArcBridgeBootstrapImpl::ArcInstanceStopped(bool clean) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  // STOPPING is the only valid state for this function.
-  // DCHECK on enum classes not supported.
-  DCHECK(state_ == State::STOPPING);
+  if (!clean)
+    LOG(ERROR) << "ARC instance crashed";
   DCHECK(delegate_);
   SetState(State::STOPPED);
   delegate_->OnStopped();
diff --git a/components/arc/arc_bridge_service_impl.cc b/components/arc/arc_bridge_service_impl.cc
index 20de50a..ca87d13 100644
--- a/components/arc/arc_bridge_service_impl.cc
+++ b/components/arc/arc_bridge_service_impl.cc
@@ -94,6 +94,9 @@
   if (binding_.is_bound())
     binding_.Close();
   bootstrap_->Stop();
+
+  // We were explicitly asked to stop, so do not reconnect.
+  reconnect_ = false;
 }
 
 void ArcBridgeServiceImpl::SetDetectedAvailability(bool arc_available) {
@@ -119,6 +122,9 @@
 
   instance_ptr_->Init(binding_.CreateInterfacePtrAndBind());
 
+  // The container can be considered to have been successfully launched, so
+  // restart if the connection goes down without being requested.
+  reconnect_ = true;
   VLOG(0) << "ARC ready";
   SetState(State::READY);
 }
@@ -154,9 +160,10 @@
     return;
   }
   VLOG(1) << "Mojo connection lost";
+  instance_ptr_.reset();
+  if (binding_.is_bound())
+    binding_.Close();
   CloseAllChannels();
-  reconnect_ = true;
-  StopInstance();
 }
 
 }  // namespace arc
diff --git a/components/arc/arc_bridge_service_unittest.cc b/components/arc/arc_bridge_service_unittest.cc
index 343cdf3..598e54b 100644
--- a/components/arc/arc_bridge_service_unittest.cc
+++ b/components/arc/arc_bridge_service_unittest.cc
@@ -121,7 +121,7 @@
   ASSERT_EQ(ArcBridgeService::State::STOPPED, state());
 }
 
-// If the channel is disconnected, it should be re-established.
+// If the instance is stopped, it should be re-started.
 TEST_F(ArcBridgeTest, Restart) {
   ASSERT_FALSE(ready());
   ASSERT_EQ(0, instance_->init_calls());
@@ -135,6 +135,7 @@
   // Simulate a connection loss.
   service_->DisableReconnectDelayForTesting();
   service_->OnChannelClosed();
+  instance_->SimulateCrash();
   instance_->WaitForInitCall();
   ASSERT_EQ(ArcBridgeService::State::READY, state());
   ASSERT_EQ(2, instance_->init_calls());
diff --git a/components/arc/test/fake_arc_bridge_bootstrap.cc b/components/arc/test/fake_arc_bridge_bootstrap.cc
index 33ac6c3..cd05697 100644
--- a/components/arc/test/fake_arc_bridge_bootstrap.cc
+++ b/components/arc/test/fake_arc_bridge_bootstrap.cc
@@ -15,6 +15,7 @@
 
 FakeArcBridgeBootstrap::FakeArcBridgeBootstrap(FakeArcBridgeInstance* instance)
     : instance_(instance) {
+  instance_->set_delegate(this);
 }
 
 void FakeArcBridgeBootstrap::Start() {
@@ -30,4 +31,8 @@
   delegate_->OnStopped();
 }
 
+void FakeArcBridgeBootstrap::OnCrashed() {
+  Stop();
+}
+
 }  // namespace arc
diff --git a/components/arc/test/fake_arc_bridge_bootstrap.h b/components/arc/test/fake_arc_bridge_bootstrap.h
index feb7d6c..f9a9b2f 100644
--- a/components/arc/test/fake_arc_bridge_bootstrap.h
+++ b/components/arc/test/fake_arc_bridge_bootstrap.h
@@ -7,22 +7,25 @@
 
 #include "base/macros.h"
 #include "components/arc/arc_bridge_bootstrap.h"
+#include "components/arc/test/fake_arc_bridge_instance.h"
 
 namespace arc {
 
-class FakeArcBridgeInstance;
-
 // A fake ArcBridgeBootstrap that creates a local connection.
-class FakeArcBridgeBootstrap : public ArcBridgeBootstrap {
+class FakeArcBridgeBootstrap : public ArcBridgeBootstrap,
+                               public FakeArcBridgeInstance::Delegate {
  public:
   explicit FakeArcBridgeBootstrap(FakeArcBridgeInstance* instance);
-  ~FakeArcBridgeBootstrap() override {}
+  ~FakeArcBridgeBootstrap() override = default;
 
   // ArcBridgeBootstrap:
   void Start() override;
   void Stop() override;
 
  private:
+  // FakeArcBridgeInstance::Delegate:
+  void OnCrashed() override;
+
   // Owned by the caller.
   FakeArcBridgeInstance* instance_;
 
diff --git a/components/arc/test/fake_arc_bridge_instance.cc b/components/arc/test/fake_arc_bridge_instance.cc
index 81aa152d..e51e54a 100644
--- a/components/arc/test/fake_arc_bridge_instance.cc
+++ b/components/arc/test/fake_arc_bridge_instance.cc
@@ -31,4 +31,10 @@
   binding_.WaitForIncomingMethodCall();
 }
 
+void FakeArcBridgeInstance::SimulateCrash() {
+  if (!delegate_)
+    return;
+  delegate_->OnCrashed();
+}
+
 }  // namespace arc
diff --git a/components/arc/test/fake_arc_bridge_instance.h b/components/arc/test/fake_arc_bridge_instance.h
index 9488ea5..5a3aa47 100644
--- a/components/arc/test/fake_arc_bridge_instance.h
+++ b/components/arc/test/fake_arc_bridge_instance.h
@@ -14,9 +14,17 @@
 
 class FakeArcBridgeInstance : public mojom::ArcBridgeInstance {
  public:
+  class Delegate {
+   public:
+    virtual ~Delegate() = default;
+    virtual void OnCrashed() = 0;
+  };
+
   FakeArcBridgeInstance();
   ~FakeArcBridgeInstance() override;
 
+  void set_delegate(Delegate* delegate) { delegate_ = delegate; }
+
   // Finalizes the connection between the host and the instance, and signals
   // the host that the boot sequence has finished.
   void Bind(mojo::InterfaceRequest<mojom::ArcBridgeInstance> interface_request);
@@ -33,7 +41,12 @@
   // The number of times Init() has been called.
   int init_calls() const { return init_calls_; }
 
+  // Simulates a crash by calling Stop() on the ArcBridgeBoostrap.
+  void SimulateCrash();
+
  private:
+  Delegate* delegate_ = nullptr;
+
   // Mojo endpoints.
   mojo::Binding<mojom::ArcBridgeInstance> binding_;
   mojom::ArcBridgeHostPtr host_ptr_;
diff --git a/components/drive/BUILD.gn b/components/drive/BUILD.gn
index 8c7e8e8..c5c95162 100644
--- a/components/drive/BUILD.gn
+++ b/components/drive/BUILD.gn
@@ -56,6 +56,7 @@
 
     # TODO(lukasza): Remove this dependency (see DEPS file for more info).
     "//content/public/browser",
+    "//device/power_save_blocker",
     "//google_apis:google_apis",
     "//net:net",
     "//third_party/cacheinvalidation",
diff --git a/components/drive/DEPS b/components/drive/DEPS
index 5586c3bf..dda68d0 100644
--- a/components/drive/DEPS
+++ b/components/drive/DEPS
@@ -2,6 +2,7 @@
   "+components/invalidation",
   "+components/keyed_service",
   "+components/prefs",
+  "+device/power_save_blocker",
   "+google_apis",
   "+google/cacheinvalidation/types.pb.h",
   "+net",
@@ -10,13 +11,6 @@
 ]
 
 specific_include_rules = {
-  # The following dependency should be removed to fully make this
-  # directory chrome/ and content/ and storage/ independent.
-  # crbug.com/257943
-  "drive_uploader\.cc": [
-    "+content/public/browser/power_save_blocker_factory.h",
-  ],
-
   # The following test dependencies should be removed to fully componentize this
   # directory. crbug.com/498951
   r"(copy_operation_unittest\.cc"
@@ -62,8 +56,9 @@
 
   # The following test dependencies should be removed to fully componentize this
   # directory. crbug.com/498951
-  r"(fake_file_system\.cc"
-  r"|file_system_unittest.cc"
+  r"(drive_uploader\.cc"
+  r"|fake_file_system\.cc"
+  r"|file_system_unittest\.cc"
   r"|file_write_watcher_unittest\.cc"
   r"|get_file_for_saving_operation_unittest\.cc"
   r"|operation_test_base\.cc"
diff --git a/components/drive/drive_uploader.cc b/components/drive/drive_uploader.cc
index e8b0c53..ed2a921 100644
--- a/components/drive/drive_uploader.cc
+++ b/components/drive/drive_uploader.cc
@@ -15,7 +15,8 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/task_runner_util.h"
 #include "components/drive/service/drive_service_interface.h"
-#include "content/public/browser/power_save_blocker_factory.h"
+#include "content/public/browser/browser_thread.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 #include "google_apis/drive/drive_api_parser.h"
 
 using google_apis::CancelCallback;
@@ -98,10 +99,14 @@
         progress_callback(progress_callback),
         content_length(0),
         next_start_position(-1),
-        power_save_blocker(content::CreatePowerSaveBlocker(
-            content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
-            content::PowerSaveBlocker::kReasonOther,
-            "Upload in progress")),
+        power_save_blocker(device::PowerSaveBlocker::CreateWithTaskRunners(
+            device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
+            device::PowerSaveBlocker::kReasonOther,
+            "Upload in progress",
+            content::BrowserThread::GetMessageLoopProxyForThread(
+                content::BrowserThread::UI),
+            content::BrowserThread::GetMessageLoopProxyForThread(
+                content::BrowserThread::FILE))),
         cancelled(false),
         weak_ptr_factory_(this) {}
 
@@ -143,7 +148,7 @@
   int64_t next_start_position;
 
   // Blocks system suspend while upload is in progress.
-  std::unique_ptr<content::PowerSaveBlocker> power_save_blocker;
+  std::unique_ptr<device::PowerSaveBlocker> power_save_blocker;
 
   // Fields for implementing cancellation. |cancel_callback| is non-null if
   // there is an in-flight HTTP request. In that case, |cancell_callback| will
diff --git a/components/flags_ui/BUILD.gn b/components/flags_ui/BUILD.gn
index 81f0f5c1..36cfed8a 100644
--- a/components/flags_ui/BUILD.gn
+++ b/components/flags_ui/BUILD.gn
@@ -24,6 +24,7 @@
     "//components/pref_registry",
     "//components/prefs",
     "//components/strings",
+    "//components/variations",
     "//ui/base",
   ]
 }
@@ -49,6 +50,7 @@
     "//base",
     "//components/prefs:test_support",
     "//components/strings",
+    "//components/variations",
     "//testing/gtest",
   ]
 }
diff --git a/components/flags_ui/DEPS b/components/flags_ui/DEPS
index 983d01e..02fddd1 100644
--- a/components/flags_ui/DEPS
+++ b/components/flags_ui/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+components/pref_registry",
   "+components/prefs",
+  "+components/variations",
   "+grit/components_strings.h",
   "+ui/base",
 ]
diff --git a/components/flags_ui/feature_entry.cc b/components/flags_ui/feature_entry.cc
index b755697..53a219c 100644
--- a/components/flags_ui/feature_entry.cc
+++ b/components/flags_ui/feature_entry.cc
@@ -6,25 +6,28 @@
 
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
 #include "grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace flags_ui {
 
-std::string FeatureEntry::NameForChoice(int index) const {
+std::string FeatureEntry::NameForOption(int index) const {
   DCHECK(type == FeatureEntry::MULTI_VALUE ||
          type == FeatureEntry::ENABLE_DISABLE_VALUE ||
-         type == FeatureEntry::FEATURE_VALUE);
-  DCHECK_LT(index, num_choices);
+         type == FeatureEntry::FEATURE_VALUE ||
+         type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE);
+  DCHECK_LT(index, num_options);
   return std::string(internal_name) + testing::kMultiSeparator +
          base::IntToString(index);
 }
 
-base::string16 FeatureEntry::DescriptionForChoice(int index) const {
+base::string16 FeatureEntry::DescriptionForOption(int index) const {
   DCHECK(type == FeatureEntry::MULTI_VALUE ||
          type == FeatureEntry::ENABLE_DISABLE_VALUE ||
-         type == FeatureEntry::FEATURE_VALUE);
-  DCHECK_LT(index, num_choices);
+         type == FeatureEntry::FEATURE_VALUE ||
+         type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE);
+  DCHECK_LT(index, num_options);
   int description_id;
   if (type == FeatureEntry::ENABLE_DISABLE_VALUE ||
       type == FeatureEntry::FEATURE_VALUE) {
@@ -34,12 +37,64 @@
         IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
     };
     description_id = kEnableDisableDescriptionIds[index];
+  } else if (type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE) {
+    if (index == 0) {
+      description_id = IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT;
+    } else if (index == 1) {
+      // Variation 1: the default enabled variation => "Enabled".
+      description_id = IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED;
+    } else if (index < num_options - 1) {
+      // Variations 2 .. n  => "Enabled <description_text>".
+      int variation_index = index - 1;
+      return l10n_util::GetStringUTF16(IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED) +
+             base::ASCIIToUTF16(" ") +
+             base::ASCIIToUTF16(
+                 feature_variations[variation_index].description_text);
+    } else {
+      DCHECK_EQ(num_options - 1, index);
+      description_id = IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED;
+    }
   } else {
     description_id = choices[index].description_id;
   }
   return l10n_util::GetStringUTF16(description_id);
 }
 
+const FeatureEntry::Choice& FeatureEntry::ChoiceForOption(int index) const {
+  DCHECK_EQ(FeatureEntry::MULTI_VALUE, type);
+  DCHECK_LT(index, num_options);
+
+  return choices[index];
+}
+
+FeatureEntry::FeatureState FeatureEntry::StateForOption(int index) const {
+  DCHECK(type == FeatureEntry::FEATURE_VALUE ||
+         type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE);
+  DCHECK_LT(index, num_options);
+
+  if (index == 0)
+    return FeatureEntry::FeatureState::DEFAULT;
+  else if (index == num_options - 1)
+    return FeatureEntry::FeatureState::DISABLED;
+  else
+    return FeatureEntry::FeatureState::ENABLED;
+}
+
+const FeatureEntry::FeatureVariation* FeatureEntry::VariationForOption(
+    int index) const {
+  DCHECK(type == FeatureEntry::FEATURE_VALUE ||
+         type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE);
+  DCHECK_LT(index, num_options);
+
+  if (type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE && index > 0 &&
+      index < num_options - 1) {
+    // We have no variations for FEATURE_VALUE type. Option at |index|
+    // corresponds to variation at |index| - 1 as the first option is "Default".
+    return &feature_variations[index - 1];
+  }
+  return nullptr;
+}
+
 namespace testing {
 
 // WARNING: '@' is also used in the html file. If you update this constant you
diff --git a/components/flags_ui/feature_entry.h b/components/flags_ui/feature_entry.h
index 4f7f081..a3930fd 100644
--- a/components/flags_ui/feature_entry.h
+++ b/components/flags_ui/feature_entry.h
@@ -47,6 +47,24 @@
     // have three states: Default, Enabled, Disabled. When not specified or set
     // to Default, the normal default value of the feature is used.
     FEATURE_VALUE,
+
+    // Corresponds to a base::Feature and additional options [O_1, ..., O_n]
+    // that specify variation parameters. Each of the options can specify a set
+    // of variation parameters. The entry will have n+2 states: Default,
+    // Enabled: V_1, ..., Enabled: V_n, Disabled. When not specified or set to
+    // Default, the normal default values of the feature and of the parameters
+    // are used.
+    FEATURE_WITH_VARIATIONS_VALUE,
+  };
+
+  // Describes state of a feature.
+  enum FeatureState {
+    // The state of the feature is not overridden by the user.
+    DEFAULT,
+    // The feature is enabled by the user.
+    ENABLED,
+    // The feature is disabled by the user.
+    DISABLED,
   };
 
   // Used for MULTI_VALUE types to describe one of the possible values the user
@@ -61,6 +79,26 @@
     const char* command_line_value;
   };
 
+  // Configures one parameter for FEATURE_WITH_VARIATIONS_VALUE.
+  struct FeatureParam {
+    const char* param_name;
+    const char* param_value;
+  };
+
+  // Specified one variation (list of parameter values) for
+  // FEATURE_WITH_VARIATIONS_VALUE.
+  struct FeatureVariation {
+    // Text that denotes the variation in chrome://flags. For each variation,
+    // the user is shown an option labeled "Enabled <description_text>" (with
+    // the exception of the first option labeled "Enabled" to make clear it is
+    // the default one). No need for description_id, chrome://flags should not
+    // get translated. The other parts here use ids for historical reasons and
+    // can realistically also be moved to direct description_texts.
+    const char* description_text;
+    const FeatureParam* params;
+    int num_params;
+  };
+
   // The internal name of the feature entry. This is never shown to the user.
   // It _is_ however stored in the prefs file, so you shouldn't change the
   // name of existing flags.
@@ -96,18 +134,43 @@
   // For FEATURE_VALUE, the base::Feature this entry corresponds to.
   const base::Feature* feature;
 
-  // This is used if type is MULTI_VALUE.
+  // Number of options to choose from. This is used if type is MULTI_VALUE,
+  // ENABLE_DISABLE_VALUE, FEATURE_VALUE, or FEATURE_WITH_VARIATIONS_VALUE.
+  int num_options;
+
+  // This describes the options if type is MULTI_VALUE.
   const Choice* choices;
 
-  // Number of |choices|.
-  // This is used if type is MULTI_VALUE.
-  int num_choices;
+  // This describes the options if type is FEATURE_WITH_VARIATIONS_VALUE.
+  // The first variation is the default "Enabled" variation, its description_id
+  // is disregarded.
+  const FeatureVariation* feature_variations;
 
-  // Returns the name used in prefs for the choice at the specified |index|.
-  std::string NameForChoice(int index) const;
+  // The name of the FieldTrial in which the selected variation parameters
+  // should be registered. This is used if type is
+  // FEATURE_WITH_VARIATIONS_VALUE.
+  const char* feature_trial_name;
 
-  // Returns the human readable description for the choice at |index|.
-  base::string16 DescriptionForChoice(int index) const;
+  // Returns the name used in prefs for the option at the specified |index|.
+  // Only used for types that use |num_options|.
+  std::string NameForOption(int index) const;
+
+  // Returns the human readable description for the option at |index|.
+  // Only used for types that use |num_options|.
+  base::string16 DescriptionForOption(int index) const;
+
+  // Returns the choice for the option at |index|. Only applicable for type
+  // FEATURE_MULTI.
+  const FeatureEntry::Choice& ChoiceForOption(int index) const;
+
+  // Returns the state of the feature at |index|. Only applicable for types
+  // FEATURE_VALUE and FEATURE_WITH_VARIATIONS_VALUE.
+  FeatureEntry::FeatureState StateForOption(int index) const;
+
+  // Returns the variation for the option at |index| or nullptr if there is no
+  // variation associated at |index|. Only applicable for types FEATURE_VALUE
+  // and FEATURE_WITH_VARIATIONS_VALUE.
+  const FeatureEntry::FeatureVariation* VariationForOption(int index) const;
 };
 
 namespace testing {
diff --git a/components/flags_ui/feature_entry_macros.h b/components/flags_ui/feature_entry_macros.h
index 1dac0f3..9394b3730 100644
--- a/components/flags_ui/feature_entry_macros.h
+++ b/components/flags_ui/feature_entry_macros.h
@@ -12,25 +12,30 @@
 // different entry types and when they should be used.
 #define SINGLE_VALUE_TYPE_AND_VALUE(command_line_switch, switch_value)     \
   flags_ui::FeatureEntry::SINGLE_VALUE, command_line_switch, switch_value, \
-      nullptr, nullptr, nullptr, nullptr, 0
+      nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr
 #define SINGLE_VALUE_TYPE(command_line_switch) \
   SINGLE_VALUE_TYPE_AND_VALUE(command_line_switch, "")
 #define SINGLE_DISABLE_VALUE_TYPE_AND_VALUE(command_line_switch, switch_value) \
   flags_ui::FeatureEntry::SINGLE_DISABLE_VALUE, command_line_switch,           \
-      switch_value, nullptr, nullptr, nullptr, nullptr, 0
+      switch_value, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr
 #define SINGLE_DISABLE_VALUE_TYPE(command_line_switch) \
   SINGLE_DISABLE_VALUE_TYPE_AND_VALUE(command_line_switch, "")
 #define ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(enable_switch, enable_value,     \
                                             disable_switch, disable_value)   \
   flags_ui::FeatureEntry::ENABLE_DISABLE_VALUE, enable_switch, enable_value, \
-      disable_switch, disable_value, nullptr, nullptr, 3
+      disable_switch, disable_value, nullptr, 3, nullptr, nullptr, nullptr
 #define ENABLE_DISABLE_VALUE_TYPE(enable_switch, disable_switch) \
   ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(enable_switch, "", disable_switch, "")
 #define MULTI_VALUE_TYPE(choices)                                          \
   flags_ui::FeatureEntry::MULTI_VALUE, nullptr, nullptr, nullptr, nullptr, \
-      nullptr, choices, arraysize(choices)
+      nullptr, arraysize(choices), choices, nullptr, nullptr
 #define FEATURE_VALUE_TYPE(feature)                                          \
   flags_ui::FeatureEntry::FEATURE_VALUE, nullptr, nullptr, nullptr, nullptr, \
-      &feature, nullptr, 3
+      &feature, 3, nullptr, nullptr, nullptr
+#define FEATURE_WITH_VARIATIONS_VALUE_TYPE(feature, feature_variations,       \
+                                           feature_trial)                     \
+  flags_ui::FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE, nullptr, nullptr,    \
+      nullptr, nullptr, &feature, 2 + arraysize(feature_variations), nullptr, \
+      feature_variations, feature_trial
 
 #endif  // COMPONENTS_FLAGS_UI_FEATURE_ENTRY_MACROS_H_
diff --git a/components/flags_ui/flags_state.cc b/components/flags_ui/flags_state.cc
index 8206ef0..cadb8ee1 100644
--- a/components/flags_ui/flags_state.cc
+++ b/components/flags_ui/flags_state.cc
@@ -11,6 +11,7 @@
 #include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/metrics/field_trial.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -19,10 +20,15 @@
 #include "components/flags_ui/feature_entry.h"
 #include "components/flags_ui/flags_storage.h"
 #include "components/flags_ui/flags_ui_switches.h"
+#include "components/variations/variations_associated_data.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace flags_ui {
 
+namespace internal {
+const char kTrialGroupAboutFlags[] = "AboutFlags";
+}  // namespace internal
+
 namespace {
 
 // Convert switch constants to proper CommandLine::StringType strings.
@@ -99,8 +105,9 @@
     case FeatureEntry::MULTI_VALUE:
     case FeatureEntry::ENABLE_DISABLE_VALUE:
     case FeatureEntry::FEATURE_VALUE:
-      for (int i = 0; i < e.num_choices; ++i)
-        names->insert(e.NameForChoice(i));
+    case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
+      for (int i = 0; i < e.num_options; ++i)
+        names->insert(e.NameForOption(i));
       break;
   }
 }
@@ -111,17 +118,17 @@
   switch (e.type) {
     case FeatureEntry::SINGLE_VALUE:
     case FeatureEntry::SINGLE_DISABLE_VALUE:
-      DCHECK_EQ(0, e.num_choices);
+      DCHECK_EQ(0, e.num_options);
       DCHECK(!e.choices);
       return true;
     case FeatureEntry::MULTI_VALUE:
-      DCHECK_GT(e.num_choices, 0);
+      DCHECK_GT(e.num_options, 0);
       DCHECK(e.choices);
-      DCHECK(e.choices[0].command_line_switch);
-      DCHECK_EQ('\0', e.choices[0].command_line_switch[0]);
+      DCHECK(e.ChoiceForOption(0).command_line_switch);
+      DCHECK_EQ('\0', e.ChoiceForOption(0).command_line_switch[0]);
       return true;
     case FeatureEntry::ENABLE_DISABLE_VALUE:
-      DCHECK_EQ(3, e.num_choices);
+      DCHECK_EQ(3, e.num_options);
       DCHECK(!e.choices);
       DCHECK(e.command_line_switch);
       DCHECK(e.command_line_value);
@@ -129,10 +136,17 @@
       DCHECK(e.disable_command_line_value);
       return true;
     case FeatureEntry::FEATURE_VALUE:
-      DCHECK_EQ(3, e.num_choices);
+      DCHECK_EQ(3, e.num_options);
       DCHECK(!e.choices);
       DCHECK(e.feature);
       return true;
+    case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
+      DCHECK_GT(e.num_options, 2);
+      DCHECK(!e.choices);
+      DCHECK(e.feature);
+      DCHECK(e.feature_variations);
+      DCHECK(e.feature_trial_name);
+      return true;
   }
   NOTREACHED();
   return false;
@@ -148,8 +162,9 @@
     case FeatureEntry::MULTI_VALUE:
     case FeatureEntry::ENABLE_DISABLE_VALUE:
     case FeatureEntry::FEATURE_VALUE:
-      for (int i = 0; i < entry.num_choices; ++i) {
-        if (enabled_entries.count(entry.NameForChoice(i)) > 0)
+    case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
+      for (int i = 0; i < entry.num_options; ++i) {
+        if (enabled_entries.count(entry.NameForOption(i)) > 0)
           return false;
       }
       return true;
@@ -159,23 +174,54 @@
 }
 
 // Returns the Value representing the choice data in the specified entry.
-base::Value* CreateChoiceData(const FeatureEntry& entry,
-                              const std::set<std::string>& enabled_entries) {
+base::Value* CreateOptionsData(const FeatureEntry& entry,
+                               const std::set<std::string>& enabled_entries) {
   DCHECK(entry.type == FeatureEntry::MULTI_VALUE ||
          entry.type == FeatureEntry::ENABLE_DISABLE_VALUE ||
-         entry.type == FeatureEntry::FEATURE_VALUE);
+         entry.type == FeatureEntry::FEATURE_VALUE ||
+         entry.type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE);
   base::ListValue* result = new base::ListValue;
-  for (int i = 0; i < entry.num_choices; ++i) {
+  for (int i = 0; i < entry.num_options; ++i) {
     std::unique_ptr<base::DictionaryValue> value(new base::DictionaryValue);
-    const std::string name = entry.NameForChoice(i);
+    const std::string name = entry.NameForOption(i);
     value->SetString("internal_name", name);
-    value->SetString("description", entry.DescriptionForChoice(i));
+    value->SetString("description", entry.DescriptionForOption(i));
     value->SetBoolean("selected", enabled_entries.count(name) > 0);
     result->Append(std::move(value));
   }
   return result;
 }
 
+// Registers variation parameters specified by |feature_variation| for the field
+// trial named |feature_trial_name|, unless a group for this trial has already
+// been created (e.g. via command-line switches that take precedence over
+// about:flags). In the trial, the function creates a new constant group called
+// |kTrialGroupAboutFlags|.
+void RegisterFeatureVariationParameters(
+    const std::string& feature_trial_name,
+    const FeatureEntry::FeatureVariation& feature_variation) {
+  std::map<std::string, std::string> params;
+  for (int i = 0; i < feature_variation.num_params; ++i) {
+    params[feature_variation.params[i].param_name] =
+        feature_variation.params[i].param_value;
+  }
+
+  bool success = variations::AssociateVariationParams(
+      feature_trial_name, internal::kTrialGroupAboutFlags, params);
+  if (success) {
+    // Successful association also means that no group is created and selected
+    // for the trial, yet. Thus, create the trial to select the group. This way,
+    // the parameters cannot get overwritten in later phases (such as from the
+    // server).
+    base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
+        feature_trial_name, internal::kTrialGroupAboutFlags);
+    if (!trial) {
+      DLOG(WARNING) << "Could not create the trial " << feature_trial_name
+                    << " with group " << internal::kTrialGroupAboutFlags;
+    }
+  }
+}
+
 }  // namespace
 
 // Keeps track of affected switches for each FeatureEntry, based on which
@@ -224,27 +270,33 @@
                          e.command_line_value, &name_to_switch_map);
         break;
       case FeatureEntry::MULTI_VALUE:
-        for (int j = 0; j < e.num_choices; ++j) {
-          AddSwitchMapping(e.NameForChoice(j), e.choices[j].command_line_switch,
-                           e.choices[j].command_line_value,
-                           &name_to_switch_map);
+        for (int j = 0; j < e.num_options; ++j) {
+          AddSwitchMapping(
+              e.NameForOption(j), e.ChoiceForOption(j).command_line_switch,
+              e.ChoiceForOption(j).command_line_value, &name_to_switch_map);
         }
         break;
       case FeatureEntry::ENABLE_DISABLE_VALUE:
-        AddSwitchMapping(e.NameForChoice(0), std::string(), std::string(),
+        AddSwitchMapping(e.NameForOption(0), std::string(), std::string(),
                          &name_to_switch_map);
-        AddSwitchMapping(e.NameForChoice(1), e.command_line_switch,
+        AddSwitchMapping(e.NameForOption(1), e.command_line_switch,
                          e.command_line_value, &name_to_switch_map);
-        AddSwitchMapping(e.NameForChoice(2), e.disable_command_line_switch,
+        AddSwitchMapping(e.NameForOption(2), e.disable_command_line_switch,
                          e.disable_command_line_value, &name_to_switch_map);
         break;
       case FeatureEntry::FEATURE_VALUE:
-        AddFeatureMapping(e.NameForChoice(0), std::string(), false,
-                          &name_to_switch_map);
-        AddFeatureMapping(e.NameForChoice(1), e.feature->name, true,
-                          &name_to_switch_map);
-        AddFeatureMapping(e.NameForChoice(2), e.feature->name, false,
-                          &name_to_switch_map);
+      case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
+        for (int j = 0; j < e.num_options; ++j) {
+          FeatureEntry::FeatureState state = e.StateForOption(j);
+          if (state == FeatureEntry::FeatureState::DEFAULT) {
+            AddFeatureMapping(e.NameForOption(j), std::string(), false,
+                              &name_to_switch_map);
+          } else {
+            AddFeatureMapping(e.NameForOption(j), e.feature->name,
+                              state == FeatureEntry::FeatureState::ENABLED,
+                              &name_to_switch_map);
+          }
+        }
         break;
     }
   }
@@ -305,11 +357,11 @@
   } else {
     if (enable) {
       // Enable the first choice.
-      needs_restart_ |= enabled_entries.insert(e->NameForChoice(0)).second;
+      needs_restart_ |= enabled_entries.insert(e->NameForOption(0)).second;
     } else {
       // Find the currently enabled choice and disable it.
-      for (int i = 0; i < e->num_choices; ++i) {
-        std::string choice_name = e->NameForChoice(i);
+      for (int i = 0; i < e->num_options; ++i) {
+        std::string choice_name = e->NameForOption(i);
         if (enabled_entries.find(choice_name) != enabled_entries.end()) {
           needs_restart_ = true;
           enabled_entries.erase(choice_name);
@@ -380,6 +432,38 @@
   appended_switches_.clear();
 }
 
+void FlagsState::RegisterAllFeatureVariationParameters(
+    FlagsStorage* flags_storage) {
+  std::set<std::string> enabled_entries;
+  GetSanitizedEnabledFlagsForCurrentPlatform(flags_storage, &enabled_entries);
+
+  for (size_t i = 0; i < num_feature_entries_; ++i) {
+    const FeatureEntry& e = feature_entries_[i];
+    if (e.type == FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE) {
+      for (int j = 0; j < e.num_options; ++j) {
+        const FeatureEntry::FeatureVariation* variation =
+            e.VariationForOption(j);
+        if (variation != nullptr && enabled_entries.count(e.NameForOption(j))) {
+          // If the option is selected by the user & has variation, register it.
+          RegisterFeatureVariationParameters(e.feature_trial_name, *variation);
+          // TODO(jkrcal) The code does not associate the feature with the field
+          // trial |e.feature_trial_name|. The reason is that features
+          // overridden in chrome://flags are translated to command-line flags
+          // and thus treated earlier in the initialization. The fix requires
+          // larger changes. As a result:
+          //  - the API calls to variations::GetVariationParamValueByFeature and
+          //    to variations::GetVariationParamsByFeature do not work; and
+          //  - the API call to base::FeatureList::IsEnabled does not mark the
+          //    field trial as active (and the trial does not appear in UMA).
+          // If the code calls variations::GetVariationParamValue or
+          // variations::GetVariationParams providing the trial name, everything
+          // should work fine.
+        }
+      }
+    }
+  }
+}
+
 void FlagsState::GetFlagFeatureEntries(
     FlagsStorage* flags_storage,
     FlagAccess access,
@@ -421,7 +505,8 @@
       case FeatureEntry::MULTI_VALUE:
       case FeatureEntry::ENABLE_DISABLE_VALUE:
       case FeatureEntry::FEATURE_VALUE:
-        data->Set("choices", CreateChoiceData(entry, enabled_entries));
+      case FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE:
+        data->Set("options", CreateOptionsData(entry, enabled_entries));
         break;
     }
 
diff --git a/components/flags_ui/flags_state.h b/components/flags_ui/flags_state.h
index e7d2ac1..6f0ff1f 100644
--- a/components/flags_ui/flags_state.h
+++ b/components/flags_ui/flags_state.h
@@ -21,6 +21,13 @@
 
 namespace flags_ui {
 
+// Internal functionality exposed for tests.
+namespace internal {
+// The trial group selected when feature variation parameters are registered via
+// FlagsState::RegisterFeatureVariationParameters().
+extern const char kTrialGroupAboutFlags[];
+}  // namespace internal
+
 struct FeatureEntry;
 class FlagsStorage;
 struct SwitchEntry;
@@ -56,6 +63,9 @@
   FlagsState(const FeatureEntry* feature_entries, size_t num_feature_entries);
   ~FlagsState();
 
+  // Reads the state from |flags_storage| and adds the command line flags
+  // belonging to the active feature entries to |command_line|. Features are
+  // appended via |enable_features_flag_name| and |disable_features_flag_name|.
   void ConvertFlagsToSwitches(FlagsStorage* flags_storage,
                               base::CommandLine* command_line,
                               SentinelsMode sentinels,
@@ -70,6 +80,10 @@
   void ResetAllFlags(FlagsStorage* flags_storage);
   void Reset();
 
+  // Registers variations parameter values stored in |flags_storage| (previously
+  // selected in about:flags).
+  void RegisterAllFeatureVariationParameters(FlagsStorage* flags_storage);
+
   // Gets the list of feature entries. Entries that are available for the
   // current platform are appended to |supported_entries|; all other entries are
   // appended to |unsupported_entries|.
diff --git a/components/flags_ui/flags_state_unittest.cc b/components/flags_ui/flags_state_unittest.cc
index 628331b..b95373a5 100644
--- a/components/flags_ui/flags_state_unittest.cc
+++ b/components/flags_ui/flags_state_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/feature_list.h"
 #include "base/format_macros.h"
 #include "base/macros.h"
+#include "base/metrics/field_trial.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
@@ -26,6 +27,7 @@
 #include "components/flags_ui/pref_service_flags_storage.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
+#include "components/variations/variations_associated_data.h"
 #include "grit/components_strings.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -40,6 +42,7 @@
 const char kFlags5[] = "flag5";
 const char kFlags6[] = "flag6";
 const char kFlags7[] = "flag7";
+const char kFlags8[] = "flag8";
 
 const char kSwitch1[] = "switch";
 const char kSwitch2[] = "switch2";
@@ -57,6 +60,26 @@
 const char kEnableFeatures[] = "dummy-enable-features";
 const char kDisableFeatures[] = "dummy-disable-features";
 
+const char kTestTrial[] = "TestTrial";
+const char kTestParam[] = "param";
+const char kTestParamValue1[] = "value1";
+const char kTestParamValue2[] = "value2";
+
+const base::Feature kTestFeature1{"FeatureName1",
+                                  base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kTestFeature2{"FeatureName2",
+                                  base::FEATURE_ENABLED_BY_DEFAULT};
+
+const FeatureEntry::FeatureParam kTestVariationDefault[] = {
+    {kTestParam, kTestParamValue1}};
+
+const FeatureEntry::FeatureParam kTestVariationOther[] = {
+    {kTestParam, kTestParamValue2}};
+
+const FeatureEntry::FeatureVariation kTestVariations[] = {
+    {"", kTestVariationDefault, 1},
+    {"dummy description", kTestVariationOther, 1}};
+
 // Those have to be valid ids for the translation system but the value are
 // never used, so pick one at random from the current component.
 const int kDummyNameId = IDS_FLAGS_UI_WARNING_HEADER;
@@ -74,44 +97,45 @@
     {kDummyDescriptionId, kMultiSwitch2, kValueForMultiSwitch2},
 };
 
-const base::Feature kTestFeature{"FeatureName",
-                                 base::FEATURE_ENABLED_BY_DEFAULT};
-
 // The entries that are set for these tests. The 3rd entry is not supported on
 // the current platform, all others are.
 static FeatureEntry kEntries[] = {
     {kFlags1, kDummyNameId, kDummyDescriptionId,
      0,  // Ends up being mapped to the current platform.
-     FeatureEntry::SINGLE_VALUE, kSwitch1, "", nullptr, nullptr, nullptr,
-     nullptr, 0},
+     FeatureEntry::SINGLE_VALUE, kSwitch1, "", nullptr, nullptr, nullptr, 0,
+     nullptr, nullptr, nullptr},
     {kFlags2, kDummyNameId, kDummyDescriptionId,
      0,  // Ends up being mapped to the current platform.
      FeatureEntry::SINGLE_VALUE, kSwitch2, kValueForSwitch2, nullptr, nullptr,
-     nullptr, nullptr, 0},
+     nullptr, 0, nullptr, nullptr, nullptr},
     {kFlags3, kDummyNameId, kDummyDescriptionId,
      0,  // This ends up enabling for an OS other than the current.
-     FeatureEntry::SINGLE_VALUE, kSwitch3, "", nullptr, nullptr, nullptr,
-     nullptr, 0},
+     FeatureEntry::SINGLE_VALUE, kSwitch3, "", nullptr, nullptr, nullptr, 0,
+     nullptr, nullptr, nullptr},
     {kFlags4, kDummyNameId, kDummyDescriptionId,
      0,  // Ends up being mapped to the current platform.
-     FeatureEntry::MULTI_VALUE, "", "", "", "", nullptr, kMultiChoices,
-     arraysize(kMultiChoices)},
+     FeatureEntry::MULTI_VALUE, "", "", "", "", nullptr,
+     arraysize(kMultiChoices), kMultiChoices, nullptr, nullptr},
     {kFlags5, kDummyNameId, kDummyDescriptionId,
      0,  // Ends up being mapped to the current platform.
      FeatureEntry::ENABLE_DISABLE_VALUE, kSwitch1, kEnableDisableValue1,
-     kSwitch2, kEnableDisableValue2, nullptr, nullptr, 3},
+     kSwitch2, kEnableDisableValue2, nullptr, 3, nullptr, nullptr, nullptr},
     {kFlags6, kDummyNameId, kDummyDescriptionId, 0,
      FeatureEntry::SINGLE_DISABLE_VALUE, kSwitch6, "", nullptr, nullptr,
-     nullptr, nullptr, 0},
+     nullptr, 0, nullptr, nullptr, nullptr},
     {kFlags7, kDummyNameId, kDummyDescriptionId,
      0,  // Ends up being mapped to the current platform.
      FeatureEntry::FEATURE_VALUE, nullptr, nullptr, nullptr, nullptr,
-     &kTestFeature, nullptr, 3},
+     &kTestFeature1, 3, nullptr, nullptr, nullptr},
+    {kFlags8, kDummyNameId, kDummyDescriptionId,
+     0,  // Ends up being mapped to the current platform.
+     FeatureEntry::FEATURE_WITH_VARIATIONS_VALUE, nullptr, nullptr, nullptr,
+     nullptr, &kTestFeature2, 4, nullptr, kTestVariations, kTestTrial},
 };
 
 class FlagsStateTest : public ::testing::Test {
  protected:
-  FlagsStateTest() : flags_storage_(&prefs_) {
+  FlagsStateTest() : flags_storage_(&prefs_), trial_list_(nullptr) {
     prefs_.registry()->RegisterListPref(prefs::kEnabledLabsExperiments);
 
     for (size_t i = 0; i < arraysize(kEntries); ++i)
@@ -127,6 +151,7 @@
   TestingPrefServiceSimple prefs_;
   PrefServiceFlagsStorage flags_storage_;
   std::unique_ptr<FlagsState> flags_state_;
+  base::FieldTrialList trial_list_;
 };
 
 TEST_F(FlagsStateTest, NoChangeNoRestart) {
@@ -157,13 +182,13 @@
   ASSERT_EQ(kFlags4, entry.internal_name);
   EXPECT_FALSE(flags_state_->IsRestartNeededToCommitChanges());
   // Enable the 2nd choice of the multi-value.
-  flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForChoice(2),
+  flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForOption(2),
                                        true);
   EXPECT_TRUE(flags_state_->IsRestartNeededToCommitChanges());
   flags_state_->Reset();
   EXPECT_FALSE(flags_state_->IsRestartNeededToCommitChanges());
   // Enable the default choice now.
-  flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForChoice(0),
+  flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForOption(0),
                                        true);
   EXPECT_TRUE(flags_state_->IsRestartNeededToCommitChanges());
 }
@@ -241,6 +266,42 @@
   EXPECT_FALSE(command_line2.HasSwitch(switches::kFlagSwitchesEnd));
 }
 
+TEST_F(FlagsStateTest, RegisterAllFeatureVariationParameters) {
+  const FeatureEntry& entry = kEntries[7];
+  // Select the "Disabled" variation.
+  flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForOption(0),
+                                       true);
+  flags_state_->RegisterAllFeatureVariationParameters(&flags_storage_);
+  // No value should be associated.
+  EXPECT_EQ("", variations::GetVariationParamValue(kTestTrial, kTestParam));
+  // The trial should not be created.
+  base::FieldTrial* trial = base::FieldTrialList::Find(kTestTrial);
+  EXPECT_EQ(nullptr, trial);
+
+  // Select the first "Enabled" variation.
+  flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForOption(1),
+                                       true);
+
+  flags_state_->RegisterAllFeatureVariationParameters(&flags_storage_);
+  // The value should be associated.
+  EXPECT_EQ(kTestParamValue1,
+            variations::GetVariationParamValue(kTestTrial, kTestParam));
+
+  // The trial should be created.
+  trial = base::FieldTrialList::Find(kTestTrial);
+  EXPECT_NE(nullptr, trial);
+  // The about:flags group should be selected for the trial.
+  EXPECT_EQ(internal::kTrialGroupAboutFlags, trial->group_name());
+
+  // Select the second "Enabled" variation.
+  flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForOption(2),
+                                       true);
+  flags_state_->RegisterAllFeatureVariationParameters(&flags_storage_);
+  // Associating for the second time should not change the value.
+  EXPECT_EQ(kTestParamValue1,
+            variations::GetVariationParamValue(kTestTrial, kTestParam));
+}
+
 base::CommandLine::StringType CreateSwitch(const std::string& value) {
 #if defined(OS_WIN)
   return base::ASCIIToUTF16(value);
@@ -349,11 +410,11 @@
       {0, nullptr, nullptr, nullptr, nullptr},
       {0, "A,B", "C", "A,B", "C"},
       // "Enable" option: should only affect enabled list.
-      {1, nullptr, nullptr, "FeatureName", nullptr},
-      {1, "A,B", "C", "A,B,FeatureName", "C"},
+      {1, nullptr, nullptr, "FeatureName1", nullptr},
+      {1, "A,B", "C", "A,B,FeatureName1", "C"},
       // "Disable" option: should only affect disabled list.
-      {2, nullptr, nullptr, nullptr, "FeatureName"},
-      {2, "A,B", "C", "A,B", "C,FeatureName"},
+      {2, nullptr, nullptr, nullptr, "FeatureName1"},
+      {2, "A,B", "C", "A,B", "C,FeatureName1"},
   };
 
   for (size_t i = 0; i < arraysize(cases); ++i) {
@@ -515,7 +576,7 @@
   }
 
   // Enable the 2nd choice of the multi-value.
-  flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForChoice(2),
+  flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForOption(2),
                                        true);
   {
     base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
@@ -529,7 +590,7 @@
   }
 
   // Disable the multi-value entry.
-  flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForChoice(0),
+  flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForOption(0),
                                        true);
   {
     base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
@@ -588,7 +649,7 @@
   }
 
   // "Enable" option selected.
-  flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForChoice(1),
+  flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForOption(1),
                                        true);
   {
     base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
@@ -601,7 +662,7 @@
   }
 
   // "Disable" option selected.
-  flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForChoice(2),
+  flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForOption(2),
                                        true);
   {
     base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
@@ -614,7 +675,7 @@
   }
 
   // "Default" option selected, same as nothing selected.
-  flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForChoice(0),
+  flags_state_->SetFeatureEntryEnabled(&flags_storage_, entry.NameForOption(0),
                                        true);
   {
     base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
@@ -642,13 +703,13 @@
       // "Default" option selected, same as nothing selected.
       {0, nullptr, nullptr, "", ""},
       // "Enable" option selected.
-      {1, nullptr, nullptr, "FeatureName", ""},
+      {1, nullptr, nullptr, "FeatureName1", ""},
       // "Disable" option selected.
-      {2, nullptr, nullptr, "", "FeatureName"},
+      {2, nullptr, nullptr, "", "FeatureName1"},
       // "Enable" option should get added to the existing list.
-      {1, "Foo,Bar", nullptr, "Foo,Bar,FeatureName", ""},
+      {1, "Foo,Bar", nullptr, "Foo,Bar,FeatureName1", ""},
       // "Disable" option should get added to the existing list.
-      {2, nullptr, "Foo,Bar", "", "Foo,Bar,FeatureName"},
+      {2, nullptr, "Foo,Bar", "", "Foo,Bar,FeatureName1"},
   };
 
   for (size_t i = 0; i < arraysize(cases); ++i) {
@@ -661,7 +722,7 @@
 
     if (cases[i].enabled_choice != -1) {
       flags_state_->SetFeatureEntryEnabled(
-          &flags_storage_, entry.NameForChoice(cases[i].enabled_choice), true);
+          &flags_storage_, entry.NameForOption(cases[i].enabled_choice), true);
     }
 
     base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
@@ -691,7 +752,7 @@
                                       &supported_entries, &unsupported_entries,
                                       base::Bind(&SkipFeatureEntry));
   // All |kEntries| except for |kFlags3| should be supported.
-  EXPECT_EQ(6u, supported_entries.GetSize());
+  EXPECT_EQ(7u, supported_entries.GetSize());
   EXPECT_EQ(1u, unsupported_entries.GetSize());
   EXPECT_EQ(arraysize(kEntries),
             supported_entries.GetSize() + unsupported_entries.GetSize());
diff --git a/components/flags_ui/resources/flags.html b/components/flags_ui/resources/flags.html
index b29c25a..aca6d35d 100644
--- a/components/flags_ui/resources/flags.html
+++ b/components/flags_ui/resources/flags.html
@@ -75,12 +75,12 @@
                    jsvalues="href: '#' + internal_name"
                    jscontent="'#' + internal_name"></a>
               </div>
-              <div jsdisplay="choices && choices.length > 0">
+              <div jsdisplay="options && options.length > 0">
                 <select
                   class="experiment-select"
                   jsvalues=".internal_name:internal_name;.disabled:!enabled">
                   <option jsvalues=".selected:selected"
-                          jsselect="choices"
+                          jsselect="options"
                           jscontent="description">NAME
                   </option>
                 </select>
diff --git a/components/image_fetcher/image_fetcher_delegate.h b/components/image_fetcher/image_fetcher_delegate.h
index dc5b83f..38d66b2 100644
--- a/components/image_fetcher/image_fetcher_delegate.h
+++ b/components/image_fetcher/image_fetcher_delegate.h
@@ -5,9 +5,9 @@
 #ifndef COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_DELEGATE_H_
 #define COMPONENTS_IMAGE_FETCHER_IMAGE_FETCHER_DELEGATE_H_
 
-#include "base/macros.h"
+#include <string>
 
-class GURL;
+#include "base/macros.h"
 
 namespace gfx {
 class Image;
@@ -19,11 +19,18 @@
  public:
   ImageFetcherDelegate() {}
 
-  // Called when an image was fetched. |id| is an identifier for the fetch (as
-  // passed to ImageFetcher::StartOrQueueNetworkRequest); |image| stores image
-  // data owned by the caller, and can be an empty gfx::Image.
+  // Called when the data for an image was fetched. |id| is an identifier for
+  // the fetch (as passed to ImageFetcher::StartOrQueueNetworkRequest); |data|
+  // stores (generally compressed) image data owned by the caller, and can be
+  // empty if the fetch failed.
+  virtual void OnImageDataFetched(const std::string& id,
+                                  const std::string& data) {};
+
+  // Called when an image was fetched and decoded. |id| is an identifier for the
+  // fetch (as passed to ImageFetcher::StartOrQueueNetworkRequest); |image|
+  // stores image data owned by the caller, and can be an empty gfx::Image.
   virtual void OnImageFetched(const std::string& id,
-                              const gfx::Image& image) = 0;
+                              const gfx::Image& image) {};
 
  protected:
   virtual ~ImageFetcherDelegate() {}
diff --git a/components/ntp_snippets/ntp_snippets_database.cc b/components/ntp_snippets/ntp_snippets_database.cc
index c1b66be..9feeacdff 100644
--- a/components/ntp_snippets/ntp_snippets_database.cc
+++ b/components/ntp_snippets/ntp_snippets_database.cc
@@ -18,6 +18,10 @@
 // synchronize with histograms.xml, AND will also become incompatible with older
 // browsers still reporting the previous values.
 const char kDatabaseUMAClientName[] = "NTPSnippets";
+const char kImageDatabaseUMAClientName[] = "NTPSnippetImages";
+
+const char kSnippetDatabaseFolder[] = "snippets";
+const char kImageDatabaseFolder[] = "images";
 }
 
 namespace ntp_snippets {
@@ -26,67 +30,116 @@
     const base::FilePath& database_dir,
     scoped_refptr<base::SequencedTaskRunner> file_task_runner)
     : database_(
-          new ProtoDatabaseImpl<SnippetProto>(std::move(file_task_runner))),
+          new ProtoDatabaseImpl<SnippetProto>(file_task_runner)),
       database_initialized_(false),
+      image_database_(
+          new ProtoDatabaseImpl<SnippetImageProto>(file_task_runner)),
+      image_database_initialized_(false),
       weak_ptr_factory_(this) {
-  database_->Init(kDatabaseUMAClientName, database_dir,
+  base::FilePath snippet_dir = database_dir.AppendASCII(kSnippetDatabaseFolder);
+  database_->Init(kDatabaseUMAClientName, snippet_dir,
                   base::Bind(&NTPSnippetsDatabase::OnDatabaseInited,
                              weak_ptr_factory_.GetWeakPtr()));
+
+  base::FilePath image_dir = database_dir.AppendASCII(kImageDatabaseFolder);
+  image_database_->Init(kImageDatabaseUMAClientName, image_dir,
+                        base::Bind(&NTPSnippetsDatabase::OnImageDatabaseInited,
+                                   weak_ptr_factory_.GetWeakPtr()));
 }
 
 NTPSnippetsDatabase::~NTPSnippetsDatabase() {}
 
-void NTPSnippetsDatabase::Load(const SnippetsLoadedCallback& callback) {
-  if (database_ && database_initialized_)
-    LoadImpl(callback);
-  else
-    pending_load_callbacks_.emplace_back(callback);
+bool NTPSnippetsDatabase::IsInitialized() const {
+  return database_ && database_initialized_ && image_database_ &&
+      image_database_initialized_;
 }
 
-void NTPSnippetsDatabase::Save(const NTPSnippet& snippet) {
+void NTPSnippetsDatabase::LoadSnippets(const SnippetsCallback& callback) {
+  if (IsInitialized())
+    LoadSnippetsImpl(callback);
+  else
+    pending_snippets_callbacks_.emplace_back(callback);
+}
+
+void NTPSnippetsDatabase::SaveSnippet(const NTPSnippet& snippet) {
   std::unique_ptr<KeyEntryVector> entries_to_save(new KeyEntryVector());
   entries_to_save->emplace_back(snippet.id(), snippet.ToProto());
-  SaveImpl(std::move(entries_to_save));
+  SaveSnippetsImpl(std::move(entries_to_save));
 }
 
-void NTPSnippetsDatabase::Save(const NTPSnippet::PtrVector& snippets) {
+void NTPSnippetsDatabase::SaveSnippets(const NTPSnippet::PtrVector& snippets) {
   std::unique_ptr<KeyEntryVector> entries_to_save(new KeyEntryVector());
   for (const std::unique_ptr<NTPSnippet>& snippet : snippets)
     entries_to_save->emplace_back(snippet->id(), snippet->ToProto());
-  SaveImpl(std::move(entries_to_save));
+  SaveSnippetsImpl(std::move(entries_to_save));
 }
 
-void NTPSnippetsDatabase::Delete(const std::string& snippet_id) {
-  DeleteImpl(base::WrapUnique(new std::vector<std::string>(1, snippet_id)));
+void NTPSnippetsDatabase::DeleteSnippet(const std::string& snippet_id) {
+  DeleteSnippetsImpl(
+      base::WrapUnique(new std::vector<std::string>(1, snippet_id)));
 }
 
-void NTPSnippetsDatabase::Delete(const NTPSnippet::PtrVector& snippets) {
+void NTPSnippetsDatabase::DeleteSnippets(
+    const NTPSnippet::PtrVector& snippets) {
   std::unique_ptr<std::vector<std::string>> keys_to_remove(
       new std::vector<std::string>());
   for (const std::unique_ptr<NTPSnippet>& snippet : snippets)
     keys_to_remove->emplace_back(snippet->id());
-  DeleteImpl(std::move(keys_to_remove));
+  DeleteSnippetsImpl(std::move(keys_to_remove));
+}
+
+void NTPSnippetsDatabase::LoadImage(const std::string& snippet_id,
+                                    const SnippetImageCallback& callback) {
+  if (IsInitialized())
+    LoadImageImpl(snippet_id, callback);
+  else
+    pending_image_callbacks_.emplace_back(snippet_id, callback);
+}
+
+void NTPSnippetsDatabase::SaveImage(const std::string& snippet_id,
+                                    const std::string& image_data) {
+  // TODO(treib): After we pass errors to the client, DCHECK(IsInitialized()).
+  if (!IsInitialized())
+    return;
+
+  SnippetImageProto image_proto;
+  image_proto.set_data(image_data);
+
+  std::unique_ptr<ImageKeyEntryVector> entries_to_save(
+      new ImageKeyEntryVector());
+  entries_to_save->emplace_back(snippet_id, std::move(image_proto));
+
+  image_database_->UpdateEntries(
+      std::move(entries_to_save),
+      base::WrapUnique(new std::vector<std::string>()),
+      base::Bind(&NTPSnippetsDatabase::OnImageDatabaseSaved,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+void NTPSnippetsDatabase::DeleteImage(const std::string& snippet_id) {
+  DeleteImagesImpl(
+      base::WrapUnique(new std::vector<std::string>(1, snippet_id)));
 }
 
 void NTPSnippetsDatabase::OnDatabaseInited(bool success) {
   DCHECK(!database_initialized_);
   if (!success) {
     DVLOG(1) << "NTPSnippetsDatabase init failed.";
-    database_.reset();
+    ResetDatabases();
     return;
   }
   database_initialized_ = true;
-  for (const SnippetsLoadedCallback& callback : pending_load_callbacks_)
-    LoadImpl(callback);
+  if (IsInitialized())
+    ProcessPendingLoads();
 }
 
 void NTPSnippetsDatabase::OnDatabaseLoaded(
-    const SnippetsLoadedCallback& callback,
+    const SnippetsCallback& callback,
     bool success,
     std::unique_ptr<std::vector<SnippetProto>> entries) {
   if (!success) {
     DVLOG(1) << "NTPSnippetsDatabase load failed.";
-    database_.reset();
+    ResetDatabases();
     return;
   }
 
@@ -109,27 +162,77 @@
   // If any of the snippet protos couldn't be converted to actual snippets,
   // clean them up now.
   if (!keys_to_remove->empty())
-    DeleteImpl(std::move(keys_to_remove));
+    DeleteSnippetsImpl(std::move(keys_to_remove));
 }
 
 void NTPSnippetsDatabase::OnDatabaseSaved(bool success) {
   if (!success) {
     DVLOG(1) << "NTPSnippetsDatabase save failed.";
-    database_.reset();
+    ResetDatabases();
   }
 }
 
-void NTPSnippetsDatabase::LoadImpl(const SnippetsLoadedCallback& callback) {
-  DCHECK(database_);
-  DCHECK(database_initialized_);
+void NTPSnippetsDatabase::OnImageDatabaseInited(bool success) {
+  DCHECK(!image_database_initialized_);
+  if (!success) {
+    DVLOG(1) << "NTPSnippetsDatabase init failed.";
+    ResetDatabases();
+    return;
+  }
+  image_database_initialized_ = true;
+  if (IsInitialized())
+    ProcessPendingLoads();
+}
+
+void NTPSnippetsDatabase::OnImageDatabaseLoaded(
+    const SnippetImageCallback& callback,
+    bool success,
+    std::unique_ptr<SnippetImageProto> entry) {
+  if (!success) {
+    DVLOG(1) << "NTPSnippetsDatabase load failed.";
+    ResetDatabases();
+    return;
+  }
+
+  if (!entry) {
+    callback.Run(std::string());
+    return;
+  }
+
+  std::unique_ptr<std::string> data(entry->release_data());
+  callback.Run(std::move(*data));
+}
+
+void NTPSnippetsDatabase::OnImageDatabaseSaved(bool success) {
+  if (!success) {
+    DVLOG(1) << "NTPSnippetsDatabase save failed.";
+    ResetDatabases();
+  }
+}
+
+void NTPSnippetsDatabase::ProcessPendingLoads() {
+  DCHECK(IsInitialized());
+
+  for (const auto& callback : pending_snippets_callbacks_)
+    LoadSnippetsImpl(callback);
+  pending_snippets_callbacks_.clear();
+
+  for (const auto& id_callback : pending_image_callbacks_)
+    LoadImageImpl(id_callback.first, id_callback.second);
+  pending_image_callbacks_.clear();
+}
+
+void NTPSnippetsDatabase::LoadSnippetsImpl(const SnippetsCallback& callback) {
+  DCHECK(IsInitialized());
   database_->LoadEntries(base::Bind(&NTPSnippetsDatabase::OnDatabaseLoaded,
                                     weak_ptr_factory_.GetWeakPtr(),
                                     callback));
 }
 
-void NTPSnippetsDatabase::SaveImpl(
+void NTPSnippetsDatabase::SaveSnippetsImpl(
     std::unique_ptr<KeyEntryVector> entries_to_save) {
-  if (!database_ || !database_initialized_)
+  // TODO(treib): After we pass errors to the client, DCHECK(IsInitialized()).
+  if (!IsInitialized())
     return;
 
   std::unique_ptr<std::vector<std::string>> keys_to_remove(
@@ -140,11 +243,15 @@
                                       weak_ptr_factory_.GetWeakPtr()));
 }
 
-void NTPSnippetsDatabase::DeleteImpl(
+void NTPSnippetsDatabase::DeleteSnippetsImpl(
     std::unique_ptr<std::vector<std::string>> keys_to_remove) {
-  if (!database_ || !database_initialized_)
+  // TODO(treib): After we pass errors to the client, DCHECK(IsInitialized()).
+  if (!IsInitialized())
     return;
 
+  DeleteImagesImpl(
+      base::WrapUnique(new std::vector<std::string>(*keys_to_remove)));
+
   std::unique_ptr<KeyEntryVector> entries_to_save(new KeyEntryVector());
   database_->UpdateEntries(std::move(entries_to_save),
                            std::move(keys_to_remove),
@@ -152,4 +259,31 @@
                                       weak_ptr_factory_.GetWeakPtr()));
 }
 
+void NTPSnippetsDatabase::LoadImageImpl(const std::string& snippet_id,
+                                        const SnippetImageCallback& callback) {
+  DCHECK(IsInitialized());
+  image_database_->GetEntry(
+      snippet_id,
+      base::Bind(&NTPSnippetsDatabase::OnImageDatabaseLoaded,
+                 weak_ptr_factory_.GetWeakPtr(), callback));
+}
+
+void NTPSnippetsDatabase::DeleteImagesImpl(
+    std::unique_ptr<std::vector<std::string>> keys_to_remove) {
+  // TODO(treib): After we pass errors to the client, DCHECK(IsInitialized()).
+  if (!IsInitialized())
+    return;
+
+  image_database_->UpdateEntries(
+      base::WrapUnique(new ImageKeyEntryVector()),
+      std::move(keys_to_remove),
+      base::Bind(&NTPSnippetsDatabase::OnImageDatabaseSaved,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+void NTPSnippetsDatabase::ResetDatabases() {
+  database_.reset();
+  image_database_.reset();
+}
+
 }  // namespace ntp_snippets
diff --git a/components/ntp_snippets/ntp_snippets_database.h b/components/ntp_snippets/ntp_snippets_database.h
index f421b20..336dad0 100644
--- a/components/ntp_snippets/ntp_snippets_database.h
+++ b/components/ntp_snippets/ntp_snippets_database.h
@@ -23,29 +23,47 @@
 
 namespace ntp_snippets {
 
+class SnippetImageProto;
 class SnippetProto;
 
 class NTPSnippetsDatabase {
  public:
-  using SnippetsLoadedCallback = base::Callback<void(NTPSnippet::PtrVector)>;
+  using SnippetsCallback = base::Callback<void(NTPSnippet::PtrVector)>;
+  using SnippetImageCallback = base::Callback<void(std::string)>;
 
   NTPSnippetsDatabase(
       const base::FilePath& database_dir,
       scoped_refptr<base::SequencedTaskRunner> file_task_runner);
   ~NTPSnippetsDatabase();
 
+  // Returns whether the database has finished initialization. While this is
+  // false, loads may already be started (they'll be serviced after
+  // initialization finishes), but no updates are allowed.
+  bool IsInitialized() const;
+
   // Loads all snippets from storage and passes them to |callback|.
-  void Load(const SnippetsLoadedCallback& callback);
+  void LoadSnippets(const SnippetsCallback& callback);
 
   // Adds or updates the given snippet.
-  void Save(const NTPSnippet& snippet);
+  void SaveSnippet(const NTPSnippet& snippet);
   // Adds or updates all the given snippets.
-  void Save(const NTPSnippet::PtrVector& snippets);
+  void SaveSnippets(const NTPSnippet::PtrVector& snippets);
 
-  // Deletes the snippet with the given ID.
-  void Delete(const std::string& snippet_id);
-  // Deletes all the given snippets (identified by their IDs).
-  void Delete(const NTPSnippet::PtrVector& snippets);
+  // Deletes the snippet with the given ID, and its image.
+  void DeleteSnippet(const std::string& snippet_id);
+  // Deletes all the given snippets (identified by their IDs) and their images.
+  void DeleteSnippets(const NTPSnippet::PtrVector& snippets);
+
+  // Loads the image data for the snippet with the given ID and passes it to
+  // |callback|. Passes an empty string if not found.
+  void LoadImage(const std::string& snippet_id,
+                 const SnippetImageCallback& callback);
+
+  // Adds or updates the image data for the given snippet ID.
+  void SaveImage(const std::string& snippet_id, const std::string& image_data);
+
+  // Deletes the image data for the given snippet ID.
+  void DeleteImage(const std::string& snippet_id);
 
  private:
   friend class NTPSnippetsDatabaseTest;
@@ -53,23 +71,46 @@
   using KeyEntryVector =
       leveldb_proto::ProtoDatabase<SnippetProto>::KeyEntryVector;
 
-  // Callbacks for ProtoDatabase operations.
+  using ImageKeyEntryVector =
+      leveldb_proto::ProtoDatabase<SnippetImageProto>::KeyEntryVector;
+
+  // Callbacks for ProtoDatabase<SnippetProto> operations.
   void OnDatabaseInited(bool success);
-  void OnDatabaseLoaded(const SnippetsLoadedCallback& callback,
+  void OnDatabaseLoaded(const SnippetsCallback& callback,
                         bool success,
                         std::unique_ptr<std::vector<SnippetProto>> entries);
   void OnDatabaseSaved(bool success);
 
-  void LoadImpl(const SnippetsLoadedCallback& callback);
+  // Callbacks for ProtoDatabase<SnippetImageProto> operations.
+  void OnImageDatabaseInited(bool success);
+  void OnImageDatabaseLoaded(const SnippetImageCallback& callback,
+                             bool success,
+                             std::unique_ptr<SnippetImageProto> entry);
+  void OnImageDatabaseSaved(bool success);
 
-  void SaveImpl(std::unique_ptr<KeyEntryVector> entries_to_save);
+  void ProcessPendingLoads();
 
-  void DeleteImpl(std::unique_ptr<std::vector<std::string>> keys_to_remove);
+  void LoadSnippetsImpl(const SnippetsCallback& callback);
+  void SaveSnippetsImpl(std::unique_ptr<KeyEntryVector> entries_to_save);
+  void DeleteSnippetsImpl(
+      std::unique_ptr<std::vector<std::string>> keys_to_remove);
+
+  void LoadImageImpl(const std::string& snippet_id,
+                     const SnippetImageCallback& callback);
+  void DeleteImagesImpl(
+      std::unique_ptr<std::vector<std::string>> keys_to_remove);
+
+  void ResetDatabases();
 
   std::unique_ptr<leveldb_proto::ProtoDatabase<SnippetProto>> database_;
   bool database_initialized_;
+  std::vector<SnippetsCallback> pending_snippets_callbacks_;
 
-  std::vector<SnippetsLoadedCallback> pending_load_callbacks_;
+  std::unique_ptr<leveldb_proto::ProtoDatabase<SnippetImageProto>>
+      image_database_;
+  bool image_database_initialized_;
+  std::vector<std::pair<std::string, SnippetImageCallback>>
+      pending_image_callbacks_;
 
   base::WeakPtrFactory<NTPSnippetsDatabase> weak_ptr_factory_;
 
diff --git a/components/ntp_snippets/ntp_snippets_database_unittest.cc b/components/ntp_snippets/ntp_snippets_database_unittest.cc
index c9f7dcc..5a7cf570 100644
--- a/components/ntp_snippets/ntp_snippets_database_unittest.cc
+++ b/components/ntp_snippets/ntp_snippets_database_unittest.cc
@@ -80,8 +80,6 @@
 
   NTPSnippetsDatabase* db() { return db_.get(); }
 
-  bool db_inited() { return db_->database_initialized_; }
-
   void OnSnippetsLoaded(NTPSnippet::PtrVector snippets) {
     OnSnippetsLoadedImpl(snippets);
   }
@@ -101,36 +99,36 @@
   ASSERT_FALSE(db());
 
   CreateDatabase();
-  EXPECT_FALSE(db_inited());
+  EXPECT_FALSE(db()->IsInitialized());
 
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(db_inited());
+  EXPECT_TRUE(db()->IsInitialized());
 }
 
 TEST_F(NTPSnippetsDatabaseTest, LoadBeforeInit) {
   CreateDatabase();
-  EXPECT_FALSE(db_inited());
+  EXPECT_FALSE(db()->IsInitialized());
 
-  db()->Load(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
-                        base::Unretained(this)));
+  db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
+                                base::Unretained(this)));
 
   EXPECT_CALL(*this, OnSnippetsLoadedImpl(_));
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(db_inited());
+  EXPECT_TRUE(db()->IsInitialized());
 }
 
 TEST_F(NTPSnippetsDatabaseTest, LoadAfterInit) {
   CreateDatabase();
-  EXPECT_FALSE(db_inited());
+  EXPECT_FALSE(db()->IsInitialized());
 
   EXPECT_CALL(*this, OnSnippetsLoadedImpl(_)).Times(0);
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(db_inited());
+  EXPECT_TRUE(db()->IsInitialized());
 
   Mock::VerifyAndClearExpectations(this);
 
-  db()->Load(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
-                        base::Unretained(this)));
+  db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
+                                base::Unretained(this)));
 
   EXPECT_CALL(*this, OnSnippetsLoadedImpl(_));
   base::RunLoop().RunUntilIdle();
@@ -139,15 +137,15 @@
 TEST_F(NTPSnippetsDatabaseTest, Save) {
   CreateDatabase();
   base::RunLoop().RunUntilIdle();
-  ASSERT_TRUE(db_inited());
+  ASSERT_TRUE(db()->IsInitialized());
 
   std::unique_ptr<NTPSnippet> snippet = CreateTestSnippet();
 
-  db()->Save(*snippet);
+  db()->SaveSnippet(*snippet);
   base::RunLoop().RunUntilIdle();
 
-  db()->Load(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
-                        base::Unretained(this)));
+  db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
+                                base::Unretained(this)));
 
   EXPECT_CALL(*this,
               OnSnippetsLoadedImpl(ElementsAre(SnippetEq(snippet.get()))));
@@ -158,8 +156,8 @@
   // The snippet should still exist after recreating the database.
   CreateDatabase();
 
-  db()->Load(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
-                        base::Unretained(this)));
+  db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
+                                base::Unretained(this)));
 
   EXPECT_CALL(*this,
               OnSnippetsLoadedImpl(ElementsAre(SnippetEq(snippet.get()))));
@@ -169,21 +167,21 @@
 TEST_F(NTPSnippetsDatabaseTest, Update) {
   CreateDatabase();
   base::RunLoop().RunUntilIdle();
-  ASSERT_TRUE(db_inited());
+  ASSERT_TRUE(db()->IsInitialized());
 
   std::unique_ptr<NTPSnippet> snippet = CreateTestSnippet();
 
-  db()->Save(*snippet);
+  db()->SaveSnippet(*snippet);
   base::RunLoop().RunUntilIdle();
 
   const std::string text("some text");
   snippet->set_snippet(text);
 
-  db()->Save(*snippet);
+  db()->SaveSnippet(*snippet);
   base::RunLoop().RunUntilIdle();
 
-  db()->Load(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
-                        base::Unretained(this)));
+  db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
+                                base::Unretained(this)));
 
   EXPECT_CALL(*this,
               OnSnippetsLoadedImpl(ElementsAre(SnippetEq(snippet.get()))));
@@ -193,18 +191,18 @@
 TEST_F(NTPSnippetsDatabaseTest, Delete) {
   CreateDatabase();
   base::RunLoop().RunUntilIdle();
-  ASSERT_TRUE(db_inited());
+  ASSERT_TRUE(db()->IsInitialized());
 
   std::unique_ptr<NTPSnippet> snippet = CreateTestSnippet();
 
-  db()->Save(*snippet);
+  db()->SaveSnippet(*snippet);
   base::RunLoop().RunUntilIdle();
 
-  db()->Delete(snippet->id());
+  db()->DeleteSnippet(snippet->id());
   base::RunLoop().RunUntilIdle();
 
-  db()->Load(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
-                        base::Unretained(this)));
+  db()->LoadSnippets(base::Bind(&NTPSnippetsDatabaseTest::OnSnippetsLoaded,
+                                base::Unretained(this)));
 
   EXPECT_CALL(*this, OnSnippetsLoadedImpl(IsEmpty()));
   base::RunLoop().RunUntilIdle();
diff --git a/components/ntp_snippets/ntp_snippets_service.cc b/components/ntp_snippets/ntp_snippets_service.cc
index 040c1c8..bf55467f 100644
--- a/components/ntp_snippets/ntp_snippets_service.cc
+++ b/components/ntp_snippets/ntp_snippets_service.cc
@@ -19,6 +19,7 @@
 #include "base/task_runner_util.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "components/image_fetcher/image_decoder.h"
 #include "components/image_fetcher/image_fetcher.h"
 #include "components/ntp_snippets/ntp_snippets_constants.h"
 #include "components/ntp_snippets/ntp_snippets_database.h"
@@ -31,6 +32,7 @@
 #include "components/variations/variations_associated_data.h"
 #include "ui/gfx/image/image.h"
 
+using image_fetcher::ImageDecoder;
 using image_fetcher::ImageFetcher;
 using suggestions::ChromeSuggestion;
 using suggestions::SuggestionsProfile;
@@ -186,6 +188,7 @@
     NTPSnippetsScheduler* scheduler,
     std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher,
     std::unique_ptr<ImageFetcher> image_fetcher,
+    std::unique_ptr<ImageDecoder> image_decoder,
     std::unique_ptr<NTPSnippetsDatabase> database)
     : state_(State::NOT_INITED),
       explicitly_disabled_(!enabled),
@@ -197,6 +200,7 @@
       scheduler_(scheduler),
       snippets_fetcher_(std::move(snippets_fetcher)),
       image_fetcher_(std::move(image_fetcher)),
+      image_decoder_(std::move(image_decoder)),
       database_(std::move(database)),
       fetch_after_load_(false) {
   // TODO(dgn) should be removed after branch point (https:://crbug.com/617585).
@@ -209,8 +213,8 @@
 
   // We transition to other states while finalizing the initialization, when the
   // database is done loading.
-  database_->Load(base::Bind(&NTPSnippetsService::OnDatabaseLoaded,
-                             base::Unretained(this)));
+  database_->LoadSnippets(base::Bind(&NTPSnippetsService::OnDatabaseLoaded,
+                                     base::Unretained(this)));
 }
 
 NTPSnippetsService::~NTPSnippetsService() {
@@ -262,21 +266,10 @@
 void NTPSnippetsService::FetchSnippetImage(
     const std::string& snippet_id,
     const ImageFetchedCallback& callback) {
-  auto it =
-      std::find_if(snippets_.begin(), snippets_.end(),
-                   [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) {
-                     return snippet->id() == snippet_id;
-                   });
-  if (it == snippets_.end()) {
-    gfx::Image empty_image;
-    callback.Run(snippet_id, empty_image);
-    return;
-  }
-
-  const NTPSnippet& snippet = *it->get();
-  image_fetcher_->StartOrQueueNetworkRequest(
-      snippet.id(), snippet.salient_image_url(), callback);
-  // TODO(treib): Cache/persist the snippet image.
+  database_->LoadImage(
+      snippet_id,
+      base::Bind(&NTPSnippetsService::OnSnippetImageFetchedFromDatabase,
+                 base::Unretained(this), snippet_id, callback));
 }
 
 void NTPSnippetsService::ClearSnippets() {
@@ -286,7 +279,7 @@
   if (snippets_.empty())
     return;
 
-  database_->Delete(snippets_);
+  database_->DeleteSnippets(snippets_);
   snippets_.clear();
 
   FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
@@ -317,7 +310,8 @@
 
   (*it)->set_discarded(true);
 
-  database_->Save(**it);
+  database_->SaveSnippet(**it);
+  database_->DeleteImage((*it)->id());
 
   discarded_snippets_.push_back(std::move(*it));
   snippets_.erase(it);
@@ -331,7 +325,7 @@
   if (!initialized())
     return;
 
-  database_->Delete(discarded_snippets_);
+  database_->DeleteSnippets(discarded_snippets_);
   discarded_snippets_.clear();
 }
 
@@ -387,6 +381,24 @@
   EnterState(GetStateForDependenciesStatus());
 }
 
+// image_fetcher::ImageFetcherDelegate implementation.
+void NTPSnippetsService::OnImageDataFetched(const std::string& snippet_id,
+                                            const std::string& image_data) {
+  if (image_data.empty())
+    return;
+
+  // Only save the image if the corresponding snippet still exists.
+  auto it =
+      std::find_if(snippets_.begin(), snippets_.end(),
+                   [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) {
+                     return snippet->id() == snippet_id;
+                   });
+  if (it == snippets_.end())
+    return;
+
+  database_->SaveImage(snippet_id, image_data);
+}
+
 void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) {
   DCHECK(state_ == State::NOT_INITED || state_ == State::SHUT_DOWN);
   if (state_ == State::SHUT_DOWN)
@@ -429,7 +441,7 @@
   }
   Compact(&snippets_);
   // Then delete the removed snippets from the database.
-  database_->Delete(to_delete);
+  database_->DeleteSnippets(to_delete);
 
   StoreSnippetHostsToPrefs(hosts);
 
@@ -455,17 +467,14 @@
 
   ClearExpiredSnippets();
 
-  // If there are still more snippets than we want to show, move the extra ones
-  // over into |to_delete|.
-  NTPSnippet::PtrVector to_delete;
+  // If there are more snippets than we want to show, delete the extra ones.
   if (snippets_.size() > kMaxSnippetCount) {
-    to_delete.insert(
-        to_delete.end(),
+    NTPSnippet::PtrVector to_delete(
         std::make_move_iterator(snippets_.begin() + kMaxSnippetCount),
-                     std::make_move_iterator(snippets_.end()));
+        std::make_move_iterator(snippets_.end()));
     snippets_.resize(kMaxSnippetCount);
+    database_->DeleteSnippets(to_delete);
   }
-  database_->Delete(to_delete);
 
   UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles",
                               snippets_.size());
@@ -533,7 +542,7 @@
   }
 
   // Save the new snippets to the DB.
-  database_->Save(new_snippets);
+  database_->SaveSnippets(new_snippets);
 
   // Insert the new snippets at the front.
   snippets_.insert(snippets_.begin(),
@@ -580,7 +589,7 @@
   Compact(&discarded_snippets_);
 
   // Finally, actually delete the removed snippets from the DB.
-  database_->Delete(to_delete);
+  database_->DeleteSnippets(to_delete);
 
   // If there are any snippets left, schedule a timer for the next expiry.
   if (snippets_.empty() && discarded_snippets_.empty())
@@ -601,6 +610,56 @@
                                  base::Unretained(this)));
 }
 
+void NTPSnippetsService::OnSnippetImageFetchedFromDatabase(
+    const std::string& snippet_id,
+    const ImageFetchedCallback& callback,
+    std::string data) {
+  // |image_decoder_| is null on iOS and in tests.
+  if (image_decoder_ && !data.empty()) {
+    image_decoder_->DecodeImage(
+        std::move(data),
+        base::Bind(&NTPSnippetsService::OnSnippetImageDecoded,
+                   base::Unretained(this), snippet_id, callback));
+    return;
+  }
+
+  // Fetching from the DB failed; start a network fetch.
+  FetchSnippetImageFromNetwork(snippet_id, callback);
+}
+
+void NTPSnippetsService::OnSnippetImageDecoded(
+    const std::string& snippet_id,
+    const ImageFetchedCallback& callback,
+    const gfx::Image& image) {
+  if (!image.IsEmpty()) {
+    callback.Run(snippet_id, image);
+    return;
+  }
+
+  // If decoding the image failed, delete the DB entry.
+  database_->DeleteImage(snippet_id);
+
+  FetchSnippetImageFromNetwork(snippet_id, callback);
+}
+
+void NTPSnippetsService::FetchSnippetImageFromNetwork(
+    const std::string& snippet_id,
+    const ImageFetchedCallback& callback) {
+  auto it =
+      std::find_if(snippets_.begin(), snippets_.end(),
+                   [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) {
+                     return snippet->id() == snippet_id;
+                   });
+  if (it == snippets_.end()) {
+    callback.Run(snippet_id, gfx::Image());
+    return;
+  }
+
+  const NTPSnippet& snippet = *it->get();
+  image_fetcher_->StartOrQueueNetworkRequest(
+      snippet.id(), snippet.salient_image_url(), callback);
+}
+
 void NTPSnippetsService::EnterStateEnabled(bool fetch_snippets) {
   if (fetch_snippets)
     FetchSnippets();
@@ -643,6 +702,10 @@
   snippets_fetcher_->SetCallback(
       base::Bind(&NTPSnippetsService::OnFetchFinished, base::Unretained(this)));
 
+  // |image_fetcher_| can be null in tests.
+  if (image_fetcher_)
+    image_fetcher_->SetImageFetcherDelegate(this);
+
   // |sync_service_| can be null in tests or if sync is disabled.
   // This is a service we want to keep listening to all the time, independently
   // from the state, since it will allow us to enable or disable the snippets
diff --git a/components/ntp_snippets/ntp_snippets_service.h b/components/ntp_snippets/ntp_snippets_service.h
index fad27ab..1b1295c 100644
--- a/components/ntp_snippets/ntp_snippets_service.h
+++ b/components/ntp_snippets/ntp_snippets_service.h
@@ -17,6 +17,7 @@
 #include "base/observer_list.h"
 #include "base/scoped_observer.h"
 #include "base/timer/timer.h"
+#include "components/image_fetcher/image_fetcher_delegate.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/ntp_snippets/ntp_snippet.h"
 #include "components/ntp_snippets/ntp_snippets_fetcher.h"
@@ -28,6 +29,7 @@
 class PrefService;
 
 namespace base {
+class RefCountedMemory;
 class Value;
 }
 
@@ -36,6 +38,7 @@
 }
 
 namespace image_fetcher {
+class ImageDecoder;
 class ImageFetcher;
 }
 
@@ -65,7 +68,8 @@
 
 // Stores and vends fresh content data for the NTP.
 class NTPSnippetsService : public KeyedService,
-                           public sync_driver::SyncServiceObserver {
+                           public sync_driver::SyncServiceObserver,
+                           public image_fetcher::ImageFetcherDelegate {
  public:
   using ImageFetchedCallback =
       base::Callback<void(const std::string& snippet_id, const gfx::Image&)>;
@@ -82,6 +86,7 @@
                      NTPSnippetsScheduler* scheduler,
                      std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher,
                      std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher,
+                     std::unique_ptr<image_fetcher::ImageDecoder> image_decoder,
                      std::unique_ptr<NTPSnippetsDatabase> database);
   ~NTPSnippetsService() override;
 
@@ -197,6 +202,10 @@
   // sync_driver::SyncServiceObserver implementation.
   void OnStateChanged() override;
 
+  // image_fetcher::ImageFetcherDelegate implementation.
+  void OnImageDataFetched(const std::string& snippet_id,
+                          const std::string& image_data) override;
+
   // Callback for the NTPSnippetsDatabase.
   void OnDatabaseLoaded(NTPSnippet::PtrVector snippets);
 
@@ -222,6 +231,17 @@
 
   void LoadingSnippetsFinished();
 
+  void OnSnippetImageFetchedFromDatabase(const std::string& snippet_id,
+                                         const ImageFetchedCallback& callback,
+                                         std::string data);
+
+  void OnSnippetImageDecoded(const std::string& snippet_id,
+                             const ImageFetchedCallback& callback,
+                             const gfx::Image& image);
+
+  void FetchSnippetImageFromNetwork(const std::string& snippet_id,
+                                    const ImageFetchedCallback& callback);
+
   // Returns whether the service should be enabled or disable depending on its
   // internal state and the state of its dependencies.
   State GetStateForDependenciesStatus();
@@ -292,6 +312,7 @@
   base::OneShotTimer expiry_timer_;
 
   std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher_;
+  std::unique_ptr<image_fetcher::ImageDecoder> image_decoder_;
 
   // The database for persisting snippets.
   std::unique_ptr<NTPSnippetsDatabase> database_;
diff --git a/components/ntp_snippets/ntp_snippets_service_unittest.cc b/components/ntp_snippets/ntp_snippets_service_unittest.cc
index e55dc707..fac43c4 100644
--- a/components/ntp_snippets/ntp_snippets_service_unittest.cc
+++ b/components/ntp_snippets/ntp_snippets_service_unittest.cc
@@ -21,6 +21,7 @@
 #include "base/test/histogram_tester.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "components/image_fetcher/image_decoder.h"
 #include "components/image_fetcher/image_fetcher.h"
 #include "components/ntp_snippets/ntp_snippet.h"
 #include "components/ntp_snippets/ntp_snippets_database.h"
@@ -326,7 +327,7 @@
             fake_signin_manager_.get(), fake_token_service_.get(),
             std::move(request_context_getter), base::Bind(&ParseJson),
             /*is_stable_channel=*/true)),
-        /*image_fetcher=*/nullptr,
+        /*image_fetcher=*/nullptr, /*image_decoder=*/nullptr,
         base::WrapUnique(new NTPSnippetsDatabase(database_dir_.path(),
                                                  task_runner))));
     if (enabled)
diff --git a/components/ntp_snippets/proto/ntp_snippets.proto b/components/ntp_snippets/proto/ntp_snippets.proto
index 49d46bcb..0225dc69 100644
--- a/components/ntp_snippets/proto/ntp_snippets.proto
+++ b/components/ntp_snippets/proto/ntp_snippets.proto
@@ -25,3 +25,7 @@
   repeated SnippetSourceProto sources = 8;
   optional bool discarded = 9;
 }
+
+message SnippetImageProto {
+  optional bytes data = 1;
+}
diff --git a/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.h b/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.h
index 84e8f8eb..bd3287c 100644
--- a/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.h
+++ b/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.h
@@ -27,8 +27,6 @@
                       const std::set<std::string>& scopes,
                       const AccessTokenCallback& callback) override;
   std::vector<AccountInfo> GetAllAccounts() const override;
-  AccountInfo GetAccountInfoForEmail(const std::string& email) const override;
-  AccountInfo GetAccountInfoForGaia(const std::string& gaia) const override;
   AuthenticationErrorCategory GetAuthenticationErrorCategory(
       const std::string& gaia_id,
       NSError* error) const override;
diff --git a/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.mm b/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.mm
index a7337f4..763fa823 100644
--- a/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.mm
+++ b/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.mm
@@ -32,26 +32,6 @@
 }
 
 ProfileOAuth2TokenServiceIOSProvider::AccountInfo
-FakeProfileOAuth2TokenServiceIOSProvider::GetAccountInfoForEmail(
-    const std::string& email) const {
-  for (const auto& account : accounts_) {
-    if (account.email == email)
-      return account;
-  }
-  return ProfileOAuth2TokenServiceIOSProvider::AccountInfo();
-}
-
-ProfileOAuth2TokenServiceIOSProvider::AccountInfo
-FakeProfileOAuth2TokenServiceIOSProvider::GetAccountInfoForGaia(
-    const std::string& gaia) const {
-  for (const auto& account : accounts_) {
-    if (account.gaia == gaia)
-      return account;
-  }
-  return ProfileOAuth2TokenServiceIOSProvider::AccountInfo();
-}
-
-ProfileOAuth2TokenServiceIOSProvider::AccountInfo
 FakeProfileOAuth2TokenServiceIOSProvider::AddAccount(const std::string& gaia,
                                                      const std::string& email) {
   ProfileOAuth2TokenServiceIOSProvider::AccountInfo account;
diff --git a/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.h b/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.h
index ed8b3d6a..4bd55c3 100644
--- a/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.h
+++ b/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.h
@@ -56,14 +56,6 @@
   // Returns the ids of all accounts.
   virtual std::vector<AccountInfo> GetAllAccounts() const;
 
-  // Returns the account info composed of a GAIA id and email corresponding to
-  // email |email|.
-  virtual AccountInfo GetAccountInfoForEmail(const std::string& email) const;
-
-  // Returns the account info composed of a GAIA id and email corresponding to
-  // GAIA id |gaia|.
-  virtual AccountInfo GetAccountInfoForGaia(const std::string& gaia) const;
-
   // Starts fetching an access token for the account with id |gaia_id| with
   // the given |scopes|. Once the token is obtained, |callback| is called.
   virtual void GetAccessToken(const std::string& gaia_id,
diff --git a/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.mm b/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.mm
index 372bfac..4144c6f 100644
--- a/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.mm
+++ b/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.mm
@@ -9,18 +9,6 @@
   return std::vector<ProfileOAuth2TokenServiceIOSProvider::AccountInfo>();
 }
 
-ProfileOAuth2TokenServiceIOSProvider::AccountInfo
-ProfileOAuth2TokenServiceIOSProvider::GetAccountInfoForEmail(
-    const std::string& email) const {
-  return ProfileOAuth2TokenServiceIOSProvider::AccountInfo();
-}
-
-ProfileOAuth2TokenServiceIOSProvider::AccountInfo
-ProfileOAuth2TokenServiceIOSProvider::GetAccountInfoForGaia(
-    const std::string& gaia) const {
-  return ProfileOAuth2TokenServiceIOSProvider::AccountInfo();
-}
-
 void ProfileOAuth2TokenServiceIOSProvider::GetAccessToken(
     const std::string& gaia_id,
     const std::string& client_id,
diff --git a/content/app/DEPS b/content/app/DEPS
index dc85fc19..961957d6 100644
--- a/content/app/DEPS
+++ b/content/app/DEPS
@@ -3,6 +3,7 @@
   "+content",
   "+device/battery",
   "+device/bluetooth",
+  "+device/power_save_blocker",
   "+device/usb",
   "+device/vibration",
   # For loading V8's initial snapshot from external files.
diff --git a/content/app/android/library_loader_hooks.cc b/content/app/android/library_loader_hooks.cc
index 9956b29..f26a706 100644
--- a/content/app/android/library_loader_hooks.cc
+++ b/content/app/android/library_loader_hooks.cc
@@ -26,6 +26,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/result_codes.h"
 #include "device/bluetooth/android/bluetooth_jni_registrar.h"
+#include "device/power_save_blocker/power_save_blocker_jni_registrar.h"
 #include "device/usb/android/usb_jni_registrar.h"
 #include "media/base/android/media_jni_registrar.h"
 #include "media/capture/video/android/capture_jni_registrar.h"
@@ -77,6 +78,9 @@
     if (!device::android::RegisterBluetoothJni(env))
       return false;
 
+    if (!device::android::RegisterPowerSaveBlockerJni(env))
+      return false;
+
     if (!device::android::RegisterUsbJni(env))
       return false;
 
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 91fce04..f5c3906 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -57,6 +57,7 @@
     "//crypto",
     "//device/battery",
     "//device/bluetooth",
+    "//device/power_save_blocker",
     "//device/vibration",
     "//gin",
     "//google_apis",
@@ -291,22 +292,9 @@
 
   if (use_x11) {
     configs += [ "//build/config/linux:x11" ]
-    if (!is_chromeos) {
-      configs += [ "//build/config/linux:xscrnsaver" ]
-    }
     deps += [ "//ui/gfx/x" ]
   }
 
-  # Dealing with power_save_blocker_{x11,ozone}.cc is a little complicated
-  # given the interaction between os_chromeos and the feature flags for X11 and
-  # ozone, so do it all in one spot.
-  if (is_chromeos || !use_ozone) {
-    sources -= [ "power_save_blocker_ozone.cc" ]
-  }
-  if (is_chromeos || !use_x11) {
-    sources -= [ "power_save_blocker_x11.cc" ]
-  }
-
   # Dealing with *wifi_data_provider_*.cc is also a bit complicated given
   # android, chromeos, linux and use_dbus.
   if (is_android) {
diff --git a/content/browser/DEPS b/content/browser/DEPS
index f6e95f0d..0297668 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -16,6 +16,7 @@
   "+content/app/strings/grit",  # For generated headers
   "+content/public/browser",
   "+device/battery",  # For battery status service.
+  "+device/power_save_blocker",
   "+device/vibration",  # For Vibration API
   "+device/vr",  # For WebVR API
   "+gin/v8_initializer.h",
diff --git a/content/browser/android/browser_jni_registrar.cc b/content/browser/android/browser_jni_registrar.cc
index 3dd22cc..94d214f0 100644
--- a/content/browser/android/browser_jni_registrar.cc
+++ b/content/browser/android/browser_jni_registrar.cc
@@ -32,13 +32,13 @@
 #include "content/browser/media/android/media_resource_getter_impl.h"
 #include "content/browser/media/session/media_session_delegate_android.h"
 #include "content/browser/mojo/service_registrar_android.h"
-#include "content/browser/power_save_blocker_android.h"
 #include "content/browser/renderer_host/ime_adapter_android.h"
 #include "content/browser/renderer_host/input/synthetic_gesture_target_android.h"
 #include "content/browser/screen_orientation/screen_orientation_delegate_android.h"
 #include "content/browser/speech/speech_recognizer_impl_android.h"
 #include "content/browser/time_zone_monitor_android.h"
 #include "content/browser/web_contents/web_contents_android.h"
+#include "device/power_save_blocker/power_save_blocker_android.h"
 #include "mojo/android/system/core_impl.h"
 
 namespace {
@@ -63,9 +63,8 @@
     {"DateTimePickerAndroid", content::RegisterDateTimeChooserAndroid},
     {"DownloadControllerAndroidImpl",
      content::DownloadControllerAndroidImpl::RegisterDownloadController},
-    {"GamepadList",
-     content::GamepadPlatformDataFetcherAndroid::
-         RegisterGamepadPlatformDataFetcherAndroid},
+    {"GamepadList", content::GamepadPlatformDataFetcherAndroid::
+                        RegisterGamepadPlatformDataFetcherAndroid},
     {"HandleViewResources",
      content::CompositedTouchHandleDrawable::RegisterHandleViewResources},
     {"InterstitialPageDelegateAndroid",
@@ -78,7 +77,6 @@
      content::NavigationControllerAndroid::Register},
     {"PopupTouchHandleDrawable",
      content::PopupTouchHandleDrawable::RegisterPopupTouchHandleDrawable},
-    {"PowerSaveBlock", content::RegisterPowerSaveBlocker},
     {"RegisterImeAdapter", content::RegisterImeAdapter},
     {"ScreenOrientationProvider",
      content::ScreenOrientationDelegateAndroid::Register},
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 41c4d7c8..47e3fb4 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -40,9 +40,9 @@
 #include "content/public/common/browser_side_navigation_policy.h"
 
 #if defined(OS_ANDROID)
-#include "content/browser/power_save_blocker_impl.h"
-#include "content/public/browser/power_save_blocker_factory.h"
+#include "content/browser/power_save_blocker_factory.h"
 #include "content/public/browser/render_widget_host_view.h"
+#include "device/power_save_blocker/power_save_blocker_impl.h"
 #endif
 
 namespace content {
@@ -501,10 +501,10 @@
 
   frame_trace_recorder_.reset(new DevToolsFrameTraceRecorder());
 #if defined(OS_ANDROID)
-  power_save_blocker_.reset(static_cast<PowerSaveBlockerImpl*>(
+  power_save_blocker_.reset(static_cast<device::PowerSaveBlockerImpl*>(
       CreatePowerSaveBlocker(
-          PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
-          PowerSaveBlocker::kReasonOther, "DevTools")
+          device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+          device::PowerSaveBlocker::kReasonOther, "DevTools")
           .release()));
   if (web_contents()->GetNativeView()) {
     view_weak_factory_.reset(new base::WeakPtrFactory<ui::ViewAndroid>(
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h
index e5d1d83..249d9d2d 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.h
+++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -23,6 +23,12 @@
 class CompositorFrameMetadata;
 }
 
+#if defined(OS_ANDROID)
+namespace device {
+class PowerSaveBlockerImpl;
+}  // namespace device
+#endif
+
 namespace content {
 
 class BrowserContext;
@@ -32,10 +38,6 @@
 class NavigationHandle;
 class RenderFrameHostImpl;
 
-#if defined(OS_ANDROID)
-class PowerSaveBlockerImpl;
-#endif
-
 namespace devtools {
 namespace browser { class BrowserHandler; }
 namespace dom { class DOMHandler; }
@@ -171,7 +173,7 @@
   std::unique_ptr<devtools::emulation::EmulationHandler> emulation_handler_;
   std::unique_ptr<DevToolsFrameTraceRecorder> frame_trace_recorder_;
 #if defined(OS_ANDROID)
-  std::unique_ptr<PowerSaveBlockerImpl> power_save_blocker_;
+  std::unique_ptr<device::PowerSaveBlockerImpl> power_save_blocker_;
   std::unique_ptr<base::WeakPtrFactory<ui::ViewAndroid>> view_weak_factory_;
 #endif
   std::unique_ptr<DevToolsProtocolHandler> protocol_handler_;
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index a32feb9..06393fab 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -30,9 +30,9 @@
 #include "content/browser/download/download_manager_impl.h"
 #include "content/browser/download/download_resource_handler.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/power_save_blocker_factory.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/download_danger_type.h"
-#include "content/public/browser/power_save_blocker_factory.h"
 #include "content/public/browser/resource_dispatcher_host_delegate.h"
 #include "content/public/browser/resource_throttle.h"
 #include "content/public/common/content_features.h"
@@ -122,13 +122,14 @@
 
 class DownloadFileWithDelay : public DownloadFileImpl {
  public:
-  DownloadFileWithDelay(std::unique_ptr<DownloadSaveInfo> save_info,
-                        const base::FilePath& default_download_directory,
-                        std::unique_ptr<ByteStreamReader> stream,
-                        const net::BoundNetLog& bound_net_log,
-                        std::unique_ptr<PowerSaveBlocker> power_save_blocker,
-                        base::WeakPtr<DownloadDestinationObserver> observer,
-                        base::WeakPtr<DownloadFileWithDelayFactory> owner);
+  DownloadFileWithDelay(
+      std::unique_ptr<DownloadSaveInfo> save_info,
+      const base::FilePath& default_download_directory,
+      std::unique_ptr<ByteStreamReader> stream,
+      const net::BoundNetLog& bound_net_log,
+      std::unique_ptr<device::PowerSaveBlocker> power_save_blocker,
+      base::WeakPtr<DownloadDestinationObserver> observer,
+      base::WeakPtr<DownloadFileWithDelayFactory> owner);
 
   ~DownloadFileWithDelay() override;
 
@@ -193,7 +194,7 @@
     const base::FilePath& default_download_directory,
     std::unique_ptr<ByteStreamReader> stream,
     const net::BoundNetLog& bound_net_log,
-    std::unique_ptr<PowerSaveBlocker> power_save_blocker,
+    std::unique_ptr<device::PowerSaveBlocker> power_save_blocker,
     base::WeakPtr<DownloadDestinationObserver> observer,
     base::WeakPtr<DownloadFileWithDelayFactory> owner)
     : DownloadFileImpl(std::move(save_info),
@@ -254,9 +255,9 @@
     std::unique_ptr<ByteStreamReader> stream,
     const net::BoundNetLog& bound_net_log,
     base::WeakPtr<DownloadDestinationObserver> observer) {
-  std::unique_ptr<PowerSaveBlocker> psb(CreatePowerSaveBlocker(
-      PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
-      PowerSaveBlocker::kReasonOther, "Download in progress"));
+  std::unique_ptr<device::PowerSaveBlocker> psb(CreatePowerSaveBlocker(
+      device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
+      device::PowerSaveBlocker::kReasonOther, "Download in progress"));
   return new DownloadFileWithDelay(std::move(save_info),
                                    default_download_directory,
                                    std::move(stream),
@@ -291,12 +292,13 @@
 
 class CountingDownloadFile : public DownloadFileImpl {
  public:
-  CountingDownloadFile(std::unique_ptr<DownloadSaveInfo> save_info,
-                       const base::FilePath& default_downloads_directory,
-                       std::unique_ptr<ByteStreamReader> stream,
-                       const net::BoundNetLog& bound_net_log,
-                       std::unique_ptr<PowerSaveBlocker> power_save_blocker,
-                       base::WeakPtr<DownloadDestinationObserver> observer)
+  CountingDownloadFile(
+      std::unique_ptr<DownloadSaveInfo> save_info,
+      const base::FilePath& default_downloads_directory,
+      std::unique_ptr<ByteStreamReader> stream,
+      const net::BoundNetLog& bound_net_log,
+      std::unique_ptr<device::PowerSaveBlocker> power_save_blocker,
+      base::WeakPtr<DownloadDestinationObserver> observer)
       : DownloadFileImpl(std::move(save_info),
                          default_downloads_directory,
                          std::move(stream),
@@ -350,9 +352,9 @@
       std::unique_ptr<ByteStreamReader> stream,
       const net::BoundNetLog& bound_net_log,
       base::WeakPtr<DownloadDestinationObserver> observer) override {
-    std::unique_ptr<PowerSaveBlocker> psb(CreatePowerSaveBlocker(
-        PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
-        PowerSaveBlocker::kReasonOther, "Download in progress"));
+    std::unique_ptr<device::PowerSaveBlocker> psb(CreatePowerSaveBlocker(
+        device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
+        device::PowerSaveBlocker::kReasonOther, "Download in progress"));
     return new CountingDownloadFile(std::move(save_info),
                                     default_downloads_directory,
                                     std::move(stream),
diff --git a/content/browser/download/download_request_core.cc b/content/browser/download/download_request_core.cc
index 2f5b2f1..27965757 100644
--- a/content/browser/download/download_request_core.cc
+++ b/content/browser/download/download_request_core.cc
@@ -24,12 +24,12 @@
 #include "content/browser/download/download_request_handle.h"
 #include "content/browser/download/download_stats.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/power_save_blocker_factory.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/download_interrupt_reasons.h"
 #include "content/public/browser/download_item.h"
 #include "content/public/browser/download_manager_delegate.h"
 #include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/power_save_blocker_factory.h"
 #include "content/public/browser/resource_context.h"
 #include "content/public/browser/web_contents.h"
 #include "net/base/elements_upload_data_stream.h"
@@ -205,8 +205,8 @@
   DCHECK(delegate_);
   RecordDownloadCount(UNTHROTTLED_COUNT);
   power_save_blocker_ = CreatePowerSaveBlocker(
-      PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
-      PowerSaveBlocker::kReasonOther, "Download in progress");
+      device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
+      device::PowerSaveBlocker::kReasonOther, "Download in progress");
   DownloadRequestData* request_data = DownloadRequestData::Get(request_);
   if (request_data) {
     save_info_ = request_data->TakeSaveInfo();
diff --git a/content/browser/download/download_request_core.h b/content/browser/download/download_request_core.h
index 84eb2e0..6469116 100644
--- a/content/browser/download/download_request_core.h
+++ b/content/browser/download/download_request_core.h
@@ -19,6 +19,10 @@
 #include "content/public/browser/download_save_info.h"
 #include "content/public/browser/download_url_parameters.h"
 
+namespace device {
+class PowerSaveBlocker;
+}  // namespace device
+
 namespace net {
 class HttpResponseHeaders;
 class URLRequest;
@@ -29,7 +33,6 @@
 class DownloadManagerImpl;
 class ByteStreamReader;
 class ByteStreamWriter;
-class PowerSaveBlocker;
 struct DownloadCreateInfo;
 
 // This class encapsulates the core logic for reading data from a URLRequest and
@@ -140,7 +143,7 @@
   // Keeps the system from sleeping while this is alive. If the
   // system enters power saving mode while a request is alive, it can cause the
   // request to fail and the associated download will be interrupted.
-  std::unique_ptr<PowerSaveBlocker> power_save_blocker_;
+  std::unique_ptr<device::PowerSaveBlocker> power_save_blocker_;
 
   // The following are used to collect stats.
   base::TimeTicks download_start_time_;
diff --git a/content/browser/download/drag_download_file_browsertest.cc b/content/browser/download/drag_download_file_browsertest.cc
index 8986c39..5821c301 100644
--- a/content/browser/download/drag_download_file_browsertest.cc
+++ b/content/browser/download/drag_download_file_browsertest.cc
@@ -14,7 +14,6 @@
 #include "content/browser/download/drag_download_util.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/power_save_blocker.h"
 #include "content/public/common/content_client.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
@@ -23,6 +22,7 @@
 #include "content/shell/browser/shell.h"
 #include "content/shell/browser/shell_browser_context.h"
 #include "content/shell/browser/shell_download_manager_delegate.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 #include "net/test/url_request/url_request_mock_http_job.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 1585270..9b5f806 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -29,6 +29,7 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/bindings_policy.h"
 #include "content/public/common/browser_side_navigation_policy.h"
+#include "content/public/common/renderer_preferences.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
@@ -4578,4 +4579,41 @@
   }
 }
 
+// Tests that POST body is not lost when decidePolicyForNavigation tells the
+// renderer to route the request via FrameHostMsg_OpenURL sent to the browser.
+// See also https://crbug.com/344348.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, PostViaOpenUrlMsg) {
+  GURL main_url(
+      embedded_test_server()->GetURL("/form_that_posts_to_echoall.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  // Ask the renderer to go through OpenURL FrameHostMsg_OpenURL IPC message.
+  // Without this, the test wouldn't repro https://crbug.com/344348.
+  shell()
+      ->web_contents()
+      ->GetMutableRendererPrefs()
+      ->browser_handles_all_top_level_requests = true;
+  shell()->web_contents()->GetRenderViewHost()->SyncRendererPrefs();
+
+  // Submit the form.
+  TestNavigationObserver form_post_observer(shell()->web_contents(), 1);
+  EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
+                            "document.getElementById('form').submit();"));
+  form_post_observer.Wait();
+
+  // Verify that we arrived at the expected location.
+  GURL target_url(embedded_test_server()->GetURL("/echoall"));
+  EXPECT_EQ(target_url, shell()->web_contents()->GetLastCommittedURL());
+
+  // Verify that POST body was correctly passed to the server and ended up in
+  // the body of the page.
+  std::string body;
+  EXPECT_TRUE(ExecuteScriptAndExtractString(
+      shell()->web_contents(),
+      "window.domAutomationController.send("
+      "document.getElementsByTagName('pre')[0].innerText);",
+      &body));
+  EXPECT_EQ("text=value\n", body);
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/navigator.h b/content/browser/frame_host/navigator.h
index 8c76f22..7270a7c 100644
--- a/content/browser/frame_host/navigator.h
+++ b/content/browser/frame_host/navigator.h
@@ -110,13 +110,16 @@
 
   // The RenderFrameHostImpl has received a request to open a URL with the
   // specified |disposition|.
-  virtual void RequestOpenURL(RenderFrameHostImpl* render_frame_host,
-                              const GURL& url,
-                              SiteInstance* source_site_instance,
-                              const Referrer& referrer,
-                              WindowOpenDisposition disposition,
-                              bool should_replace_current_entry,
-                              bool user_gesture) {}
+  virtual void RequestOpenURL(
+      RenderFrameHostImpl* render_frame_host,
+      const GURL& url,
+      bool uses_post,
+      const scoped_refptr<ResourceRequestBodyImpl>& body,
+      SiteInstance* source_site_instance,
+      const Referrer& referrer,
+      WindowOpenDisposition disposition,
+      bool should_replace_current_entry,
+      bool user_gesture) {}
 
   // The RenderFrameHostImpl wants to transfer the request to a new renderer.
   // |redirect_chain| contains any redirect URLs (excluding |url|) that happened
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index 263dd716..c63d436 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -648,13 +648,16 @@
   return GetContentClient()->browser()->ShouldAssignSiteForURL(url);
 }
 
-void NavigatorImpl::RequestOpenURL(RenderFrameHostImpl* render_frame_host,
-                                   const GURL& url,
-                                   SiteInstance* source_site_instance,
-                                   const Referrer& referrer,
-                                   WindowOpenDisposition disposition,
-                                   bool should_replace_current_entry,
-                                   bool user_gesture) {
+void NavigatorImpl::RequestOpenURL(
+    RenderFrameHostImpl* render_frame_host,
+    const GURL& url,
+    bool uses_post,
+    const scoped_refptr<ResourceRequestBodyImpl>& body,
+    SiteInstance* source_site_instance,
+    const Referrer& referrer,
+    WindowOpenDisposition disposition,
+    bool should_replace_current_entry,
+    bool user_gesture) {
   // Note: This can be called for subframes (even when OOPIFs are not possible)
   // if the disposition calls for a different window.
 
@@ -692,6 +695,8 @@
   OpenURLParams params(dest_url, referrer, frame_tree_node_id, disposition,
                        ui::PAGE_TRANSITION_LINK,
                        true /* is_renderer_initiated */);
+  params.uses_post = uses_post;
+  params.post_data = body;
   params.source_site_instance = source_site_instance;
   if (redirect_chain.size() > 0)
     params.redirect_chain = redirect_chain;
diff --git a/content/browser/frame_host/navigator_impl.h b/content/browser/frame_host/navigator_impl.h
index 3ee2c8b..f4df998 100644
--- a/content/browser/frame_host/navigator_impl.h
+++ b/content/browser/frame_host/navigator_impl.h
@@ -65,6 +65,8 @@
                              const std::string& unique_name) override;
   void RequestOpenURL(RenderFrameHostImpl* render_frame_host,
                       const GURL& url,
+                      bool uses_post,
+                      const scoped_refptr<ResourceRequestBodyImpl>& body,
                       SiteInstance* source_site_instance,
                       const Referrer& referrer,
                       WindowOpenDisposition disposition,
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 20a458b..aa02e59a 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -2183,9 +2183,9 @@
   TRACE_EVENT1("navigation", "RenderFrameHostImpl::OpenURL", "url",
                validated_url.possibly_invalid_spec());
   frame_tree_node_->navigator()->RequestOpenURL(
-      this, validated_url, source_site_instance, params.referrer,
-      params.disposition, params.should_replace_current_entry,
-      params.user_gesture);
+      this, validated_url, params.uses_post, params.resource_request_body,
+      source_site_instance, params.referrer, params.disposition,
+      params.should_replace_current_entry, params.user_gesture);
 }
 
 void RenderFrameHostImpl::Stop() {
diff --git a/content/browser/frame_host/render_frame_proxy_host.cc b/content/browser/frame_host/render_frame_proxy_host.cc
index 9f7a80c..6ee07fd 100644
--- a/content/browser/frame_host/render_frame_proxy_host.cc
+++ b/content/browser/frame_host/render_frame_proxy_host.cc
@@ -260,11 +260,11 @@
 
   // TODO(alexmos, creis): Figure out whether |params.user_gesture| needs to be
   // passed in as well.
-  // TODO(lukasza): https://crbug.com/344348: Pass real method and post_data.
   frame_tree_node_->navigator()->RequestTransferURL(
       current_rfh, validated_url, site_instance_.get(), std::vector<GURL>(),
       params.referrer, ui::PAGE_TRANSITION_LINK, GlobalRequestID(),
-      params.should_replace_current_entry, "GET", nullptr);
+      params.should_replace_current_entry, params.uses_post ? "POST" : "GET",
+      params.resource_request_body);
 }
 
 void RenderFrameProxyHost::OnRouteMessageEvent(
diff --git a/content/browser/loader/DEPS b/content/browser/loader/DEPS
index f01c3f6..24dd2400 100644
--- a/content/browser/loader/DEPS
+++ b/content/browser/loader/DEPS
@@ -94,6 +94,7 @@
     "+content/public/browser/resource_throttle.h",
 
     # TODO: these all have to be removed.
+    "+content/public/browser/browser_thread.h",
     "+content/public/browser/power_save_blocker_factory.h",
   ],
   "resource_dispatcher_host_impl\.(cc|h)": [
diff --git a/content/browser/loader/power_save_block_resource_throttle.cc b/content/browser/loader/power_save_block_resource_throttle.cc
index 9ef3e2b..47ce12b 100644
--- a/content/browser/loader/power_save_block_resource_throttle.cc
+++ b/content/browser/loader/power_save_block_resource_throttle.cc
@@ -4,7 +4,8 @@
 
 #include "content/browser/loader/power_save_block_resource_throttle.h"
 
-#include "content/public/browser/power_save_blocker_factory.h"
+#include "content/public/browser/browser_thread.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 
 namespace content {
 
@@ -40,9 +41,11 @@
 }
 
 void PowerSaveBlockResourceThrottle::ActivatePowerSaveBlocker() {
-  power_save_blocker_ = CreatePowerSaveBlocker(
-      PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
-      PowerSaveBlocker::kReasonOther, "Uploading data to " + host_);
+  power_save_blocker_ = device::PowerSaveBlocker::CreateWithTaskRunners(
+      device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
+      device::PowerSaveBlocker::kReasonOther, "Uploading data to " + host_,
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
 }
 
 }  // namespace content
diff --git a/content/browser/loader/power_save_block_resource_throttle.h b/content/browser/loader/power_save_block_resource_throttle.h
index 3f6f1d36..7e4b9ba 100644
--- a/content/browser/loader/power_save_block_resource_throttle.h
+++ b/content/browser/loader/power_save_block_resource_throttle.h
@@ -13,9 +13,11 @@
 #include "base/timer/timer.h"
 #include "content/public/browser/resource_throttle.h"
 
-namespace content {
-
+namespace device {
 class PowerSaveBlocker;
+}  // namespace device
+
+namespace content {
 
 // This ResourceThrottle blocks power save until large upload request finishes.
 class PowerSaveBlockResourceThrottle : public ResourceThrottle {
@@ -33,7 +35,7 @@
 
   const std::string host_;
   base::OneShotTimer timer_;
-  std::unique_ptr<PowerSaveBlocker> power_save_blocker_;
+  std::unique_ptr<device::PowerSaveBlocker> power_save_blocker_;
 
   DISALLOW_COPY_AND_ASSIGN(PowerSaveBlockResourceThrottle);
 };
diff --git a/content/browser/media/capture/aura_window_capture_machine.cc b/content/browser/media/capture/aura_window_capture_machine.cc
index 529d09a8..86f9524 100644
--- a/content/browser/media/capture/aura_window_capture_machine.cc
+++ b/content/browser/media/capture/aura_window_capture_machine.cc
@@ -14,8 +14,8 @@
 #include "components/display_compositor/gl_helper.h"
 #include "content/browser/compositor/image_transport_factory.h"
 #include "content/browser/media/capture/desktop_capture_device_uma_types.h"
+#include "content/browser/power_save_blocker_factory.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/power_save_blocker_factory.h"
 #include "media/base/video_capture_types.h"
 #include "media/base/video_util.h"
 #include "media/capture/content/thread_safe_capture_oracle.h"
@@ -87,8 +87,9 @@
 
   power_save_blocker_.reset(
       CreatePowerSaveBlocker(
-          PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
-          PowerSaveBlocker::kReasonOther, "DesktopCaptureDevice is running")
+          device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+          device::PowerSaveBlocker::kReasonOther,
+          "DesktopCaptureDevice is running")
           .release());
 
   return true;
diff --git a/content/browser/media/capture/aura_window_capture_machine.h b/content/browser/media/capture/aura_window_capture_machine.h
index ceb6e7f..848c325 100644
--- a/content/browser/media/capture/aura_window_capture_machine.h
+++ b/content/browser/media/capture/aura_window_capture_machine.h
@@ -18,19 +18,19 @@
 #include "ui/compositor/compositor_animation_observer.h"
 
 namespace cc {
-
 class CopyOutputResult;
-
 }  // namespace cc
 
+namespace device {
+class PowerSaveBlocker;
+}  // namespace device
+
 namespace display_compositor {
 class ReadbackYUVInterface;
 }
 
 namespace content {
 
-class PowerSaveBlocker;
-
 class AuraWindowCaptureMachine
     : public media::VideoCaptureMachine,
       public aura::WindowObserver,
@@ -124,7 +124,7 @@
 
   // TODO(jiayl): Remove power_save_blocker_ when there is an API to keep the
   // screen from sleeping for the drive-by web.
-  std::unique_ptr<PowerSaveBlocker> power_save_blocker_;
+  std::unique_ptr<device::PowerSaveBlocker> power_save_blocker_;
 
   // WeakPtrs are used for the asynchronous capture callbacks passed to external
   // modules.  They are only valid on the UI thread and become invalidated
diff --git a/content/browser/media/capture/desktop_capture_device.cc b/content/browser/media/capture/desktop_capture_device.cc
index 415096a..d468f01 100644
--- a/content/browser/media/capture/desktop_capture_device.cc
+++ b/content/browser/media/capture/desktop_capture_device.cc
@@ -20,9 +20,9 @@
 #include "base/timer/timer.h"
 #include "build/build_config.h"
 #include "content/browser/media/capture/desktop_capture_device_uma_types.h"
+#include "content/browser/power_save_blocker_factory.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/desktop_media_id.h"
-#include "content/public/browser/power_save_blocker_factory.h"
 #include "media/base/video_util.h"
 #include "media/capture/content/capture_resolution_chooser.h"
 #include "third_party/libyuv/include/libyuv/scale_argb.h"
@@ -133,7 +133,7 @@
 
   // TODO(jiayl): Remove power_save_blocker_ when there is an API to keep the
   // screen from sleeping for the drive-by web.
-  std::unique_ptr<PowerSaveBlocker> power_save_blocker_;
+  std::unique_ptr<device::PowerSaveBlocker> power_save_blocker_;
 
   DISALLOW_COPY_AND_ASSIGN(Core);
 };
@@ -174,8 +174,9 @@
 
   power_save_blocker_.reset(
       CreatePowerSaveBlocker(
-          PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
-          PowerSaveBlocker::kReasonOther, "DesktopCaptureDevice is running")
+          device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+          device::PowerSaveBlocker::kReasonOther,
+          "DesktopCaptureDevice is running")
           .release());
 
   desktop_capturer_->Start(this);
diff --git a/content/browser/media/media_web_contents_observer.cc b/content/browser/media/media_web_contents_observer.cc
index fd3a9c0..55d8533a4 100644
--- a/content/browser/media/media_web_contents_observer.cc
+++ b/content/browser/media/media_web_contents_observer.cc
@@ -10,12 +10,12 @@
 #include "build/build_config.h"
 #include "content/browser/media/audible_metrics.h"
 #include "content/browser/media/audio_stream_monitor.h"
-#include "content/browser/power_save_blocker_impl.h"
+#include "content/browser/power_save_blocker_factory.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/media/media_player_delegate_messages.h"
-#include "content/public/browser/power_save_blocker_factory.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
+#include "device/power_save_blocker/power_save_blocker_impl.h"
 #include "ipc/ipc_message_macros.h"
 
 namespace content {
@@ -185,21 +185,21 @@
 void MediaWebContentsObserver::CreateAudioPowerSaveBlocker() {
   DCHECK(!audio_power_save_blocker_);
   audio_power_save_blocker_ = CreatePowerSaveBlocker(
-      PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
-      PowerSaveBlocker::kReasonAudioPlayback, "Playing audio");
+      device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
+      device::PowerSaveBlocker::kReasonAudioPlayback, "Playing audio");
 }
 
 void MediaWebContentsObserver::CreateVideoPowerSaveBlocker() {
   DCHECK(!video_power_save_blocker_);
   DCHECK(!active_video_players_.empty());
   video_power_save_blocker_ = CreatePowerSaveBlocker(
-      PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
-      PowerSaveBlocker::kReasonVideoPlayback, "Playing video");
+      device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+      device::PowerSaveBlocker::kReasonVideoPlayback, "Playing video");
 #if defined(OS_ANDROID)
   if (web_contents()->GetNativeView()) {
     view_weak_factory_.reset(new base::WeakPtrFactory<ui::ViewAndroid>(
         web_contents()->GetNativeView()));
-    static_cast<PowerSaveBlockerImpl*>(video_power_save_blocker_.get())
+    static_cast<device::PowerSaveBlockerImpl*>(video_power_save_blocker_.get())
         ->InitDisplaySleepBlocker(view_weak_factory_->GetWeakPtr());
   }
 #endif
diff --git a/content/browser/media/media_web_contents_observer.h b/content/browser/media/media_web_contents_observer.h
index 281e3e3..540a921 100644
--- a/content/browser/media/media_web_contents_observer.h
+++ b/content/browser/media/media_web_contents_observer.h
@@ -20,9 +20,11 @@
 #include "ui/android/view_android.h"
 #endif  // OS_ANDROID
 
-namespace content {
-
+namespace device {
 class PowerSaveBlocker;
+}  // namespace device
+
+namespace content {
 
 // This class manages all RenderFrame based media related managers at the
 // browser side. It receives IPC messages from media RenderFrameObservers and
@@ -98,8 +100,8 @@
   // Tracking variables and associated power save blockers for media playback.
   ActiveMediaPlayerMap active_audio_players_;
   ActiveMediaPlayerMap active_video_players_;
-  std::unique_ptr<PowerSaveBlocker> audio_power_save_blocker_;
-  std::unique_ptr<PowerSaveBlocker> video_power_save_blocker_;
+  std::unique_ptr<device::PowerSaveBlocker> audio_power_save_blocker_;
+  std::unique_ptr<device::PowerSaveBlocker> video_power_save_blocker_;
 #if defined(OS_ANDROID)
   std::unique_ptr<base::WeakPtrFactory<ui::ViewAndroid>> view_weak_factory_;
 #endif
diff --git a/content/browser/media/webrtc/webrtc_internals.cc b/content/browser/media/webrtc/webrtc_internals.cc
index 3046722..de28bb0 100644
--- a/content/browser/media/webrtc/webrtc_internals.cc
+++ b/content/browser/media/webrtc/webrtc_internals.cc
@@ -9,10 +9,10 @@
 #include "base/strings/string_number_conversions.h"
 #include "build/build_config.h"
 #include "content/browser/media/webrtc/webrtc_internals_ui_observer.h"
+#include "content/browser/power_save_blocker_factory.h"
 #include "content/browser/web_contents/web_contents_view.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/power_save_blocker_factory.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 
@@ -501,8 +501,9 @@
     DVLOG(1) << ("Preventing the application from being suspended while one or "
                  "more PeerConnections are active.");
     power_save_blocker_ = content::CreatePowerSaveBlocker(
-        PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
-        PowerSaveBlocker::kReasonOther, "WebRTC has active PeerConnections");
+        device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
+        device::PowerSaveBlocker::kReasonOther,
+        "WebRTC has active PeerConnections");
   }
 }
 
diff --git a/content/browser/media/webrtc/webrtc_internals.h b/content/browser/media/webrtc/webrtc_internals.h
index e319313d..ddcb671 100644
--- a/content/browser/media/webrtc/webrtc_internals.h
+++ b/content/browser/media/webrtc/webrtc_internals.h
@@ -20,9 +20,12 @@
 #include "content/public/browser/render_process_host_observer.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
 
+namespace device {
+class PowerSaveBlocker;
+}  // namespace device
+
 namespace content {
 
-class PowerSaveBlocker;
 class WebContents;
 class WebRTCInternalsUIObserver;
 
@@ -202,7 +205,7 @@
   // While |peer_connection_data_| is non-empty, hold an instance of
   // PowerSaveBlocker.  This prevents the application from being suspended while
   // remoting.
-  std::unique_ptr<PowerSaveBlocker> power_save_blocker_;
+  std::unique_ptr<device::PowerSaveBlocker> power_save_blocker_;
 
   // Set of render process hosts that |this| is registered as an observer on.
   base::hash_set<int> render_process_id_set_;
diff --git a/content/browser/power_save_blocker_android.h b/content/browser/power_save_blocker_android.h
deleted file mode 100644
index 1df7d69..0000000
--- a/content/browser/power_save_blocker_android.h
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <jni.h>
-
-namespace content {
-
-bool RegisterPowerSaveBlocker(JNIEnv* env);
-
-}  // namespace content
diff --git a/content/browser/power_save_blocker_factory.cc b/content/browser/power_save_blocker_factory.cc
index d496029..113e35b 100644
--- a/content/browser/power_save_blocker_factory.cc
+++ b/content/browser/power_save_blocker_factory.cc
@@ -2,18 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/public/browser/power_save_blocker_factory.h"
+#include "content/browser/power_save_blocker_factory.h"
 
 #include "base/threading/sequenced_worker_pool.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace content {
 
-std::unique_ptr<PowerSaveBlocker> CreatePowerSaveBlocker(
-    PowerSaveBlocker::PowerSaveBlockerType type,
-    PowerSaveBlocker::Reason reason,
+std::unique_ptr<device::PowerSaveBlocker> CreatePowerSaveBlocker(
+    device::PowerSaveBlocker::PowerSaveBlockerType type,
+    device::PowerSaveBlocker::Reason reason,
     const std::string& description) {
-  return PowerSaveBlocker::CreateWithTaskRunners(
+  return device::PowerSaveBlocker::CreateWithTaskRunners(
       type, reason, description,
       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
diff --git a/content/browser/power_save_blocker_factory.h b/content/browser/power_save_blocker_factory.h
new file mode 100644
index 0000000..3d430d8a
--- /dev/null
+++ b/content/browser/power_save_blocker_factory.h
@@ -0,0 +1,25 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_POWER_SAVE_BLOCKER_FACTORY_H_
+#define CONTENT_BROWSER_POWER_SAVE_BLOCKER_FACTORY_H_
+
+#include <memory>
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
+#include "content/common/content_export.h"
+#include "device/power_save_blocker/power_save_blocker.h"
+
+namespace content {
+
+CONTENT_EXPORT std::unique_ptr<device::PowerSaveBlocker> CreatePowerSaveBlocker(
+    device::PowerSaveBlocker::PowerSaveBlockerType type,
+    device::PowerSaveBlocker::Reason reason,
+    const std::string& description);
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_POWER_SAVE_BLOCKER_FACTORY_H_
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index a5ab74c8..b9cc76e 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -82,8 +82,8 @@
 #include "ui/snapshot/snapshot.h"
 
 #if defined(OS_MACOSX)
-#include "content/public/browser/power_save_blocker.h"
-#include "content/public/browser/power_save_blocker_factory.h"
+#include "content/browser/power_save_blocker_factory.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 #endif
 
@@ -1296,8 +1296,8 @@
     DCHECK(!power_save_blocker_);
     power_save_blocker_.reset(
         CreatePowerSaveBlocker(
-            PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
-            PowerSaveBlocker::kReasonOther, "GetSnapshot")
+            device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+            device::PowerSaveBlocker::kReasonOther, "GetSnapshot")
             .release());
   }
 #endif
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index a957311..502fc12 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -68,6 +68,12 @@
 class CompositorFrameAck;
 }
 
+#if defined(OS_MACOSX)
+namespace device {
+class PowerSaveBlocker;
+}  // namespace device
+#endif
+
 namespace gfx {
 class Range;
 }
@@ -87,10 +93,6 @@
 struct ResizeParams;
 struct TextInputState;
 
-#if defined(OS_MACOSX)
-class PowerSaveBlocker;
-#endif
-
 // This implements the RenderWidgetHost interface that is exposed to
 // embedders of content, and adds things only visible to content.
 class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost,
@@ -829,7 +831,7 @@
   base::TimeDelta new_content_rendering_delay_;
 
 #if defined(OS_MACOSX)
-  std::unique_ptr<PowerSaveBlocker> power_save_blocker_;
+  std::unique_ptr<device::PowerSaveBlocker> power_save_blocker_;
 #endif
 
   base::WeakPtrFactory<RenderWidgetHostImpl> weak_factory_;
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index 68b3476..6b759cee 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -597,9 +597,6 @@
         ->GetInputEventRouter()
         ->AddSurfaceIdNamespaceOwner(GetSurfaceIdNamespace(), this);
   }
-
-  if (!render_widget_host_->is_hidden())
-    EnsureBrowserCompositorView();
 }
 
 RenderWidgetHostViewMac::~RenderWidgetHostViewMac() {
@@ -643,7 +640,6 @@
 // RenderWidgetHostViewMac, RenderWidgetHostView implementation:
 
 void RenderWidgetHostViewMac::EnsureBrowserCompositorView() {
-  DCHECK(!render_widget_host_->is_hidden());
   TRACE_EVENT0("browser",
                "RenderWidgetHostViewMac::EnsureBrowserCompositorView");
 
@@ -720,7 +716,6 @@
 
   // This should only be reached if |render_widget_host_| is hidden, destroyed,
   // or in the process of being destroyed.
-  DCHECK(!render_widget_host_ || render_widget_host_->is_hidden());
   DestroyBrowserCompositorView();
 }
 
@@ -892,12 +887,8 @@
 void RenderWidgetHostViewMac::Show() {
   ScopedCAActionDisabler disabler;
   [cocoa_view_ setHidden:NO];
-  if (!render_widget_host_->is_hidden()) {
-    DCHECK_EQ(browser_compositor_state_, BrowserCompositorActive);
+  if (!render_widget_host_->is_hidden())
     return;
-  }
-
-  WasUnOccluded();
 
   // Re-create the browser compositor. If the DelegatedFrameHost has a cached
   // frame from the last time it was visible, then it will immediately be
@@ -905,6 +896,8 @@
   // frame is swapped.
   EnsureBrowserCompositorView();
 
+  WasUnOccluded();
+
   // If there is not a frame being currently drawn, kick one, so that the below
   // pause will have a frame to wait on.
   render_widget_host_->ScheduleComposite();
@@ -924,11 +917,6 @@
     // completes. As a result you won't get a thumbnail for the page unless you
     // execute these two statements in this specific order.
     render_widget_host_->WasHidden();
-    // Re-check hidden flag, as the thumbnail generation could have called
-    // WasUnOccluded and unhidden itself.
-    if (!render_widget_host_->is_hidden()) {
-      return;
-    }
     SuspendBrowserCompositorView();
   }
   DestroySuspendedBrowserCompositorViewIfNeeded();
@@ -944,7 +932,6 @@
       render_widget_host_->GetLatencyComponentId(),
       0);
   render_widget_host_->WasShown(renderer_latency_info);
-  EnsureBrowserCompositorView();
 }
 
 void RenderWidgetHostViewMac::WasOccluded() {
@@ -1507,7 +1494,8 @@
     gfx::Size dip_size = gfx::ConvertSizeToDIP(scale_factor, pixel_size);
 
     root_layer_->SetBounds(gfx::Rect(dip_size));
-    if (browser_compositor_ && browser_compositor_->compositor()) {
+    if (!render_widget_host_->is_hidden()) {
+      EnsureBrowserCompositorView();
       browser_compositor_->compositor()->SetScaleAndSize(
           scale_factor, pixel_size);
     }
diff --git a/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm b/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm
index 42275cb5..5a8cfef 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm
@@ -20,7 +20,6 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
-#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 #include "ui/base/layout.h"
 
 using content::RenderWidgetHostViewMac;
@@ -134,10 +133,6 @@
 
   base::mac::ScopedNSAutoreleasePool pool;
 
-  base::MessageLoop message_loop;
-  ui::WindowResizeHelperMac::Get()->Init(
-    base::MessageLoop::current()->task_runner());
-
   // Owned by its |cocoa_view()|, i.e. |rwhv_cocoa|.
   RenderWidgetHostViewMac* rwhv_mac = new RenderWidgetHostViewMac(
       render_widget, false);
@@ -162,10 +157,11 @@
   rwhv_cocoa.reset();
   pool.Recycle();
 
-  // The |render_widget|'s process needs to be deleted within |message_loop|.
-  delete render_widget;
-
-  ui::WindowResizeHelperMac::Get()->ShutdownForTests();
+  {
+    // The |render_widget|'s process needs to be deleted within |message_loop|.
+    base::MessageLoop message_loop;
+    delete render_widget;
+  }
 }
 
 // Test RenderWidgetHostViewMacEditCommandHelper::AddEditingSelectorsToClass
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index cd5835c..f9d6d7f 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -87,8 +87,8 @@
   GURL extension_url("https://bar.com/simple_page.html");
   WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell->web_contents());
   wc->GetFrameTree()->root()->navigator()->RequestOpenURL(
-      wc->GetFrameTree()->root()->current_frame_host(), extension_url, nullptr,
-      Referrer(), CURRENT_TAB, false, true);
+      wc->GetFrameTree()->root()->current_frame_host(), extension_url, false,
+      nullptr, nullptr, Referrer(), CURRENT_TAB, false, true);
 
   // Since the navigation above requires a cross-process swap, there will be a
   // speculative/pending RenderFrameHost. Ensure it exists and is in a different
diff --git a/content/browser/wake_lock/wake_lock_service_context.cc b/content/browser/wake_lock/wake_lock_service_context.cc
index 1f0f0c5..48d3454 100644
--- a/content/browser/wake_lock/wake_lock_service_context.cc
+++ b/content/browser/wake_lock/wake_lock_service_context.cc
@@ -8,13 +8,13 @@
 
 #include "base/bind.h"
 #include "build/build_config.h"
-#include "content/browser/power_save_blocker_impl.h"
+#include "content/browser/power_save_blocker_factory.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/power_save_blocker_factory.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/service_registry.h"
+#include "device/power_save_blocker/power_save_blocker_impl.h"
 
 namespace content {
 
@@ -69,8 +69,8 @@
 void WakeLockServiceContext::CreateWakeLock() {
   DCHECK(!wake_lock_);
   wake_lock_ = CreatePowerSaveBlocker(
-      PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
-      PowerSaveBlocker::kReasonOther, "Wake Lock API");
+      device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+      device::PowerSaveBlocker::kReasonOther, "Wake Lock API");
 
 #if defined(OS_ANDROID)
   // On Android, additionaly associate the blocker with this WebContents.
@@ -79,7 +79,7 @@
   if (web_contents()->GetNativeView()) {
     view_weak_factory_.reset(new base::WeakPtrFactory<ui::ViewAndroid>(
         web_contents()->GetNativeView()));
-    static_cast<PowerSaveBlockerImpl*>(wake_lock_.get())
+    static_cast<device::PowerSaveBlockerImpl*>(wake_lock_.get())
         ->InitDisplaySleepBlocker(view_weak_factory_->GetWeakPtr());
   }
 #endif
diff --git a/content/browser/wake_lock/wake_lock_service_context.h b/content/browser/wake_lock/wake_lock_service_context.h
index 28ce108..31bd1cb 100644
--- a/content/browser/wake_lock/wake_lock_service_context.h
+++ b/content/browser/wake_lock/wake_lock_service_context.h
@@ -20,9 +20,12 @@
 #include "ui/android/view_android.h"
 #endif  // OS_ANDROID
 
+namespace device {
+class PowerSaveBlocker;
+}  // namespace device
+
 namespace content {
 
-class PowerSaveBlocker;
 class RenderFrameHost;
 class WebContents;
 
@@ -62,7 +65,7 @@
   std::set<std::pair<int, int>> frames_requesting_lock_;
 
   // The actual power save blocker for screen.
-  std::unique_ptr<PowerSaveBlocker> wake_lock_;
+  std::unique_ptr<device::PowerSaveBlocker> wake_lock_;
 #if defined(OS_ANDROID)
   std::unique_ptr<base::WeakPtrFactory<ui::ViewAndroid>> view_weak_factory_;
 #endif
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 520b312..e3ae870 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -452,6 +452,9 @@
 // the browser process should look for an existing history item for the frame.
 IPC_STRUCT_BEGIN(FrameHostMsg_OpenURL_Params)
   IPC_STRUCT_MEMBER(GURL, url)
+  IPC_STRUCT_MEMBER(bool, uses_post)
+  IPC_STRUCT_MEMBER(scoped_refptr<content::ResourceRequestBodyImpl>,
+                    resource_request_body)
   IPC_STRUCT_MEMBER(content::Referrer, referrer)
   IPC_STRUCT_MEMBER(WindowOpenDisposition, disposition)
   IPC_STRUCT_MEMBER(bool, should_replace_current_entry)
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index c01062f..09ded70 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -18,6 +18,7 @@
     '../device/battery/battery.gyp:device_battery_mojo_bindings',
     '../device/bluetooth/bluetooth.gyp:device_bluetooth',
     '../device/usb/usb.gyp:device_usb',
+    '../device/power_save_blocker/power_save_blocker.gyp:device_power_save_blocker',
     '../device/vibration/vibration.gyp:device_vibration',
     '../device/vibration/vibration.gyp:device_vibration_mojo_bindings',
     '../gin/gin.gyp:gin',
@@ -102,6 +103,7 @@
   ],
   'variables': {
     'public_browser_sources': [
+      'browser/power_save_blocker_factory.h',
       'public/browser/access_token_store.h',
       'public/browser/android/browser_media_player_manager_register.cc',
       'public/browser/android/browser_media_player_manager_register.h',
@@ -253,8 +255,6 @@
       'public/browser/plugin_data_remover.h',
       'public/browser/plugin_service.h',
       'public/browser/plugin_service_filter.h',
-      'public/browser/power_save_blocker.h',
-      'public/browser/power_save_blocker_factory.h',
       'public/browser/presentation_screen_availability_listener.h',
       'public/browser/presentation_service_delegate.h',
       'public/browser/presentation_session.cc',
@@ -1174,15 +1174,7 @@
       'browser/permissions/permission_service_impl.h',
       'browser/power_monitor_message_broadcaster.cc',
       'browser/power_monitor_message_broadcaster.h',
-      'browser/power_save_blocker_android.h',
-      'browser/power_save_blocker_chromeos.cc',
       'browser/power_save_blocker_factory.cc',
-      'browser/power_save_blocker_impl.cc',
-      'browser/power_save_blocker_impl.h',
-      'browser/power_save_blocker_mac.cc',
-      'browser/power_save_blocker_ozone.cc',
-      'browser/power_save_blocker_win.cc',
-      'browser/power_save_blocker_x11.cc',
       'browser/power_usage_monitor_impl.cc',
       'browser/power_usage_monitor_impl.h',
       'browser/presentation/presentation_service_impl.cc',
@@ -1710,7 +1702,6 @@
       'browser/android/tracing_controller_android.h',
       'browser/android/web_contents_observer_proxy.cc',
       'browser/android/web_contents_observer_proxy.h',
-      'browser/power_save_blocker_android.cc',
       'browser/renderer_host/compositor_impl_android.cc',
       'browser/renderer_host/compositor_impl_android.h',
       'browser/renderer_host/ime_adapter_android.cc',
@@ -1766,8 +1757,8 @@
       'browser/compositor/browser_compositor_output_surface.h',
       'browser/compositor/gpu_browser_compositor_output_surface.cc',
       'browser/compositor/gpu_browser_compositor_output_surface.h',
-      'browser/compositor/gpu_output_surface_mac.mm',
       'browser/compositor/gpu_output_surface_mac.h',
+      'browser/compositor/gpu_output_surface_mac.mm',
       'browser/compositor/gpu_process_transport_factory.cc',
       'browser/compositor/gpu_process_transport_factory.h',
       'browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc',
@@ -2111,8 +2102,6 @@
       'sources!': [
         'browser/device_sensors/data_fetcher_shared_memory_default.cc',
         'browser/geolocation/wifi_data_provider_linux.cc',
-        'browser/power_save_blocker_ozone.cc',
-        'browser/power_save_blocker_x11.cc',
       ],
     }],
     ['os_bsd==1', {
diff --git a/content/content_jni.gypi b/content/content_jni.gypi
index 141c169..5ed0cc7 100644
--- a/content/content_jni.gypi
+++ b/content/content_jni.gypi
@@ -31,7 +31,6 @@
     'public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java',
     'public/android/java/src/org/chromium/content/browser/MediaThrottler.java',
     'public/android/java/src/org/chromium/content/browser/MotionEventSynthesizer.java',
-    'public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java',
     'public/android/java/src/org/chromium/content/browser/ServiceRegistrar.java',
     'public/android/java/src/org/chromium/content/browser/ServiceRegistry.java',
     'public/android/java/src/org/chromium/content/browser/ScreenOrientationProvider.java',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 1f59c45..bcd6f4c 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -985,11 +985,6 @@
             '../third_party/libvpx/libvpx.gyp:libvpx',
           ],
         }],
-        ['OS=="mac"', {
-          'dependencies': [
-            '../ui/accelerated_widget_mac/accelerated_widget_mac.gyp:accelerated_widget_mac',
-          ],
-        }],
         ['OS=="android"', {
           'dependencies': [
             '../ui/android/ui_android.gyp:ui_android',
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index 0c181c7..61e90bc 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -35,6 +35,7 @@
     "//device/battery:mojo_bindings_java",
     "//device/battery/android:battery_monitor_android",
     "//device/bluetooth:java",
+    "//device/power_save_blocker:java",
     "//device/usb:java",
     "//device/vibration:mojo_bindings_java",
     "//device/vibration/android:vibration_manager_android",
@@ -132,7 +133,6 @@
     "java/src/org/chromium/content/browser/PepperPluginManager.java",
     "java/src/org/chromium/content/browser/PopupZoomer.java",
     "java/src/org/chromium/content/browser/PositionObserver.java",
-    "java/src/org/chromium/content/browser/PowerSaveBlocker.java",
     "java/src/org/chromium/content/browser/RenderCoordinates.java",
     "java/src/org/chromium/content/browser/SPenSupport.java",
     "java/src/org/chromium/content/browser/ScreenOrientationListener.java",
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
index 4107dd9..e1d56fa9 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
@@ -24,6 +24,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.FlakyTest;
 import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
@@ -628,6 +629,7 @@
     @CommandLineFlags.Add("enable-features=ImeThread")
     @MediumTest
     @Feature({"TextInput"})
+    @FlakyTest
     public void testPasteLongText() throws Exception {
         int textLength = 25000;
         String text = new String(new char[textLength]).replace("\0", "a");
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index 6b1faf1..a8c4629 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -43,6 +43,7 @@
     "//cc",
     "//content/browser",  # Must not be public_deps!
     "//content/public/common:common_sources",
+    "//device/power_save_blocker",
     "//gpu",
     "//media",
     "//net",
diff --git a/content/public/browser/power_save_blocker_factory.h b/content/public/browser/power_save_blocker_factory.h
deleted file mode 100644
index a40c0ce..0000000
--- a/content/public/browser/power_save_blocker_factory.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_PUBLIC_BROWSER_POWER_SAVE_BLOCKER_FACTORY_H_
-#define CONTENT_PUBLIC_BROWSER_POWER_SAVE_BLOCKER_FACTORY_H_
-
-#include <memory>
-#include <string>
-
-#include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner.h"
-#include "content/common/content_export.h"
-#include "content/public/browser/power_save_blocker.h"
-
-namespace content {
-
-CONTENT_EXPORT std::unique_ptr<PowerSaveBlocker> CreatePowerSaveBlocker(
-    PowerSaveBlocker::PowerSaveBlockerType type,
-    PowerSaveBlocker::Reason reason,
-    const std::string& description);
-
-}  // namespace content
-
-#endif  // CONTENT_PUBLIC_BROWSER_POWER_SAVE_BLOCKER_FACTORY_H_
diff --git a/content/public/test/test_renderer_host.cc b/content/public/test/test_renderer_host.cc
index 8983d7a..35d4ca6 100644
--- a/content/public/test/test_renderer_host.cc
+++ b/content/public/test/test_renderer_host.cc
@@ -37,10 +37,6 @@
 #include "ui/wm/core/default_activation_client.h"
 #endif
 
-#if defined(OS_MACOSX)
-#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
-#endif
-
 namespace content {
 
 // RenderFrameHostTester ------------------------------------------------------
@@ -215,11 +211,6 @@
 
   if (IsBrowserSideNavigationEnabled())
     BrowserSideNavigationSetUp();
-
-#if defined(OS_MACOSX)
-  ui::WindowResizeHelperMac::Get()->Init(
-    base::MessageLoop::current()->task_runner());
-#endif  // OS_MACOSX
 }
 
 void RenderViewHostTestHarness::TearDown() {
@@ -235,10 +226,6 @@
   // before we destroy the browser context.
   base::RunLoop().RunUntilIdle();
 
-#if defined(OS_MACOSX)
-  ui::WindowResizeHelperMac::Get()->ShutdownForTests();
-#endif  // OS_MACOSX
-
 #if defined(OS_WIN)
   ole_initializer_.reset();
 #endif
diff --git a/content/renderer/media/media_stream_audio_processor.cc b/content/renderer/media/media_stream_audio_processor.cc
index 68aefcbf..272a70f 100644
--- a/content/renderer/media/media_stream_audio_processor.cc
+++ b/content/renderer/media/media_stream_audio_processor.cc
@@ -136,6 +136,11 @@
     thread_checker_.DetachFromThread();
   }
 
+  void ReattachThreadChecker() {
+    thread_checker_.DetachFromThread();
+    DCHECK(thread_checker_.CalledOnValidThread());
+  }
+
   media::AudioBus* bus() {
     DCHECK(thread_checker_.CalledOnValidThread());
     return bus_.get();
@@ -194,6 +199,12 @@
     thread_checker_.DetachFromThread();
   }
 
+  void ReattachThreadChecker() {
+    thread_checker_.DetachFromThread();
+    DCHECK(thread_checker_.CalledOnValidThread());
+    destination_->ReattachThreadChecker();
+  }
+
   void Push(const media::AudioBus& source, base::TimeDelta audio_delay) {
     DCHECK(thread_checker_.CalledOnValidThread());
     DCHECK_EQ(source.channels(), source_channels_);
@@ -474,6 +485,12 @@
   render_fifo_.reset();
 }
 
+void MediaStreamAudioProcessor::OnRenderThreadChanged() {
+  render_thread_checker_.DetachFromThread();
+  DCHECK(render_thread_checker_.CalledOnValidThread());
+  render_fifo_->ReattachThreadChecker();
+}
+
 void MediaStreamAudioProcessor::GetStats(AudioProcessorStats* stats) {
   stats->typing_noise_detected =
       (base::subtle::Acquire_Load(&typing_detected_) != false);
diff --git a/content/renderer/media/media_stream_audio_processor.h b/content/renderer/media/media_stream_audio_processor.h
index 6629015..7cf9af0 100644
--- a/content/renderer/media/media_stream_audio_processor.h
+++ b/content/renderer/media/media_stream_audio_processor.h
@@ -124,6 +124,7 @@
                      int sample_rate,
                      int audio_delay_milliseconds) override;
   void OnPlayoutDataSourceChanged() override;
+  void OnRenderThreadChanged() override;
 
   // webrtc::AudioProcessorInterface implementation.
   // This method is called on the libjingle thread.
diff --git a/content/renderer/media/rtc_video_encoder.cc b/content/renderer/media/rtc_video_encoder.cc
index 4ce16d5..cb7752b 100644
--- a/content/renderer/media/rtc_video_encoder.cc
+++ b/content/renderer/media/rtc_video_encoder.cc
@@ -453,10 +453,10 @@
     size_t payload_size,
     bool key_frame,
     base::TimeDelta timestamp) {
-  DVLOG(3) << "Impl::BitstreamBufferReady(): "
-              "bitstream_buffer_id=" << bitstream_buffer_id
-           << ", payload_size=" << payload_size
-           << ", key_frame=" << key_frame;
+  DVLOG(3) << "Impl::BitstreamBufferReady(): bitstream_buffer_id="
+           << bitstream_buffer_id << ", payload_size=" << payload_size
+           << ", key_frame=" << key_frame
+           << ", timestamp ms=" << timestamp.InMilliseconds();
   DCHECK(thread_checker_.CalledOnValidThread());
 
   if (bitstream_buffer_id < 0 ||
@@ -473,11 +473,17 @@
   }
   output_buffers_free_count_--;
 
+  // CrOS Nyan provides invalid timestamp. Use the current time for now.
+  // TODO(wuchengli): use the timestamp in BitstreamBufferReady after Nyan is
+  // fixed. http://crbug.com/620565.
+  const int64_t capture_time_us = rtc::TimeMicros();
+
   // Derive the capture time (in ms) and RTP timestamp (in 90KHz ticks).
-  // This is based on how input timestamps are calculated in
-  // webrtc/video/video_capture_input.cc.
-  const uint32_t rtp_timestamp =
-      static_cast<uint32_t>(timestamp.InMilliseconds()) * 90;
+  const int64_t capture_time_ms =
+      capture_time_us / base::Time::kMicrosecondsPerMillisecond;
+
+  const uint32_t rtp_timestamp = static_cast<uint32_t>(
+      capture_time_us * 90 / base::Time::kMicrosecondsPerMillisecond);
 
   webrtc::EncodedImage image(
       reinterpret_cast<uint8_t*>(output_buffer->memory()), payload_size,
@@ -485,7 +491,7 @@
   image._encodedWidth = input_visible_size_.width();
   image._encodedHeight = input_visible_size_.height();
   image._timeStamp = rtp_timestamp;
-  image.capture_time_ms_ = timestamp.InMilliseconds();
+  image.capture_time_ms_ = capture_time_ms;
   image._frameType =
       (key_frame ? webrtc::kVideoFrameKey : webrtc::kVideoFrameDelta);
   image._completeFrame = true;
diff --git a/content/renderer/media/webrtc_audio_device_impl.cc b/content/renderer/media/webrtc_audio_device_impl.cc
index 7f46506..2cb2eac 100644
--- a/content/renderer/media/webrtc_audio_device_impl.cc
+++ b/content/renderer/media/webrtc_audio_device_impl.cc
@@ -4,6 +4,7 @@
 
 #include "content/renderer/media/webrtc_audio_device_impl.h"
 
+#include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/string_util.h"
 #include "base/win/windows_version.h"
@@ -62,9 +63,15 @@
                                        int sample_rate,
                                        int audio_delay_milliseconds,
                                        base::TimeDelta* current_time) {
-  DCHECK(audio_renderer_thread_checker_.CalledOnValidThread());
   {
     base::AutoLock auto_lock(lock_);
+#if DCHECK_IS_ON()
+    DCHECK(renderer_->CurrentThreadIsRenderingThread());
+    if (!audio_renderer_thread_checker_.CalledOnValidThread()) {
+      for (const auto& sink : playout_sinks_)
+        sink->OnRenderThreadChanged();
+    }
+#endif
     if (!playing_) {
       // Force silence to AudioBus after stopping playout in case
       // there is lingering audio data in AudioBus.
diff --git a/content/renderer/media/webrtc_audio_device_impl.h b/content/renderer/media/webrtc_audio_device_impl.h
index 6af4a86..1e3f05f1 100644
--- a/content/renderer/media/webrtc_audio_device_impl.h
+++ b/content/renderer/media/webrtc_audio_device_impl.h
@@ -219,7 +219,7 @@
   class Sink {
    public:
     // Callback to get the playout data.
-    // Called on the render audio thread.
+    // Called on the audio render thread.
     virtual void OnPlayoutData(media::AudioBus* audio_bus,
                                int sample_rate,
                                int audio_delay_milliseconds) = 0;
@@ -228,6 +228,11 @@
     // Called on the main render thread.
     virtual void OnPlayoutDataSourceChanged() = 0;
 
+    // Called to notify that the audio render thread has changed, and
+    // OnPlayoutData() will from now on be called on the new thread.
+    // Called on the new audio render thread.
+    virtual void OnRenderThreadChanged() = 0;
+
    protected:
     virtual ~Sink() {}
   };
diff --git a/content/renderer/media/webrtc_audio_renderer.cc b/content/renderer/media/webrtc_audio_renderer.cc
index f508a541..d5dec1b 100644
--- a/content/renderer/media/webrtc_audio_renderer.cc
+++ b/content/renderer/media/webrtc_audio_renderer.cc
@@ -208,7 +208,6 @@
   WebRtcLogMessage(base::StringPrintf(
       "WAR::WAR. source_render_frame_id=%d, session_id=%d, effects=%i",
       source_render_frame_id, session_id, sink_params_.effects()));
-  audio_renderer_thread_checker_.DetachFromThread();
 }
 
 WebRtcAudioRenderer::~WebRtcAudioRenderer() {
@@ -240,7 +239,7 @@
   PrepareSink();
   {
     // No need to reassert the preconditions because the other thread accessing
-    // the fields (checked by |audio_renderer_thread_checker_|) only reads them.
+    // the fields only reads them.
     base::AutoLock auto_lock(lock_);
     source_ = source;
 
@@ -266,6 +265,10 @@
   return start_ref_count_ != 0;
 }
 
+bool WebRtcAudioRenderer::CurrentThreadIsRenderingThread() {
+  return sink_->CurrentThreadIsRenderingThread();
+}
+
 void WebRtcAudioRenderer::Start() {
   DVLOG(1) << "WebRtcAudioRenderer::Start()";
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -406,7 +409,6 @@
   // callback may currently be executing and trying to grab the lock while we're
   // stopping the thread on which it runs.
   sink_->Stop();
-  audio_renderer_thread_checker_.DetachFromThread();
   sink_ = new_sink;
   output_device_id_ = device_id;
   security_origin_ = security_origin;
@@ -423,7 +425,7 @@
 int WebRtcAudioRenderer::Render(media::AudioBus* audio_bus,
                                 uint32_t frames_delayed,
                                 uint32_t frames_skipped) {
-  DCHECK(audio_renderer_thread_checker_.CalledOnValidThread());
+  DCHECK(sink_->CurrentThreadIsRenderingThread());
   base::AutoLock auto_lock(lock_);
   if (!source_)
     return 0;
@@ -480,7 +482,7 @@
 // Called by AudioPullFifo when more data is necessary.
 void WebRtcAudioRenderer::SourceCallback(
     int fifo_frame_delay, media::AudioBus* audio_bus) {
-  DCHECK(audio_renderer_thread_checker_.CalledOnValidThread());
+  DCHECK(sink_->CurrentThreadIsRenderingThread());
   base::TimeTicks start_time = base::TimeTicks::Now();
   DVLOG(2) << "WebRtcAudioRenderer::SourceCallback("
            << fifo_frame_delay << ", "
diff --git a/content/renderer/media/webrtc_audio_renderer.h b/content/renderer/media/webrtc_audio_renderer.h
index f13ac8d..1e0a335 100644
--- a/content/renderer/media/webrtc_audio_renderer.h
+++ b/content/renderer/media/webrtc_audio_renderer.h
@@ -109,6 +109,9 @@
   int sample_rate() const { return sink_params_.sample_rate(); }
   int frames_per_buffer() const { return sink_params_.frames_per_buffer(); }
 
+  // Returns true if called on rendering thread, otherwise false.
+  bool CurrentThreadIsRenderingThread();
+
  private:
   // MediaStreamAudioRenderer implementation.  This is private since we want
   // callers to use proxy objects.
@@ -155,7 +158,6 @@
 
   // Used to DCHECK that we are called on the correct thread.
   base::ThreadChecker thread_checker_;
-  base::ThreadChecker audio_renderer_thread_checker_;
 
   // Flag to keep track the state of the renderer.
   State state_;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 5f3ab60..b57c63c 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -808,6 +808,10 @@
               ssl_status.connection_status);
 }
 
+bool IsHttpPost(const blink::WebURLRequest& request) {
+  return request.httpMethod().utf8() == "POST";
+}
+
 #if defined(OS_ANDROID)
 // Returns true if WMPI should be used for playback, false otherwise.
 //
@@ -2989,8 +2993,9 @@
                                                    request.url(), referrer,
                                                    suggested_name));
   } else {
-    OpenURL(request.url(), referrer, policy, should_replace_current_entry,
-            false);
+    OpenURL(request.url(), IsHttpPost(request),
+            GetRequestBodyForWebURLRequest(request), referrer, policy,
+            should_replace_current_entry, false);
   }
 }
 
@@ -4890,8 +4895,9 @@
   if (is_content_initiated && IsTopLevelNavigation(frame_) &&
       render_view_->renderer_preferences_
           .browser_handles_all_top_level_requests) {
-    OpenURL(url, referrer, info.defaultPolicy, info.replacesCurrentHistoryItem,
-            false);
+    OpenURL(url, IsHttpPost(info.urlRequest),
+            GetRequestBodyForWebURLRequest(info.urlRequest), referrer,
+            info.defaultPolicy, info.replacesCurrentHistoryItem, false);
     return blink::WebNavigationPolicyIgnore;  // Suppress the load here.
   }
 
@@ -4900,8 +4906,9 @@
   // FrameNavigationEntry.  If none is found, fall back to the default url.
   if (SiteIsolationPolicy::UseSubframeNavigationEntries() &&
       info.isHistoryNavigationInNewChildFrame && is_content_initiated) {
-    OpenURL(url, referrer, info.defaultPolicy, info.replacesCurrentHistoryItem,
-            true);
+    OpenURL(url, IsHttpPost(info.urlRequest),
+            GetRequestBodyForWebURLRequest(info.urlRequest), referrer,
+            info.defaultPolicy, info.replacesCurrentHistoryItem, true);
     // Suppress the load in Blink but mark the frame as loading.
     return blink::WebNavigationPolicyHandledByClient;
   }
@@ -4916,15 +4923,6 @@
   // an extension or app origin, leaving a WebUI page, etc). We only care about
   // top-level navigations (not iframes). But we sometimes navigate to
   // about:blank to clear a tab, and we want to still allow that.
-  //
-  // Note: this is known to break POST submissions when crossing process
-  // boundaries until http://crbug.com/101395 is fixed.  This is better for
-  // security than loading a WebUI, extension or app page in the wrong process.
-  // POST requests don't work because this mechanism does not preserve form
-  // POST data. We will need to send the request's httpBody data up to the
-  // browser process, and issue a special POST navigation in WebKit (via
-  // FrameLoader::loadFrameRequest). See ResourceDispatcher and WebURLLoaderImpl
-  // for examples of how to send the httpBody data.
   if (!frame_->parent() && is_content_initiated &&
       !url.SchemeIs(url::kAboutScheme)) {
     bool send_referrer = false;
@@ -4964,7 +4962,9 @@
     }
 
     if (should_fork) {
-      OpenURL(url, send_referrer ? referrer : Referrer(), info.defaultPolicy,
+      OpenURL(url, IsHttpPost(info.urlRequest),
+              GetRequestBodyForWebURLRequest(info.urlRequest),
+              send_referrer ? referrer : Referrer(), info.defaultPolicy,
               info.replacesCurrentHistoryItem, false);
       return blink::WebNavigationPolicyIgnore;  // Suppress the load here.
     }
@@ -5004,8 +5004,9 @@
 
   if (is_fork) {
     // Open the URL via the browser, not via WebKit.
-    OpenURL(url, Referrer(), info.defaultPolicy,
-            info.replacesCurrentHistoryItem, false);
+    OpenURL(url, IsHttpPost(info.urlRequest),
+            GetRequestBodyForWebURLRequest(info.urlRequest), Referrer(),
+            info.defaultPolicy, info.replacesCurrentHistoryItem, false);
     return blink::WebNavigationPolicyIgnore;
   }
 
@@ -5335,13 +5336,18 @@
 #endif
 #endif
 
-void RenderFrameImpl::OpenURL(const GURL& url,
-                              const Referrer& referrer,
-                              WebNavigationPolicy policy,
-                              bool should_replace_current_entry,
-                              bool is_history_navigation_in_new_child) {
+void RenderFrameImpl::OpenURL(
+    const GURL& url,
+    bool uses_post,
+    const scoped_refptr<ResourceRequestBodyImpl>& resource_request_body,
+    const Referrer& referrer,
+    WebNavigationPolicy policy,
+    bool should_replace_current_entry,
+    bool is_history_navigation_in_new_child) {
   FrameHostMsg_OpenURL_Params params;
   params.url = url;
+  params.uses_post = uses_post;
+  params.resource_request_body = resource_request_body;
   params.referrer = referrer;
   params.disposition = RenderViewImpl::NavigationPolicyToDisposition(policy);
 
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 77ab89e..8c2b6010 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -17,6 +17,7 @@
 #include "base/id_map.h"
 #include "base/macros.h"
 #include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/process/process_handle.h"
@@ -852,11 +853,14 @@
   // |is_history_navigation_in_new_child| is true, the browser process should
   // look for a matching FrameNavigationEntry in the last committed entry to use
   // instead of |url|.
-  void OpenURL(const GURL& url,
-               const Referrer& referrer,
-               blink::WebNavigationPolicy policy,
-               bool should_replace_current_entry,
-               bool is_history_navigation_in_new_child);
+  void OpenURL(
+      const GURL& url,
+      bool uses_post,
+      const scoped_refptr<ResourceRequestBodyImpl>& resource_request_body,
+      const Referrer& referrer,
+      blink::WebNavigationPolicy policy,
+      bool should_replace_current_entry,
+      bool is_history_navigation_in_new_child);
 
   // Performs a navigation in the frame. This provides a unified function for
   // the current code path and the browser-side navigation path (in
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index 1dd8b44..74bcd08 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -10,6 +10,7 @@
 
 #include "base/command_line.h"
 #include "base/lazy_instance.h"
+#include "content/child/web_url_request_util.h"
 #include "content/child/webmessageportchannel_impl.h"
 #include "content/common/content_security_policy_header.h"
 #include "content/common/frame_messages.h"
@@ -446,6 +447,8 @@
                                 bool should_replace_current_entry) {
   FrameHostMsg_OpenURL_Params params;
   params.url = request.url();
+  params.uses_post = request.httpMethod().utf8() == "POST";
+  params.resource_request_body = GetRequestBodyForWebURLRequest(request);
   params.referrer = Referrer(
       blink::WebStringToGURL(
           request.httpHeaderField(blink::WebString::fromUTF8("Referer"))),
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 61f8529..a59f6e4f 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -197,10 +197,6 @@
   if (v8_use_external_startup_data) {
     deps += [ "//gin:gin" ]
   }
-
-  if (is_mac) {
-    deps += [ "//ui/accelerated_widget_mac" ]
-  }
 }
 
 # browsertest_support can be used by targets that run content_shell based
@@ -796,7 +792,6 @@
     deps += [
       "//third_party/mozilla",
       "//third_party/ocmock",
-      "//ui/accelerated_widget_mac",
     ]
   }
   if (is_chromeos) {
diff --git a/content/test/data/form_that_posts_to_echoall.html b/content/test/data/form_that_posts_to_echoall.html
new file mode 100644
index 0000000..ddd726e
--- /dev/null
+++ b/content/test/data/form_that_posts_to_echoall.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <head></head>
+  <body>
+    <form id="form" method="POST" action="/echoall">
+      <input type="text" name="text" value="value">
+      <input type="submit">
+    </form>
+  </body>
+</html>
diff --git a/device/BUILD.gn b/device/BUILD.gn
index dde0cd0..eb63e5e 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -70,6 +70,7 @@
     "//device/bluetooth",
     "//device/bluetooth:mocks",
     "//device/nfc",
+    "//device/power_save_blocker",
     "//device/vr",
     "//device/vr:fakes",
     "//device/vr:mojo_bindings",
diff --git a/device/power_save_blocker/BUILD.gn b/device/power_save_blocker/BUILD.gn
new file mode 100644
index 0000000..abd1856
--- /dev/null
+++ b/device/power_save_blocker/BUILD.gn
@@ -0,0 +1,96 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/features.gni")
+import("//build/config/ui.gni")
+
+if (is_android) {
+  import("//build/config/android/rules.gni")
+}
+
+component("power_save_blocker") {
+  sources = [
+    "power_save_blocker.h",
+    "power_save_blocker_android.cc",
+    "power_save_blocker_android.h",
+    "power_save_blocker_chromeos.cc",
+    "power_save_blocker_impl.cc",
+    "power_save_blocker_impl.h",
+    "power_save_blocker_mac.cc",
+    "power_save_blocker_ozone.cc",
+    "power_save_blocker_win.cc",
+    "power_save_blocker_x11.cc",
+  ]
+
+  defines = [ "DEVICE_POWER_SAVE_BLOCKER_IMPLEMENTATION" ]
+
+  deps = [
+    "//base",
+  ]
+
+  if (use_dbus) {
+    deps += [ "//dbus" ]
+  }
+
+  if (use_x11) {
+    configs += [ "//build/config/linux:x11" ]
+    if (!is_chromeos) {
+      configs += [ "//build/config/linux:xscrnsaver" ]
+    }
+    deps += [ "//ui/gfx/x" ]
+  }
+
+  # Dealing with power_save_blocker_{x11,ozone}.cc is a little complicated
+  # given the interaction between os_chromeos and the feature flags for X11 and
+  # ozone, so do it all in one spot.
+  if (is_chromeos || !use_ozone) {
+    sources -= [ "power_save_blocker_ozone.cc" ]
+  }
+  if (is_chromeos || !use_x11) {
+    sources -= [ "power_save_blocker_x11.cc" ]
+  }
+
+  if (is_android) {
+    sources += [
+      "power_save_blocker_jni_registrar.cc",
+      "power_save_blocker_jni_registrar.h",
+    ]
+
+    deps += [
+      ":jni_headers",
+      "//ui/android",
+    ]
+  }
+
+  if (is_chromeos) {
+    deps += [
+      "//chromeos",
+      "//chromeos:power_manager_proto",
+    ]
+  }
+
+  if (is_mac) {
+    libs = [
+      "CoreFoundation.framework",
+      "IOKit.framework",
+    ]
+  }
+}
+
+if (is_android) {
+  java_sources_needing_jni = [ "android/java/src/org/chromium/device/power_save_blocker/PowerSaveBlocker.java" ]
+
+  generate_jni("jni_headers") {
+    sources = java_sources_needing_jni
+    jni_package = "device"
+  }
+
+  android_library("java") {
+    java_files = java_sources_needing_jni
+    deps = [
+      "//base:base_java",
+      "//ui/android:ui_java",
+    ]
+  }
+}
diff --git a/device/power_save_blocker/DEPS b/device/power_save_blocker/DEPS
new file mode 100644
index 0000000..9bc85d9
--- /dev/null
+++ b/device/power_save_blocker/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+  "+dbus",
+  "+jni",
+  "+ui/android",
+  "+ui/gfx/x",
+]
diff --git a/device/power_save_blocker/OWNERS b/device/power_save_blocker/OWNERS
new file mode 100644
index 0000000..9cd2ee4
--- /dev/null
+++ b/device/power_save_blocker/OWNERS
@@ -0,0 +1,3 @@
+boliu@chromium.org
+hashimoto@chromium.org
+scottmg@chromium.org
diff --git a/content/public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java b/device/power_save_blocker/android/java/src/org/chromium/device/power_save_blocker/PowerSaveBlocker.java
similarity index 94%
rename from content/public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java
rename to device/power_save_blocker/android/java/src/org/chromium/device/power_save_blocker/PowerSaveBlocker.java
index 915d668d..3638d98 100644
--- a/content/public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java
+++ b/device/power_save_blocker/android/java/src/org/chromium/device/power_save_blocker/PowerSaveBlocker.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.content.browser;
+package org.chromium.device.power_save_blocker;
 
 import android.view.View;
 
@@ -12,7 +12,7 @@
 
 import java.lang.ref.WeakReference;
 
-@JNINamespace("content")
+@JNINamespace("device")
 class PowerSaveBlocker {
     // WeakReference to prevent leaks in Android WebView.
     private WeakReference<View> mKeepScreenOnView;
diff --git a/device/power_save_blocker/power_save_blocker.gyp b/device/power_save_blocker/power_save_blocker.gyp
new file mode 100644
index 0000000..23e779ac
--- /dev/null
+++ b/device/power_save_blocker/power_save_blocker.gyp
@@ -0,0 +1,54 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'targets': [
+    {
+      # GN version: //device/power_save_blocker
+      'target_name': 'device_power_save_blocker',
+      'type': '<(component)',
+      'dependencies': [
+        '../../base/base.gyp:base',
+      ],
+      'defines': [
+        'DEVICE_POWER_SAVE_BLOCKER_IMPLEMENTATION',
+      ],
+      'sources': [
+        # Note: file list duplicated in GN build, other than Android, as gyp
+        # for Android isn't supported.
+        'power_save_blocker.h',
+        'power_save_blocker_chromeos.cc',
+        'power_save_blocker_impl.cc',
+        'power_save_blocker_impl.h',
+        'power_save_blocker_mac.cc',
+        'power_save_blocker_ozone.cc',
+        'power_save_blocker_win.cc',
+        'power_save_blocker_x11.cc',
+      ],
+      'conditions': [
+        ['chromeos==1', {
+          'sources!': [
+            'power_save_blocker_ozone.cc',
+            'power_save_blocker_x11.cc',
+          ],
+          'dependencies': [
+            '../../chromeos/chromeos.gyp:chromeos',
+            '../../chromeos/chromeos.gyp:power_manager_proto',
+          ],
+        }],
+        ['OS == "mac"', {
+          'link_settings': {
+            'libraries': [
+              '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
+              '$(SDKROOT)/System/Library/Frameworks/IOKit.framework',
+            ],
+          },
+        }],
+      ],
+    },
+  ],
+}
diff --git a/content/public/browser/power_save_blocker.h b/device/power_save_blocker/power_save_blocker.h
similarity index 86%
rename from content/public/browser/power_save_blocker.h
rename to device/power_save_blocker/power_save_blocker.h
index db3c0f2..096d816 100644
--- a/content/public/browser/power_save_blocker.h
+++ b/device/power_save_blocker/power_save_blocker.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 CONTENT_PUBLIC_BROWSER_POWER_SAVE_BLOCKER_H_
-#define CONTENT_PUBLIC_BROWSER_POWER_SAVE_BLOCKER_H_
+#ifndef DEVICE_POWER_SAVE_BLOCKER_POWER_SAVE_BLOCKER_H_
+#define DEVICE_POWER_SAVE_BLOCKER_POWER_SAVE_BLOCKER_H_
 
 #include <memory>
 #include <string>
@@ -11,13 +11,13 @@
 #include "base/memory/ref_counted.h"
 #include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
-#include "content/common/content_export.h"
+#include "device/power_save_blocker/power_save_blocker_export.h"
 
-namespace content {
+namespace device {
 
 // A RAII-style class to block the system from entering low-power (sleep) mode.
 // This class is thread-safe; it may be constructed and deleted on any thread.
-class CONTENT_EXPORT PowerSaveBlocker {
+class DEVICE_POWER_SAVE_BLOCKER_EXPORT PowerSaveBlocker {
  public:
   enum PowerSaveBlockerType {
     // Prevent the application from being suspended. On some platforms, apps may
@@ -59,6 +59,6 @@
       scoped_refptr<base::SingleThreadTaskRunner> file_task_runner);
 };
 
-}  // namespace content
+}  // namespace device
 
-#endif  // CONTENT_PUBLIC_BROWSER_POWER_SAVE_BLOCKER_H_
+#endif  // DEVICE_POWER_SAVE_BLOCKER_POWER_SAVE_BLOCKER_H_
diff --git a/content/browser/power_save_blocker_android.cc b/device/power_save_blocker/power_save_blocker_android.cc
similarity index 94%
rename from content/browser/power_save_blocker_android.cc
rename to device/power_save_blocker/power_save_blocker_android.cc
index 6b46bc3..534ed5d4 100644
--- a/content/browser/power_save_blocker_android.cc
+++ b/device/power_save_blocker/power_save_blocker_android.cc
@@ -7,11 +7,11 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "content/browser/power_save_blocker_impl.h"
+#include "device/power_save_blocker/power_save_blocker_impl.h"
 #include "jni/PowerSaveBlocker_jni.h"
 #include "ui/android/view_android.h"
 
-namespace content {
+namespace device {
 
 using base::android::AttachCurrentThread;
 
@@ -46,8 +46,7 @@
   java_power_save_blocker_.Reset(Java_PowerSaveBlocker_create(env));
 }
 
-PowerSaveBlockerImpl::Delegate::~Delegate() {
-}
+PowerSaveBlockerImpl::Delegate::~Delegate() {}
 
 void PowerSaveBlockerImpl::Delegate::ApplyBlock() {
   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
@@ -102,4 +101,4 @@
   return RegisterNativesImpl(env);
 }
 
-}  // namespace content
+}  // namespace device
diff --git a/device/power_save_blocker/power_save_blocker_android.h b/device/power_save_blocker/power_save_blocker_android.h
new file mode 100644
index 0000000..3313958
--- /dev/null
+++ b/device/power_save_blocker/power_save_blocker_android.h
@@ -0,0 +1,16 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_POWER_SAVE_BLOCKER_POWER_SAVE_BLOCKER_ANDROID_H_
+#define DEVICE_POWER_SAVE_BLOCKER_POWER_SAVE_BLOCKER_ANDROID_H_
+
+#include <jni.h>
+
+namespace device {
+
+bool RegisterPowerSaveBlocker(JNIEnv* env);
+
+}  // namespace device
+
+#endif  // DEVICE_POWER_SAVE_BLOCKER_POWER_SAVE_BLOCKER_ANDROID_H_
diff --git a/content/browser/power_save_blocker_chromeos.cc b/device/power_save_blocker/power_save_blocker_chromeos.cc
similarity index 96%
rename from content/browser/power_save_blocker_chromeos.cc
rename to device/power_save_blocker/power_save_blocker_chromeos.cc
index 2913f09..31803583c 100644
--- a/content/browser/power_save_blocker_chromeos.cc
+++ b/device/power_save_blocker/power_save_blocker_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 "content/browser/power_save_blocker_impl.h"
+#include "device/power_save_blocker/power_save_blocker_impl.h"
 
 #include <string>
 
@@ -13,7 +13,7 @@
 #include "base/memory/ref_counted.h"
 #include "chromeos/dbus/power_policy_controller.h"
 
-namespace content {
+namespace device {
 
 namespace {
 
@@ -109,4 +109,4 @@
                             base::Bind(&Delegate::RemoveBlock, delegate_));
 }
 
-}  // namespace content
+}  // namespace device
diff --git a/device/power_save_blocker/power_save_blocker_export.h b/device/power_save_blocker/power_save_blocker_export.h
new file mode 100644
index 0000000..171405f
--- /dev/null
+++ b/device/power_save_blocker/power_save_blocker_export.h
@@ -0,0 +1,28 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_POWER_SAVE_BLOCKER_DEVICE_POWER_SAVE_BLOCKER_EXPORT_H_
+#define DEVICE_POWER_SAVE_BLOCKER_DEVICE_POWER_SAVE_BLOCKER_EXPORT_H_
+
+#if defined(COMPONENT_BUILD) && defined(WIN32)
+
+#if defined(DEVICE_POWER_SAVE_BLOCKER_IMPLEMENTATION)
+#define DEVICE_POWER_SAVE_BLOCKER_EXPORT __declspec(dllexport)
+#else
+#define DEVICE_POWER_SAVE_BLOCKER_EXPORT __declspec(dllimport)
+#endif
+
+#elif defined(COMPONENT_BUILD) && !defined(WIN32)
+
+#if defined(DEVICE_POWER_SAVE_BLOCKER_IMPLEMENTATION)
+#define DEVICE_POWER_SAVE_BLOCKER_EXPORT __attribute__((visibility("default")))
+#else
+#define DEVICE_POWER_SAVE_BLOCKER_EXPORT
+#endif
+
+#else
+#define DEVICE_POWER_SAVE_BLOCKER_EXPORT
+#endif
+
+#endif  // DEVICE_POWER_SAVE_BLOCKER_DEVICE_POWER_SAVE_BLOCKER_EXPORT_H_
diff --git a/content/browser/power_save_blocker_impl.cc b/device/power_save_blocker/power_save_blocker_impl.cc
similarity index 87%
rename from content/browser/power_save_blocker_impl.cc
rename to device/power_save_blocker/power_save_blocker_impl.cc
index 70f536cc..c37e6db 100644
--- a/content/browser/power_save_blocker_impl.cc
+++ b/device/power_save_blocker/power_save_blocker_impl.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/power_save_blocker_impl.h"
+#include "device/power_save_blocker/power_save_blocker_impl.h"
 
 #include "build/build_config.h"
 
-namespace content {
+namespace device {
 
 PowerSaveBlocker::~PowerSaveBlocker() {}
 
@@ -21,4 +21,4 @@
       type, reason, description, ui_task_runner, blocking_task_runner));
 }
 
-}  // namespace content
+}  // namespace device
diff --git a/content/browser/power_save_blocker_impl.h b/device/power_save_blocker/power_save_blocker_impl.h
similarity index 83%
rename from content/browser/power_save_blocker_impl.h
rename to device/power_save_blocker/power_save_blocker_impl.h
index dcc9e62..2f7cadb 100644
--- a/content/browser/power_save_blocker_impl.h
+++ b/device/power_save_blocker/power_save_blocker_impl.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 CONTENT_BROWSER_POWER_SAVE_BLOCKER_IMPL_H_
-#define CONTENT_BROWSER_POWER_SAVE_BLOCKER_IMPL_H_
+#ifndef DEVICE_POWER_SAVE_BLOCKER_POWER_SAVE_BLOCKER_IMPL_H_
+#define DEVICE_POWER_SAVE_BLOCKER_POWER_SAVE_BLOCKER_IMPL_H_
 
 #include <string>
 
@@ -13,13 +13,14 @@
 #include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
 #include "build/build_config.h"
-#include "content/public/browser/power_save_blocker.h"
+#include "device/power_save_blocker/power_save_blocker.h"
+#include "device/power_save_blocker/power_save_blocker_export.h"
 
 #if defined(OS_ANDROID)
 #include "ui/android/view_android.h"
 #endif  // OS_ANDROID
 
-namespace content {
+namespace device {
 
 class WebContents;
 
@@ -37,7 +38,7 @@
   // On Android, the kPowerSaveBlockPreventDisplaySleep type of
   // PowerSaveBlocker should associated with a View, so the blocker can be
   // removed by the platform.
-  void InitDisplaySleepBlocker(
+  DEVICE_POWER_SAVE_BLOCKER_EXPORT void InitDisplaySleepBlocker(
       const base::WeakPtr<ui::ViewAndroid>& view_android);
 #endif
 
@@ -69,6 +70,6 @@
   DISALLOW_COPY_AND_ASSIGN(PowerSaveBlockerImpl);
 };
 
-}  // namespace content
+}  // namespace device
 
-#endif  // CONTENT_BROWSER_POWER_SAVE_BLOCKER_IMPL_H_
+#endif  // DEVICE_POWER_SAVE_BLOCKER_POWER_SAVE_BLOCKER_IMPL_H_
diff --git a/device/power_save_blocker/power_save_blocker_jni_registrar.cc b/device/power_save_blocker/power_save_blocker_jni_registrar.cc
new file mode 100644
index 0000000..11afbe9
--- /dev/null
+++ b/device/power_save_blocker/power_save_blocker_jni_registrar.cc
@@ -0,0 +1,28 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/power_save_blocker/power_save_blocker_jni_registrar.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_registrar.h"
+#include "base/macros.h"
+#include "device/power_save_blocker/power_save_blocker_android.h"
+
+namespace device {
+namespace android {
+namespace {
+
+const base::android::RegistrationMethod kRegisteredMethods[] = {
+    {"PowerSaveBlock", device::RegisterPowerSaveBlocker},
+};
+
+}  // namespace
+
+bool RegisterPowerSaveBlockerJni(JNIEnv* env) {
+  return RegisterNativeMethods(env, kRegisteredMethods,
+                               arraysize(kRegisteredMethods));
+}
+
+}  // namespace android
+}  // namespace device
diff --git a/device/power_save_blocker/power_save_blocker_jni_registrar.h b/device/power_save_blocker/power_save_blocker_jni_registrar.h
new file mode 100644
index 0000000..7e05d366
--- /dev/null
+++ b/device/power_save_blocker/power_save_blocker_jni_registrar.h
@@ -0,0 +1,24 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_POWER_SAVE_BLOCKER_ANDROID_POWER_SAVE_BLOCKER_JNI_REGISTRAR_H_
+#define DEVICE_POWER_SAVE_BLOCKER_ANDROID_POWER_SAVE_BLOCKER_JNI_REGISTRAR_H_
+
+#include <jni.h>
+
+#include "device/power_save_blocker/power_save_blocker_export.h"
+
+namespace device {
+namespace android {
+
+// Registers C++ methods in device/power_save_blocker classes with JNI.
+// See https://www.chromium.org/developers/design-documents/android-jni
+//
+// Must be called before classes in the Bluetooth module are used.
+DEVICE_POWER_SAVE_BLOCKER_EXPORT bool RegisterPowerSaveBlockerJni(JNIEnv* env);
+
+}  // namespace android
+}  // namespace device
+
+#endif  // DEVICE_POWER_SAVE_BLOCKER_ANDROID_POWER_SAVE_BLOCKER_JNI_REGISTRAR_H_
diff --git a/content/browser/power_save_blocker_mac.cc b/device/power_save_blocker/power_save_blocker_mac.cc
similarity index 85%
rename from content/browser/power_save_blocker_mac.cc
rename to device/power_save_blocker/power_save_blocker_mac.cc
index 581e9b9..251cc22 100644
--- a/content/browser/power_save_blocker_mac.cc
+++ b/device/power_save_blocker/power_save_blocker_mac.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/power_save_blocker_impl.h"
+#include "device/power_save_blocker/power_save_blocker_impl.h"
 
 #include <IOKit/pwr_mgt/IOPMLib.h>
 
@@ -13,13 +13,14 @@
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread.h"
 
-namespace content {
+namespace device {
 namespace {
 
 // Power management cannot be done on the UI thread. IOPMAssertionCreate does a
 // synchronous MIG call to configd, so if it is called on the main thread the UI
 // is at the mercy of another process. See http://crbug.com/79559 and
-// http://www.opensource.apple.com/source/IOKitUser/IOKitUser-514.16.31/pwr_mgt.subproj/IOPMLibPrivate.c .
+// http://www.opensource.apple.com/source/IOKitUser/IOKitUser-514.16.31/pwr_mgt.subproj/IOPMLibPrivate.c
+// .
 struct PowerSaveBlockerLazyInstanceTraits {
   static const bool kRegisterOnExit = false;
 #ifndef NDEBUG
@@ -31,7 +32,7 @@
     thread->Start();
     return thread;
   }
-  static void Delete(base::Thread* instance) { }
+  static void Delete(base::Thread* instance) {}
 };
 base::LazyInstance<base::Thread, PowerSaveBlockerLazyInstanceTraits>
     g_power_thread = LAZY_INSTANCE_INITIALIZER;
@@ -81,8 +82,8 @@
         base::SysUTF8ToCFStringRef(description_));
     IOReturn result = IOPMAssertionCreateWithName(level, kIOPMAssertionLevelOn,
                                                   cf_description, &assertion_);
-    LOG_IF(ERROR, result != kIOReturnSuccess)
-        << "IOPMAssertionCreate: " << result;
+    LOG_IF(ERROR, result != kIOReturnSuccess) << "IOPMAssertionCreate: "
+                                              << result;
   }
 }
 
@@ -92,8 +93,8 @@
 
   if (assertion_ != kIOPMNullAssertionID) {
     IOReturn result = IOPMAssertionRelease(assertion_);
-    LOG_IF(ERROR, result != kIOReturnSuccess)
-        << "IOPMAssertionRelease: " << result;
+    LOG_IF(ERROR, result != kIOReturnSuccess) << "IOPMAssertionRelease: "
+                                              << result;
   }
 }
 
@@ -107,14 +108,12 @@
       ui_task_runner_(ui_task_runner),
       blocking_task_runner_(blocking_task_runner) {
   g_power_thread.Pointer()->message_loop()->PostTask(
-      FROM_HERE,
-      base::Bind(&Delegate::ApplyBlock, delegate_));
+      FROM_HERE, base::Bind(&Delegate::ApplyBlock, delegate_));
 }
 
 PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {
   g_power_thread.Pointer()->message_loop()->PostTask(
-      FROM_HERE,
-      base::Bind(&Delegate::RemoveBlock, delegate_));
+      FROM_HERE, base::Bind(&Delegate::RemoveBlock, delegate_));
 }
 
-}  // namespace content
+}  // namespace device
diff --git a/content/browser/power_save_blocker_ozone.cc b/device/power_save_blocker/power_save_blocker_ozone.cc
similarity index 87%
rename from content/browser/power_save_blocker_ozone.cc
rename to device/power_save_blocker/power_save_blocker_ozone.cc
index 1618a85..caf15a5 100644
--- a/content/browser/power_save_blocker_ozone.cc
+++ b/device/power_save_blocker/power_save_blocker_ozone.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/power_save_blocker_impl.h"
+#include "device/power_save_blocker/power_save_blocker_impl.h"
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 
-namespace content {
+namespace device {
 
 // TODO(derat): Consider renaming this file; '_ozone' is a misnomer as power
 // save is OS-specific, not display-system-specific.  This implementation
@@ -35,6 +35,6 @@
       ui_task_runner_(ui_task_runner),
       blocking_task_runner_(blocking_task_runner) {}
 
-PowerSaveBlockerImpl::~PowerSaveBlockerImpl() { }
+PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {}
 
-}  // namespace content
+}  // namespace device
diff --git a/content/browser/power_save_blocker_win.cc b/device/power_save_blocker/power_save_blocker_win.cc
similarity index 96%
rename from content/browser/power_save_blocker_win.cc
rename to device/power_save_blocker/power_save_blocker_win.cc
index e9650a5..8464c210 100644
--- a/content/browser/power_save_blocker_win.cc
+++ b/device/power_save_blocker/power_save_blocker_win.cc
@@ -10,9 +10,9 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/windows_version.h"
-#include "content/browser/power_save_blocker_impl.h"
+#include "device/power_save_blocker/power_save_blocker_impl.h"
 
-namespace content {
+namespace device {
 namespace {
 
 int g_blocker_count[2];
@@ -57,8 +57,7 @@
   DCHECK(success);
 }
 
-void ApplySimpleBlock(PowerSaveBlocker::PowerSaveBlockerType type,
-                      int delta) {
+void ApplySimpleBlock(PowerSaveBlocker::PowerSaveBlockerType type, int delta) {
   g_blocker_count[type] += delta;
   DCHECK_GE(g_blocker_count[type], 0);
 
@@ -157,4 +156,4 @@
                             base::Bind(&Delegate::RemoveBlock, delegate_));
 }
 
-}  // namespace content
+}  // namespace device
diff --git a/content/browser/power_save_blocker_x11.cc b/device/power_save_blocker/power_save_blocker_x11.cc
similarity index 97%
rename from content/browser/power_save_blocker_x11.cc
rename to device/power_save_blocker/power_save_blocker_x11.cc
index a177e39..ed66813 100644
--- a/content/browser/power_save_blocker_x11.cc
+++ b/device/power_save_blocker/power_save_blocker_x11.cc
@@ -9,7 +9,7 @@
 
 #include <memory>
 
-#include "content/browser/power_save_blocker_impl.h"
+#include "device/power_save_blocker/power_save_blocker_impl.h"
 // Xlib #defines Status, but we can't have that for some of our headers.
 #ifdef Status
 #undef Status
@@ -45,9 +45,9 @@
 // Can be OR'd together and passed as argument to the Inhibit() method
 // to specify which power management features we want to suspend.
 enum GnomeAPIInhibitFlags {
-  INHIBIT_LOGOUT            = 1,
-  INHIBIT_SWITCH_USER       = 2,
-  INHIBIT_SUSPEND_SESSION   = 4,
+  INHIBIT_LOGOUT = 1,
+  INHIBIT_SWITCH_USER = 2,
+  INHIBIT_SUSPEND_SESSION = 4,
   INHIBIT_MARK_SESSION_IDLE = 8
 };
 
@@ -68,7 +68,7 @@
 
 }  // namespace
 
-namespace content {
+namespace device {
 
 class PowerSaveBlockerImpl::Delegate
     : public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
@@ -256,8 +256,7 @@
       return;
     case GNOME_API:
       object_proxy = bus_->GetObjectProxy(
-          kGnomeAPIServiceName,
-          dbus::ObjectPath(kGnomeAPIObjectPath));
+          kGnomeAPIServiceName, dbus::ObjectPath(kGnomeAPIObjectPath));
       method_call.reset(
           new dbus::MethodCall(kGnomeAPIInterfaceName, "Inhibit"));
       message_writer.reset(new dbus::MessageWriter(method_call.get()));
@@ -366,8 +365,7 @@
       return;
     case GNOME_API:
       object_proxy = bus_->GetObjectProxy(
-          kGnomeAPIServiceName,
-          dbus::ObjectPath(kGnomeAPIObjectPath));
+          kGnomeAPIServiceName, dbus::ObjectPath(kGnomeAPIObjectPath));
       method_call.reset(
           new dbus::MethodCall(kGnomeAPIInterfaceName, "Uninhibit"));
       break;
@@ -505,4 +503,4 @@
     freedesktop_suspend_delegate_->CleanUp();
 }
 
-}  // namespace content
+}  // namespace device
diff --git a/device/test/run_all_unittests.cc b/device/test/run_all_unittests.cc
index 06b32a8..3048912 100644
--- a/device/test/run_all_unittests.cc
+++ b/device/test/run_all_unittests.cc
@@ -11,12 +11,15 @@
 #if defined(OS_ANDROID)
 #include "base/android/jni_android.h"
 #include "device/bluetooth/android/bluetooth_jni_registrar.h"
+#include "device/power_save_blocker/power_save_blocker_jni_registrar.h"
 #include "device/usb/android/usb_jni_registrar.h"
 #endif
 
 int main(int argc, char** argv) {
 #if defined(OS_ANDROID)
   device::android::RegisterBluetoothJni(base::android::AttachCurrentThread());
+  device::android::RegisterPowerSaveBlockerJni(
+      base::android::AttachCurrentThread());
   device::android::RegisterUsbJni(base::android::AttachCurrentThread());
 #endif
 
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index cbaecf3..bf4d6d9 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -62,6 +62,7 @@
       "//device/bluetooth",
       "//device/core",
       "//device/hid",
+      "//device/power_save_blocker",
       "//device/serial",
       "//device/usb",
       "//extensions/common/api/cast_channel:cast_channel_proto",
diff --git a/extensions/browser/DEPS b/extensions/browser/DEPS
index 4d6eaeb..1fb5effd 100644
--- a/extensions/browser/DEPS
+++ b/extensions/browser/DEPS
@@ -13,6 +13,7 @@
   "+components/zoom",
   "+content/public/browser",
   "+device/bluetooth",
+  "+device/power_save_blocker",
   "+device/serial",
   "+device/usb",
   "+google_apis/gaia",
diff --git a/extensions/browser/api/power/power_api.cc b/extensions/browser/api/power/power_api.cc
index c12d86b..8190896 100644
--- a/extensions/browser/api/power/power_api.cc
+++ b/extensions/browser/api/power/power_api.cc
@@ -6,7 +6,8 @@
 
 #include "base/bind.h"
 #include "base/lazy_instance.h"
-#include "content/public/browser/power_save_blocker_factory.h"
+#include "content/public/browser/browser_thread.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/api/power.h"
 #include "extensions/common/extension.h"
@@ -17,17 +18,17 @@
 
 const char kPowerSaveBlockerDescription[] = "extension";
 
-content::PowerSaveBlocker::PowerSaveBlockerType LevelToPowerSaveBlockerType(
+device::PowerSaveBlocker::PowerSaveBlockerType LevelToPowerSaveBlockerType(
     api::power::Level level) {
   switch (level) {
     case api::power::LEVEL_SYSTEM:
-      return content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension;
+      return device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension;
     case api::power::LEVEL_DISPLAY:  // fallthrough
     case api::power::LEVEL_NONE:
-      return content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
+      return device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
   }
   NOTREACHED() << "Unhandled level " << level;
-  return content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
+  return device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
 }
 
 base::LazyInstance<BrowserContextKeyedAPIFactory<PowerAPI>> g_factory =
@@ -72,9 +73,10 @@
 
 void PowerAPI::SetCreateBlockerFunctionForTesting(
     CreateBlockerFunction function) {
-  create_blocker_function_ = !function.is_null()
-                                 ? function
-                                 : base::Bind(&content::CreatePowerSaveBlocker);
+  create_blocker_function_ =
+      !function.is_null()
+          ? function
+          : base::Bind(&device::PowerSaveBlocker::CreateWithTaskRunners);
 }
 
 void PowerAPI::OnExtensionUnloaded(content::BrowserContext* browser_context,
@@ -86,7 +88,8 @@
 
 PowerAPI::PowerAPI(content::BrowserContext* context)
     : browser_context_(context),
-      create_blocker_function_(base::Bind(&content::CreatePowerSaveBlocker)),
+      create_blocker_function_(
+          base::Bind(&device::PowerSaveBlocker::CreateWithTaskRunners)),
       current_level_(api::power::LEVEL_SYSTEM) {
   ExtensionRegistry::Get(browser_context_)->AddObserver(this);
 }
@@ -111,12 +114,16 @@
   // to ensure that there isn't a brief period where power management is
   // unblocked.
   if (!power_save_blocker_ || new_level != current_level_) {
-    content::PowerSaveBlocker::PowerSaveBlockerType type =
+    device::PowerSaveBlocker::PowerSaveBlockerType type =
         LevelToPowerSaveBlockerType(new_level);
-    std::unique_ptr<content::PowerSaveBlocker> new_blocker(
-        create_blocker_function_.Run(type,
-                                     content::PowerSaveBlocker::kReasonOther,
-                                     kPowerSaveBlockerDescription));
+    std::unique_ptr<device::PowerSaveBlocker> new_blocker(
+        create_blocker_function_.Run(
+            type, device::PowerSaveBlocker::kReasonOther,
+            kPowerSaveBlockerDescription,
+            content::BrowserThread::GetMessageLoopProxyForThread(
+                content::BrowserThread::UI),
+            content::BrowserThread::GetMessageLoopProxyForThread(
+                content::BrowserThread::FILE)));
     power_save_blocker_.swap(new_blocker);
     current_level_ = new_level;
   }
diff --git a/extensions/browser/api/power/power_api.h b/extensions/browser/api/power/power_api.h
index e68bd57..73db136 100644
--- a/extensions/browser/api/power/power_api.h
+++ b/extensions/browser/api/power/power_api.h
@@ -11,7 +11,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "content/public/browser/power_save_blocker.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 #include "extensions/browser/browser_context_keyed_api_factory.h"
 #include "extensions/browser/extension_function.h"
 #include "extensions/browser/extension_registry_observer.h"
@@ -53,10 +53,12 @@
 class PowerAPI : public BrowserContextKeyedAPI,
                  public extensions::ExtensionRegistryObserver {
  public:
-  typedef base::Callback<std::unique_ptr<content::PowerSaveBlocker>(
-      content::PowerSaveBlocker::PowerSaveBlockerType,
-      content::PowerSaveBlocker::Reason,
-      const std::string&)>
+  typedef base::Callback<std::unique_ptr<device::PowerSaveBlocker>(
+      device::PowerSaveBlocker::PowerSaveBlockerType,
+      device::PowerSaveBlocker::Reason,
+      const std::string&,
+      scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
+      scoped_refptr<base::SingleThreadTaskRunner> file_task_runner)>
       CreateBlockerFunction;
 
   static PowerAPI* Get(content::BrowserContext* context);
@@ -104,7 +106,7 @@
   // actually changing the system power-saving settings.
   CreateBlockerFunction create_blocker_function_;
 
-  std::unique_ptr<content::PowerSaveBlocker> power_save_blocker_;
+  std::unique_ptr<device::PowerSaveBlocker> power_save_blocker_;
 
   // Current level used by |power_save_blocker_|.  Meaningless if
   // |power_save_blocker_| is NULL.
diff --git a/extensions/browser/api/power/power_api_unittest.cc b/extensions/browser/api/power/power_api_unittest.cc
index 54b8403d..06e4d8f3 100644
--- a/extensions/browser/api/power/power_api_unittest.cc
+++ b/extensions/browser/api/power/power_api_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "content/public/browser/power_save_blocker.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 #include "extensions/browser/api_test_utils.h"
 #include "extensions/browser/api_unittest.h"
 #include "extensions/common/extension.h"
@@ -38,9 +38,9 @@
   NONE,
 };
 
-// Stub implementation of content::PowerSaveBlocker that just runs a
-// callback on destruction.
-class PowerSaveBlockerStub : public content::PowerSaveBlocker {
+// Stub implementation of device::PowerSaveBlocker that just runs a callback on
+// destruction.
+class PowerSaveBlockerStub : public device::PowerSaveBlocker {
  public:
   explicit PowerSaveBlockerStub(base::Closure unblock_callback)
       : unblock_callback_(unblock_callback) {
@@ -88,22 +88,24 @@
 
  private:
   // Creates a new PowerSaveBlockerStub of type |type|.
-  std::unique_ptr<content::PowerSaveBlocker> CreateStub(
-      content::PowerSaveBlocker::PowerSaveBlockerType type,
-      content::PowerSaveBlocker::Reason reason,
-      const std::string& description) {
+  std::unique_ptr<device::PowerSaveBlocker> CreateStub(
+      device::PowerSaveBlocker::PowerSaveBlockerType type,
+      device::PowerSaveBlocker::Reason reason,
+      const std::string& description,
+      scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
+      scoped_refptr<base::SingleThreadTaskRunner> file_task_runner) {
     Request unblock_request = NONE;
     switch (type) {
-      case content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension:
+      case device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension:
         requests_.push_back(BLOCK_APP_SUSPENSION);
         unblock_request = UNBLOCK_APP_SUSPENSION;
         break;
-      case content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep:
+      case device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep:
         requests_.push_back(BLOCK_DISPLAY_SLEEP);
         unblock_request = UNBLOCK_DISPLAY_SLEEP;
         break;
     }
-    return std::unique_ptr<content::PowerSaveBlocker>(new PowerSaveBlockerStub(
+    return std::unique_ptr<device::PowerSaveBlocker>(new PowerSaveBlockerStub(
         base::Bind(&PowerSaveBlockerStubManager::AppendRequest,
                    weak_ptr_factory_.GetWeakPtr(), unblock_request)));
   }
diff --git a/extensions/common/permissions/settings_override_permission.cc b/extensions/common/permissions/settings_override_permission.cc
index 263f9dc..b44d8810 100644
--- a/extensions/common/permissions/settings_override_permission.cc
+++ b/extensions/common/permissions/settings_override_permission.cc
@@ -51,7 +51,14 @@
     const base::Value* value,
     std::string* /*error*/,
     std::vector<std::string>* unhandled_permissions) {
-  return value && value->GetAsString(&setting_value_);
+  // Ugly hack: |value| being null should be an error. But before M46 beta, we
+  // didn't store the parameter for settings override permissions in prefs.
+  // See crbug.com/533086 and crbug.com/619759.
+  // TODO(treib,devlin): Remove this for M56, when hopefully all users will have
+  // updated prefs.
+  // This should read:
+  // return value && value->GetAsString(&setting_value_);
+  return !value || value->GetAsString(&setting_value_);
 }
 
 std::unique_ptr<base::Value> SettingsOverrideAPIPermission::ToValue() const {
diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp
index b37a4bd..73e248c 100644
--- a/extensions/extensions.gyp
+++ b/extensions/extensions.gyp
@@ -57,6 +57,7 @@
         '../device/bluetooth/bluetooth.gyp:device_bluetooth',
         # For Mojo generated headers for generated_api.cc.
         '../device/serial/serial.gyp:device_serial_mojo',
+        '../device/power_save_blocker/power_save_blocker.gyp:device_power_save_blocker',
         '../device/usb/usb.gyp:device_usb',
         '../ipc/ipc.gyp:ipc',
         '../net/net.gyp:net',
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index c19fa7e7..0dbf9d0 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -54,6 +54,8 @@
     "gl_state_restorer_impl.h",
     "gl_utils.cc",
     "gl_utils.h",
+    "gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc",
+    "gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h",
     "gles2_cmd_clear_framebuffer.cc",
     "gles2_cmd_clear_framebuffer.h",
     "gles2_cmd_copy_tex_image.cc",
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 06bb664..ee805dd 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -89,6 +89,7 @@
       multisampled_render_to_texture(false),
       use_img_for_multisampled_render_to_texture(false),
       chromium_screen_space_antialiasing(false),
+      use_chromium_screen_space_antialiasing_via_shaders(false),
       oes_standard_derivatives(false),
       oes_egl_image_external(false),
       nv_egl_stream_consumer_external(false),
@@ -179,6 +180,9 @@
   disable_shader_translator_ =
       command_line->HasSwitch(switches::kDisableGLSLTranslator);
 
+  enable_cmaa_shaders_switch_ =
+      command_line->HasSwitch(switches::kEnableCMAAShaders);
+
   unsafe_es3_apis_enabled_ = false;
 
   // Default context_type_ to a GLES2 Context.
@@ -881,6 +885,17 @@
   if (extensions.Contains("GL_INTEL_framebuffer_CMAA")) {
     feature_flags_.chromium_screen_space_antialiasing = true;
     AddExtensionString("GL_CHROMIUM_screen_space_antialiasing");
+  } else if (enable_cmaa_shaders_switch_ &&
+             (gl_version_info_->IsAtLeastGLES(3, 1) ||
+              (gl_version_info_->IsAtLeastGL(3, 0) &&
+               extensions.Contains("GL_ARB_shading_language_420pack") &&
+               extensions.Contains("GL_ARB_texture_gather") &&
+               extensions.Contains("GL_ARB_explicit_uniform_location") &&
+               extensions.Contains("GL_ARB_explicit_attrib_location") &&
+               extensions.Contains("GL_ARB_shader_image_load_store")))) {
+    feature_flags_.chromium_screen_space_antialiasing = true;
+    feature_flags_.use_chromium_screen_space_antialiasing_via_shaders = true;
+    AddExtensionString("GL_CHROMIUM_screen_space_antialiasing");
   }
 
   if (extensions.Contains("GL_OES_depth24") || gl::HasDesktopGLFeatures() ||
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index ff6b354..c8ea959 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -42,6 +42,7 @@
     // Use the IMG GLenum values and functions rather than EXT.
     bool use_img_for_multisampled_render_to_texture;
     bool chromium_screen_space_antialiasing;
+    bool use_chromium_screen_space_antialiasing_via_shaders;
     bool oes_standard_derivatives;
     bool oes_egl_image_external;
     bool nv_egl_stream_consumer_external;
@@ -191,6 +192,9 @@
   bool disable_shader_translator_;
   std::unique_ptr<gl::GLVersionInfo> gl_version_info_;
 
+  // Whether the command line switch kEnableCMAAShaders is passed in.
+  bool enable_cmaa_shaders_switch_;
+
   DISALLOW_COPY_AND_ASSIGN(FeatureInfo);
 };
 
diff --git a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc
new file mode 100644
index 0000000..56490303a
--- /dev/null
+++ b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc
@@ -0,0 +1,1826 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h"
+
+#include "base/logging.h"
+#include "gpu/command_buffer/service/framebuffer_manager.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_gl_api_implementation.h"
+#include "ui/gl/gl_version_info.h"
+
+namespace gpu {
+
+ApplyFramebufferAttachmentCMAAINTELResourceManager::
+    ApplyFramebufferAttachmentCMAAINTELResourceManager()
+    : initialized_(false),
+      textures_initialized_(false),
+      is_in_gamma_correct_mode_(false),
+      supports_usampler_(true),
+      supports_r8_image_(true),
+      supports_r8_read_format_(true),
+      is_gles31_compatible_(false),
+      frame_id_(0),
+      width_(0),
+      height_(0),
+      copy_to_framebuffer_shader_(0),
+      copy_to_image_shader_(0),
+      edges0_shader_(0),
+      edges1_shader_(0),
+      edges_combine_shader_(0),
+      process_and_apply_shader_(0),
+      debug_display_edges_shader_(0),
+      cmaa_framebuffer_(0),
+      copy_framebuffer_(0),
+      rgba8_texture_(0),
+      working_color_texture_(0),
+      edges0_texture_(0),
+      edges1_texture_(0),
+      mini4_edge_texture_(0),
+      mini4_edge_depth_texture_(0),
+      edges1_shader_result_texture_float4_slot1_(0),
+      edges1_shader_result_texture_(0),
+      edges_combine_shader_result_texture_float4_slot1_(0),
+      process_and_apply_shader_result_texture_float4_slot1_(0),
+      edges_combine_shader_result_texture_slot2_(0),
+      copy_to_image_shader_outTexture_(0) {}
+
+ApplyFramebufferAttachmentCMAAINTELResourceManager::
+    ~ApplyFramebufferAttachmentCMAAINTELResourceManager() {
+  Destroy();
+}
+
+void ApplyFramebufferAttachmentCMAAINTELResourceManager::Initialize(
+    gles2::GLES2Decoder* decoder) {
+  DCHECK(decoder);
+  is_gles31_compatible_ =
+      decoder->GetGLContext()->GetVersionInfo()->IsAtLeastGLES(3, 1);
+
+  copy_to_image_shader_ = CreateProgram("", vert_str_, copy_frag_str_);
+  copy_to_framebuffer_shader_ =
+      CreateProgram("#define OUT_FBO 1\n", vert_str_, copy_frag_str_);
+
+  // Check if RGBA8UI is supported as an FBO colour target with depth.
+  // If not supported, GLSL needs to convert the data to/from float so there is
+  // a small extra cost.
+  {
+    GLuint rgba8ui_texture = 0, depth_texture = 0;
+    glGenTextures(1, &rgba8ui_texture);
+    glBindTexture(GL_TEXTURE_2D, rgba8ui_texture);
+    glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8UI, 4, 4);
+
+    glGenTextures(1, &depth_texture);
+    glBindTexture(GL_TEXTURE_2D, depth_texture);
+    glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT16, 4, 4);
+
+    // Create the FBO
+    GLuint rgba8ui_framebuffer = 0;
+    glGenFramebuffersEXT(1, &rgba8ui_framebuffer);
+    glBindFramebufferEXT(GL_FRAMEBUFFER, rgba8ui_framebuffer);
+
+    // Bind to the FBO to test support
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                              GL_TEXTURE_2D, rgba8ui_texture, 0);
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                              GL_TEXTURE_2D, depth_texture, 0);
+    GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
+
+    supports_usampler_ = (status == GL_FRAMEBUFFER_COMPLETE);
+
+    glDeleteFramebuffersEXT(1, &rgba8ui_framebuffer);
+    glDeleteTextures(1, &rgba8ui_texture);
+    glDeleteTextures(1, &depth_texture);
+  }
+
+  // Check to see if R8 images are supported
+  // If not supported, images are bound as R32F for write targets, not R8.
+  {
+    GLuint r8_texture = 0;
+    glGenTextures(1, &r8_texture);
+    glBindTexture(GL_TEXTURE_2D, r8_texture);
+    glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_R8, 4, 4);
+
+    glGetError();  // reset all previous errors
+    glBindImageTextureEXT(0, r8_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R8);
+    if (glGetError() != GL_NO_ERROR)
+      supports_r8_image_ = false;
+
+    glDeleteTextures(1, &r8_texture);
+  }
+
+  // Check if R8 GLSL read formats are supported.
+  // If not supported, r32f is used instead.
+  {
+    const char shader_source[] =
+        "layout(r8) restrict writeonly uniform highp image2D g_r8Image;     \n"
+        "void main()                                                        \n"
+        "{                                                                  \n"
+        "    imageStore(g_r8Image, ivec2(0, 0), vec4(1.0, 0.0, 0.0, 0.0));  \n"
+        "}                                                                  \n";
+
+    GLuint shader = CreateShader(GL_FRAGMENT_SHADER, "", shader_source);
+    supports_r8_read_format_ = (shader != 0);
+    if (shader != 0) {
+      glDeleteShader(shader);
+    }
+  }
+
+  VLOG(1) << "ApplyFramebufferAttachmentCMAAINTEL: "
+          << "Supports USampler is " << (supports_usampler_ ? "true" : "false");
+  VLOG(1) << "ApplyFramebufferAttachmentCMAAINTEL: "
+          << "Supports R8 Images is "
+          << (supports_r8_image_ ? "true" : "false");
+  VLOG(1) << "ApplyFramebufferAttachmentCMAAINTEL: "
+          << "Supports R8 Read Format is "
+          << (supports_r8_read_format_ ? "true" : "false");
+
+  // Create the shaders
+  std::ostringstream defines, edge1, edge2, combineEdges, blur, displayEdges,
+      cmaa_frag;
+
+  cmaa_frag << cmaa_frag_s1_ << cmaa_frag_s2_;
+  std::string cmaa_frag_string = cmaa_frag.str();
+  const char* cmaa_frag_c_str = cmaa_frag_string.c_str();
+
+  if (supports_usampler_) {
+    defines << "#define SUPPORTS_USAMPLER2D\n";
+  }
+
+  if (is_in_gamma_correct_mode_) {
+    defines << "#define IN_GAMMA_CORRECT_MODE\n";
+  }
+
+  if (supports_r8_read_format_) {
+    defines << "#define EDGE_READ_FORMAT r8\n";
+  } else {
+    defines << "#define EDGE_READ_FORMAT r32f\n";
+  }
+
+  displayEdges << defines.str() << "#define DISPLAY_EDGES\n";
+  debug_display_edges_shader_ =
+      CreateProgram(displayEdges.str().c_str(), vert_str_, cmaa_frag_c_str);
+
+  edge1 << defines.str() << "#define DETECT_EDGES1\n";
+  edges0_shader_ =
+      CreateProgram(edge1.str().c_str(), vert_str_, cmaa_frag_c_str);
+
+  edge2 << defines.str() << "#define DETECT_EDGES2\n";
+  edges1_shader_ =
+      CreateProgram(edge2.str().c_str(), vert_str_, cmaa_frag_c_str);
+
+  combineEdges << defines.str() << "#define COMBINE_EDGES\n";
+  edges_combine_shader_ =
+      CreateProgram(combineEdges.str().c_str(), vert_str_, cmaa_frag_c_str);
+
+  blur << defines.str() << "#define BLUR_EDGES\n";
+  process_and_apply_shader_ =
+      CreateProgram(blur.str().c_str(), vert_str_, cmaa_frag_c_str);
+
+  edges1_shader_result_texture_float4_slot1_ =
+      glGetUniformLocation(edges0_shader_, "g_resultTextureFlt4Slot1");
+  edges1_shader_result_texture_ =
+      glGetUniformLocation(edges1_shader_, "g_resultTexture");
+  edges_combine_shader_result_texture_float4_slot1_ =
+      glGetUniformLocation(edges_combine_shader_, "g_resultTextureFlt4Slot1");
+  edges_combine_shader_result_texture_slot2_ =
+      glGetUniformLocation(edges_combine_shader_, "g_resultTextureSlot2");
+  process_and_apply_shader_result_texture_float4_slot1_ = glGetUniformLocation(
+      process_and_apply_shader_, "g_resultTextureFlt4Slot1");
+  copy_to_image_shader_outTexture_ =
+      glGetUniformLocation(copy_to_image_shader_, "outTexture");
+
+  initialized_ = true;
+}
+
+void ApplyFramebufferAttachmentCMAAINTELResourceManager::Destroy() {
+  if (!initialized_)
+    return;
+
+  ReleaseTextures();
+
+  glDeleteProgram(copy_to_image_shader_);
+  glDeleteProgram(copy_to_framebuffer_shader_);
+  glDeleteProgram(process_and_apply_shader_);
+  glDeleteProgram(edges_combine_shader_);
+  glDeleteProgram(edges1_shader_);
+  glDeleteProgram(edges0_shader_);
+  glDeleteProgram(debug_display_edges_shader_);
+
+  initialized_ = false;
+}
+
+// Apply CMAA(Conservative Morphological Anti-Aliasing) algorithm to the
+// color attachments of currently bound draw framebuffer.
+// Reference GL_INTEL_framebuffer_CMAA for details.
+void ApplyFramebufferAttachmentCMAAINTELResourceManager::
+    ApplyFramebufferAttachmentCMAAINTEL(gles2::GLES2Decoder* decoder,
+                                        gles2::Framebuffer* framebuffer) {
+  DCHECK(decoder);
+  DCHECK(initialized_);
+  if (!framebuffer)
+    return;
+
+  GLuint last_framebuffer = framebuffer->service_id();
+
+  // Process each color attachment of the current draw framebuffer.
+  uint32_t max_draw_buffers = decoder->GetContextGroup()->max_draw_buffers();
+  for (uint32_t i = 0; i < max_draw_buffers; i++) {
+    const gles2::Framebuffer::Attachment* attachment =
+        framebuffer->GetAttachment(GL_COLOR_ATTACHMENT0 + i);
+    if (attachment && attachment->IsTextureAttachment()) {
+      // Get the texture info.
+      GLuint source_texture_client_id = attachment->object_name();
+      GLuint source_texture = 0;
+      if (!decoder->GetServiceTextureId(source_texture_client_id,
+                                        &source_texture))
+        continue;
+      GLsizei width = attachment->width();
+      GLsizei height = attachment->height();
+      GLenum internal_format = attachment->internal_format();
+
+      // Resize internal structures - only if needed.
+      OnSize(width, height);
+
+      // CMAA internally expects GL_RGBA8 textures.
+      // Process using a GL_RGBA8 copy if this is not the case.
+      bool do_copy = internal_format != GL_RGBA8;
+
+      // Copy source_texture to rgba8_texture_
+      if (do_copy) {
+        CopyTexture(source_texture, rgba8_texture_, false);
+      }
+
+      // CMAA Effect
+      glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, last_framebuffer);
+      if (do_copy) {
+        ApplyCMAAEffectTexture(rgba8_texture_, rgba8_texture_);
+      } else {
+        ApplyCMAAEffectTexture(source_texture, source_texture);
+      }
+
+      // Copy rgba8_texture_ to source_texture
+      if (do_copy) {
+        // Move source_texture to the first color attachment of the copy fbo.
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, last_framebuffer);
+        glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
+                                  GL_TEXTURE_2D, 0, 0);
+        glBindFramebufferEXT(GL_FRAMEBUFFER, copy_framebuffer_);
+        glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                  GL_TEXTURE_2D, source_texture, 0);
+
+        CopyTexture(rgba8_texture_, source_texture, true);
+
+        // Restore color attachments
+        glBindFramebufferEXT(GL_FRAMEBUFFER, copy_framebuffer_);
+        glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                  GL_TEXTURE_2D, rgba8_texture_, 0);
+        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, last_framebuffer);
+        glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
+                                  GL_TEXTURE_2D, source_texture, 0);
+      }
+    }
+  }
+
+  // Restore state
+  decoder->RestoreAllAttributes();
+  decoder->RestoreTextureUnitBindings(0);
+  decoder->RestoreTextureUnitBindings(1);
+  decoder->RestoreActiveTexture();
+  decoder->RestoreProgramBindings();
+  decoder->RestoreBufferBindings();
+  decoder->RestoreFramebufferBindings();
+  decoder->RestoreGlobalState();
+}
+
+void ApplyFramebufferAttachmentCMAAINTELResourceManager::ApplyCMAAEffectTexture(
+    GLuint source_texture,
+    GLuint dest_texture) {
+  frame_id_++;
+
+  GLuint edge_texture_a;
+  GLuint edge_texture_b;
+
+  // Flip flop - One pass clears the texture that needs clearing for the other
+  // one (actually it's only important that it clears the highest bit)
+  if ((frame_id_ % 2) == 0) {
+    edge_texture_a = edges0_texture_;
+    edge_texture_b = edges1_texture_;
+  } else {
+    edge_texture_a = edges1_texture_;
+    edge_texture_b = edges0_texture_;
+  }
+
+  // Setup the main fbo
+  glBindFramebufferEXT(GL_FRAMEBUFFER, cmaa_framebuffer_);
+  glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+                            mini4_edge_texture_, 0);
+  glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
+                            mini4_edge_depth_texture_, 0);
+#if DCHECK_IS_ON()
+  GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
+  if (status != GL_FRAMEBUFFER_COMPLETE) {
+    DLOG(ERROR) << "ApplyFramebufferAttachmentCMAAINTEL: "
+                << "Incomplete framebuffer.";
+    Destroy();
+    return;
+  }
+#endif
+
+  // Setup the viewport to match the fbo
+  glViewport(0, 0, (width_ + 1) / 2, (height_ + 1) / 2);
+  glEnable(GL_DEPTH_TEST);
+
+  // Detect edges Pass 0
+  //   - For every pixel detect edges to the right and down and output depth
+  //   mask where edges detected (1 - far, for detected, 0-near for empty
+  //   pixels)
+
+  // Inputs
+  //  g_screenTexture                     source_texture               tex0
+  // Outputs
+  //  gl_FragDepth                        mini4_edge_depth_texture_    fbo.depth
+  //  out uvec4 outEdges                  mini4_edge_texture_          fbo.col
+  //  image2D g_resultTextureFlt4Slot1    working_color_texture_       image1
+  GLenum edge_format = supports_r8_image_ ? GL_R8 : GL_R32F;
+
+  {
+    glUseProgram(edges0_shader_);
+    glUniform1f(0, 1.0f);
+    glUniform2f(1, 1.0f / width_, 1.0f / height_);
+    glDepthMask(GL_TRUE);
+    glDepthFunc(GL_ALWAYS);
+    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+    if (!is_gles31_compatible_) {
+      glUniform1i(edges1_shader_result_texture_float4_slot1_, 1);
+    }
+    glBindImageTextureEXT(1, working_color_texture_, 0, GL_FALSE, 0,
+                          GL_WRITE_ONLY, GL_RGBA8);
+
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, source_texture);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+    glDrawArrays(GL_TRIANGLES, 0, 3);
+  }
+
+  // Detect edges Pass 1 (finish the previous pass edge processing).
+  // Do the culling of non-dominant local edges (leave mainly locally dominant
+  // edges) and merge Right and Bottom edges into TopRightBottomLeft
+
+  // Inputs
+  //  g_src0Texture4Uint                  mini4_edge_texture_          tex1
+  // Outputs
+  //  image2D g_resultTexture             edge_texture_b               image0
+  {
+    glUseProgram(edges1_shader_);
+    glUniform1f(0, 0.0f);
+    glUniform2f(1, 1.0f / width_, 1.0f / height_);
+    glDepthMask(GL_FALSE);
+    glDepthFunc(GL_LESS);
+    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+    if (!is_gles31_compatible_) {
+      glUniform1i(edges1_shader_result_texture_, 0);
+    }
+    glBindImageTextureEXT(0, edge_texture_b, 0, GL_FALSE, 0, GL_WRITE_ONLY,
+                          edge_format);
+
+    glActiveTexture(GL_TEXTURE1);
+    glBindTexture(GL_TEXTURE_2D, mini4_edge_texture_);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+    glDrawArrays(GL_TRIANGLES, 0, 3);
+  }
+
+  //  - Combine RightBottom (.xy) edges from previous pass into
+  //    RightBottomLeftTop (.xyzw) edges and output it into the mask (have to
+  //    fill in the whole buffer including empty ones for the line length
+  //    detection to work correctly).
+  //  - On all pixels with any edge, input buffer into a temporary color buffer
+  //    needed for correct blending in the next pass (other pixels not needed
+  //    so not copied to avoid bandwidth use).
+  //  - On all pixels with 2 or more edges output positive depth mask for the
+  //    next pass.
+
+  // Inputs
+  //  g_src0TextureFlt                    edge_texture_b               tex1 //ps
+  // Outputs
+  //  image2D g_resultTextureSlot2        edge_texture_a               image2
+  //  gl_FragDepth                        mini4_edge_texture_          fbo.depth
+  {
+    // Combine edges: each pixel will now contain info on all (top, right,
+    // bottom, left) edges; also create depth mask as above depth and mark
+    // potential Z sAND also copy source color data but only on edge pixels
+    glUseProgram(edges_combine_shader_);
+    glUniform1f(0, 1.0f);
+    glUniform2f(1, 1.0f / width_, 1.0f / height_);
+    glDepthMask(GL_TRUE);
+    glDepthFunc(GL_ALWAYS);
+    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+    if (!is_gles31_compatible_) {
+      glUniform1i(edges_combine_shader_result_texture_float4_slot1_, 1);
+      glUniform1i(edges_combine_shader_result_texture_slot2_, 2);
+    }
+    glBindImageTextureEXT(1, dest_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY,
+                          GL_RGBA8);
+    glBindImageTextureEXT(2, edge_texture_a, 0, GL_FALSE, 0, GL_WRITE_ONLY,
+                          edge_format);
+
+    glActiveTexture(GL_TEXTURE1);
+    glBindTexture(GL_TEXTURE_2D, edge_texture_b);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+    glDrawArrays(GL_TRIANGLES, 0, 3);
+  }
+
+  // Using depth mask and [earlydepthstencil] to work on pixels with 2, 3, 4
+  // edges:
+  //    - First blend simple blur map for 2,3,4 edge pixels
+  //    - Then do the lines (line length counter -should- guarantee no overlap
+  //      with other pixels - pixels with 1 edge are excluded in the previous
+  //      pass and the pixels with 2 parallel edges are excluded in the simple
+  //      blur)
+
+  // Inputs
+  //  g_screenTexture                      working_color_texture_      tex0
+  //  g_src0TextureFlt                     edge_texture_a              tex1 //ps
+  //  sampled
+  // Outputs
+  //  g_resultTextureFlt4Slot1             dest_texture                image1
+  //  gl_FragDepth                         mini4_edge_texture_         fbo.depth
+  {
+    glUseProgram(process_and_apply_shader_);
+    glUniform1f(0, 0.0f);
+    glUniform2f(1, 1.0f / width_, 1.0f / height_);
+    glDepthMask(GL_FALSE);
+    glDepthFunc(GL_LESS);
+    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+    if (!is_gles31_compatible_) {
+      glUniform1i(process_and_apply_shader_result_texture_float4_slot1_, 1);
+    }
+    glBindImageTextureEXT(1, dest_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY,
+                          GL_RGBA8);
+
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, working_color_texture_);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+    glActiveTexture(GL_TEXTURE1);
+    glBindTexture(GL_TEXTURE_2D, edge_texture_a);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+    glDrawArrays(GL_TRIANGLES, 0, 3);
+  }
+
+  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+  glDisable(GL_DEPTH_TEST);
+  glDepthMask(GL_FALSE);
+  glActiveTexture(GL_TEXTURE0);
+}
+
+void ApplyFramebufferAttachmentCMAAINTELResourceManager::OnSize(GLint width,
+                                                                GLint height) {
+  if (height_ == height && width_ == width)
+    return;
+
+  ReleaseTextures();
+
+  height_ = height;
+  width_ = width;
+
+  glGenFramebuffersEXT(1, &copy_framebuffer_);
+  glGenTextures(1, &rgba8_texture_);
+  glBindTexture(GL_TEXTURE_2D, rgba8_texture_);
+  glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
+
+  // Edges texture - R8
+  // OpenGLES has no single component 8/16-bit image support, so needs to be R32
+  // Although CHT does support R8.
+  GLenum edge_format = supports_r8_image_ ? GL_R8 : GL_R32F;
+  glGenTextures(1, &edges0_texture_);
+  glBindTexture(GL_TEXTURE_2D, edges0_texture_);
+  glTexStorage2DEXT(GL_TEXTURE_2D, 1, edge_format, width, height);
+
+  glGenTextures(1, &edges1_texture_);
+  glBindTexture(GL_TEXTURE_2D, edges1_texture_);
+  glTexStorage2DEXT(GL_TEXTURE_2D, 1, edge_format, width, height);
+
+  // Color working texture - RGBA8
+  glGenTextures(1, &working_color_texture_);
+  glBindTexture(GL_TEXTURE_2D, working_color_texture_);
+  glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
+
+  // Half*half compressed 4-edge-per-pixel texture - RGBA8
+  glGenTextures(1, &mini4_edge_texture_);
+  glBindTexture(GL_TEXTURE_2D, mini4_edge_texture_);
+  GLenum format = GL_RGBA8UI;
+  if (!supports_usampler_) {
+    format = GL_RGBA8;
+  }
+  glTexStorage2DEXT(GL_TEXTURE_2D, 1, format, (width + 1) / 2,
+                    (height + 1) / 2);
+
+  // Depth
+  glGenTextures(1, &mini4_edge_depth_texture_);
+  glBindTexture(GL_TEXTURE_2D, mini4_edge_depth_texture_);
+  glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT16, (width + 1) / 2,
+                    (height + 1) / 2);
+
+  // Create the FBO
+  glGenFramebuffersEXT(1, &cmaa_framebuffer_);
+  glBindFramebufferEXT(GL_FRAMEBUFFER, cmaa_framebuffer_);
+
+  // We need to clear the textures before they are first used.
+  // The algorithm self-clears them later.
+  glViewport(0, 0, width_, height_);
+  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+  glBindFramebufferEXT(GL_FRAMEBUFFER, cmaa_framebuffer_);
+  glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+                            edges0_texture_, 0);
+  glClear(GL_COLOR_BUFFER_BIT);
+
+  glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+                            edges1_texture_, 0);
+  glClear(GL_COLOR_BUFFER_BIT);
+
+  textures_initialized_ = true;
+}
+
+void ApplyFramebufferAttachmentCMAAINTELResourceManager::ReleaseTextures() {
+  if (textures_initialized_) {
+    glDeleteFramebuffersEXT(1, &copy_framebuffer_);
+    glDeleteFramebuffersEXT(1, &cmaa_framebuffer_);
+    glDeleteTextures(1, &rgba8_texture_);
+    glDeleteTextures(1, &edges0_texture_);
+    glDeleteTextures(1, &edges1_texture_);
+    glDeleteTextures(1, &mini4_edge_texture_);
+    glDeleteTextures(1, &mini4_edge_depth_texture_);
+    glDeleteTextures(1, &working_color_texture_);
+  }
+  textures_initialized_ = false;
+}
+
+void ApplyFramebufferAttachmentCMAAINTELResourceManager::CopyTexture(
+    GLint source,
+    GLint dest,
+    bool via_fbo) {
+  glViewport(0, 0, width_, height_);
+  glActiveTexture(GL_TEXTURE0);
+  glBindTexture(GL_TEXTURE_2D, source);
+
+  if (!via_fbo) {
+    glUseProgram(copy_to_image_shader_);
+    if (!is_gles31_compatible_) {
+      glUniform1i(copy_to_image_shader_outTexture_, 0);
+    }
+    glBindImageTextureEXT(0, dest, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
+  } else {
+    glDisable(GL_DEPTH_TEST);
+    glDisable(GL_STENCIL_TEST);
+    glDisable(GL_CULL_FACE);
+    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+    glDepthMask(GL_FALSE);
+    glDisable(GL_BLEND);
+    glUseProgram(copy_to_framebuffer_shader_);
+  }
+
+  glDrawArrays(GL_TRIANGLES, 0, 3);
+  glUseProgram(0);
+  glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+GLuint ApplyFramebufferAttachmentCMAAINTELResourceManager::CreateProgram(
+    const char* defines,
+    const char* vs_source,
+    const char* fs_source) {
+  GLuint program = glCreateProgram();
+
+  GLuint vs = CreateShader(GL_VERTEX_SHADER, defines, vs_source);
+  GLuint fs = CreateShader(GL_FRAGMENT_SHADER, defines, fs_source);
+
+  glAttachShader(program, vs);
+  glDeleteShader(vs);
+  glAttachShader(program, fs);
+  glDeleteShader(fs);
+
+  glLinkProgram(program);
+  GLint link_status;
+  glGetProgramiv(program, GL_LINK_STATUS, &link_status);
+
+  if (link_status == 0) {
+#if DCHECK_IS_ON()
+    GLint info_log_length;
+    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_log_length);
+    std::vector<GLchar> info_log(info_log_length);
+    glGetProgramInfoLog(program, static_cast<GLsizei>(info_log.size()), NULL,
+                        &info_log[0]);
+    DLOG(ERROR) << "ApplyFramebufferAttachmentCMAAINTEL: "
+                << "program link failed: " << &info_log[0];
+#endif
+    glDeleteProgram(program);
+    program = 0;
+  }
+
+  return program;
+}
+
+GLuint ApplyFramebufferAttachmentCMAAINTELResourceManager::CreateShader(
+    GLenum type,
+    const char* defines,
+    const char* source) {
+  GLuint shader = glCreateShader(type);
+
+  const char header_es31[] =
+      "#version 310 es                                                      \n";
+  const char header_gl30[] =
+      "#version 130                                                         \n"
+      "#extension GL_ARB_shading_language_420pack  : require                \n"
+      "#extension GL_ARB_texture_gather            : require                \n"
+      "#extension GL_ARB_explicit_uniform_location : require                \n"
+      "#extension GL_ARB_explicit_attrib_location  : require                \n"
+      "#extension GL_ARB_shader_image_load_store   : require                \n";
+
+  const char* header = NULL;
+  if (is_gles31_compatible_) {
+    header = header_es31;
+  } else {
+    header = header_gl30;
+  }
+
+  const char* source_array[4] = {header, defines, "\n", source};
+  glShaderSource(shader, 4, source_array, NULL);
+
+  glCompileShader(shader);
+
+  GLint compile_result;
+  glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_result);
+  if (compile_result == 0) {
+#if DCHECK_IS_ON()
+    GLint info_log_length;
+    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_length);
+    std::vector<GLchar> info_log(info_log_length);
+    glGetShaderInfoLog(shader, static_cast<GLsizei>(info_log.size()), NULL,
+                       &info_log[0]);
+    DLOG(ERROR) << "ApplyFramebufferAttachmentCMAAINTEL: "
+                << "shader compilation failed: "
+                << (type == GL_VERTEX_SHADER
+                        ? "GL_VERTEX_SHADER"
+                        : (type == GL_FRAGMENT_SHADER ? "GL_FRAGMENT_SHADER"
+                                                      : "UNKNOWN_SHADER"))
+                << " shader compilation failed: " << &info_log[0];
+#endif
+    glDeleteShader(shader);
+    shader = 0;
+  }
+
+  return shader;
+}
+
+// Shaders used in the CMAA algorithm.
+const char ApplyFramebufferAttachmentCMAAINTELResourceManager::vert_str_[] =
+    "precision highp float;                                                 \n"
+    "layout(location = 0) uniform float g_Depth;                            \n"
+    "// No input data.                                                      \n"
+    "// Verts are autogenerated.                                            \n"
+    "//                                                                     \n"
+    "// vertexID 0,1,2 should generate                                      \n"
+    "// POS: (-1,-1), (+3,-1), (-1,+3)                                      \n"
+    "//                                                                     \n"
+    "// This generates a triangle that completely covers the -1->1 viewport \n"
+    "//                                                                     \n"
+    "void main()                                                            \n"
+    "{                                                                      \n"
+    "   float x = -1.0 + float((gl_VertexID & 1) << 2);                     \n"
+    "   float y = -1.0 + float((gl_VertexID & 2) << 1);                     \n"
+    "   gl_Position = vec4(x, y, g_Depth, 1.0);                             \n"
+    "}                                                                      \n"
+    "                                                                       \n";
+
+const char ApplyFramebufferAttachmentCMAAINTELResourceManager::cmaa_frag_s1_[] =
+    "precision highp float;                                                 \n"
+    "precision highp int;                                                   \n"
+    "                                                                       \n"
+    "#define SETTINGS_ALLOW_SHORT_Zs 1                                      \n"
+    "#define EDGE_DETECT_THRESHOLD 13.0f                                    \n"
+    "                                                                       \n"
+    "#define saturate(x) clamp((x), 0.0, 1.0)                               \n"
+    "                                                                       \n"
+    "// bind to location 0                                                  \n"
+    "layout(location = 0) uniform float g_Depth;                            \n"
+    "// bind to a uniform buffer bind point 0                               \n"
+    "layout(location = 1) uniform vec2 g_OneOverScreenSize;                 \n"
+    "#ifndef EDGE_DETECT_THRESHOLD                                          \n"
+    "layout(location = 2) uniform float g_ColorThreshold;                   \n"
+    "#endif                                                                 \n"
+    "                                                                       \n"
+    "#ifdef SUPPORTS_USAMPLER2D                                             \n"
+    "#define USAMPLER usampler2D                                            \n"
+    "#define UVEC4 uvec4                                                    \n"
+    "#define LOAD_UINT(arg) arg                                             \n"
+    "#define STORE_UVEC4(arg) arg                                           \n"
+    "#else                                                                  \n"
+    "#define USAMPLER sampler2D                                             \n"
+    "#define UVEC4 vec4                                                     \n"
+    "#define LOAD_UINT(arg) uint(arg * 255.0f)                              \n"
+    "#define STORE_UVEC4(arg) vec4(float(arg.x) / 255.0f,                   \n"
+    "                              float(arg.y) / 255.0f,                   \n"
+    "                              float(arg.z) / 255.0f,                   \n"
+    "                              float(arg.w) / 255.0f)                   \n"
+    "#endif                                                                 \n"
+    "                                                                       \n"
+    "// bind to texture stage 0/1                                           \n"
+    "layout(binding = 0) uniform highp sampler2D g_screenTexture;           \n"
+    "layout(binding = 1) uniform highp sampler2D g_src0TextureFlt;          \n"
+    "layout(binding = 1) uniform highp USAMPLER g_src0Texture4Uint;         \n"
+    "                                                                       \n"
+    "// bind to image stage 0/1/2                                           \n"
+    "#ifdef GL_ES                                                           \n"
+    "layout(binding = 0, EDGE_READ_FORMAT) restrict writeonly uniform highp \n"
+    "    image2D g_resultTexture;                                           \n"
+    "layout(binding = 1, rgba8) restrict writeonly uniform highp            \n"
+    "    image2D g_resultTextureFlt4Slot1;                                  \n"
+    "layout(binding = 2, EDGE_READ_FORMAT) restrict writeonly uniform highp \n"
+    "    image2D g_resultTextureSlot2;                                      \n"
+    "#else                                                                  \n"
+    "layout(EDGE_READ_FORMAT) restrict writeonly uniform highp              \n"
+    "    image2D g_resultTexture;                                           \n"
+    "layout(rgba8) restrict writeonly uniform highp                         \n"
+    "    image2D g_resultTextureFlt4Slot1;                                  \n"
+    "layout(EDGE_READ_FORMAT) restrict writeonly uniform highp              \n"
+    "    image2D g_resultTextureSlot2;                                      \n"
+    "#endif                                                                 \n"
+    "                                                                       \n"
+    "// Constants                                                           \n"
+    "const vec4 c_lumWeights = vec4(0.2126f, 0.7152f, 0.0722f, 0.0000f);    \n"
+    "                                                                       \n"
+    "#ifdef EDGE_DETECT_THRESHOLD                                           \n"
+    "const float c_ColorThreshold = 1.0f / EDGE_DETECT_THRESHOLD;           \n"
+    "#endif                                                                 \n"
+    "                                                                       \n"
+    "// Must be even number; Will work with ~16 pretty good too for         \n"
+    "// additional performance, or with ~64 for highest quality.            \n"
+    "const int c_maxLineLength = 64;                                        \n"
+    "                                                                       \n"
+    "const vec4 c_edgeDebugColours[5] = vec4[5](vec4(0.5, 0.5, 0.5, 0.4),   \n"
+    "                                           vec4(1.0, 0.1, 1.0, 0.8),   \n"
+    "                                           vec4(0.9, 0.0, 0.0, 0.8),   \n"
+    "                                           vec4(0.0, 0.9, 0.0, 0.8),   \n"
+    "                                           vec4(0.0, 0.0, 0.9, 0.8));  \n"
+    "                                                                       \n"
+    "// this isn't needed if colour UAV is _SRGB but that doesn't work      \n"
+    "// everywhere                                                          \n"
+    "#ifdef IN_GAMMA_CORRECT_MODE                                           \n"
+    "///////////////////////////////////////////////////////////////////////\n"
+    "//                                                                     \n"
+    "// SRGB Helper Functions taken from D3DX_DXGIFormatConvert.inl         \n"
+    "float D3DX_FLOAT_to_SRGB(float val) {                                  \n"
+    "  if (val < 0.0031308f)                                                \n"
+    "    val *= 12.92f;                                                     \n"
+    "  else {                                                               \n"
+    "    val = 1.055f * pow(val, 1.0f / 2.4f) - 0.055f;                     \n"
+    "  }                                                                    \n"
+    "  return val;                                                          \n"
+    "}                                                                      \n"
+    "//                                                                     \n"
+    "vec3 D3DX_FLOAT3_to_SRGB(vec3 val) {                                   \n"
+    "  vec3 outVal;                                                         \n"
+    "  outVal.x = D3DX_FLOAT_to_SRGB(val.x);                                \n"
+    "  outVal.y = D3DX_FLOAT_to_SRGB(val.y);                                \n"
+    "  outVal.z = D3DX_FLOAT_to_SRGB(val.z);                                \n"
+    "  return outVal;                                                       \n"
+    "}                                                                      \n"
+    "//                                                                     \n"
+    "///////////////////////////////////////////////////////////////////////\n"
+    "#endif  // IN_GAMMA_CORRECT_MODE                                       \n"
+    "                                                                       \n"
+    "// how .rgba channels from the edge texture maps to pixel edges:       \n"
+    "//                                                                     \n"
+    "//                   A - 0x08                                          \n"
+    "//              |¯¯¯¯¯¯¯¯¯|                                            \n"
+    "//              |         |                                            \n"
+    "//     0x04 - B |  pixel  | R - 0x01                                   \n"
+    "//              |         |                                            \n"
+    "//              |_________|                                            \n"
+    "//                   G - 0x02                                          \n"
+    "//                                                                     \n"
+    "// (A - there's an edge between us and a pixel above us)               \n"
+    "// (R - there's an edge between us and a pixel to the right)           \n"
+    "// (G - there's an edge between us and a pixel at the bottom)          \n"
+    "// (B - there's an edge between us and a pixel to the left)            \n"
+    "                                                                       \n"
+    "// Expecting values of 1 and 0 only!                                   \n"
+    "uint PackEdge(uvec4 edges) {                                           \n"
+    "  return (edges.x << 0u) | (edges.y << 1u) | (edges.z << 2u) |         \n"
+    "         (edges.w << 3u);                                              \n"
+    "}                                                                      \n"
+    "                                                                       \n"
+    "uvec4 UnpackEdge(uint value) {                                         \n"
+    "  uvec4 ret;                                                           \n"
+    "  ret.x = (value & 0x01u) != 0u ? 1u : 0u;                             \n"
+    "  ret.y = (value & 0x02u) != 0u ? 1u : 0u;                             \n"
+    "  ret.z = (value & 0x04u) != 0u ? 1u : 0u;                             \n"
+    "  ret.w = (value & 0x08u) != 0u ? 1u : 0u;                             \n"
+    "  return ret;                                                          \n"
+    "}                                                                      \n"
+    "                                                                       \n"
+    "uint PackZ(const uvec2 screenPos, const bool invertedZShape) {         \n"
+    "  uint retVal = screenPos.x | (screenPos.y << 15u);                    \n"
+    "  if (invertedZShape)                                                  \n"
+    "    retVal |= (1u << 30u);                                             \n"
+    "  return retVal;                                                       \n"
+    "}                                                                      \n"
+    "                                                                       \n"
+    "void UnpackZ(uint packedZ, out uvec2 screenPos,                        \n"
+    "                           out bool invertedZShape)                    \n"
+    "{                                                                      \n"
+    "  screenPos.x = packedZ & 0x7FFFu;                                     \n"
+    "  screenPos.y = (packedZ >> 15u) & 0x7FFFu;                            \n"
+    "  invertedZShape = (packedZ >> 30u) == 1u;                             \n"
+    "}                                                                      \n"
+    "                                                                       \n"
+    "uint PackZ(const uvec2 screenPos,                                      \n"
+    "           const bool invertedZShape,                                  \n"
+    "           const bool horizontal) {                                    \n"
+    "  uint retVal = screenPos.x | (screenPos.y << 15u);                    \n"
+    "  if (invertedZShape)                                                  \n"
+    "    retVal |= (1u << 30u);                                             \n"
+    "  if (horizontal)                                                      \n"
+    "    retVal |= (1u << 31u);                                             \n"
+    "  return retVal;                                                       \n"
+    "}                                                                      \n"
+    "                                                                       \n"
+    "void UnpackZ(uint packedZ,                                             \n"
+    "             out uvec2 screenPos,                                      \n"
+    "             out bool invertedZShape,                                  \n"
+    "             out bool horizontal) {                                    \n"
+    "  screenPos.x = packedZ & 0x7FFFu;                                     \n"
+    "  screenPos.y = (packedZ >> 15u) & 0x7FFFu;                            \n"
+    "  invertedZShape = (packedZ & (1u << 30u)) != 0u;                      \n"
+    "  horizontal = (packedZ & (1u << 31u)) != 0u;                          \n"
+    "}                                                                      \n"
+    "                                                                       \n"
+    "vec4 PackBlurAAInfo(ivec2 pixelPos, uint shapeType) {                  \n"
+    "  uint packedEdges = uint(                                             \n"
+    "      texelFetch(g_src0TextureFlt, pixelPos, 0).r * 255.5);            \n"
+    "                                                                       \n"
+    "  float retval = float(packedEdges + (shapeType << 4u));               \n"
+    "                                                                       \n"
+    "  return vec4(retval / 255.0);                                         \n"
+    "}                                                                      \n"
+    "                                                                       \n"
+    "void UnpackBlurAAInfo(float packedValue, out uint edges,               \n"
+    "                      out uint shapeType) {                            \n"
+    "  uint packedValueInt = uint(packedValue * 255.5);                     \n"
+    "  edges = packedValueInt & 0xFu;                                       \n"
+    "  shapeType = packedValueInt >> 4u;                                    \n"
+    "}                                                                      \n"
+    "                                                                       \n"
+    "float EdgeDetectColorCalcDiff(vec3 colorA, vec3 colorB) {              \n"
+    "#ifdef IN_BGR_MODE                                                     \n"
+    "  vec3 LumWeights = c_lumWeights.bgr;                                  \n"
+    "#else                                                                  \n"
+    "  vec3 LumWeights = c_lumWeights.rgb;                                  \n"
+    "#endif                                                                 \n"
+    "                                                                       \n"
+    "  return dot(abs(colorA.rgb - colorB.rgb), LumWeights);                \n"
+    "}                                                                      \n"
+    "                                                                       \n"
+    "bool EdgeDetectColor(vec3 colorA, vec3 colorB) {                       \n"
+    "#ifdef EDGE_DETECT_THRESHOLD                                           \n"
+    "  return EdgeDetectColorCalcDiff(colorA, colorB) > c_ColorThreshold;   \n"
+    "#else                                                                  \n"
+    "  return EdgeDetectColorCalcDiff(colorA, colorB) > g_ColorThreshold;   \n"
+    "#endif                                                                 \n"
+    "}                                                                      \n"
+    "                                                                       \n"
+    "void FindLineLength(out int lineLengthLeft,                            \n"
+    "                    out int lineLengthRight,                           \n"
+    "                    ivec2 screenPos,                                   \n"
+    "                    const bool horizontal,                             \n"
+    "                    const bool invertedZShape,                         \n"
+    "                    const ivec2 stepRight) {                           \n"
+    "  // TODO: there must be a cleaner and faster way to get to these -    \n"
+    "  // a precalculated array indexing maybe?                             \n"
+    "  uint maskLeft, bitsContinueLeft, maskRight, bitsContinueRight;       \n"
+    "  {                                                                    \n"
+    "  // Horizontal (vertical is the same, just rotated 90º                \n"
+    "  // counter-clockwise)                                                \n"
+    "  // Inverted Z case:              // Normal Z case:                   \n"
+    "  //   __                          // __                               \n"
+    "  //  X|                           //  X|                              \n"
+    "  // --                            //    --                            \n"
+    "  //                                                                   \n"
+    "    uint maskTraceLeft, maskTraceRight;                                \n"
+    "    uint maskStopLeft, maskStopRight;                                  \n"
+    "    if (horizontal) {                                                  \n"
+    "      if (invertedZShape) {                                            \n"
+    "        maskTraceLeft = 0x02u;  // tracing bottom edge                 \n"
+    "        maskTraceRight = 0x08u; // tracing top edge                    \n"
+    "      } else {                                                         \n"
+    "        maskTraceLeft = 0x08u;  // tracing top edge                    \n"
+    "        maskTraceRight = 0x02u; // tracing bottom edge                 \n"
+    "      }                                                                \n"
+    "      maskStopLeft = 0x01u;  // stop on right edge                     \n"
+    "      maskStopRight = 0x04u; // stop on left edge                      \n"
+    "    } else {                                                           \n"
+    "      if (invertedZShape) {                                            \n"
+    "        maskTraceLeft = 0x01u;  // tracing right edge                  \n"
+    "        maskTraceRight = 0x04u; // tracing left edge                   \n"
+    "      } else {                                                         \n"
+    "        maskTraceLeft = 0x04u;  // tracing left edge                   \n"
+    "        maskTraceRight = 0x01u; // tracing right edge                  \n"
+    "      }                                                                \n"
+    "      maskStopLeft = 0x08u;  // stop on top edge                       \n"
+    "      maskStopRight = 0x02u; // stop on bottom edge                    \n"
+    "    }                                                                  \n"
+    "                                                                       \n"
+    "    maskLeft = maskTraceLeft | maskStopLeft;                           \n"
+    "    bitsContinueLeft = maskTraceLeft;                                  \n"
+    "    maskRight = maskTraceRight | maskStopRight;                        \n"
+    "    bitsContinueRight = maskTraceRight;                                \n"
+    "  }                                                                    \n"
+    "///////////////////////////////////////////////////////////////////////\n"
+    "                                                                       \n"
+    "#ifdef SETTINGS_ALLOW_SHORT_Zs                                         \n"
+    "  int i = 1;                                                           \n"
+    "#else                                                                  \n"
+    "  int i = 2; // starting from 2 because we already know it's at least 2\n"
+    "#endif                                                                 \n"
+    "  for (; i < c_maxLineLength; i++) {                                   \n"
+    "    uint edgeLeft = uint(                                              \n"
+    "        texelFetch(g_src0TextureFlt,                                   \n"
+    "                   ivec2(screenPos.xy - stepRight * i), 0).r * 255.5); \n"
+    "    uint edgeRight = uint(                                             \n"
+    "        texelFetch(g_src0TextureFlt,                                   \n"
+    "                   ivec2(screenPos.xy + stepRight * (i + 1)),          \n"
+    "                   0).r * 255.5);                                      \n"
+    "                                                                       \n"
+    "    // stop on encountering 'stopping' edge (as defined by masks)      \n"
+    "    int stopLeft = (edgeLeft & maskLeft) != bitsContinueLeft ? 1 : 0;  \n"
+    "    int stopRight =                                                    \n"
+    "        (edgeRight & maskRight) != bitsContinueRight ? 1 : 0;          \n"
+    "                                                                       \n"
+    "    if (bool(stopLeft) || bool(stopRight)) {                           \n"
+    "      lineLengthLeft = 1 + i - stopLeft;                               \n"
+    "      lineLengthRight = 1 + i - stopRight;                             \n"
+    "      return;                                                          \n"
+    "    }                                                                  \n"
+    "  }                                                                    \n"
+    "  lineLengthLeft = lineLengthRight = i;                                \n"
+    "  return;                                                              \n"
+    "}                                                                      \n"
+    "                                                                       \n"
+    "void ProcessDetectedZ(ivec2 screenPos, bool horizontal,                \n"
+    "                      bool invertedZShape) {                           \n"
+    "  int lineLengthLeft, lineLengthRight;                                 \n"
+    "                                                                       \n"
+    "  ivec2 stepRight = (horizontal) ? (ivec2(1, 0)) : (ivec2(0, -1));     \n"
+    "  vec2 blendDir = (horizontal) ? (vec2(0, -1)) : (vec2(-1, 0));        \n"
+    "                                                                       \n"
+    "  FindLineLength(lineLengthLeft, lineLengthRight, screenPos,           \n"
+    "                 horizontal, invertedZShape, stepRight);               \n"
+    "                                                                       \n"
+    "  vec2 pixelSize = g_OneOverScreenSize;                                \n"
+    "                                                                       \n"
+    "  float leftOdd = 0.15 * float(lineLengthLeft % 2);                    \n"
+    "  float rightOdd = 0.15 * float(lineLengthRight % 2);                  \n"
+    "                                                                       \n"
+    "  int loopFrom = -int((lineLengthLeft + 1) / 2) + 1;                   \n"
+    "  int loopTo = int((lineLengthRight + 1) / 2);                         \n"
+    "                                                                       \n"
+    "  float totalLength = float(loopTo - loopFrom) + 1.0 - leftOdd -       \n"
+    "                      rightOdd;                                        \n"
+    "                                                                       \n"
+    "  for (int i = loopFrom; i <= loopTo; i++) {                           \n"
+    "    highp ivec2 pixelPos = screenPos + stepRight * i;                  \n"
+    "    vec2 pixelPosFlt = vec2(float(pixelPos.x) + 0.5,                   \n"
+    "                            float(pixelPos.y) + 0.5);                  \n"
+    "                                                                       \n"
+    "#ifdef DEBUG_OUTPUT_AAINFO                                             \n"
+    "    imageStore(g_resultTextureSlot2, pixelPos,                         \n"
+    "               PackBlurAAInfo(pixelPos, 1u));                          \n"
+    "#endif                                                                 \n"
+    "                                                                       \n"
+    "    float m = (float(i) + 0.5 - leftOdd - float(loopFrom)) /           \n"
+    "               totalLength;                                            \n"
+    "    m = saturate(m);                                                   \n"
+    "    float k = m - ((i > 0) ? 1.0 : 0.0);                               \n"
+    "    k = (invertedZShape) ? (-k) : (k);                                 \n"
+    "                                                                       \n"
+    "    vec4 color = textureLod(g_screenTexture,                           \n"
+    "                            (pixelPosFlt + blendDir * k) * pixelSize,  \n"
+    "                            0.0);                                      \n"
+    "                                                                       \n"
+    "#ifdef IN_GAMMA_CORRECT_MODE                                           \n"
+    "    color.rgb = D3DX_FLOAT3_to_SRGB(color.rgb);                        \n"
+    "#endif                                                                 \n"
+    "    imageStore(g_resultTextureFlt4Slot1, pixelPos, color);             \n"
+    "  }                                                                    \n"
+    "}                                                                      \n"
+    "                                                                       \n"
+    "vec4 CalcDbgDisplayColor(const vec4 blurMap) {                         \n"
+    "  vec3 pixelC = vec3(0.0, 0.0, 0.0);                                   \n"
+    "  vec3 pixelL = vec3(0.0, 0.0, 1.0);                                   \n"
+    "  vec3 pixelT = vec3(1.0, 0.0, 0.0);                                   \n"
+    "  vec3 pixelR = vec3(0.0, 1.0, 0.0);                                   \n"
+    "  vec3 pixelB = vec3(0.8, 0.8, 0.0);                                   \n"
+    "                                                                       \n"
+    "  const float centerWeight = 1.0;                                      \n"
+    "  float fromBelowWeight = (1.0 / (1.0 - blurMap.x)) - 1.0;             \n"
+    "  float fromAboveWeight = (1.0 / (1.0 - blurMap.y)) - 1.0;             \n"
+    "  float fromRightWeight = (1.0 / (1.0 - blurMap.z)) - 1.0;             \n"
+    "  float fromLeftWeight = (1.0 / (1.0 - blurMap.w)) - 1.0;              \n"
+    "                                                                       \n"
+    "  float weightSum = centerWeight + dot(vec4(fromBelowWeight,           \n"
+    "                                            fromAboveWeight,           \n"
+    "                                            fromRightWeight,           \n"
+    "                                            fromLeftWeight),           \n"
+    "                                       vec4(1, 1, 1, 1));              \n"
+    "                                                                       \n"
+    "  vec4 pixel;                                                          \n"
+    "                                                                       \n"
+    "  pixel.rgb = pixelC.rgb + fromAboveWeight * pixelT +                  \n"
+    "                           fromBelowWeight * pixelB +                  \n"
+    "                           fromLeftWeight * pixelL +                   \n"
+    "                           fromRightWeight * pixelR;                   \n"
+    "  pixel.rgb /= weightSum;                                              \n"
+    "                                                                       \n"
+    "  pixel.a = dot(pixel.rgb, vec3(1, 1, 1)) * 100.0;                     \n"
+    "                                                                       \n"
+    "  return saturate(pixel);                                              \n"
+    "}                                                                      \n"
+    "                                                                       \n"
+    "#ifdef DETECT_EDGES1                                                   \n"
+    "layout(location = 0) out UVEC4 outEdges;                               \n"
+    "void DetectEdges1() {                                                  \n"
+    "  uvec4 outputEdges;                                                   \n"
+    "  ivec2 screenPosI = ivec2(gl_FragCoord.xy) * ivec2(2, 2);             \n"
+    "                                                                       \n"
+    "  // .rgb contains colour, .a contains flag whether to output it to    \n"
+    "  // working colour texture                                            \n"
+    "  vec4 pixel00 = texelFetch(g_screenTexture, screenPosI.xy, 0);        \n"
+    "  vec4 pixel10 =                                                       \n"
+    "      texelFetchOffset(g_screenTexture, screenPosI.xy, 0, ivec2(1, 0));\n"
+    "  vec4 pixel20 =                                                       \n"
+    "      texelFetchOffset(g_screenTexture, screenPosI.xy, 0, ivec2(2, 0));\n"
+    "  vec4 pixel01 =                                                       \n"
+    "      texelFetchOffset(g_screenTexture, screenPosI.xy, 0, ivec2(0, 1));\n"
+    "  vec4 pixel11 =                                                       \n"
+    "      texelFetchOffset(g_screenTexture, screenPosI.xy, 0, ivec2(1, 1));\n"
+    "  vec4 pixel21 =                                                       \n"
+    "      texelFetchOffset(g_screenTexture, screenPosI.xy, 0, ivec2(2, 1));\n"
+    "  vec4 pixel02 =                                                       \n"
+    "      texelFetchOffset(g_screenTexture, screenPosI.xy, 0, ivec2(0, 2));\n"
+    "  vec4 pixel12 =                                                       \n"
+    "      texelFetchOffset(g_screenTexture, screenPosI.xy, 0, ivec2(1, 2));\n"
+    "                                                                       \n"
+    "  float storeFlagPixel00 = 0.0;                                        \n"
+    "  float storeFlagPixel10 = 0.0;                                        \n"
+    "  float storeFlagPixel20 = 0.0;                                        \n"
+    "  float storeFlagPixel01 = 0.0;                                        \n"
+    "  float storeFlagPixel11 = 0.0;                                        \n"
+    "  float storeFlagPixel21 = 0.0;                                        \n"
+    "  float storeFlagPixel02 = 0.0;                                        \n"
+    "  float storeFlagPixel12 = 0.0;                                        \n"
+    "                                                                       \n"
+    "  vec2 et;                                                             \n"
+    "                                                                       \n"
+    "#ifdef EDGE_DETECT_THRESHOLD                                           \n"
+    "  float threshold = c_ColorThreshold;                                  \n"
+    "#else                                                                  \n"
+    "  float threshold = g_ColorThreshold;                                  \n"
+    "#endif                                                                 \n"
+    "                                                                       \n"
+    "  {                                                                    \n"
+    "    et.x = EdgeDetectColorCalcDiff(pixel00.rgb, pixel10.rgb);          \n"
+    "    et.y = EdgeDetectColorCalcDiff(pixel00.rgb, pixel01.rgb);          \n"
+    "    et = saturate(et - threshold);                                     \n"
+    "    ivec2 eti = ivec2(et * 15.0 + 0.99);                               \n"
+    "    outputEdges.x = uint(eti.x | (eti.y << 4));                        \n"
+    "                                                                       \n"
+    "    storeFlagPixel00 += et.x;                                          \n"
+    "    storeFlagPixel00 += et.y;                                          \n"
+    "    storeFlagPixel10 += et.x;                                          \n"
+    "    storeFlagPixel01 += et.y;                                          \n"
+    "  }                                                                    \n"
+    "                                                                       \n"
+    "  {                                                                    \n"
+    "    et.x = EdgeDetectColorCalcDiff(pixel10.rgb, pixel20.rgb);          \n"
+    "    et.y = EdgeDetectColorCalcDiff(pixel10.rgb, pixel11.rgb);          \n"
+    "    et = saturate(et - threshold);                                     \n"
+    "    ivec2 eti = ivec2(et * 15.0 + 0.99);                               \n"
+    "    outputEdges.y = uint(eti.x | (eti.y << 4));                        \n"
+    "                                                                       \n"
+    "    storeFlagPixel10 += et.x;                                          \n"
+    "    storeFlagPixel10 += et.y;                                          \n"
+    "    storeFlagPixel20 += et.x;                                          \n"
+    "    storeFlagPixel11 += et.y;                                          \n"
+    "  }                                                                    \n"
+    "                                                                       \n"
+    "  {                                                                    \n"
+    "    et.x = EdgeDetectColorCalcDiff(pixel01.rgb, pixel11.rgb);          \n"
+    "    et.y = EdgeDetectColorCalcDiff(pixel01.rgb, pixel02.rgb);          \n"
+    "    et = saturate(et - threshold);                                     \n"
+    "    ivec2 eti = ivec2(et * 15.0 + 0.99);                               \n"
+    "    outputEdges.z = uint(eti.x | (eti.y << 4));                        \n"
+    "                                                                       \n"
+    "    storeFlagPixel01 += et.x;                                          \n"
+    "    storeFlagPixel01 += et.y;                                          \n"
+    "    storeFlagPixel11 += et.x;                                          \n"
+    "    storeFlagPixel02 += et.y;                                          \n"
+    "  }                                                                    \n"
+    "                                                                       \n"
+    "  {                                                                    \n"
+    "    et.x = EdgeDetectColorCalcDiff(pixel11.rgb, pixel21.rgb);          \n"
+    "    et.y = EdgeDetectColorCalcDiff(pixel11.rgb, pixel12.rgb);          \n"
+    "    et = saturate(et - threshold);                                     \n"
+    "    ivec2 eti = ivec2(et * 15.0 + 0.99);                               \n"
+    "    outputEdges.w = uint(eti.x | (eti.y << 4));                        \n"
+    "                                                                       \n"
+    "    storeFlagPixel11 += et.x;                                          \n"
+    "    storeFlagPixel11 += et.y;                                          \n"
+    "    storeFlagPixel21 += et.x;                                          \n"
+    "    storeFlagPixel12 += et.y;                                          \n"
+    "  }                                                                    \n"
+    "                                                                       \n"
+    "  gl_FragDepth = any(bvec4(outputEdges)) ? 1.0 : 0.0;                  \n"
+    "                                                                       \n"
+    "  if (gl_FragDepth != 0.0) {                                           \n"
+    "    if (storeFlagPixel00 != 0.0)                                       \n"
+    "      imageStore(g_resultTextureFlt4Slot1, screenPosI.xy + ivec2(0, 0),\n"
+    "                 pixel00);                                             \n"
+    "    if (storeFlagPixel10 != 0.0)                                       \n"
+    "      imageStore(g_resultTextureFlt4Slot1, screenPosI.xy + ivec2(1, 0),\n"
+    "                 pixel10);                                             \n"
+    "    if (storeFlagPixel20 != 0.0)                                       \n"
+    "      imageStore(g_resultTextureFlt4Slot1, screenPosI.xy + ivec2(2, 0),\n"
+    "                 pixel20);                                             \n"
+    "    if (storeFlagPixel01 != 0.0)                                       \n"
+    "      imageStore(g_resultTextureFlt4Slot1, screenPosI.xy + ivec2(0, 1),\n"
+    "                 pixel01);                                             \n"
+    "    if (storeFlagPixel02 != 0.0)                                       \n"
+    "      imageStore(g_resultTextureFlt4Slot1, screenPosI.xy + ivec2(0, 2),\n"
+    "                 pixel02);                                             \n"
+    "    if (storeFlagPixel11 != 0.0)                                       \n"
+    "      imageStore(g_resultTextureFlt4Slot1, screenPosI.xy + ivec2(1, 1),\n"
+    "                 pixel11);                                             \n"
+    "    if (storeFlagPixel21 != 0.0)                                       \n"
+    "      imageStore(g_resultTextureFlt4Slot1, screenPosI.xy + ivec2(2, 1),\n"
+    "                 pixel21);                                             \n"
+    "    if (storeFlagPixel12 != 0.0)                                       \n"
+    "      imageStore(g_resultTextureFlt4Slot1, screenPosI.xy + ivec2(1, 2),\n"
+    "                 pixel12);                                             \n"
+    "  }                                                                    \n"
+    "  outEdges = STORE_UVEC4(outputEdges);                                 \n"
+    "}                                                                      \n"
+    "#endif  // DETECT_EDGES1                                               \n"
+    "                                                                       \n"
+    "vec2 UnpackThresholds(uint val) {                                      \n"
+    "  return vec2(val & 0x0Fu, val >> 4u) / 15.0f;                         \n"
+    "}                                                                      \n"
+    "                                                                       \n"
+    "uint PruneNonDominantEdges(vec4 edges[3]) {                            \n"
+    "  vec4 maxE4 = vec4(0.0, 0.0, 0.0, 0.0);                               \n"
+    "                                                                       \n"
+    "  float avg = 0.0;                                                     \n"
+    "                                                                       \n"
+    "  for (int i = 0; i < 3; i++) {                                        \n"
+    "    maxE4 = max(maxE4, edges[i]);                                      \n"
+    "                                                                       \n"
+    "    avg = dot(edges[i], vec4(1, 1, 1, 1) / (3.0 * 4.0));               \n"
+    "  }                                                                    \n"
+    "                                                                       \n"
+    "  vec2 maxE2 = max(maxE4.xy, maxE4.zw);                                \n"
+    "  float maxE = max(maxE2.x, maxE2.y);                                  \n"
+    "                                                                       \n"
+    "  float threshold = avg * 0.65 + maxE * 0.35;                          \n"
+    "                                                                       \n"
+    "  // threshold = 0.0001; // this disables non-dominant edge pruning!   \n"
+    "                                                                       \n"
+    "  uint cx = edges[0].x >= threshold ? 1u : 0u;                         \n"
+    "  uint cy = edges[0].y >= threshold ? 1u : 0u;                         \n"
+    "  return PackEdge(uvec4(cx, cy, 0, 0));                                \n"
+    "}                                                                      \n"
+    "                                                                       \n"
+    "void CollectEdges(int offX,                                            \n"
+    "                  int offY,                                            \n"
+    "                  out vec4 edges[3],                                   \n"
+    "                  const uint packedVals[6 * 6]) {                      \n"
+    "  vec2 pixelP0P0 = UnpackThresholds(packedVals[(offX)*6+(offY)]);      \n"
+    "  vec2 pixelP1P0 = UnpackThresholds(packedVals[(offX+1)*6+(offY)]);    \n"
+    "  vec2 pixelP0P1 = UnpackThresholds(packedVals[(offX)*6+(offY+1)]);    \n"
+    "  vec2 pixelM1P0 = UnpackThresholds(packedVals[(offX-1)*6 +(offY)]);   \n"
+    "  vec2 pixelP0M1 = UnpackThresholds(packedVals[(offX)*6+(offY-1)]);    \n"
+    "  vec2 pixelP1M1 = UnpackThresholds(packedVals[(offX+1)*6 +(offY-1)]); \n"
+    "  vec2 pixelM1P1 = UnpackThresholds(packedVals[(offX-1)*6+(offY+1)]);  \n"
+    "                                                                       \n"
+    "  edges[0].x = pixelP0P0.x;                                            \n"
+    "  edges[0].y = pixelP0P0.y;                                            \n"
+    "  edges[0].z = pixelP1P0.x;                                            \n"
+    "  edges[0].w = pixelP1P0.y;                                            \n"
+    "  edges[1].x = pixelP0P1.x;                                            \n"
+    "  edges[1].y = pixelP0P1.y;                                            \n"
+    "  edges[1].z = pixelM1P0.x;                                            \n"
+    "  edges[1].w = pixelM1P0.y;                                            \n"
+    "  edges[2].x = pixelP0M1.x;                                            \n"
+    "  edges[2].y = pixelP0M1.y;                                            \n"
+    "  edges[2].z = pixelP1M1.y;                                            \n"
+    "  edges[2].w = pixelM1P1.x;                                            \n"
+    "}                                                                      \n"
+    "                                                                       \n"
+    "#ifdef DETECT_EDGES2                                                   \n"
+    "layout(early_fragment_tests) in;                                       \n"
+    "void DetectEdges2() {                                                  \n"
+    "  ivec2 screenPosI = ivec2(gl_FragCoord.xy);                           \n"
+    "                                                                       \n"
+    "  // source : edge differences from previous pass                      \n"
+    "  uint packedVals[6 * 6];                                              \n"
+    "                                                                       \n"
+    "  // center pixel (our output)                                         \n"
+    "  UVEC4 packedQ4 = texelFetch(g_src0Texture4Uint, screenPosI.xy, 0);   \n"
+    "  packedVals[(2) * 6 + (2)] = LOAD_UINT(packedQ4.x);                   \n"
+    "  packedVals[(3) * 6 + (2)] = LOAD_UINT(packedQ4.y);                   \n"
+    "  packedVals[(2) * 6 + (3)] = LOAD_UINT(packedQ4.z);                   \n"
+    "  packedVals[(3) * 6 + (3)] = LOAD_UINT(packedQ4.w);                   \n"
+    "                                                                       \n"
+    "  vec4 edges[3];                                                       \n"
+    "  if (bool(packedVals[(2) * 6 + (2)]) ||                               \n"
+    "      bool(packedVals[(3) * 6 + (2)])) {                               \n"
+    "    UVEC4 packedQ1 = texelFetchOffset(g_src0Texture4Uint,              \n"
+    "                                      screenPosI.xy, 0, ivec2(0, -1)); \n"
+    "    packedVals[(2) * 6 + (0)] = LOAD_UINT(packedQ1.x);                 \n"
+    "    packedVals[(3) * 6 + (0)] = LOAD_UINT(packedQ1.y);                 \n"
+    "    packedVals[(2) * 6 + (1)] = LOAD_UINT(packedQ1.z);                 \n"
+    "    packedVals[(3) * 6 + (1)] = LOAD_UINT(packedQ1.w);                 \n"
+    "  }                                                                    \n"
+    "                                                                       \n"
+    "  if (bool(packedVals[(2) * 6 + (2)]) ||                               \n"
+    "      bool(packedVals[(2) * 6 + (3)])) {                               \n"
+    "    UVEC4 packedQ3 = texelFetchOffset(g_src0Texture4Uint,              \n"
+    "                                      screenPosI.xy, 0, ivec2(-1, 0)); \n"
+    "    packedVals[(0) * 6 + (2)] = LOAD_UINT(packedQ3.x);                 \n"
+    "    packedVals[(1) * 6 + (2)] = LOAD_UINT(packedQ3.y);                 \n"
+    "    packedVals[(0) * 6 + (3)] = LOAD_UINT(packedQ3.z);                 \n"
+    "    packedVals[(1) * 6 + (3)] = LOAD_UINT(packedQ3.w);                 \n"
+    "  }                                                                    \n"
+    "                                                                       \n"
+    "  if (bool(packedVals[(2) * 6 + (2)])) {                               \n"
+    "    CollectEdges(2, 2, edges, packedVals);                             \n"
+    "    uint pe = PruneNonDominantEdges(edges);                            \n"
+    "    if (pe != 0u) {                                                    \n"
+    "      imageStore(g_resultTexture, 2 * screenPosI.xy + ivec2(0, 0),     \n"
+    "                 vec4(float(0x80u | pe) / 255.0, 0, 0, 0));            \n"
+    "    }                                                                  \n"
+    "  }                                                                    \n"
+    "                                                                       \n"
+    "  if (bool(packedVals[(3) * 6 + (2)]) ||                               \n"
+    "      bool(packedVals[(3) * 6 + (3)])) {                               \n"
+    "    UVEC4 packedQ5 = texelFetchOffset(g_src0Texture4Uint,              \n"
+    "                                      screenPosI.xy, 0, ivec2(1, 0));  \n"
+    "    packedVals[(4) * 6 + (2)] = LOAD_UINT(packedQ5.x);                 \n"
+    "    packedVals[(5) * 6 + (2)] = LOAD_UINT(packedQ5.y);                 \n"
+    "    packedVals[(4) * 6 + (3)] = LOAD_UINT(packedQ5.z);                 \n"
+    "    packedVals[(5) * 6 + (3)] = LOAD_UINT(packedQ5.w);                 \n"
+    "  }                                                                    \n"
+    "                                                                       \n"
+    "  if (bool(packedVals[(3) * 6 + (2)])) {                               \n"
+    "    UVEC4 packedQ2 = texelFetchOffset(g_src0Texture4Uint,              \n"
+    "                                      screenPosI.xy, 0, ivec2(1, -1)); \n"
+    "    packedVals[(4) * 6 + (0)] = LOAD_UINT(packedQ2.x);                 \n"
+    "    packedVals[(5) * 6 + (0)] = LOAD_UINT(packedQ2.y);                 \n"
+    "    packedVals[(4) * 6 + (1)] = LOAD_UINT(packedQ2.z);                 \n"
+    "    packedVals[(5) * 6 + (1)] = LOAD_UINT(packedQ2.w);                 \n"
+    "                                                                       \n"
+    "    CollectEdges(3, 2, edges, packedVals);                             \n"
+    "    uint pe = PruneNonDominantEdges(edges);                            \n"
+    "    if (pe != 0u) {                                                    \n"
+    "      imageStore(g_resultTexture, 2 * screenPosI.xy + ivec2(1, 0),     \n"
+    "                 vec4(float(0x80u | pe) / 255.0, 0, 0, 0));            \n"
+    "    }                                                                  \n"
+    "  }                                                                    \n"
+    "                                                                       \n"
+    "  if (bool(packedVals[(2) * 6 + (3)]) ||                               \n"
+    "      bool(packedVals[(3) * 6 + (3)])) {                               \n"
+    "    UVEC4 packedQ7 = texelFetchOffset(g_src0Texture4Uint,              \n"
+    "                                      screenPosI.xy, 0, ivec2(0, 1));  \n"
+    "    packedVals[(2) * 6 + (4)] = LOAD_UINT(packedQ7.x);                 \n"
+    "    packedVals[(3) * 6 + (4)] = LOAD_UINT(packedQ7.y);                 \n"
+    "    packedVals[(2) * 6 + (5)] = LOAD_UINT(packedQ7.z);                 \n"
+    "    packedVals[(3) * 6 + (5)] = LOAD_UINT(packedQ7.w);                 \n"
+    "  }                                                                    \n"
+    "                                                                       \n"
+    "  if (bool(packedVals[(2) * 6 + (3)])) {                               \n"
+    "    UVEC4 packedQ6 = texelFetchOffset(g_src0Texture4Uint,              \n"
+    "                                      screenPosI.xy, 0, ivec2(-1, -1));\n"
+    "    packedVals[(0) * 6 + (4)] = LOAD_UINT(packedQ6.x);                 \n"
+    "    packedVals[(1) * 6 + (4)] = LOAD_UINT(packedQ6.y);                 \n"
+    "    packedVals[(0) * 6 + (5)] = LOAD_UINT(packedQ6.z);                 \n"
+    "    packedVals[(1) * 6 + (5)] = LOAD_UINT(packedQ6.w);                 \n"
+    "                                                                       \n"
+    "    CollectEdges(2, 3, edges, packedVals);                             \n"
+    "    uint pe = PruneNonDominantEdges(edges);                            \n"
+    "    if (pe != 0u) {                                                    \n"
+    "      imageStore(g_resultTexture, 2 * screenPosI.xy + ivec2(0, 1),     \n"
+    "                 vec4(float(0x80u | pe) / 255.0, 0, 0, 0));            \n"
+    "    }                                                                  \n"
+    "  }                                                                    \n"
+    "                                                                       \n"
+    "  if (bool(packedVals[(3) * 6 + (3)])) {                               \n"
+    "    CollectEdges(3, 3, edges, packedVals);                             \n"
+    "    uint pe = PruneNonDominantEdges(edges);                            \n"
+    "    if (pe != 0u) {                                                    \n"
+    "      imageStore(g_resultTexture, 2 * screenPosI.xy + ivec2(1, 1),     \n"
+    "                 vec4(float(0x80u | pe) / 255.0, 0, 0, 0));            \n"
+    "    }                                                                  \n"
+    "  }                                                                    \n"
+    "}                                                                      \n"
+    "#endif  // DETECT_EDGES2                                               \n"
+    "                                                                       \n";
+
+const char ApplyFramebufferAttachmentCMAAINTELResourceManager::cmaa_frag_s2_[] =
+    "#ifdef COMBINE_EDGES                                                   \n"
+    "void CombineEdges() {                                                  \n"
+    "  ivec3 screenPosIBase = ivec3(ivec2(gl_FragCoord.xy) * 2, 0);         \n"
+    "  vec3 screenPosBase = vec3(screenPosIBase);                           \n"
+    "  uint packedEdgesArray[3 * 3];                                        \n"
+    "                                                                       \n"
+    "  // use only if it has the 'prev frame' flag:[sample * 255.0 - 127.5] \n"
+    "  //-> if it has the last bit flag (128), it's going to stay above 0   \n"
+    "  uvec4 sampA = uvec4(                                                 \n"
+    "      textureGatherOffset(g_src0TextureFlt,                            \n"
+    "                          screenPosBase.xy * g_OneOverScreenSize,      \n"
+    "                          ivec2(1, 0)) * 255.0 - 127.5);               \n"
+    "  uvec4 sampB = uvec4(                                                 \n"
+    "      textureGatherOffset(g_src0TextureFlt,                            \n"
+    "                          screenPosBase.xy * g_OneOverScreenSize,      \n"
+    "                          ivec2(0, 1)) * 255.0 - 127.5);               \n"
+    "  uint sampC = uint(                                                   \n"
+    "      texelFetchOffset(g_src0TextureFlt, screenPosIBase.xy, 0,         \n"
+    "                       ivec2(1, 1)).r * 255.0 - 127.5);                \n"
+    "                                                                       \n"
+    "  packedEdgesArray[(0) * 3 + (0)] = 0u;                                \n"
+    "  packedEdgesArray[(1) * 3 + (0)] = sampA.w;                           \n"
+    "  packedEdgesArray[(2) * 3 + (0)] = sampA.z;                           \n"
+    "  packedEdgesArray[(1) * 3 + (1)] = sampA.x;                           \n"
+    "  packedEdgesArray[(2) * 3 + (1)] = sampA.y;                           \n"
+    "  packedEdgesArray[(0) * 3 + (1)] = sampB.w;                           \n"
+    "  packedEdgesArray[(0) * 3 + (2)] = sampB.x;                           \n"
+    "  packedEdgesArray[(1) * 3 + (2)] = sampB.y;                           \n"
+    "  packedEdgesArray[(2) * 3 + (2)] = sampC;                             \n"
+    "                                                                       \n"
+    "  uvec4 pixelsC = uvec4(packedEdgesArray[(1 + 0) * 3 + (1 + 0)],       \n"
+    "                        packedEdgesArray[(1 + 1) * 3 + (1 + 0)],       \n"
+    "                        packedEdgesArray[(1 + 0) * 3 + (1 + 1)],       \n"
+    "                        packedEdgesArray[(1 + 1) * 3 + (1 + 1)]);      \n"
+    "  uvec4 pixelsL = uvec4(packedEdgesArray[(0 + 0) * 3 + (1 + 0)],       \n"
+    "                        packedEdgesArray[(0 + 1) * 3 + (1 + 0)],       \n"
+    "                        packedEdgesArray[(0 + 0) * 3 + (1 + 1)],       \n"
+    "                        packedEdgesArray[(0 + 1) * 3 + (1 + 1)]);      \n"
+    "  uvec4 pixelsU = uvec4(packedEdgesArray[(1 + 0) * 3 + (0 + 0)],       \n"
+    "                        packedEdgesArray[(1 + 1) * 3 + (0 + 0)],       \n"
+    "                        packedEdgesArray[(1 + 0) * 3 + (0 + 1)],       \n"
+    "                        packedEdgesArray[(1 + 1) * 3 + (0 + 1)]);      \n"
+    "                                                                       \n"
+    "  uvec4 outEdge4 =                                                     \n"
+    "      pixelsC | ((pixelsL & 0x01u) << 2u) | ((pixelsU & 0x02u) << 2u); \n"
+    "  vec4 outEdge4Flt = vec4(outEdge4) / 255.0;                           \n"
+    "                                                                       \n"
+    "  imageStore(g_resultTextureSlot2, screenPosIBase.xy + ivec2(0, 0),    \n"
+    "             outEdge4Flt.xxxx);                                        \n"
+    "  imageStore(g_resultTextureSlot2, screenPosIBase.xy + ivec2(1, 0),    \n"
+    "             outEdge4Flt.yyyy);                                        \n"
+    "  imageStore(g_resultTextureSlot2, screenPosIBase.xy + ivec2(0, 1),    \n"
+    "             outEdge4Flt.zzzz);                                        \n"
+    "  imageStore(g_resultTextureSlot2, screenPosIBase.xy + ivec2(1, 1),    \n"
+    "             outEdge4Flt.wwww);                                        \n"
+    "                                                                       \n"
+    "  // uvec4 numberOfEdges4 = uvec4(bitCount(outEdge4));                 \n"
+    "  // gl_FragDepth =                                                    \n"
+    "  //     any(greaterThan(numberOfEdges4, uvec4(1))) ? 1.0 : 0.0;       \n"
+    "                                                                       \n"
+    "  gl_FragDepth =                                                       \n"
+    "      any(greaterThan(outEdge4, uvec4(1))) ? 1.0 : 0.0;                \n"
+    "}                                                                      \n"
+    "#endif  // COMBINE_EDGES                                               \n"
+    "                                                                       \n"
+    "#ifdef BLUR_EDGES                                                      \n"
+    "layout(early_fragment_tests) in;                                       \n"
+    "void BlurEdges() {                                                     \n"
+    "  int _i;                                                              \n"
+    "                                                                       \n"
+    "  ivec3 screenPosIBase = ivec3(ivec2(gl_FragCoord.xy) * 2, 0);         \n"
+    "  vec3 screenPosBase = vec3(screenPosIBase);                           \n"
+    "  uint forFollowUpCount = 0u;                                          \n"
+    "  ivec4 forFollowUpCoords[4];                                          \n"
+    "                                                                       \n"
+    "  uint packedEdgesArray[4 * 4];                                        \n"
+    "                                                                       \n"
+    "  uvec4 sampA = uvec4(                                                 \n"
+    "      textureGatherOffset(g_src0TextureFlt,                            \n"
+    "                          screenPosBase.xy * g_OneOverScreenSize,      \n"
+    "                          ivec2(0, 0)) *255.5);                        \n"
+    "  uvec4 sampB = uvec4(                                                 \n"
+    "      textureGatherOffset(g_src0TextureFlt,                            \n"
+    "                          screenPosBase.xy * g_OneOverScreenSize,      \n"
+    "                          ivec2(2, 0)) *255.5);                        \n"
+    "  uvec4 sampC = uvec4(                                                 \n"
+    "      textureGatherOffset(g_src0TextureFlt,                            \n"
+    "                          screenPosBase.xy * g_OneOverScreenSize,      \n"
+    "                          ivec2(0, 2)) *255.5);                        \n"
+    "  uvec4 sampD = uvec4(                                                 \n"
+    "      textureGatherOffset(g_src0TextureFlt,                            \n"
+    "                          screenPosBase.xy * g_OneOverScreenSize,      \n"
+    "                          ivec2(2, 2)) *255.5);                        \n"
+    "                                                                       \n"
+    "  packedEdgesArray[(0) * 4 + (0)] = sampA.w;                           \n"
+    "  packedEdgesArray[(1) * 4 + (0)] = sampA.z;                           \n"
+    "  packedEdgesArray[(0) * 4 + (1)] = sampA.x;                           \n"
+    "  packedEdgesArray[(1) * 4 + (1)] = sampA.y;                           \n"
+    "  packedEdgesArray[(2) * 4 + (0)] = sampB.w;                           \n"
+    "  packedEdgesArray[(3) * 4 + (0)] = sampB.z;                           \n"
+    "  packedEdgesArray[(2) * 4 + (1)] = sampB.x;                           \n"
+    "  packedEdgesArray[(3) * 4 + (1)] = sampB.y;                           \n"
+    "  packedEdgesArray[(0) * 4 + (2)] = sampC.w;                           \n"
+    "  packedEdgesArray[(1) * 4 + (2)] = sampC.z;                           \n"
+    "  packedEdgesArray[(0) * 4 + (3)] = sampC.x;                           \n"
+    "  packedEdgesArray[(1) * 4 + (3)] = sampC.y;                           \n"
+    "  packedEdgesArray[(2) * 4 + (2)] = sampD.w;                           \n"
+    "  packedEdgesArray[(3) * 4 + (2)] = sampD.z;                           \n"
+    "  packedEdgesArray[(2) * 4 + (3)] = sampD.x;                           \n"
+    "  packedEdgesArray[(3) * 4 + (3)] = sampD.y;                           \n"
+    "                                                                       \n"
+    "  for (_i = 0; _i < 4; _i++) {                                         \n"
+    "    int _x = _i % 2;                                                   \n"
+    "    int _y = _i / 2;                                                   \n"
+    "                                                                       \n"
+    "    ivec3 screenPosI = screenPosIBase + ivec3(_x, _y, 0);              \n"
+    "                                                                       \n"
+    "    uint packedEdgesC = packedEdgesArray[(1 + _x) * 4 + (1 + _y)];     \n"
+    "                                                                       \n"
+    "    uvec4 edges = UnpackEdge(packedEdgesC);                            \n"
+    "    vec4 edgesFlt = vec4(edges);                                       \n"
+    "                                                                       \n"
+    "    float numberOfEdges = dot(edgesFlt, vec4(1, 1, 1, 1));             \n"
+    "    if (numberOfEdges < 2.0)                                           \n"
+    "      continue;                                                        \n"
+    "                                                                       \n"
+    "    float fromRight = edgesFlt.r;                                      \n"
+    "    float fromBelow = edgesFlt.g;                                      \n"
+    "    float fromLeft = edgesFlt.b;                                       \n"
+    "    float fromAbove = edgesFlt.a;                                      \n"
+    "                                                                       \n"
+    "    vec4 xFroms = vec4(fromBelow, fromAbove, fromRight, fromLeft);     \n"
+    "                                                                       \n"
+    "    float blurCoeff = 0.0;                                             \n"
+    "                                                                       \n"
+    "    // These are additional blurs that complement the main line-based  \n"
+    "    // blurring; Unlike line-based, these do not necessarily preserve  \n"
+    "    // the total amount of screen colour as they will take             \n"
+    "    // neighbouring pixel colours and apply them to the one currently  \n"
+    "    // processed.                                                      \n"
+    "                                                                       \n"
+    "    // 1.) L-like shape.                                               \n"
+    "    // For this shape, the total amount of screen colour will be       \n"
+    "    // preserved when this is a part of a (zigzag) diagonal line as the\n"
+    "    // corners from the other side  will do the same and take some of  \n"
+    "    // the current pixel's colour in return.                           \n"
+    "    // However, in the case when this is an actual corner, the pixel's \n"
+    "    // colour will be partially overwritten by it's 2 neighbours.      \n"
+    "    // if( numberOfEdges > 1.0 )                                       \n"
+    "    {                                                                  \n"
+    "      // with value of 0.15, the pixel will retain approx 77% of its   \n"
+    "      // colour and the remaining 23% will come from its 2 neighbours  \n"
+    "      // (which are likely to be blurred too in the opposite direction)\n"
+    "      blurCoeff = 0.08;                                                \n"
+    "                                                                       \n"
+    "      // Only do blending if it's L shape - if we're between two       \n"
+    "      // parallel edges, don't do anything                             \n"
+    "      blurCoeff *= (1.0 - fromBelow * fromAbove) *                     \n"
+    "                   (1.0 - fromRight * fromLeft);                       \n"
+    "    }                                                                  \n"
+    "                                                                       \n"
+    "    // 2.) U-like shape (surrounded with edges from 3 sides)           \n"
+    "    if (numberOfEdges > 2.0) {                                         \n"
+    "      // with value of 0.13, the pixel will retain approx 72% of its   \n"
+    "      // colour and the remaining 28% will be picked from its 3        \n"
+    "      // neighbours (which are unlikely to be blurred too but could be)\n"
+    "      blurCoeff = 0.11;                                                \n"
+    "    }                                                                  \n"
+    "                                                                       \n"
+    "    // 3.) Completely surrounded with edges from all 4 sides           \n"
+    "    if (numberOfEdges > 3.0) {                                         \n"
+    "      // with value of 0.07, the pixel will retain 78% of its colour   \n"
+    "      // and the remaining 22% will come from its 4 neighbours (which  \n"
+    "      // are unlikely to be blurred)                                   \n"
+    "      blurCoeff = 0.05;                                                \n"
+    "    }                                                                  \n"
+    "                                                                       \n"
+    "    if (blurCoeff == 0.0) {                                            \n"
+    "      // this avoids Z search below as well but that's ok because a Z  \n"
+    "      // shape will also always have some blurCoeff                    \n"
+    "      continue;                                                        \n"
+    "    }                                                                  \n"
+    "                                                                       \n"
+    "    vec4 blurMap = xFroms * blurCoeff;                                 \n"
+    "                                                                       \n"
+    "    vec4 pixelC = texelFetch(g_screenTexture, screenPosI.xy, 0);       \n"
+    "                                                                       \n"
+    "    const float centerWeight = 1.0;                                    \n"
+    "    float fromBelowWeight = blurMap.x;                                 \n"
+    "    float fromAboveWeight = blurMap.y;                                 \n"
+    "    float fromRightWeight = blurMap.z;                                 \n"
+    "    float fromLeftWeight  = blurMap.w;                                 \n"
+    "                                                                       \n"
+    "    // this would be the proper math for blending if we were handling  \n"
+    "    // lines (Zs) and mini kernel smoothing here, but since we're doing\n"
+    "    // lines separately, no need to complicate, just tweak the settings\n"
+    "    // float fromBelowWeight = (1.0 / (1.0 - blurMap.x)) - 1.0;        \n"
+    "    // float fromAboveWeight = (1.0 / (1.0 - blurMap.y)) - 1.0;        \n"
+    "    // float fromRightWeight = (1.0 / (1.0 - blurMap.z)) - 1.0;        \n"
+    "    // float fromLeftWeight  = (1.0 / (1.0 - blurMap.w)) - 1.0;        \n"
+    "                                                                       \n"
+    "    float fourWeightSum = dot(blurMap, vec4(1, 1, 1, 1));              \n"
+    "    float allWeightSum = centerWeight + fourWeightSum;                 \n"
+    "                                                                       \n"
+    "    vec4 color = vec4(0, 0, 0, 0);                                     \n"
+    "    if (fromLeftWeight > 0.0) {                                        \n"
+    "      vec3 pixelL = texelFetchOffset(g_screenTexture, screenPosI.xy, 0,\n"
+    "                                     ivec2(-1, 0)).rgb;                \n"
+    "      color.rgb += fromLeftWeight * pixelL;                            \n"
+    "    }                                                                  \n"
+    "    if (fromAboveWeight > 0.0) {                                       \n"
+    "      vec3 pixelT = texelFetchOffset(g_screenTexture, screenPosI.xy, 0,\n"
+    "                                     ivec2(0, -1)).rgb;                \n"
+    "      color.rgb += fromAboveWeight * pixelT;                           \n"
+    "    }                                                                  \n"
+    "    if (fromRightWeight > 0.0) {                                       \n"
+    "      vec3 pixelR = texelFetchOffset(g_screenTexture, screenPosI.xy, 0,\n"
+    "                                     ivec2(1, 0)).rgb;                 \n"
+    "      color.rgb += fromRightWeight * pixelR;                           \n"
+    "    }                                                                  \n"
+    "    if (fromBelowWeight > 0.0) {                                       \n"
+    "      vec3 pixelB = texelFetchOffset(g_screenTexture, screenPosI.xy, 0,\n"
+    "                                     ivec2(0, 1)).rgb;                 \n"
+    "      color.rgb += fromBelowWeight * pixelB;                           \n"
+    "    }                                                                  \n"
+    "                                                                       \n"
+    "    color /= fourWeightSum + 0.0001;                                   \n"
+    "    color.a = 1.0 - centerWeight / allWeightSum;                       \n"
+    "                                                                       \n"
+    "    color.rgb = mix(pixelC.rgb, color.rgb, color.a).rgb;               \n"
+    "#ifdef IN_GAMMA_CORRECT_MODE                                           \n"
+    "    color.rgb = D3DX_FLOAT3_to_SRGB(color.rgb);                        \n"
+    "#endif                                                                 \n"
+    "                                                                       \n"
+    "#ifdef DEBUG_OUTPUT_AAINFO                                             \n"
+    "    imageStore(g_resultTextureSlot2, screenPosI.xy,                    \n"
+    "               PackBlurAAInfo(screenPosI.xy, uint(numberOfEdges)));    \n"
+    "#endif                                                                 \n"
+    "    imageStore(g_resultTextureFlt4Slot1, screenPosI.xy,                \n"
+    "               vec4(color.rgb, pixelC.a));                             \n"
+    "                                                                       \n"
+    "    if (numberOfEdges == 2.0) {                                        \n"
+    "      uint packedEdgesL = packedEdgesArray[(0 + _x) * 4 + (1 + _y)];   \n"
+    "      uint packedEdgesT = packedEdgesArray[(1 + _x) * 4 + (0 + _y)];   \n"
+    "      uint packedEdgesR = packedEdgesArray[(2 + _x) * 4 + (1 + _y)];   \n"
+    "      uint packedEdgesB = packedEdgesArray[(1 + _x) * 4 + (2 + _y)];   \n"
+    "                                                                       \n"
+    "      bool isHorizontalA = ((packedEdgesC) == (0x01u | 0x02u)) &&      \n"
+    "         ((packedEdgesR & (0x01u | 0x08u)) == (0x08u));                \n"
+    "      bool isHorizontalB = ((packedEdgesC) == (0x01u | 0x08u)) &&      \n"
+    "         ((packedEdgesR & (0x01u | 0x02u)) == (0x02u));                \n"
+    "                                                                       \n"
+    "      bool isHCandidate = isHorizontalA || isHorizontalB;              \n"
+    "                                                                       \n"
+    "      bool isVerticalA = ((packedEdgesC) == (0x08u | 0x01u)) &&        \n"
+    "         ((packedEdgesT & (0x08u | 0x04u)) == (0x04u));                \n"
+    "      bool isVerticalB = ((packedEdgesC) == (0x08u | 0x04u)) &&        \n"
+    "         ((packedEdgesT & (0x08u | 0x01u)) == (0x01u));                \n"
+    "      bool isVCandidate = isVerticalA || isVerticalB;                  \n"
+    "                                                                       \n"
+    "      bool isCandidate = isHCandidate || isVCandidate;                 \n"
+    "                                                                       \n"
+    "      if (!isCandidate)                                                \n"
+    "        continue;                                                      \n"
+    "                                                                       \n"
+    "      bool horizontal = isHCandidate;                                  \n"
+    "                                                                       \n"
+    "      // what if both are candidates? do additional pruning (still not \n"
+    "      // 100% but gets rid of worst case errors)                       \n"
+    "      if (isHCandidate && isVCandidate)                                \n"
+    "        horizontal =                                                   \n"
+    "           (isHorizontalA && ((packedEdgesL & 0x02u) == 0x02u)) ||     \n"
+    "           (isHorizontalB && ((packedEdgesL & 0x08u) == 0x08u));       \n"
+    "                                                                       \n"
+    "      ivec2 offsetC;                                                   \n"
+    "      uint packedEdgesM1P0;                                            \n"
+    "      uint packedEdgesP1P0;                                            \n"
+    "      if (horizontal) {                                                \n"
+    "        packedEdgesM1P0 = packedEdgesL;                                \n"
+    "        packedEdgesP1P0 = packedEdgesR;                                \n"
+    "        offsetC = ivec2(2, 0);                                         \n"
+    "      } else {                                                         \n"
+    "        packedEdgesM1P0 = packedEdgesB;                                \n"
+    "        packedEdgesP1P0 = packedEdgesT;                                \n"
+    "        offsetC = ivec2(0, -2);                                        \n"
+    "      }                                                                \n"
+    "                                                                       \n"
+    "      uvec4 edgesM1P0 = UnpackEdge(packedEdgesM1P0);                   \n"
+    "      uvec4 edgesP1P0 = UnpackEdge(packedEdgesP1P0);                   \n"
+    "      uvec4 edgesP2P0 = UnpackEdge(uint(texelFetch(                    \n"
+    "         g_src0TextureFlt, screenPosI.xy + offsetC, 0).r * 255.5));    \n"
+    "                                                                       \n"
+    "      uvec4 arg0;                                                      \n"
+    "      uvec4 arg1;                                                      \n"
+    "      uvec4 arg2;                                                      \n"
+    "      uvec4 arg3;                                                      \n"
+    "      bool arg4;                                                       \n"
+    "                                                                       \n"
+    "      if (horizontal) {                                                \n"
+    "        arg0 = uvec4(edges);                                           \n"
+    "        arg1 = edgesM1P0;                                              \n"
+    "        arg2 = edgesP1P0;                                              \n"
+    "        arg3 = edgesP2P0;                                              \n"
+    "        arg4 = true;                                                   \n"
+    "      } else {                                                         \n"
+    "        // Reuse the same code for vertical (used for horizontal above)\n"
+    "        // but rotate input data 90º counter-clockwise, so that:       \n"
+    "        // left     becomes     bottom                                 \n"
+    "        // top      becomes     left                                   \n"
+    "        // right    becomes     top                                    \n"
+    "        // bottom   becomes     right                                  \n"
+    "                                                                       \n"
+    "        // we also have to rotate edges, thus .argb                    \n"
+    "        arg0 = uvec4(edges.argb);                                      \n"
+    "        arg1 = edgesM1P0.argb;                                         \n"
+    "        arg2 = edgesP1P0.argb;                                         \n"
+    "        arg3 = edgesP2P0.argb;                                         \n"
+    "        arg4 = false;                                                  \n"
+    "      }                                                                \n"
+    "                                                                       \n"
+    "      {                                                                \n"
+    "        ivec2 screenPos = screenPosI.xy;                               \n"
+    "        uvec4 _edges = arg0;                                           \n"
+    "        uvec4 _edgesM1P0 = arg1;                                       \n"
+    "        uvec4 _edgesP1P0 = arg2;                                       \n"
+    "        uvec4 _edgesP2P0 = arg3;                                       \n"
+    "        bool horizontal = arg4;                                        \n"
+    "        // Inverted Z case:                                            \n"
+    "        //   __                                                        \n"
+    "        //  X|                                                         \n"
+    "        // ¯¯                                                          \n"
+    "        bool isInvertedZ = false;                                      \n"
+    "        bool isNormalZ = false;                                        \n"
+    "        {                                                              \n"
+    "#ifndef SETTINGS_ALLOW_SHORT_Zs                                        \n"
+    "          // (1u-_edges.a) constraint can be removed; it was added for \n"
+    "          // some rare cases                                           \n"
+    "          uint isZShape = _edges.r * _edges.g * _edgesM1P0.g *         \n"
+    "             _edgesP1P0.a *_edgesP2P0.a * (1u - _edges.b) *            \n"
+    "              (1u - _edgesP1P0.r) * (1u - _edges.a) *                  \n"
+    "              (1u - _edgesP1P0.g);                                     \n"
+    "#else                                                                  \n"
+    "          uint isZShape = _edges.r * _edges.g * _edgesP1P0.a *         \n"
+    "              (1u - _edges.b) * (1u - _edgesP1P0.r) * (1u - _edges.a) *\n"
+    "                          (1u - _edgesP1P0.g);                         \n"
+    "          isZShape *= (_edgesM1P0.g + _edgesP2P0.a);                   \n"
+    "                          // and at least one of these need to be there\n"
+    "#endif                                                                 \n"
+    "          if (isZShape > 0u) {                                         \n"
+    "            isInvertedZ = true;                                        \n"
+    "          }                                                            \n"
+    "        }                                                              \n"
+    "                                                                       \n"
+    "        // Normal Z case:                                              \n"
+    "        // __                                                          \n"
+    "        //  X|                                                         \n"
+    "        //   ¯¯                                                        \n"
+    "        {                                                              \n"
+    "#ifndef SETTINGS_ALLOW_SHORT_Zs                                        \n"
+    "          uint isZShape = _edges.r * _edges.a * _edgesM1P0.a *         \n"
+    "              _edgesP1P0.g * _edgesP2P0.g * (1u - _edges.b) *          \n"
+    "              (1u - _edgesP1P0.r) * (1u - _edges.g) *                  \n"
+    "              (1u - _edgesP1P0.a);                                     \n"
+    "#else                                                                  \n"
+    "          uint isZShape = _edges.r * _edges.a * _edgesP1P0.g *         \n"
+    "              (1u - _edges.b) * (1u - _edgesP1P0.r) * (1u - _edges.g) *\n"
+    "              (1u - _edgesP1P0.a);                                     \n"
+    "          isZShape *=                                                  \n"
+    "              (_edgesM1P0.a + _edgesP2P0.g);                           \n"
+    "                          // and at least one of these need to be there\n"
+    "#endif                                                                 \n"
+    "                                                                       \n"
+    "          if (isZShape > 0u) {                                         \n"
+    "            isNormalZ = true;                                          \n"
+    "          }                                                            \n"
+    "        }                                                              \n"
+    "                                                                       \n"
+    "        bool isZ = isInvertedZ || isNormalZ;                           \n"
+    "        if (isZ) {                                                     \n"
+    "          forFollowUpCoords[forFollowUpCount++] =                      \n"
+    "              ivec4(screenPosI.xy, horizontal, isInvertedZ);           \n"
+    "        }                                                              \n"
+    "      }                                                                \n"
+    "    }                                                                  \n"
+    "  }                                                                    \n"
+    "                                                                       \n"
+    "  // This code below is the only potential bug with this algorithm :   \n"
+    "  // it HAS to be executed after the simple shapes above. It used to be\n"
+    "  // executed as separate compute shader (by storing the packed        \n"
+    "  // 'forFollowUpCoords' in an append buffer and  consuming it later)  \n"
+    "  // but the whole thing (append/consume buffers, using CS) appears to \n"
+    "  // be too inefficient on most hardware.                              \n"
+    "  // However, it seems to execute fairly efficiently here and without  \n"
+    "  // any issues, although there is no 100% guarantee that this code    \n"
+    "  // below will execute across all pixels (it has a c_maxLineLength    \n"
+    "  // wide kernel) after other shaders processing same pixels have done \n"
+    "  // solving simple shapes. It appears to work regardless, across all  \n"
+    "  // hardware; pixels with 1-edge or two opposing edges are ignored by \n"
+    "  // simple  shapes anyway and other shapes stop the long line         \n"
+    "  // algorithm from executing the only danger appears to be simple     \n"
+    "  // shape L's colliding with Z shapes from neighbouring pixels but I  \n"
+    "  // couldn't reproduce any problems on any hardware.                  \n"
+    "  for (uint _i = 0u; _i < forFollowUpCount; _i++) {                    \n"
+    "    ivec4 data = forFollowUpCoords[_i];                                \n"
+    "    ProcessDetectedZ(data.xy, bool(data.z), bool(data.w));             \n"
+    "  }                                                                    \n"
+    "}                                                                      \n"
+    "#endif  // BLUR_EDGES                                                  \n"
+    "                                                                       \n"
+    "#ifdef DISPLAY_EDGES                                                   \n"
+    "layout(location = 0) out vec4 color;                                   \n"
+    "layout(location = 1) out vec4 hasEdges;                                \n"
+    "void DisplayEdges() {                                                  \n"
+    "  ivec2 screenPosI = ivec2(gl_FragCoord.xy);                           \n"
+    "                                                                       \n"
+    "  uint packedEdges, shapeType;                                         \n"
+    "  UnpackBlurAAInfo(texelFetch(g_src0TextureFlt, screenPosI, 0).r,      \n"
+    "                   packedEdges, shapeType);                            \n"
+    "                                                                       \n"
+    "  vec4 edges = vec4(UnpackEdge(packedEdges));                          \n"
+    "  if (any(greaterThan(edges.xyzw, vec4(0)))) {                         \n"
+    "#ifdef IN_BGR_MODE                                                     \n"
+    "    color = c_edgeDebugColours[shapeType].bgra;                        \n"
+    "#else                                                                  \n"
+    "    color = c_edgeDebugColours[shapeType];                             \n"
+    "#endif                                                                 \n"
+    "    hasEdges = vec4(1.0);                                              \n"
+    "  } else {                                                             \n"
+    "    color = vec4(0);                                                   \n"
+    "    hasEdges = vec4(0.0);                                              \n"
+    "  }                                                                    \n"
+    "}                                                                      \n"
+    "#endif  // DISPLAY_EDGES                                               \n"
+    "                                                                       \n"
+    "void main() {                                                          \n"
+    "#ifdef DETECT_EDGES1                                                   \n"
+    "  DetectEdges1();                                                      \n"
+    "#endif                                                                 \n"
+    "#if defined DETECT_EDGES2                                              \n"
+    "  DetectEdges2();                                                      \n"
+    "#endif                                                                 \n"
+    "#if defined COMBINE_EDGES                                              \n"
+    "  CombineEdges();                                                      \n"
+    "#endif                                                                 \n"
+    "#if defined BLUR_EDGES                                                 \n"
+    "  BlurEdges();                                                         \n"
+    "#endif                                                                 \n"
+    "#if defined DISPLAY_EDGES                                              \n"
+    "  DisplayEdges();                                                      \n"
+    "#endif                                                                 \n"
+    "}                                                                      \n";
+
+const char
+    ApplyFramebufferAttachmentCMAAINTELResourceManager::copy_frag_str_[] =
+        "precision highp float;                                             \n"
+        "layout(binding = 0) uniform highp sampler2D inTexture;             \n"
+        "layout(location = 0) out vec4 outColor;                            \n"
+        "#ifdef GL_ES                                                       \n"
+        "layout(binding = 0, rgba8) restrict writeonly uniform highp        \n"
+        "                                               image2D outTexture; \n"
+        "#else                                                              \n"
+        "layout(rgba8) restrict writeonly uniform highp image2D outTexture; \n"
+        "#endif                                                             \n"
+        "                                                                   \n"
+        "void main() {                                                      \n"
+        "  ivec2 screenPosI = ivec2( gl_FragCoord.xy );                     \n"
+        "  vec4 pixel = texelFetch(inTexture, screenPosI, 0);               \n"
+        "#ifdef OUT_FBO                                                     \n"
+        "  outColor = pixel;                                                \n"
+        "#else                                                              \n"
+        "  imageStore(outTexture, screenPosI, pixel);                       \n"
+        "#endif                                                             \n"
+        "}                                                                  \n";
+
+}  // namespace gpu
\ No newline at end of file
diff --git a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h
new file mode 100644
index 0000000..4f5b4833
--- /dev/null
+++ b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h
@@ -0,0 +1,102 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_APPLY_FRAMEBUFFER_ATTACHMENT_CMAA_INTEL_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_APPLY_FRAMEBUFFER_ATTACHMENT_CMAA_INTEL_H_
+
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/gpu_export.h"
+
+namespace {
+class CMAAEffect;
+}
+
+namespace gpu {
+namespace gles2 {
+class GLES2Decoder;
+class Framebuffer;
+}
+
+// This class encapsulates the resources required to implement the
+// GL_INTEL_framebuffer_CMAA extension via shaders.
+//
+// The CMAA Conservative Morphological Anti-Aliasing) algorithm is applied to
+// all color attachments of the currently bound draw framebuffer.
+//
+// Reference GL_INTEL_framebuffer_CMAA for details.
+class GPU_EXPORT ApplyFramebufferAttachmentCMAAINTELResourceManager {
+ public:
+  ApplyFramebufferAttachmentCMAAINTELResourceManager();
+  ~ApplyFramebufferAttachmentCMAAINTELResourceManager();
+
+  void Initialize(gles2::GLES2Decoder* decoder);
+  void Destroy();
+
+  // Applies the algorithm to the color attachments of the currently bound draw
+  // framebuffer.
+  void ApplyFramebufferAttachmentCMAAINTEL(gles2::GLES2Decoder* decoder,
+                                           gles2::Framebuffer* framebuffer);
+
+ private:
+  // Applies the CMAA algorithm to a texture.
+  void ApplyCMAAEffectTexture(GLuint source_texture, GLuint dest_texture);
+
+  void OnSize(GLint width, GLint height);
+  void ReleaseTextures();
+
+  void CopyTexture(GLint source, GLint dest, bool via_fbo);
+  GLuint CreateProgram(const char* defines,
+                       const char* vs_source,
+                       const char* fs_source);
+  GLuint CreateShader(GLenum type, const char* defines, const char* source);
+
+  bool initialized_;
+  bool textures_initialized_;
+  bool is_in_gamma_correct_mode_;
+  bool supports_usampler_;
+  bool supports_r8_image_;
+  bool supports_r8_read_format_;
+  bool is_gles31_compatible_;
+
+  int frame_id_;
+
+  GLint width_;
+  GLint height_;
+
+  GLuint copy_to_framebuffer_shader_;
+  GLuint copy_to_image_shader_;
+  GLuint edges0_shader_;
+  GLuint edges1_shader_;
+  GLuint edges_combine_shader_;
+  GLuint process_and_apply_shader_;
+  GLuint debug_display_edges_shader_;
+
+  GLuint cmaa_framebuffer_;
+  GLuint copy_framebuffer_;
+
+  GLuint rgba8_texture_;
+  GLuint working_color_texture_;
+  GLuint edges0_texture_;
+  GLuint edges1_texture_;
+  GLuint mini4_edge_texture_;
+  GLuint mini4_edge_depth_texture_;
+
+  GLuint edges1_shader_result_texture_float4_slot1_;
+  GLuint edges1_shader_result_texture_;
+  GLuint edges_combine_shader_result_texture_float4_slot1_;
+  GLuint process_and_apply_shader_result_texture_float4_slot1_;
+  GLuint edges_combine_shader_result_texture_slot2_;
+  GLuint copy_to_image_shader_outTexture_;
+
+  static const char vert_str_[];
+  static const char cmaa_frag_s1_[];
+  static const char cmaa_frag_s2_[];
+  static const char copy_frag_str_[];
+
+  DISALLOW_COPY_AND_ASSIGN(ApplyFramebufferAttachmentCMAAINTELResourceManager);
+};
+
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_APPLY_FRAMEBUFFER_ATTACHMENT_CMAA_INTEL_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index cc703d4e..71ee18f 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -39,6 +39,7 @@
 #include "gpu/command_buffer/service/framebuffer_manager.h"
 #include "gpu/command_buffer/service/gl_stream_texture_image.h"
 #include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h"
 #include "gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h"
 #include "gpu/command_buffer/service/gles2_cmd_copy_tex_image.h"
 #include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h"
@@ -2159,6 +2160,8 @@
   // Log extra info.
   bool service_logging_;
 
+  std::unique_ptr<ApplyFramebufferAttachmentCMAAINTELResourceManager>
+      apply_framebuffer_attachment_cmaa_intel_;
   std::unique_ptr<CopyTexImageResourceManager> copy_tex_image_blit_;
   std::unique_ptr<CopyTextureCHROMIUMResourceManager> copy_texture_CHROMIUM_;
   std::unique_ptr<ClearFramebufferResourceManager> clear_framebuffer_blit_;
@@ -4286,6 +4289,11 @@
   }
   ReleaseAllBackTextures();
   if (have_context) {
+    if (apply_framebuffer_attachment_cmaa_intel_.get()) {
+      apply_framebuffer_attachment_cmaa_intel_->Destroy();
+      apply_framebuffer_attachment_cmaa_intel_.reset();
+    }
+
     if (copy_tex_image_blit_.get()) {
       copy_tex_image_blit_->Destroy();
       copy_tex_image_blit_.reset();
@@ -4362,6 +4370,7 @@
   // state_.current_program object.
   state_.current_program = NULL;
 
+  apply_framebuffer_attachment_cmaa_intel_.reset();
   copy_tex_image_blit_.reset();
   copy_texture_CHROMIUM_.reset();
   clear_framebuffer_blit_.reset();
@@ -15313,7 +15322,28 @@
   // Apply CMAA(Conservative Morphological Anti-Aliasing) algorithm to the
   // color attachments of currently bound draw framebuffer.
   // Reference GL_INTEL_framebuffer_CMAA for details.
-  glApplyFramebufferAttachmentCMAAINTEL();
+  // Use platform version if available.
+  if (!feature_info_->feature_flags()
+           .use_chromium_screen_space_antialiasing_via_shaders) {
+    glApplyFramebufferAttachmentCMAAINTEL();
+  } else {
+    // Defer initializing the CopyTextureCHROMIUMResourceManager until it is
+    // needed because it takes ??s of milliseconds to initialize.
+    if (!apply_framebuffer_attachment_cmaa_intel_.get()) {
+      LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER(
+          "glApplyFramebufferAttachmentCMAAINTEL");
+      apply_framebuffer_attachment_cmaa_intel_.reset(
+          new ApplyFramebufferAttachmentCMAAINTELResourceManager());
+      apply_framebuffer_attachment_cmaa_intel_->Initialize(this);
+      RestoreCurrentFramebufferBindings();
+      if (LOCAL_PEEK_GL_ERROR("glApplyFramebufferAttachmentCMAAINTEL") !=
+          GL_NO_ERROR)
+        return;
+    }
+    apply_framebuffer_attachment_cmaa_intel_
+        ->ApplyFramebufferAttachmentCMAAINTEL(
+            this, GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER));
+  }
 }
 
 void GLES2DecoderImpl::DoInsertEventMarkerEXT(
diff --git a/gpu/command_buffer_service.gypi b/gpu/command_buffer_service.gypi
index c75c35e..c419cb5 100644
--- a/gpu/command_buffer_service.gypi
+++ b/gpu/command_buffer_service.gypi
@@ -58,6 +58,8 @@
     'command_buffer/service/gl_state_restorer_impl.h',
     'command_buffer/service/gl_utils.cc',
     'command_buffer/service/gl_utils.h',
+    'command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc',
+    'command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.h',
     'command_buffer/service/gles2_cmd_clear_framebuffer.cc',
     'command_buffer/service/gles2_cmd_clear_framebuffer.h',
     'command_buffer/service/gles2_cmd_copy_tex_image.cc',
diff --git a/ios/chrome/browser/ntp_snippets/ios_chrome_ntp_snippets_service_factory.cc b/ios/chrome/browser/ntp_snippets/ios_chrome_ntp_snippets_service_factory.cc
index eef5186a..c4cb4251 100644
--- a/ios/chrome/browser/ntp_snippets/ios_chrome_ntp_snippets_service_factory.cc
+++ b/ios/chrome/browser/ntp_snippets/ios_chrome_ntp_snippets_service_factory.cc
@@ -11,6 +11,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "components/browser_sync/browser/profile_sync_service.h"
+#include "components/image_fetcher/image_decoder.h"
 #include "components/image_fetcher/image_fetcher.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
 #include "components/ntp_snippets/ntp_snippets_constants.h"
@@ -109,6 +110,8 @@
               base::SequencedWorkerPool::GetSequenceToken(),
               base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
 
+  // TODO(treib,markusheintz): Inject an image_fetcher::ImageDecoder once that's
+  // implemented on iOS. crbug.com/609127
   return base::WrapUnique(new ntp_snippets::NTPSnippetsService(
       false /* enabled */, chrome_browser_state->GetPrefs(), sync_service,
       suggestions_service, GetApplicationContext()->GetApplicationLocale(),
@@ -118,6 +121,7 @@
                      GetChannel() == version_info::Channel::STABLE)),
       base::WrapUnique(new ImageFetcherImpl(request_context.get(),
                                             web::WebThread::GetBlockingPool())),
+      nullptr, /* image_decoder */
       base::WrapUnique(
           new ntp_snippets::NTPSnippetsDatabase(database_dir, task_runner))));
 }
diff --git a/media/audio/audio_device_thread.cc b/media/audio/audio_device_thread.cc
index 20874599..5d0767a 100644
--- a/media/audio/audio_device_thread.cc
+++ b/media/audio/audio_device_thread.cc
@@ -230,11 +230,17 @@
   CHECK_GT(total_segments_, 0);
   CHECK_EQ(memory_length_ % total_segments_, 0);
   segment_length_ = memory_length_ / total_segments_;
+  thread_checker_.DetachFromThread();
 }
 
 AudioDeviceThread::Callback::~Callback() {}
 
 void AudioDeviceThread::Callback::InitializeOnAudioThread() {
+  // Normally this function is called before the thread checker is used
+  // elsewhere, but it's not guaranteed. DCHECK to ensure it was not used on
+  // another thread before we get here.
+  DCHECK(thread_checker_.CalledOnValidThread())
+      << "Thread checker was attached on the wrong thread";
   MapSharedMemory();
   CHECK(shared_memory_.memory());
 }
diff --git a/media/audio/audio_device_thread.h b/media/audio/audio_device_thread.h
index 61e5e872..1ffefc5 100644
--- a/media/audio/audio_device_thread.h
+++ b/media/audio/audio_device_thread.h
@@ -12,6 +12,7 @@
 #include "base/memory/shared_memory.h"
 #include "base/sync_socket.h"
 #include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
 #include "media/base/audio_parameters.h"
 #include "media/base/media_export.h"
 
@@ -68,6 +69,11 @@
     const int total_segments_;
     int segment_length_;
 
+    // Detached in constructor and attached in InitializeOnAudioThread() which
+    // is called on the audio device thread. Sub-classes can then use it for
+    // various thread checking purposes.
+    base::ThreadChecker thread_checker_;
+
    private:
     DISALLOW_COPY_AND_ASSIGN(Callback);
   };
diff --git a/media/audio/audio_output_device.cc b/media/audio/audio_output_device.cc
index 12d102c..e618b3b 100644
--- a/media/audio/audio_output_device.cc
+++ b/media/audio/audio_output_device.cc
@@ -41,6 +41,10 @@
   // Called whenever we receive notifications about pending data.
   void Process(uint32_t pending_data) override;
 
+  // Returns whether the current thread is the audio device thread or not.
+  // Will always return true if DCHECKs are not enabled.
+  bool CurrentThreadIsAudioDeviceThread();
+
  private:
   AudioRendererSink::RenderCallback* render_callback_;
   std::unique_ptr<AudioBus> output_bus_;
@@ -154,6 +158,13 @@
                           device_status_, output_params_);
 }
 
+bool AudioOutputDevice::CurrentThreadIsRenderingThread() {
+  // Since this function is supposed to be called on the rendering thread,
+  // it's safe to access |audio_callback_| here. It will always be valid when
+  // the rendering thread is running.
+  return audio_callback_->CurrentThreadIsAudioDeviceThread();
+}
+
 void AudioOutputDevice::RequestDeviceAuthorizationOnIOThread() {
   DCHECK(task_runner()->BelongsToCurrentThread());
   DCHECK_EQ(state_, IDLE);
@@ -477,4 +488,9 @@
                            frames_skipped);
 }
 
+bool AudioOutputDevice::AudioThreadCallback::
+    CurrentThreadIsAudioDeviceThread() {
+  return thread_checker_.CalledOnValidThread();
+}
+
 }  // namespace media
diff --git a/media/audio/audio_output_device.h b/media/audio/audio_output_device.h
index c0faacd..23f416c8 100644
--- a/media/audio/audio_output_device.h
+++ b/media/audio/audio_output_device.h
@@ -109,6 +109,7 @@
   void Pause() override;
   bool SetVolume(double volume) override;
   OutputDeviceInfo GetOutputDeviceInfo() override;
+  bool CurrentThreadIsRenderingThread() override;
 
   // Methods called on IO thread ----------------------------------------------
   // AudioOutputIPCDelegate methods.
diff --git a/media/audio/audio_output_stream_sink.cc b/media/audio/audio_output_stream_sink.cc
index 3acc6a8..b94e2d2 100644
--- a/media/audio/audio_output_stream_sink.cc
+++ b/media/audio/audio_output_stream_sink.cc
@@ -77,6 +77,11 @@
   return OutputDeviceInfo();
 }
 
+bool AudioOutputStreamSink::CurrentThreadIsRenderingThread() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
 int AudioOutputStreamSink::OnMoreData(AudioBus* dest,
                                       uint32_t total_bytes_delay,
                                       uint32_t frames_skipped) {
diff --git a/media/audio/audio_output_stream_sink.h b/media/audio/audio_output_stream_sink.h
index d8656ee..672c3a05 100644
--- a/media/audio/audio_output_stream_sink.h
+++ b/media/audio/audio_output_stream_sink.h
@@ -40,6 +40,7 @@
   void Play() override;
   bool SetVolume(double volume) override;
   OutputDeviceInfo GetOutputDeviceInfo() override;
+  bool CurrentThreadIsRenderingThread() override;
 
   // AudioSourceCallback implementation.
   int OnMoreData(AudioBus* dest,
diff --git a/media/audio/clockless_audio_sink.cc b/media/audio/clockless_audio_sink.cc
index 91de5e0..d0dd7e94 100644
--- a/media/audio/clockless_audio_sink.cc
+++ b/media/audio/clockless_audio_sink.cc
@@ -133,6 +133,11 @@
   return device_info_;
 }
 
+bool ClocklessAudioSink::CurrentThreadIsRenderingThread() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
 void ClocklessAudioSink::StartAudioHashForTesting() {
   DCHECK(!initialized_);
   hashing_ = true;
diff --git a/media/audio/clockless_audio_sink.h b/media/audio/clockless_audio_sink.h
index a6db62c5..2b60d83 100644
--- a/media/audio/clockless_audio_sink.h
+++ b/media/audio/clockless_audio_sink.h
@@ -37,6 +37,7 @@
   void Play() override;
   bool SetVolume(double volume) override;
   OutputDeviceInfo GetOutputDeviceInfo() override;
+  bool CurrentThreadIsRenderingThread() override;
 
   // Returns the time taken to consume all the audio.
   base::TimeDelta render_time() { return playback_time_; }
diff --git a/media/audio/null_audio_sink.cc b/media/audio/null_audio_sink.cc
index 6d40c93..43221998 100644
--- a/media/audio/null_audio_sink.cc
+++ b/media/audio/null_audio_sink.cc
@@ -79,6 +79,10 @@
   return OutputDeviceInfo();
 }
 
+bool NullAudioSink::CurrentThreadIsRenderingThread() {
+  return task_runner_->BelongsToCurrentThread();
+}
+
 void NullAudioSink::SwitchOutputDevice(const std::string& device_id,
                                        const url::Origin& security_origin,
                                        const OutputDeviceStatusCB& callback) {
diff --git a/media/audio/null_audio_sink.h b/media/audio/null_audio_sink.h
index 6d24fbe..b9c9c80 100644
--- a/media/audio/null_audio_sink.h
+++ b/media/audio/null_audio_sink.h
@@ -34,6 +34,7 @@
   void Play() override;
   bool SetVolume(double volume) override;
   OutputDeviceInfo GetOutputDeviceInfo() override;
+  bool CurrentThreadIsRenderingThread() override;
   void SwitchOutputDevice(const std::string& device_id,
                           const url::Origin& security_origin,
                           const OutputDeviceStatusCB& callback) override;
diff --git a/media/base/audio_renderer_mixer_input.cc b/media/base/audio_renderer_mixer_input.cc
index 921a0174..3d2263f 100644
--- a/media/base/audio_renderer_mixer_input.cc
+++ b/media/base/audio_renderer_mixer_input.cc
@@ -122,6 +122,11 @@
                                                 device_id_, security_origin_);
 }
 
+bool AudioRendererMixerInput::CurrentThreadIsRenderingThread() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
 void AudioRendererMixerInput::SwitchOutputDevice(
     const std::string& device_id,
     const url::Origin& security_origin,
diff --git a/media/base/audio_renderer_mixer_input.h b/media/base/audio_renderer_mixer_input.h
index 042fe06..23be849 100644
--- a/media/base/audio_renderer_mixer_input.h
+++ b/media/base/audio_renderer_mixer_input.h
@@ -51,6 +51,7 @@
   void SwitchOutputDevice(const std::string& device_id,
                           const url::Origin& security_origin,
                           const OutputDeviceStatusCB& callback) override;
+  bool CurrentThreadIsRenderingThread() override;
 
   // Called by AudioRendererMixer when an error occurs.
   void OnRenderError();
diff --git a/media/base/audio_renderer_sink.h b/media/base/audio_renderer_sink.h
index b0b5f26..268b9b6c4 100644
--- a/media/base/audio_renderer_sink.h
+++ b/media/base/audio_renderer_sink.h
@@ -70,6 +70,11 @@
   // Must never be called on the IO thread.
   virtual OutputDeviceInfo GetOutputDeviceInfo() = 0;
 
+  // If DCHECKs are enabled, this function returns true if called on rendering
+  // thread, otherwise false. With DCHECKs disabled, it returns true. Thus, it
+  // is intended to be used for DCHECKing.
+  virtual bool CurrentThreadIsRenderingThread() = 0;
+
  protected:
   friend class base::RefCountedThreadSafe<AudioRendererSink>;
   virtual ~AudioRendererSink() {}
diff --git a/media/base/fake_audio_renderer_sink.cc b/media/base/fake_audio_renderer_sink.cc
index 6cc0201..f21eb71c 100644
--- a/media/base/fake_audio_renderer_sink.cc
+++ b/media/base/fake_audio_renderer_sink.cc
@@ -69,6 +69,11 @@
   return output_device_info_;
 }
 
+bool FakeAudioRendererSink::CurrentThreadIsRenderingThread() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
 bool FakeAudioRendererSink::Render(AudioBus* dest,
                                    uint32_t frames_delayed,
                                    int* frames_written) {
diff --git a/media/base/fake_audio_renderer_sink.h b/media/base/fake_audio_renderer_sink.h
index 3fc95d6b..2a90600b 100644
--- a/media/base/fake_audio_renderer_sink.h
+++ b/media/base/fake_audio_renderer_sink.h
@@ -39,6 +39,7 @@
   void Play() override;
   bool SetVolume(double volume) override;
   OutputDeviceInfo GetOutputDeviceInfo() override;
+  bool CurrentThreadIsRenderingThread() override;
 
   // Attempts to call Render() on the callback provided to
   // Initialize() with |dest| and |frames_delayed|.
diff --git a/media/base/mock_audio_renderer_sink.h b/media/base/mock_audio_renderer_sink.h
index a7185080..68ba2a4 100644
--- a/media/base/mock_audio_renderer_sink.h
+++ b/media/base/mock_audio_renderer_sink.h
@@ -29,6 +29,7 @@
   MOCK_METHOD0(Pause, void());
   MOCK_METHOD0(Play, void());
   MOCK_METHOD1(SetVolume, bool(double volume));
+  MOCK_METHOD0(CurrentThreadIsRenderingThread, bool());
 
   OutputDeviceInfo GetOutputDeviceInfo();
 
diff --git a/media/blink/webaudiosourceprovider_impl.cc b/media/blink/webaudiosourceprovider_impl.cc
index 6d998e5..e54dbc8 100644
--- a/media/blink/webaudiosourceprovider_impl.cc
+++ b/media/blink/webaudiosourceprovider_impl.cc
@@ -163,6 +163,19 @@
   bus_wrapper_->Scale(volume_);
 }
 
+void WebAudioSourceProviderImpl::Initialize(const AudioParameters& params,
+                                            RenderCallback* renderer) {
+  base::AutoLock auto_lock(sink_lock_);
+  DCHECK_EQ(state_, kStopped);
+
+  tee_filter_->Initialize(renderer, params.channels(), params.sample_rate());
+
+  sink_->Initialize(params, tee_filter_.get());
+
+  if (!set_format_cb_.is_null())
+    base::ResetAndReturn(&set_format_cb_).Run();
+}
+
 void WebAudioSourceProviderImpl::Start() {
   base::AutoLock auto_lock(sink_lock_);
   DCHECK(tee_filter_);
@@ -208,6 +221,11 @@
   return sink_->GetOutputDeviceInfo();
 }
 
+bool WebAudioSourceProviderImpl::CurrentThreadIsRenderingThread() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
 void WebAudioSourceProviderImpl::SwitchOutputDevice(
     const std::string& device_id,
     const url::Origin& security_origin,
@@ -219,19 +237,6 @@
     sink_->SwitchOutputDevice(device_id, security_origin, callback);
 }
 
-void WebAudioSourceProviderImpl::Initialize(const AudioParameters& params,
-                                            RenderCallback* renderer) {
-  base::AutoLock auto_lock(sink_lock_);
-  DCHECK_EQ(state_, kStopped);
-
-  tee_filter_->Initialize(renderer, params.channels(), params.sample_rate());
-
-  sink_->Initialize(params, tee_filter_.get());
-
-  if (!set_format_cb_.is_null())
-    base::ResetAndReturn(&set_format_cb_).Run();
-}
-
 void WebAudioSourceProviderImpl::SetCopyAudioCallback(
     const CopyAudioCB& callback) {
   DCHECK(!callback.is_null());
diff --git a/media/blink/webaudiosourceprovider_impl.h b/media/blink/webaudiosourceprovider_impl.h
index c3844b9e..1ffdd90 100644
--- a/media/blink/webaudiosourceprovider_impl.h
+++ b/media/blink/webaudiosourceprovider_impl.h
@@ -56,14 +56,15 @@
                     size_t number_of_frames) override;
 
   // RestartableAudioRendererSink implementation.
+  void Initialize(const AudioParameters& params,
+                  RenderCallback* renderer) override;
   void Start() override;
   void Stop() override;
   void Play() override;
   void Pause() override;
   bool SetVolume(double volume) override;
   OutputDeviceInfo GetOutputDeviceInfo() override;
-  void Initialize(const AudioParameters& params,
-                  RenderCallback* renderer) override;
+  bool CurrentThreadIsRenderingThread() override;
   void SwitchOutputDevice(const std::string& device_id,
                           const url::Origin& security_origin,
                           const OutputDeviceStatusCB& callback) override;
diff --git a/net/url_request/sdch_dictionary_fetcher.cc b/net/url_request/sdch_dictionary_fetcher.cc
index 040e9c2..a3d3565 100644
--- a/net/url_request/sdch_dictionary_fetcher.cc
+++ b/net/url_request/sdch_dictionary_fetcher.cc
@@ -308,10 +308,8 @@
 
   // If there's been an error, abort the current request.
   if (rv != OK) {
-    current_request_.reset();
-    buffer_ = NULL;
+    ResetRequest();
     next_state_ = STATE_SEND_REQUEST;
-
     return OK;
   }
 
@@ -343,8 +341,7 @@
 
   // An error; abort the current request.
   if (rv < 0) {
-    current_request_.reset();
-    buffer_ = NULL;
+    ResetRequest();
     next_state_ = STATE_SEND_REQUEST;
     return OK;
   }
diff --git a/net/url_request/sdch_dictionary_fetcher_unittest.cc b/net/url_request/sdch_dictionary_fetcher_unittest.cc
index 0dc3d1f..02a9987 100644
--- a/net/url_request/sdch_dictionary_fetcher_unittest.cc
+++ b/net/url_request/sdch_dictionary_fetcher_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "net/url_request/sdch_dictionary_fetcher.h"
 
+#include <algorithm>
 #include <string>
 #include <utility>
 #include <vector>
@@ -13,14 +14,16 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "net/base/load_flags.h"
+#include "net/base/net_errors.h"
 #include "net/base/sdch_manager.h"
 #include "net/http/http_response_headers.h"
-#include "net/url_request/url_request_data_job.h"
 #include "net/url_request/url_request_filter.h"
 #include "net/url_request/url_request_interceptor.h"
+#include "net/url_request/url_request_job.h"
 #include "net/url_request/url_request_redirect_job.h"
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -33,7 +36,10 @@
 const char kTestDomain1[] = "top.domain.test";
 const char kTestDomain2[] = "top2.domain.test";
 
-class URLRequestSpecifiedResponseJob : public URLRequestSimpleJob {
+// A URLRequestJob that returns a fixed response body, based on the URL, with
+// the specified HttpResponseInfo. Can also be made to return an error after the
+// response body has been read.
+class URLRequestSpecifiedResponseJob : public URLRequestJob {
  public:
   // Called on destruction with load flags used for this request.
   typedef base::Callback<void(int)> DestructionCallback;
@@ -43,13 +49,45 @@
       NetworkDelegate* network_delegate,
       const HttpResponseInfo& response_info_to_return,
       const DestructionCallback& destruction_callback)
-      : URLRequestSimpleJob(request, network_delegate),
+      : URLRequestJob(request, network_delegate),
         response_info_to_return_(response_info_to_return),
         last_load_flags_seen_(request->load_flags()),
-        destruction_callback_(destruction_callback) {
+        destruction_callback_(destruction_callback),
+        bytes_read_(0),
+        final_read_result_(OK),
+        weak_factory_(this) {
     DCHECK(!destruction_callback.is_null());
   }
 
+  ~URLRequestSpecifiedResponseJob() override {
+    destruction_callback_.Run(last_load_flags_seen_);
+  }
+
+  // Sets the result of the final read, after the entire body has been read.
+  // Defaults to OK.
+  void set_final_read_result(Error final_read_result) {
+    final_read_result_ = final_read_result;
+  }
+
+  // URLRequestJob implementation:
+  void Start() override {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&URLRequestSpecifiedResponseJob::StartAsync,
+                              weak_factory_.GetWeakPtr()));
+  }
+
+  int ReadRawData(IOBuffer* buf, int buf_size) override {
+    std::string response = ExpectedResponseForURL(request_->url());
+    response = response.substr(bytes_read_);
+    size_t bytes_to_copy =
+        std::min(static_cast<size_t>(buf_size), response.size());
+    if (bytes_to_copy == 0)
+      return final_read_result_;
+    memcpy(buf->data(), response.c_str(), bytes_to_copy);
+    bytes_read_ += bytes_to_copy;
+    return bytes_to_copy;
+  }
+
   static std::string ExpectedResponseForURL(const GURL& url) {
     return base::StringPrintf("Response for %s\n%s\nEnd Response for %s\n",
                               url.spec().c_str(),
@@ -57,30 +95,22 @@
                               url.spec().c_str());
   }
 
-  // URLRequestJob
   void GetResponseInfo(HttpResponseInfo* info) override {
     *info = response_info_to_return_;
   }
 
  private:
-  ~URLRequestSpecifiedResponseJob() override {
-    destruction_callback_.Run(last_load_flags_seen_);
-  }
-
-  // URLRequestSimpleJob implementation:
-  int GetData(std::string* mime_type,
-              std::string* charset,
-              std::string* data,
-              const CompletionCallback& callback) const override {
-    GURL url(request_->url());
-    *data = ExpectedResponseForURL(url);
-    return OK;
-  }
+  void StartAsync() { NotifyHeadersComplete(); }
 
   const HttpResponseInfo response_info_to_return_;
   int last_load_flags_seen_;
   const DestructionCallback destruction_callback_;
 
+  int bytes_read_;
+  Error final_read_result_;
+
+  base::WeakPtrFactory<URLRequestSpecifiedResponseJob> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(URLRequestSpecifiedResponseJob);
 };
 
@@ -105,7 +135,9 @@
   const base::Closure destruction_callback_;
 };
 
-static const char* redirect_signal = "/redirect/";
+const char kRedirectPath[] = "/redirect/";
+const char kBodyErrorPath[] = "/body_error/";
+
 class SDCHTestRequestInterceptor : public URLRequestInterceptor {
  public:
   // A callback to be called whenever a URLRequestJob child of this
@@ -137,16 +169,20 @@
     lifecycle_callback_.Run(1, 0);
 
     std::string path = request->url().path();
-    if (path.substr(0, strlen(redirect_signal)) == redirect_signal) {
+    if (base::StartsWith(path, kRedirectPath, base::CompareCase::SENSITIVE)) {
       return new TestURLRequestRedirectJob(
-          request, network_delegate, GURL(path.substr(strlen(redirect_signal))),
+          request, network_delegate, GURL(path.substr(strlen(kRedirectPath))),
           URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT, "testing",
           base::Bind(lifecycle_callback_, -1, 0));
     }
 
-    return new URLRequestSpecifiedResponseJob(
-        request, network_delegate, *http_response_info_,
-        base::Bind(lifecycle_callback_, -1));
+    std::unique_ptr<URLRequestSpecifiedResponseJob> job(
+        new URLRequestSpecifiedResponseJob(
+            request, network_delegate, *http_response_info_,
+            base::Bind(lifecycle_callback_, -1)));
+    if (base::StartsWith(path, kBodyErrorPath, base::CompareCase::SENSITIVE))
+      job->set_final_read_result(net::ERR_FAILED);
+    return job.release();
   }
 
   // The caller must ensure that both |*http_response_info| and the
@@ -518,6 +554,26 @@
   EXPECT_FALSE(last_load_flags_seen() & LOAD_ONLY_FROM_CACHE);
 }
 
+// Check the case of two requests for different URLs, where the first request
+// fails after receiving body data.
+TEST_F(SdchDictionaryFetcherTest, TwoDictionariesFirstFails) {
+  GURL dictionary_with_error_url(PathToGurl("body_error/"));
+  GURL dictionary_url(PathToGurl("dictionary"));
+  EXPECT_TRUE(
+      fetcher()->Schedule(dictionary_with_error_url, GetDefaultCallback()));
+  EXPECT_TRUE(fetcher()->Schedule(dictionary_url, GetDefaultCallback()));
+  WaitForNoJobs();
+
+  EXPECT_EQ(2, jobs_requested());
+  std::vector<DictionaryAdditions> additions;
+  GetDictionaryAdditions(&additions);
+  // Should only have a dictionary for the successful request.
+  ASSERT_EQ(1u, additions.size());
+  EXPECT_EQ(
+      URLRequestSpecifiedResponseJob::ExpectedResponseForURL(dictionary_url),
+      additions[0].dictionary_text);
+}
+
 }  // namespace
 
 }  // namespace net
diff --git a/sandbox/win/BUILD.gn b/sandbox/win/BUILD.gn
index 89eaaed..60bb499a 100644
--- a/sandbox/win/BUILD.gn
+++ b/sandbox/win/BUILD.gn
@@ -205,11 +205,14 @@
     "tests/common/test_utils.cc",
     "tests/common/test_utils.h",
     "tests/integration_tests/integration_tests.cc",
+    "tests/integration_tests/integration_tests_common.h",
     "tests/integration_tests/integration_tests_test.cc",
   ]
 
   deps = [
     ":sandbox",
+    ":sbox_integration_test_hook_dll",
+    ":sbox_integration_test_win_proc",
     "//base/test:test_support",
     "//testing/gtest",
   ]
@@ -217,6 +220,23 @@
   libs = [ "dxva2.lib" ]
 }
 
+loadable_module("sbox_integration_test_hook_dll") {
+  sources = [
+    "tests/integration_tests/hooking_dll.cc",
+    "tests/integration_tests/integration_tests_common.h",
+  ]
+}
+
+executable("sbox_integration_test_win_proc") {
+  sources = [
+    "tests/integration_tests/hooking_win_proc.cc",
+    "tests/integration_tests/integration_tests_common.h",
+  ]
+
+  configs -= [ "//build/config/win:console" ]
+  configs += [ "//build/config/win:windowed" ]
+}
+
 test("sbox_validation_tests") {
   sources = [
     "tests/common/controller.cc",
diff --git a/sandbox/win/sandbox_win.gypi b/sandbox/win/sandbox_win.gypi
index 8ac9e59..e9673aa9 100644
--- a/sandbox/win/sandbox_win.gypi
+++ b/sandbox/win/sandbox_win.gypi
@@ -197,6 +197,8 @@
       'type': 'executable',
       'dependencies': [
         'sandbox',
+        'sbox_integration_test_hook_dll',
+        'sbox_integration_test_win_proc',
         '../base/base.gyp:test_support_base',
         '../testing/gtest.gyp:gtest',
       ],
@@ -224,6 +226,7 @@
         'tests/common/test_utils.cc',
         'tests/common/test_utils.h',
         'tests/integration_tests/integration_tests.cc',
+        'tests/integration_tests/integration_tests_common.h',
       ],
       'link_settings': {
         'libraries': [
@@ -232,6 +235,31 @@
       },
     },
     {
+      'target_name': 'sbox_integration_test_hook_dll',
+      'type': 'shared_library',
+      'dependencies': [
+      ],
+      'sources': [
+        'tests/integration_tests/hooking_dll.cc',
+        'tests/integration_tests/integration_tests_common.h',
+      ],
+    },
+    {
+      'target_name': 'sbox_integration_test_win_proc',
+      'type': 'executable',
+      'dependencies': [
+      ],
+      'sources': [
+        'tests/integration_tests/hooking_win_proc.cc',
+        'tests/integration_tests/integration_tests_common.h',
+      ],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'SubSystem': '2',  # Set /SUBSYSTEM:WINDOWS
+        },
+      },
+    },
+    {
       'target_name': 'sbox_validation_tests',
       'type': 'executable',
       'dependencies': [
diff --git a/sandbox/win/src/process_mitigations.cc b/sandbox/win/src/process_mitigations.cc
index adcc17c9..1fa5209 100644
--- a/sandbox/win/src/process_mitigations.cc
+++ b/sandbox/win/src/process_mitigations.cc
@@ -137,8 +137,8 @@
     }
   }
 
-  // Enable dll extension policies.
-  if (flags & MITIGATION_EXTENSION_DLL_DISABLE) {
+  // Enable extension point policies.
+  if (flags & MITIGATION_EXTENSION_POINT_DISABLE) {
     PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = {};
     policy.DisableExtensionPoints = true;
 
@@ -254,7 +254,7 @@
         PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON;
   }
 
-  if (flags & MITIGATION_EXTENSION_DLL_DISABLE) {
+  if (flags & MITIGATION_EXTENSION_POINT_DISABLE) {
     *policy_flags |=
         PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON;
   }
@@ -333,7 +333,7 @@
         MITIGATION_RELOCATE_IMAGE_REQUIRED |
         MITIGATION_BOTTOM_UP_ASLR |
         MITIGATION_STRICT_HANDLE_CHECKS |
-        MITIGATION_EXTENSION_DLL_DISABLE |
+        MITIGATION_EXTENSION_POINT_DISABLE |
         MITIGATION_DLL_SEARCH_ORDER |
         MITIGATION_HARDEN_TOKEN_IL_POLICY |
         MITIGATION_WIN32K_DISABLE |
diff --git a/sandbox/win/src/process_mitigations_test.cc b/sandbox/win/src/process_mitigations_test.cc
index 97636bcd..bf89a9a 100644
--- a/sandbox/win/src/process_mitigations_test.cc
+++ b/sandbox/win/src/process_mitigations_test.cc
@@ -1,36 +1,48 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 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 <initguid.h>
+#include "sandbox/win/src/process_mitigations.h"
+
 #include <d3d9.h>
-#include <Opmapi.h>
+#include <initguid.h>
+#include <opmapi.h>
+#include <psapi.h>
 #include <windows.h>
 
 #include <map>
 #include <string>
 
+#include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/ref_counted.h"
 #include "base/path_service.h"
 #include "base/process/launch.h"
+#include "base/scoped_native_library.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/test_timeouts.h"
+#include "base/win/registry.h"
 #include "base/win/scoped_handle.h"
+#include "base/win/startup_information.h"
+#include "base/win/win_util.h"
 #include "base/win/windows_version.h"
 #include "sandbox/win/src/nt_internals.h"
-#include "sandbox/win/src/process_mitigations.h"
 #include "sandbox/win/src/process_mitigations_win32k_policy.h"
 #include "sandbox/win/src/sandbox.h"
 #include "sandbox/win/src/sandbox_factory.h"
 #include "sandbox/win/src/target_services.h"
-#include "sandbox/win/src/win_utils.h"
 #include "sandbox/win/tests/common/controller.h"
+#include "sandbox/win/tests/integration_tests/integration_tests_common.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
 
+// Timeouts for synchronization.
+#define event_timeout \
+  static_cast<DWORD>((TestTimeouts::action_timeout()).InMillisecondsRoundedUp())
+
 // API defined in winbase.h.
 typedef decltype(GetProcessDEPPolicy)* GetProcessDEPPolicyFunction;
 
@@ -43,6 +55,10 @@
 typedef decltype(AddFontMemResourceEx)* AddFontMemResourceExFunction;
 typedef decltype(RemoveFontMemResourceEx)* RemoveFontMemResourceExFunction;
 
+// APIs defined in integration_tests_common.h
+typedef decltype(WasHookCalled)* WasHookCalledFunction;
+typedef decltype(SetHook)* SetHookFunction;
+
 #if !defined(_WIN64)
 bool CheckWin8DepPolicy() {
   PROCESS_MITIGATION_DEP_POLICY policy = {};
@@ -59,7 +75,7 @@
   PROCESS_MITIGATION_ASLR_POLICY policy = {};
   if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessASLRPolicy,
                                      &policy, sizeof(policy))) {
-     return false;
+    return false;
   }
   return policy.EnableForceRelocateImages && policy.DisallowStrippedImages;
 }
@@ -68,9 +84,9 @@
 bool CheckWin8StrictHandlePolicy() {
   PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = {};
   if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                     ProcessStrictHandleCheckPolicy,
-                                     &policy, sizeof(policy))) {
-     return false;
+                                     ProcessStrictHandleCheckPolicy, &policy,
+                                     sizeof(policy))) {
+    return false;
   }
   return policy.RaiseExceptionOnInvalidHandleReference &&
          policy.HandleExceptionsPermanentlyEnabled;
@@ -79,19 +95,19 @@
 bool CheckWin8Win32CallPolicy() {
   PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = {};
   if (!get_process_mitigation_policy(::GetCurrentProcess(),
-                                     ProcessSystemCallDisablePolicy,
-                                     &policy, sizeof(policy))) {
-     return false;
+                                     ProcessSystemCallDisablePolicy, &policy,
+                                     sizeof(policy))) {
+    return false;
   }
   return policy.DisallowWin32kSystemCalls;
 }
 
-bool CheckWin8DllExtensionPolicy() {
+bool CheckWin8ExtensionPointPolicy() {
   PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = {};
   if (!get_process_mitigation_policy(::GetCurrentProcess(),
                                      ProcessExtensionPointDisablePolicy,
                                      &policy, sizeof(policy))) {
-     return false;
+    return false;
   }
   return policy.DisableExtensionPoints;
 }
@@ -116,8 +132,309 @@
   return policy.NoRemoteImages;
 }
 
+// Spawn Windows process (with or without mitigation enabled).
+bool SpawnWinProc(PROCESS_INFORMATION* pi, bool success_test, HANDLE* event) {
+  base::win::StartupInformation startup_info;
+  DWORD creation_flags = 0;
+
+  if (!success_test) {
+    DWORD64 flags =
+        PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON;
+    // This test only runs on >= Win8, so don't have to handle
+    // illegal 64-bit flags on 32-bit <= Win7.
+    size_t flags_size = sizeof(flags);
+
+    if (!startup_info.InitializeProcThreadAttributeList(1) ||
+        !startup_info.UpdateProcThreadAttribute(
+            PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &flags, flags_size)) {
+      ADD_FAILURE();
+      return false;
+    }
+    creation_flags = EXTENDED_STARTUPINFO_PRESENT;
+  }
+
+  // Command line must be writable.
+  base::string16 cmd_writeable(g_winproc_file);
+
+  if (!::CreateProcessW(NULL, &cmd_writeable[0], NULL, NULL, FALSE,
+                        creation_flags, NULL, NULL, startup_info.startup_info(),
+                        pi)) {
+    ADD_FAILURE();
+    return false;
+  }
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(*event, event_timeout));
+
+  return true;
+}
+
+//------------------------------------------------------------------------------
+// 1. Spawn a Windows process (with or without mitigation enabled).
+// 2. Load the hook Dll locally.
+// 3. Create a global named event for the hook to trigger.
+// 4. Start the hook (for the specific WinProc or globally).
+// 5. Send a keystroke event.
+// 6. Ask the hook Dll if it received a hook callback.
+// 7. Cleanup the hooking.
+// 8. Signal the Windows process to shutdown.
+//
+// Do NOT use any ASSERTs in this function.  Cleanup required.
+//------------------------------------------------------------------------------
+void TestWin8ExtensionPointHookWrapper(bool is_success_test, bool global_hook) {
+  // Set up a couple global events that this test will use.
+  HANDLE winproc_event = ::CreateEventW(NULL, FALSE, FALSE, g_winproc_event);
+  if (winproc_event == NULL || winproc_event == INVALID_HANDLE_VALUE) {
+    ADD_FAILURE();
+    return;
+  }
+  base::win::ScopedHandle scoped_winproc_event(winproc_event);
+
+  HANDLE hook_event = ::CreateEventW(NULL, FALSE, FALSE, g_hook_event);
+  if (hook_event == NULL || hook_event == INVALID_HANDLE_VALUE) {
+    ADD_FAILURE();
+    return;
+  }
+  base::win::ScopedHandle scoped_hook_event(hook_event);
+
+  // 1. Spawn WinProc.
+  PROCESS_INFORMATION proc_info = {};
+  if (!SpawnWinProc(&proc_info, is_success_test, &winproc_event))
+    return;
+
+  // From this point on, no return on failure.  Cleanup required.
+  bool all_good = true;
+
+  // 2. Load the hook DLL.
+  base::FilePath hook_dll_path(g_hook_dll_file);
+  base::ScopedNativeLibrary dll(hook_dll_path);
+  EXPECT_TRUE(dll.is_valid());
+
+  HOOKPROC hook_proc =
+      reinterpret_cast<HOOKPROC>(dll.GetFunctionPointer(g_hook_handler_func));
+  WasHookCalledFunction was_hook_called =
+      reinterpret_cast<WasHookCalledFunction>(
+          dll.GetFunctionPointer(g_was_hook_called_func));
+  SetHookFunction set_hook = reinterpret_cast<SetHookFunction>(
+      dll.GetFunctionPointer(g_set_hook_func));
+  if (!hook_proc || !was_hook_called || !set_hook) {
+    ADD_FAILURE();
+    all_good = false;
+  }
+
+  // 3. Try installing the hook (either on a remote target thread,
+  //    or globally).
+  HHOOK hook = nullptr;
+  if (all_good) {
+    DWORD target = 0;
+    if (!global_hook)
+      target = proc_info.dwThreadId;
+    hook = ::SetWindowsHookExW(WH_KEYBOARD, hook_proc, dll.get(), target);
+    if (!hook) {
+      ADD_FAILURE();
+      all_good = false;
+    } else
+      // Pass the hook DLL the hook handle.
+      set_hook(hook);
+  }
+
+  // 4. Inject a keyboard event.
+  if (all_good) {
+    // Note: that PostThreadMessage and SendMessage APIs will not deliver
+    // a keystroke in such a way that triggers a "legitimate" hook.
+    // Have to use targetless SendInput or keybd_event.  The latter is
+    // less code and easier to work with.
+    keybd_event(VkKeyScan(L'A'), 0, 0, 0);
+    keybd_event(VkKeyScan(L'A'), 0, KEYEVENTF_KEYUP, 0);
+    // Give it a chance to hit the hook handler...
+    ::WaitForSingleObject(hook_event, event_timeout);
+
+    // 5. Did the hook get hit?  Was it expected to?
+    if (global_hook)
+      EXPECT_EQ((is_success_test ? true : false), was_hook_called());
+    else
+      // ***IMPORTANT: when targeting a specific thread id, the
+      // PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE
+      // mitigation does NOT disable the hook API.  It ONLY
+      // stops global hooks from running in a process.  Hence,
+      // the hook will hit (TRUE) even in the "failure"
+      // case for a non-global/targeted hook.
+      EXPECT_EQ((is_success_test ? true : true), was_hook_called());
+  }
+
+  // 6. Disable hook.
+  if (hook)
+    EXPECT_TRUE(::UnhookWindowsHookEx(hook));
+
+  // 7. Trigger shutdown of WinProc.
+  if (proc_info.hProcess) {
+    if (::PostThreadMessageW(proc_info.dwThreadId, WM_QUIT, 0, 0)) {
+      // Note: The combination/perfect-storm of a Global Hook, in a
+      // WinProc that has the EXTENSION_POINT_DISABLE mitigation ON, and the
+      // use of the SendInput or keybd_event API to inject a keystroke,
+      // results in the target becoming unresponsive.  If any one of these
+      // states are changed, the problem does not occur.  This means the WM_QUIT
+      // message is not handled and the call to WaitForSingleObject times out.
+      // Therefore not checking the return val.
+      ::WaitForSingleObject(winproc_event, event_timeout);
+    } else {
+      // Ensure no strays.
+      ::TerminateProcess(proc_info.hProcess, 0);
+      ADD_FAILURE();
+    }
+    EXPECT_TRUE(::CloseHandle(proc_info.hThread));
+    EXPECT_TRUE(::CloseHandle(proc_info.hProcess));
+  }
+}
+
+//------------------------------------------------------------------------------
+// 1. Set up the AppInit Dll in registry settings. (Enable)
+// 2. Spawn a Windows process (with or without mitigation enabled).
+// 3. Check if the AppInit Dll got loaded in the Windows process or not.
+// 4. Signal the Windows process to shutdown.
+// 5. Restore original reg settings.
+//
+// Do NOT use any ASSERTs in this function.  Cleanup required.
+//------------------------------------------------------------------------------
+void TestWin8ExtensionPointAppInitWrapper(bool is_success_test) {
+  // 0.5 Get path of current module.  The appropriate build of the
+  //     AppInit DLL will be in the same directory (and the
+  //     full path is needed for reg).
+  wchar_t path[MAX_PATH];
+  if (!::GetModuleFileNameW(NULL, path, MAX_PATH)) {
+    ADD_FAILURE();
+    return;
+  }
+  // Only want the directory.  Switch file name for the AppInit DLL.
+  base::FilePath full_dll_path(path);
+  full_dll_path = full_dll_path.DirName();
+  full_dll_path = full_dll_path.Append(g_hook_dll_file);
+  wchar_t* non_const = const_cast<wchar_t*>(full_dll_path.value().c_str());
+  // Now make sure the path is in "short-name" form for registry.
+  DWORD length = ::GetShortPathNameW(non_const, NULL, 0);
+  std::vector<wchar_t> short_name(length);
+  if (!::GetShortPathNameW(non_const, &short_name[0], length)) {
+    ADD_FAILURE();
+    return;
+  }
+
+  // 1. Reg setup.
+  const wchar_t* app_init_reg_path =
+      L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
+  const wchar_t* dlls_value_name = L"AppInit_DLLs";
+  const wchar_t* enabled_value_name = L"LoadAppInit_DLLs";
+  const wchar_t* signing_value_name = L"RequireSignedAppInit_DLLs";
+  std::wstring orig_dlls;
+  std::wstring new_dlls;
+  DWORD orig_enabled_value = 0;
+  DWORD orig_signing_value = 0;
+  base::win::RegKey app_init_key(HKEY_LOCAL_MACHINE, app_init_reg_path,
+                                 KEY_QUERY_VALUE | KEY_SET_VALUE);
+  // Backup the existing settings.
+  if (!app_init_key.Valid() || !app_init_key.HasValue(dlls_value_name) ||
+      !app_init_key.HasValue(enabled_value_name) ||
+      ERROR_SUCCESS != app_init_key.ReadValue(dlls_value_name, &orig_dlls) ||
+      ERROR_SUCCESS !=
+          app_init_key.ReadValueDW(enabled_value_name, &orig_enabled_value)) {
+    ADD_FAILURE();
+    return;
+  }
+  if (app_init_key.HasValue(signing_value_name)) {
+    if (ERROR_SUCCESS !=
+        app_init_key.ReadValueDW(signing_value_name, &orig_signing_value)) {
+      ADD_FAILURE();
+      return;
+    }
+  }
+
+  // Set the new settings (obviously requires local admin privileges).
+  new_dlls = orig_dlls;
+  if (!orig_dlls.empty())
+    new_dlls.append(L",");
+  new_dlls.append(short_name.data());
+
+  // From this point on, no return on failure.  Cleanup required.
+  bool all_good = true;
+
+  if (app_init_key.HasValue(signing_value_name)) {
+    if (ERROR_SUCCESS !=
+        app_init_key.WriteValue(signing_value_name, static_cast<DWORD>(0))) {
+      ADD_FAILURE();
+      all_good = false;
+    }
+  }
+  if (ERROR_SUCCESS !=
+          app_init_key.WriteValue(dlls_value_name, new_dlls.c_str()) ||
+      ERROR_SUCCESS !=
+          app_init_key.WriteValue(enabled_value_name, static_cast<DWORD>(1))) {
+    ADD_FAILURE();
+    all_good = false;
+  }
+
+  // 2. Spawn WinProc.
+  HANDLE winproc_event = INVALID_HANDLE_VALUE;
+  base::win::ScopedHandle scoped_event;
+  PROCESS_INFORMATION proc_info = {};
+  if (all_good) {
+    winproc_event = ::CreateEventW(NULL, FALSE, FALSE, g_winproc_event);
+    if (winproc_event == NULL || winproc_event == INVALID_HANDLE_VALUE) {
+      ADD_FAILURE();
+      all_good = false;
+    } else {
+      scoped_event.Set(winproc_event);
+      if (!SpawnWinProc(&proc_info, is_success_test, &winproc_event))
+        all_good = false;
+    }
+  }
+
+  // 3. Check loaded modules in WinProc to see if the AppInit dll is loaded.
+  bool dll_loaded = false;
+  if (all_good) {
+    std::vector<HMODULE>(modules);
+    if (!base::win::GetLoadedModulesSnapshot(proc_info.hProcess, &modules)) {
+      ADD_FAILURE();
+      all_good = false;
+    } else {
+      for (auto module : modules) {
+        wchar_t name[MAX_PATH] = {};
+        if (::GetModuleFileNameExW(proc_info.hProcess, module, name,
+                                   MAX_PATH) &&
+            ::wcsstr(name, g_hook_dll_file)) {
+          // Found it.
+          dll_loaded = true;
+          break;
+        }
+      }
+    }
+  }
+
+  // Was the test result as expected?
+  if (all_good)
+    EXPECT_EQ((is_success_test ? true : false), dll_loaded);
+
+  // 4. Trigger shutdown of WinProc.
+  if (proc_info.hProcess) {
+    if (::PostThreadMessageW(proc_info.dwThreadId, WM_QUIT, 0, 0)) {
+      ::WaitForSingleObject(winproc_event, event_timeout);
+    } else {
+      // Ensure no strays.
+      ::TerminateProcess(proc_info.hProcess, 0);
+      ADD_FAILURE();
+    }
+    EXPECT_TRUE(::CloseHandle(proc_info.hThread));
+    EXPECT_TRUE(::CloseHandle(proc_info.hProcess));
+  }
+
+  // 5. Reg Restore
+  EXPECT_EQ(ERROR_SUCCESS,
+            app_init_key.WriteValue(enabled_value_name, orig_enabled_value));
+  if (app_init_key.HasValue(signing_value_name))
+    EXPECT_EQ(ERROR_SUCCESS,
+              app_init_key.WriteValue(signing_value_name, orig_signing_value));
+  EXPECT_EQ(ERROR_SUCCESS,
+            app_init_key.WriteValue(dlls_value_name, orig_dlls.c_str()));
+}
+
 void TestWin10ImageLoadRemote(bool is_success_test) {
-  // ***Insert your manual testing share UNC path here!
+  // ***Insert a manual testing share UNC path here!
   // E.g.: \\\\hostname\\sharename\\calc.exe
   std::wstring unc = L"\"\\\\hostname\\sharename\\calc.exe\"";
 
@@ -526,17 +843,15 @@
 //------------------------------------------------------------------------------
 // Win8 Checks:
 // MITIGATION_DEP(_NO_ATL_THUNK)
-// MITIGATION_EXTENSION_DLL_DISABLE
 // MITIGATION_RELOCATE_IMAGE(_REQUIRED) - ASLR, release only
 // MITIGATION_STRICT_HANDLE_CHECKS
 // >= Win8
 //------------------------------------------------------------------------------
 
-SBOX_TESTS_COMMAND int CheckWin8(int argc, wchar_t **argv) {
+SBOX_TESTS_COMMAND int CheckWin8(int argc, wchar_t** argv) {
   get_process_mitigation_policy =
-      reinterpret_cast<GetProcessMitigationPolicyFunction>(
-          ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"),
-                           "GetProcessMitigationPolicy"));
+      reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress(
+          ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy"));
   if (!get_process_mitigation_policy)
     return SBOX_TEST_NOT_FOUND;
 
@@ -553,9 +868,6 @@
   if (!CheckWin8StrictHandlePolicy())
     return SBOX_TEST_THIRD_ERROR;
 
-  if (!CheckWin8DllExtensionPolicy())
-    return SBOX_TEST_FIFTH_ERROR;
-
   return SBOX_TEST_SUCCEEDED;
 }
 
@@ -566,12 +878,10 @@
   TestRunner runner;
   sandbox::TargetPolicy* policy = runner.GetPolicy();
 
-  sandbox::MitigationFlags mitigations = MITIGATION_DEP |
-                                         MITIGATION_DEP_NO_ATL_THUNK |
-                                         MITIGATION_EXTENSION_DLL_DISABLE;
+  sandbox::MitigationFlags mitigations =
+      MITIGATION_DEP | MITIGATION_DEP_NO_ATL_THUNK;
 #if defined(NDEBUG)  // ASLR cannot be forced in debug builds.
-  mitigations |= MITIGATION_RELOCATE_IMAGE |
-                 MITIGATION_RELOCATE_IMAGE_REQUIRED;
+  mitigations |= MITIGATION_RELOCATE_IMAGE | MITIGATION_RELOCATE_IMAGE_REQUIRED;
 #endif
 
   EXPECT_EQ(policy->SetProcessMitigations(mitigations), SBOX_ALL_OK);
@@ -588,17 +898,16 @@
 // < Win8 x86
 //------------------------------------------------------------------------------
 
-SBOX_TESTS_COMMAND int CheckDep(int argc, wchar_t **argv) {
+SBOX_TESTS_COMMAND int CheckDep(int argc, wchar_t** argv) {
   GetProcessDEPPolicyFunction get_process_dep_policy =
-      reinterpret_cast<GetProcessDEPPolicyFunction>(
-          ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"),
-                           "GetProcessDEPPolicy"));
+      reinterpret_cast<GetProcessDEPPolicyFunction>(::GetProcAddress(
+          ::GetModuleHandleW(L"kernel32.dll"), "GetProcessDEPPolicy"));
   if (get_process_dep_policy) {
     BOOL is_permanent = FALSE;
     DWORD dep_flags = 0;
 
     if (!get_process_dep_policy(::GetCurrentProcess(), &dep_flags,
-        &is_permanent)) {
+                                &is_permanent)) {
       return SBOX_TEST_FIRST_ERROR;
     }
 
@@ -608,7 +917,7 @@
   } else {
     NtQueryInformationProcessFunction query_information_process = NULL;
     ResolveNTFunctionPtr("NtQueryInformationProcess",
-                          &query_information_process);
+                         &query_information_process);
     if (!query_information_process)
       return SBOX_TEST_NOT_FOUND;
 
@@ -624,8 +933,8 @@
     static const int MEM_EXECUTE_OPTION_PERMANENT = 8;
     dep_flags &= 0xff;
 
-    if (dep_flags != (MEM_EXECUTE_OPTION_DISABLE |
-                      MEM_EXECUTE_OPTION_PERMANENT)) {
+    if (dep_flags !=
+        (MEM_EXECUTE_OPTION_DISABLE | MEM_EXECUTE_OPTION_PERMANENT)) {
       return SBOX_TEST_FOURTH_ERROR;
     }
   }
@@ -641,10 +950,9 @@
   TestRunner runner;
   sandbox::TargetPolicy* policy = runner.GetPolicy();
 
-  EXPECT_EQ(policy->SetProcessMitigations(
-                MITIGATION_DEP |
-                MITIGATION_DEP_NO_ATL_THUNK |
-                MITIGATION_SEHOP),
+  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_DEP |
+                                          MITIGATION_DEP_NO_ATL_THUNK |
+                                          MITIGATION_SEHOP),
             SBOX_ALL_OK);
   EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckDep"));
 }
@@ -655,11 +963,10 @@
 // >= Win8
 //------------------------------------------------------------------------------
 
-SBOX_TESTS_COMMAND int CheckWin8Lockdown(int argc, wchar_t **argv) {
+SBOX_TESTS_COMMAND int CheckWin8Lockdown(int argc, wchar_t** argv) {
   get_process_mitigation_policy =
-      reinterpret_cast<GetProcessMitigationPolicyFunction>(
-          ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"),
-                           "GetProcessMitigationPolicy"));
+      reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress(
+          ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy"));
   if (!get_process_mitigation_policy)
     return SBOX_TEST_NOT_FOUND;
 
@@ -1029,6 +1336,158 @@
 }
 
 //------------------------------------------------------------------------------
+// Disable extension points (MITIGATION_EXTENSION_POINT_DISABLE).
+// >= Win8
+//------------------------------------------------------------------------------
+SBOX_TESTS_COMMAND int CheckWin8ExtensionPointSetting(int argc,
+                                                      wchar_t** argv) {
+  get_process_mitigation_policy =
+      reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress(
+          ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy"));
+  if (!get_process_mitigation_policy)
+    return SBOX_TEST_NOT_FOUND;
+
+  if (!CheckWin8ExtensionPointPolicy())
+    return SBOX_TEST_FIRST_ERROR;
+  return SBOX_TEST_SUCCEEDED;
+}
+
+// This test validates that setting the MITIGATION_EXTENSION_POINT_DISABLE
+// mitigation enables the setting on a process.
+TEST(ProcessMitigationsTest, CheckWin8ExtensionPointPolicySuccess) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  TestRunner runner;
+  sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+  EXPECT_EQ(policy->SetProcessMitigations(MITIGATION_EXTENSION_POINT_DISABLE),
+            SBOX_ALL_OK);
+  EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+            runner.RunTest(L"CheckWin8ExtensionPointSetting"));
+}
+
+// This test validates that a "legitimate" global hook CAN be set on the
+// sandboxed proc/thread if the MITIGATION_EXTENSION_POINT_DISABLE
+// mitigation is not set.
+//
+// MANUAL testing only.
+TEST(ProcessMitigationsTest,
+     DISABLED_CheckWin8ExtensionPoint_GlobalHook_Success) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
+  EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE);
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout));
+
+  // (is_success_test, global_hook)
+  TestWin8ExtensionPointHookWrapper(true, true);
+
+  EXPECT_TRUE(::ReleaseMutex(mutex));
+  EXPECT_TRUE(::CloseHandle(mutex));
+}
+
+// This test validates that setting the MITIGATION_EXTENSION_POINT_DISABLE
+// mitigation prevents a global hook on WinProc.
+//
+// MANUAL testing only.
+TEST(ProcessMitigationsTest,
+     DISABLED_CheckWin8ExtensionPoint_GlobalHook_Failure) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
+  EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE);
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout));
+
+  // (is_success_test, global_hook)
+  TestWin8ExtensionPointHookWrapper(false, true);
+
+  EXPECT_TRUE(::ReleaseMutex(mutex));
+  EXPECT_TRUE(::CloseHandle(mutex));
+}
+
+// This test validates that a "legitimate" hook CAN be set on the sandboxed
+// proc/thread if the MITIGATION_EXTENSION_POINT_DISABLE mitigation is not set.
+//
+// MANUAL testing only.
+TEST(ProcessMitigationsTest, DISABLED_CheckWin8ExtensionPoint_Hook_Success) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
+  EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE);
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout));
+
+  // (is_success_test, global_hook)
+  TestWin8ExtensionPointHookWrapper(true, false);
+
+  EXPECT_TRUE(::ReleaseMutex(mutex));
+  EXPECT_TRUE(::CloseHandle(mutex));
+}
+
+// *** Important: MITIGATION_EXTENSION_POINT_DISABLE does NOT prevent
+// hooks targetted at a specific thread id.  It only prevents
+// global hooks.  So this test does NOT actually expect the hook
+// to fail (see TestWin8ExtensionPointHookWrapper function) even
+// with the mitigation on.
+//
+// MANUAL testing only.
+TEST(ProcessMitigationsTest, DISABLED_CheckWin8ExtensionPoint_Hook_Failure) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
+  EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE);
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout));
+
+  // (is_success_test, global_hook)
+  TestWin8ExtensionPointHookWrapper(false, false);
+
+  EXPECT_TRUE(::ReleaseMutex(mutex));
+  EXPECT_TRUE(::CloseHandle(mutex));
+}
+
+// This test validates that an AppInit Dll CAN be added to a target
+// WinProc if the MITIGATION_EXTENSION_POINT_DISABLE mitigation is not set.
+//
+// MANUAL testing only.
+// Must run this test as admin/elevated.
+TEST(ProcessMitigationsTest, DISABLED_CheckWin8ExtensionPoint_AppInit_Success) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
+  EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE);
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout));
+
+  TestWin8ExtensionPointAppInitWrapper(true);
+
+  EXPECT_TRUE(::ReleaseMutex(mutex));
+  EXPECT_TRUE(::CloseHandle(mutex));
+}
+
+// This test validates that setting the MITIGATION_EXTENSION_POINT_DISABLE
+// mitigation prevents the loading of any AppInit Dll into WinProc.
+//
+// MANUAL testing only.
+// Must run this test as admin/elevated.
+TEST(ProcessMitigationsTest, DISABLED_CheckWin8ExtensionPoint_AppInit_Failure) {
+  if (base::win::GetVersion() < base::win::VERSION_WIN8)
+    return;
+
+  HANDLE mutex = ::CreateMutexW(NULL, FALSE, g_extension_point_test_mutex);
+  EXPECT_TRUE(mutex != NULL && mutex != INVALID_HANDLE_VALUE);
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(mutex, event_timeout));
+
+  TestWin8ExtensionPointAppInitWrapper(false);
+
+  EXPECT_TRUE(::ReleaseMutex(mutex));
+  EXPECT_TRUE(::CloseHandle(mutex));
+}
+
+//------------------------------------------------------------------------------
 // Disable non-system font loads (MITIGATION_NONSYSTEM_FONT_DISABLE)
 // >= Win10
 //------------------------------------------------------------------------------
@@ -1193,7 +1652,7 @@
 // a remote UNC device, if the MITIGATION_IMAGE_LOAD_NO_REMOTE
 // mitigation is NOT set.
 //
-// DISABLED for automated testing bots.  Enable for manual testing.
+// MANUAL testing only.
 TEST(ProcessMitigationsTest, DISABLED_CheckWin10ImageLoadNoRemoteSuccess) {
   if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2)
     return;
@@ -1205,7 +1664,7 @@
 // mitigation prevents creating a new process from a remote
 // UNC device.
 //
-// DISABLED for automated testing bots.  Enable for manual testing.
+// MANUAL testing only.
 TEST(ProcessMitigationsTest, DISABLED_CheckWin10ImageLoadNoRemoteFailure) {
   if (base::win::GetVersion() < base::win::VERSION_WIN10_TH2)
     return;
diff --git a/sandbox/win/src/security_level.h b/sandbox/win/src/security_level.h
index 87abdebad..d8524c1 100644
--- a/sandbox/win/src/security_level.h
+++ b/sandbox/win/src/security_level.h
@@ -187,10 +187,14 @@
 // PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON.
 const MitigationFlags MITIGATION_WIN32K_DISABLE                   = 0x00000200;
 
-// Disables common DLL injection methods (e.g. window hooks and
-// App_InitDLLs). Corresponds to
+// Prevents certain built-in third party extension points from being used.
+// - App_Init DLLs
+// - Winsock Layered Service Providers (LSPs)
+// - Global Windows Hooks (NOT thread-targeted hooks)
+// - Legacy Input Method Editors (IMEs).
+// I.e.: Disable legacy hooking mechanisms.  Corresponds to
 // PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON.
-const MitigationFlags MITIGATION_EXTENSION_DLL_DISABLE            = 0x00000400;
+const MitigationFlags MITIGATION_EXTENSION_POINT_DISABLE = 0x00000400;
 
 // Prevents the process from loading non-system fonts into GDI.
 // Corresponds to
diff --git a/sandbox/win/tests/integration_tests/hooking_dll.cc b/sandbox/win/tests/integration_tests/hooking_dll.cc
new file mode 100644
index 0000000..f275ae6
--- /dev/null
+++ b/sandbox/win/tests/integration_tests/hooking_dll.cc
@@ -0,0 +1,64 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+#include <windows.h>
+
+#define _DLL_EXPORTING
+#include "integration_tests_common.h"
+
+// This data section creates a common area that is accessible
+// to all instances of the DLL (in every process).  They map to
+// the same physical memory location.
+// **Note that each instance of this DLL runs in the context of
+// the process it's injected into, so things like pointers and
+// addresses won't work.
+// **Note that any variables must be initialized to put them in
+// the specified segment, otherwise they will end up in the
+// default data segment.
+#pragma data_seg(".hook")
+HHOOK hook = NULL;
+bool hook_called = false;
+#pragma data_seg()
+#pragma comment(linker, "/SECTION:.hook,RWS")
+
+namespace {
+
+HANDLE event = NULL;
+}
+
+void SetHook(HHOOK hook_handle) {
+  hook = hook_handle;
+
+  return;
+}
+
+bool WasHookCalled() {
+  return hook_called;
+}
+
+LRESULT HookProc(int code, WPARAM w_param, LPARAM l_param) {
+  hook_called = true;
+  if (event)
+    ::SetEvent(event);
+
+  // Recent versions of Windows do not require the HHOOK to be passed along,
+  // but I'm doing it here to show the shared use of the HHOOK variable in
+  // the shared data segment.  It is set by the instance of the DLL in the
+  // main test process.
+  return CallNextHookEx(hook, code, w_param, l_param);
+}
+
+BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) {
+  if (reason == DLL_PROCESS_ATTACH) {
+    // The testing process should have set up this named event already
+    // (if the test needs this event to be signaled).
+    event = ::OpenEventW(EVENT_MODIFY_STATE, FALSE, g_hook_event);
+  }
+
+  if (reason == DLL_PROCESS_DETACH)
+    ::CloseHandle(event);
+
+  return TRUE;
+}
diff --git a/sandbox/win/tests/integration_tests/hooking_win_proc.cc b/sandbox/win/tests/integration_tests/hooking_win_proc.cc
new file mode 100644
index 0000000..3c6770abff
--- /dev/null
+++ b/sandbox/win/tests/integration_tests/hooking_win_proc.cc
@@ -0,0 +1,87 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "integration_tests_common.h"
+
+#include <windows.h>
+
+LRESULT CALLBACK WndProc(HWND window,
+                         UINT message,
+                         WPARAM w_param,
+                         LPARAM l_param) {
+  // Injected keystroke via PostThreadMessage won't be dispatched to here.
+  // Have to use SendMessage or SendInput to trigger the keyboard hook.
+  switch (message) {
+    case WM_KEYDOWN:
+      break;
+    case WM_KEYUP:
+      break;
+    case WM_CLOSE:
+      ::DestroyWindow(window);
+      break;
+    case WM_DESTROY:
+      ::PostQuitMessage(0);
+      break;
+    default:
+      return ::DefWindowProc(window, message, w_param, l_param);
+  }
+  return 0;
+}
+
+int WINAPI WinMain(HINSTANCE instance,
+                   HINSTANCE prev_instance,
+                   LPSTR cmd_line,
+                   int cmd_show) {
+  // The parent process should have set up this named event already.
+  HANDLE event = ::OpenEventW(EVENT_MODIFY_STATE, FALSE, g_winproc_event);
+  if (event == NULL || event == INVALID_HANDLE_VALUE)
+    return 1;
+
+  // Step 1: Registering the Window Class.
+  WNDCLASSEX window_class;
+  window_class.cbSize = sizeof(WNDCLASSEX);
+  window_class.style = 0;
+  window_class.lpfnWndProc = WndProc;
+  window_class.cbClsExtra = 0;
+  window_class.cbWndExtra = 0;
+  window_class.hInstance = instance;
+  window_class.hIcon = ::LoadIcon(NULL, IDI_APPLICATION);
+  window_class.hCursor = ::LoadCursor(NULL, IDC_ARROW);
+  window_class.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOWFRAME);
+  window_class.lpszMenuName = NULL;
+  window_class.lpszClassName = g_winproc_class_name;
+  window_class.hIconSm = ::LoadIcon(NULL, IDI_APPLICATION);
+
+  if (!::RegisterClassEx(&window_class))
+    return 1;
+
+  // Step 2: Create the Window.
+  HWND window = ::CreateWindowExW(WS_EX_CLIENTEDGE, g_winproc_class_name,
+                                  g_winproc_window_name, WS_OVERLAPPEDWINDOW,
+                                  CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL,
+                                  NULL, instance, NULL);
+
+  if (window == NULL)
+    return 1;
+
+  ::ShowWindow(window, cmd_show);
+  ::UpdateWindow(window);
+
+  // Step 3: Signal that WinProc is up and running.
+  ::SetEvent(event);
+
+  // Step 4: The Message Loop
+  // WM_QUIT results in a 0 value from GetMessageW,
+  // breaking the loop.
+  MSG message;
+  while (::GetMessageW(&message, NULL, 0, 0) > 0) {
+    ::TranslateMessage(&message);
+    ::DispatchMessageW(&message);
+  }
+
+  ::SetEvent(event);
+  ::CloseHandle(event);
+
+  return message.wParam;
+}
diff --git a/sandbox/win/tests/integration_tests/integration_tests_common.h b/sandbox/win/tests/integration_tests/integration_tests_common.h
new file mode 100644
index 0000000..841e6e4b
--- /dev/null
+++ b/sandbox/win/tests/integration_tests/integration_tests_common.h
@@ -0,0 +1,43 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_TESTS_INTEGRATION_TESTS_COMMON_H_
+#define SANDBOX_TESTS_INTEGRATION_TESTS_COMMON_H_
+
+#include <windows.h>
+
+// Use the same header file for DLL and importers.
+#ifdef _DLL_EXPORTING
+#define DECLSPEC extern "C" __declspec(dllexport)
+#else
+#define DECLSPEC extern "C" __declspec(dllimport)
+#endif
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+const wchar_t* g_extension_point_test_mutex = L"ChromeExtensionTestMutex";
+
+//------------------------------------------------------------------------------
+// Hooking WinProc exe.
+//------------------------------------------------------------------------------
+const wchar_t* g_winproc_file = L"sbox_integration_test_win_proc.exe ";
+const wchar_t* g_winproc_class_name = L"myWindowClass";
+const wchar_t* g_winproc_window_name = L"ChromeMitigationTests";
+const wchar_t* g_winproc_event = L"ChromeExtensionTestEvent";
+
+//------------------------------------------------------------------------------
+// Hooking dll.
+//------------------------------------------------------------------------------
+const wchar_t* g_hook_dll_file = L"sbox_integration_test_hook_dll.dll";
+const wchar_t* g_hook_event = L"ChromeExtensionTestHookEvent";
+const char* g_hook_handler_func = "HookProc";
+const char* g_was_hook_called_func = "WasHookCalled";
+const char* g_set_hook_func = "SetHook";
+
+DECLSPEC LRESULT HookProc(int code, WPARAM wParam, LPARAM lParam);
+DECLSPEC bool WasHookCalled();
+DECLSPEC void SetHook(HHOOK hook_handle);
+
+#endif  // SANDBOX_TESTS_INTEGRATION_TESTS_COMMON_H_
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
index 99e2076..a8e09d2 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
@@ -4,9 +4,6 @@
 # https://crbug.com/611838 - regression when geolocation tests use JS mock.
 http/tests/security/powerfulFeatureRestrictions/geolocation-on-secure-origin-in-insecure-origin.html [ Timeout ]
 
-# https://crbug.com/344348 - No POST data support in FrameHostMsg_OpenURL.
-http/tests/navigation/form-targets-cross-site-frame-post.html [ Failure ]
-
 # https://crbug.com/611154 - DCHECK in NavigatorImpl::DidStartProvisionalLoad.
 http/tests/security/upgrade-insecure-requests/iframe-upgrade.https.html [ Crash ]
 http/tests/security/upgrade-insecure-requests/iframe-upgrade-csp.https.html [ Crash ]
diff --git a/third_party/WebKit/LayoutTests/LeakExpectations b/third_party/WebKit/LayoutTests/LeakExpectations
index c9488b6..0638d28f 100644
--- a/third_party/WebKit/LayoutTests/LeakExpectations
+++ b/third_party/WebKit/LayoutTests/LeakExpectations
@@ -36,8 +36,6 @@
 crbug.com/410974 virtual/scroll_customization/fast/scroll-behavior/scroll-customization/touch-scroll-customization.html [ Leak ]
 crbug.com/410974 virtual/scroll_customization/fast/scroll-behavior/scroll-customization/scrollstate-distribute-to-scroll-chain-descendant.html [ Leak ]
 
-crbug.com/616775 http/tests/inspector-enabled/dedicated-workers-list.html [ Crash ]
-
 # -----------------------------------------------------------------
 # Untriaged but known real leaks.
 # -----------------------------------------------------------------
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-at-unique-origin-denied.php b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-at-unique-origin-denied.php
index 629b65f..413ece6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-at-unique-origin-denied.php
+++ b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-at-unique-origin-denied.php
@@ -4,17 +4,37 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script>
+var orginURL = document.URL;
 test(function () {
     assert_throws('SecurityError', function () {
-        history.pushState(null, null, document.URL + "/path");
+        history.pushState(null, null, orginURL + "/path");
     });
 }, 'pushState to a new path in unique origin should fail with SecurityError');
+
 test(function () {
     try {
-        history.pushState(null, null, document.URL + "#hash");
+        history.pushState(null, null, orginURL + "#hash");
         done();
     } catch (e) {
-        assert_unreached("pushState to a new hash should not fail.");
+        assert_unreached("pushState #hash should not fail.");
     }
-}, 'pushState to new hash in unique origin should not fail with SecurityError');
+}, 'pushState #hash in unique origin should not fail with SecurityError');
+
+test(function () {
+    try {
+        history.pushState(null, null, orginURL + "?hash");
+        done();
+    } catch (e) {
+        assert_unreached("pushState ?hash should not fail.");
+    }
+}, 'pushState ?hash in unique origin should not fail with SecurityError');
+
+test(function () {
+    try {
+        history.pushState(null, null, orginURL + "?hash#base");
+        done();
+    } catch (e) {
+        assert_unreached("pushState ?hash#base should not fail.");
+    }
+}, 'pushState ?hash#base in unique origin should not fail with SecurityError');
 </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-at-unique-origin-denied.php b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-at-unique-origin-denied.php
index 612162a..164d9f6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-at-unique-origin-denied.php
+++ b/third_party/WebKit/LayoutTests/http/tests/navigation/pushstate-whitelisted-at-unique-origin-denied.php
@@ -4,22 +4,41 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script>
+var orginURL = document.URL;
 test(function () {
     testRunner.addOriginAccessWhitelistEntry(location.origin, location.protocol, '', false);
 }, 'testRunner.addOriginAccessWhitelistEntry is required for this test');
 
 test(function () {
     assert_throws('SecurityError', function () {
-        history.pushState(null, null, document.URL + "/path");
+        history.pushState(null, null, orginURL + "/path");
     });
 }, 'pushState at unique origin should fail with SecurityError (even with whitelisted origins)');
 
 test(function () {
     try {
-        history.pushState(null, null, document.URL + "#hash");
+        history.pushState(null, null, orginURL + "#hash");
         done();
     } catch (e) {
-        assert_unreached("pushState to a new hash should not fail.");
+        assert_unreached("pushState #hash should not fail.");
     }
-}, 'pushState to new hash in unique origin should not fail with SecurityError');
+}, 'pushState #hash in unique origin should not fail with SecurityError');
+
+test(function () {
+    try {
+        history.pushState(null, null, orginURL + "?hash");
+        done();
+    } catch (e) {
+        assert_unreached("pushState ?hash should not fail.");
+    }
+}, 'pushState ?hash in unique origin should not fail with SecurityError');
+
+test(function () {
+    try {
+        history.pushState(null, null, orginURL + "?hash#base");
+        done();
+    } catch (e) {
+        assert_unreached("pushState ?hash#base should not fail.");
+    }
+}, 'pushState ?hash#base in unique origin should not fail with SecurityError');
 </script>
diff --git a/third_party/WebKit/LayoutTests/payments/promises-keep-request-alive.html b/third_party/WebKit/LayoutTests/payments/promises-keep-request-alive.html
index db250f3..80187b5 100644
--- a/third_party/WebKit/LayoutTests/payments/promises-keep-request-alive.html
+++ b/third_party/WebKit/LayoutTests/payments/promises-keep-request-alive.html
@@ -30,7 +30,7 @@
           return result;
         })
       .then(response => {
-          completeResult = response.complete(true);
+          completeResult = response.complete("success");
           // Return before calling gc() to make sure reference to response
           // is gone.
         })
diff --git a/third_party/WebKit/Source/core/frame/History.cpp b/third_party/WebKit/Source/core/frame/History.cpp
index 393394f..dc78024 100644
--- a/third_party/WebKit/Source/core/frame/History.cpp
+++ b/third_party/WebKit/Source/core/frame/History.cpp
@@ -59,6 +59,23 @@
     return true;
 }
 
+bool equalIgnoringQueryAndFragment(const KURL& a, const KURL& b)
+{
+    int aLength = a.pathEnd();
+    int bLength = b.pathEnd();
+
+    if (aLength != bLength)
+        return false;
+
+    const String& aString = a.getString();
+    const String& bString = b.getString();
+    for (int i = 0; i < aLength; ++i) {
+        if (aString[i] != bString[i])
+            return false;
+    }
+    return true;
+}
+
 }  // namespace
 
 History::History(LocalFrame* frame)
@@ -196,7 +213,7 @@
     // 'pushState'/'replaceState' to modify the URL fragment: see
     // https://crbug.com/528681 for the compatibility concerns.
     if (documentOrigin->isUnique() || documentOrigin->isLocal())
-        return equalIgnoringFragmentIdentifier(url, documentURL);
+        return equalIgnoringQueryAndFragment(url, documentURL);
 
     if (!equalIgnoringPathQueryAndFragment(url, documentURL))
         return false;
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp
index 8ba59de..f33a86d9 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp
@@ -153,11 +153,12 @@
 
     SVGSVGElement* svg = toSVGSVGElement(node());
     ASSERT(svg);
+    m_isLayoutSizeChanged = selfNeedsLayout() || (svg->hasRelativeLengths() && oldSize != size());
     // When hasRelativeLengths() is false, no descendants have relative lengths
     // (hence no one is interested in viewport size changes).
-    m_isLayoutSizeChanged = svg->hasRelativeLengths() && (selfNeedsLayout() || oldSize != size());
+    bool layoutSizeChanged = m_isLayoutSizeChanged && svg->hasRelativeLengths();
 
-    SVGLayoutSupport::layoutChildren(firstChild(), false, m_didScreenScaleFactorChange, m_isLayoutSizeChanged);
+    SVGLayoutSupport::layoutChildren(firstChild(), false, m_didScreenScaleFactorChange, layoutSizeChanged);
 
     if (m_needsBoundariesOrTransformUpdate) {
         updateCachedBoundaries();
diff --git a/third_party/WebKit/Source/core/workers/WorkerBackingThread.cpp b/third_party/WebKit/Source/core/workers/WorkerBackingThread.cpp
index 5f04775..0c7ae4e 100644
--- a/third_party/WebKit/Source/core/workers/WorkerBackingThread.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerBackingThread.cpp
@@ -61,30 +61,6 @@
 
 WorkerBackingThread::~WorkerBackingThread()
 {
-#if DCHECK_IS_ON()
-    MutexLocker locker(m_mutex);
-    DCHECK_EQ(0u, m_workerScriptCount);
-#endif
-}
-
-void WorkerBackingThread::attach()
-{
-    {
-        MutexLocker locker(m_mutex);
-        if (++m_workerScriptCount > 1)
-            return;
-    }
-    initialize();
-}
-
-void WorkerBackingThread::detach()
-{
-    {
-        MutexLocker locker(m_mutex);
-        if (--m_workerScriptCount > 0)
-            return;
-    }
-    shutdown();
 }
 
 void WorkerBackingThread::initialize()
diff --git a/third_party/WebKit/Source/core/workers/WorkerBackingThread.h b/third_party/WebKit/Source/core/workers/WorkerBackingThread.h
index afbc4a0..389586706 100644
--- a/third_party/WebKit/Source/core/workers/WorkerBackingThread.h
+++ b/third_party/WebKit/Source/core/workers/WorkerBackingThread.h
@@ -18,8 +18,8 @@
 class WebThreadSupportingGC;
 
 // WorkerBackingThread represents a WebThread with Oilpan and V8 potentially
-// shared by multiple WebWorker scripts. A WebWorker needs to call attach() when
-// attaching itself to the backing thread, and call detach() when the script
+// shared by multiple WebWorker scripts. A WebWorker needs to call initialize()
+// to using V8 and Oilpan functionalities, and call detach() when the script
 // no longer needs the thread.
 // A WorkerBackingThread represents a WebThread while a WorkerThread corresponds
 // to a web worker. There is one-to-one correspondence between WorkerThread and
@@ -37,21 +37,12 @@
 
     ~WorkerBackingThread();
 
-    // attach() and detach() attaches and detaches Oilpan and V8 to / from
-    // the caller worker script, respectively. attach() and detach() increments
-    // and decrements m_workerScriptCount. attach() initializes Oilpan and V8
-    // when m_workerScriptCount is 0. detach() terminates Oilpan and V8 when
-    // m_workerScriptCount is 1. A worker script must not call any function
-    // after calling detach().
+    // initialize() and shutdown() attaches and detaches Oilpan and V8 to / from
+    // the caller worker script, respectively. A worker script must not call
+    // any function after calling shutdown().
     // They should be called from |this| thread.
-    void attach();
-    void detach();
-
-    unsigned workerScriptCount()
-    {
-        MutexLocker locker(m_mutex);
-        return m_workerScriptCount;
-    }
+    void initialize();
+    void shutdown();
 
     WebThreadSupportingGC& backingThread()
     {
@@ -67,14 +58,9 @@
 private:
     WorkerBackingThread(const char* name, bool shouldCallGCOnShutdown);
     WorkerBackingThread(WebThread*, bool shouldCallGCOnSHutdown);
-    void initialize();
-    void shutdown();
 
-    // Protects |m_workerScriptCount|.
-    Mutex m_mutex;
     OwnPtr<WebThreadSupportingGC> m_backingThread;
     v8::Isolate* m_isolate = nullptr;
-    unsigned m_workerScriptCount = 0;
     bool m_isOwningThread;
     bool m_shouldCallGCOnShutdown;
 };
diff --git a/third_party/WebKit/Source/core/workers/WorkerThread.cpp b/third_party/WebKit/Source/core/workers/WorkerThread.cpp
index 27ff8425..4c9fd41 100644
--- a/third_party/WebKit/Source/core/workers/WorkerThread.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerThread.cpp
@@ -398,17 +398,10 @@
     // scope is already disposed, so we don't have to explicitly terminate the
     // worker execution.
     //
-    // (2) |workerScriptCount() == 1|: If other WorkerGlobalScopes are running
-    // on the worker thread, we should not terminate the worker execution. This
-    // condition is not entirely correct because other scripts can be being
-    // initialized or terminated simuletaneously. Though this function itself is
-    // protected by a mutex, it is possible that |workerScriptCount()| here is
-    // not consistent with that in |initialize| and |shutdown|.
-    //
-    // (3) |m_runningDebuggerTask|: Terminating during debugger task may lead to
+    // (2) |m_runningDebuggerTask|: Terminating during debugger task may lead to
     // crash due to heavy use of v8 api in debugger. Any debugger task is
     // guaranteed to finish, so we can wait for the completion.
-    bool shouldScheduleToTerminateExecution = !m_readyToShutdown && (workerBackingThread().workerScriptCount() == 1) && !m_runningDebuggerTask;
+    bool shouldScheduleToTerminateExecution = !m_readyToShutdown && !m_runningDebuggerTask;
 
     if (shouldScheduleToTerminateExecution) {
         if (mode == TerminationMode::Forcible) {
@@ -461,7 +454,8 @@
             return;
         }
 
-        workerBackingThread().attach();
+        if (isOwningBackingThread())
+            workerBackingThread().initialize();
 
         if (shouldAttachThreadDebugger())
             V8PerIsolateData::from(isolate())->setThreadDebugger(adoptPtr(new WorkerThreadDebugger(this, isolate())));
@@ -546,7 +540,8 @@
     m_workerGlobalScope->notifyContextDestroyed();
     m_workerGlobalScope = nullptr;
 
-    workerBackingThread().detach();
+    if (isOwningBackingThread())
+        workerBackingThread().shutdown();
     // We must not touch workerBackingThread() from now on.
 
     m_microtaskRunner = nullptr;
diff --git a/third_party/WebKit/Source/core/workers/WorkerThread.h b/third_party/WebKit/Source/core/workers/WorkerThread.h
index d31ff1f..556c934 100644
--- a/third_party/WebKit/Source/core/workers/WorkerThread.h
+++ b/third_party/WebKit/Source/core/workers/WorkerThread.h
@@ -161,6 +161,13 @@
     // Called on the worker thread.
     virtual WorkerGlobalScope* createWorkerGlobalScope(PassOwnPtr<WorkerThreadStartupData>) = 0;
 
+    // Returns true when this WorkerThread owns the associated
+    // WorkerBackingThread exclusively. If this function returns true, the
+    // WorkerThread initializes / shutdowns the backing thread. Otherwise
+    // workerBackingThread() should be initialized / shutdown properly
+    // out of this class.
+    virtual bool isOwningBackingThread() const { return true; }
+
     // Called on the worker thread.
     virtual void postInitialize() { }
 
diff --git a/third_party/WebKit/Source/modules/ModulesInitializer.cpp b/third_party/WebKit/Source/modules/ModulesInitializer.cpp
index 7aabb48..b04f7fca 100644
--- a/third_party/WebKit/Source/modules/ModulesInitializer.cpp
+++ b/third_party/WebKit/Source/modules/ModulesInitializer.cpp
@@ -65,7 +65,6 @@
 {
     ASSERT(isInitialized());
     DatabaseManager::terminateDatabaseThread();
-    CompositorWorkerThread::terminateExecution();
     CoreInitializer::shutdown();
     CompositorWorkerThread::clearSharedBackingThread();
 }
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.cpp b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.cpp
index 2458e8af..de797ad 100644
--- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.cpp
+++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.cpp
@@ -15,6 +15,7 @@
 #include "platform/WaitableEvent.h"
 #include "platform/WebThreadSupportingGC.h"
 #include "public/platform/Platform.h"
+#include "wtf/Assertions.h"
 
 namespace blink {
 
@@ -39,20 +40,10 @@
             s_instance = new BackingThreadHolder;
     }
 
-    static void terminateExecution()
-    {
-        MutexLocker locker(holderInstanceMutex());
-        if (s_instance && s_instance->m_initialized) {
-            s_instance->thread()->isolate()->TerminateExecution();
-            s_instance->m_terminatingExecution = true;
-        }
-    }
-
     static void clear()
     {
         MutexLocker locker(holderInstanceMutex());
         if (s_instance) {
-            DCHECK(!s_instance->m_initialized || s_instance->m_terminatingExecution);
             s_instance->shutdownAndWait();
             delete s_instance;
             s_instance = nullptr;
@@ -85,8 +76,8 @@
     void initializeOnThread()
     {
         MutexLocker locker(holderInstanceMutex());
-        DCHECK_EQ(0u, m_thread->workerScriptCount()) << "BackingThreadHolder should be the first to attach to WorkerBackingThread";
-        m_thread->attach();
+        DCHECK(!m_initialized);
+        m_thread->initialize();
         m_initialized = true;
     }
 
@@ -100,13 +91,11 @@
 
     void shutdownOnThread(WaitableEvent* doneEvent)
     {
-        DCHECK_EQ(1u, m_thread->workerScriptCount()) << "BackingThreadHolder should be the last to detach from WorkerBackingThread";
-        m_thread->detach();
+        m_thread->shutdown();
         doneEvent->signal();
     }
 
     OwnPtr<WorkerBackingThread> m_thread;
-    bool m_terminatingExecution = false;
     bool m_initialized = false;
 
     static BackingThreadHolder* s_instance;
@@ -151,12 +140,6 @@
     BackingThreadHolder::ensureInstance();
 }
 
-void CompositorWorkerThread::terminateExecution()
-{
-    DCHECK(isMainThread());
-    BackingThreadHolder::terminateExecution();
-}
-
 void CompositorWorkerThread::clearSharedBackingThread()
 {
     DCHECK(isMainThread());
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.h b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.h
index 9e349071..b72fe9c 100644
--- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.h
+++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.h
@@ -12,7 +12,6 @@
 
 class InProcessWorkerObjectProxy;
 
-// This class is overridden in unit-tests.
 class MODULES_EXPORT CompositorWorkerThread final : public WorkerThread {
 public:
     static PassOwnPtr<CompositorWorkerThread> create(PassRefPtr<WorkerLoaderProxy>, InProcessWorkerObjectProxy&, double timeOrigin);
@@ -25,15 +24,13 @@
     static void ensureSharedBackingThread();
     static void createSharedBackingThreadForTest();
 
-    // This is called before CoreInitializer::shutdown as shutdown waits for
-    // worker threads that can be blocked by scripts.
-    static void terminateExecution();
     static void clearSharedBackingThread();
 
 protected:
     CompositorWorkerThread(PassRefPtr<WorkerLoaderProxy>, InProcessWorkerObjectProxy&, double timeOrigin);
 
     WorkerGlobalScope* createWorkerGlobalScope(PassOwnPtr<WorkerThreadStartupData>) override;
+    bool isOwningBackingThread() const override { return false; }
 
 private:
     InProcessWorkerObjectProxy& m_workerObjectProxy;
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp
index 947cf80..1b3c0d83 100644
--- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp
+++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp
@@ -106,7 +106,6 @@
     void TearDown() override
     {
         m_page.reset();
-        CompositorWorkerThread::terminateExecution();
         CompositorWorkerThread::clearSharedBackingThread();
     }
 
@@ -142,7 +141,6 @@
 private:
     void executeScriptInWorker(WorkerThread* worker, WaitableEvent* waitEvent)
     {
-        EXPECT_GT(worker->workerBackingThread().workerScriptCount(), 0u);
         WorkerOrWorkletScriptController* scriptController = worker->workerGlobalScope()->scriptController();
         bool evaluateResult = scriptController->evaluate(ScriptSourceCode("var counter = 0; ++counter;"));
         ASSERT_UNUSED(evaluateResult, evaluateResult);
@@ -174,7 +172,9 @@
 
     // Create the second worker and immediately destroy the first worker.
     OwnPtr<CompositorWorkerThread> secondWorker = createCompositorWorker();
-    firstWorker->terminateAndWait();
+    // We don't use terminateAndWait here to avoid forcible termination.
+    firstWorker->terminate();
+    firstWorker->waitForShutdownForTesting();
 
     // Wait until the second worker is initialized. Verify that the second worker is using the same
     // thread and Isolate as the first worker.
@@ -196,21 +196,18 @@
 {
     // Create the first worker, wait until it is initialized, and terminate it.
     OwnPtr<CompositorWorkerThread> compositorWorker = createCompositorWorker();
-    WorkerBackingThread* workerBackingThread = &compositorWorker->workerBackingThread();
     WebThreadSupportingGC* firstThread = &compositorWorker->workerBackingThread().backingThread();
     checkWorkerCanExecuteScript(compositorWorker.get());
 
-    ASSERT_EQ(2u, workerBackingThread->workerScriptCount());
-    compositorWorker->terminateAndWait();
-
-    ASSERT_EQ(1u, workerBackingThread->workerScriptCount());
+    // We don't use terminateAndWait here to avoid forcible termination.
+    compositorWorker->terminate();
+    compositorWorker->waitForShutdownForTesting();
 
     // Create the second worker. The backing thread is same.
     compositorWorker = createCompositorWorker();
     WebThreadSupportingGC* secondThread = &compositorWorker->workerBackingThread().backingThread();
     EXPECT_EQ(firstThread, secondThread);
     checkWorkerCanExecuteScript(compositorWorker.get());
-    ASSERT_EQ(2u, workerBackingThread->workerScriptCount());
 
     compositorWorker->terminateAndWait();
 }
@@ -225,7 +222,6 @@
 
     // Request termination of the first worker and create the second worker
     // as soon as possible.
-    EXPECT_EQ(2u, firstWorker->workerBackingThread().workerScriptCount());
     firstWorker->terminate();
     // We don't wait for its termination.
     // Note: We rely on the assumption that the termination steps don't run
diff --git a/third_party/WebKit/Source/modules/payments/PaymentCompleter.h b/third_party/WebKit/Source/modules/payments/PaymentCompleter.h
index 284d2a1..70e5c80 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentCompleter.h
+++ b/third_party/WebKit/Source/modules/payments/PaymentCompleter.h
@@ -11,11 +11,17 @@
 
 namespace blink {
 
+enum PaymentComplete {
+    Success,
+    Fail,
+    Unknown
+};
+
 class ScriptState;
 
 class MODULES_EXPORT PaymentCompleter : public GarbageCollectedMixin {
 public:
-    virtual ScriptPromise complete(ScriptState*, bool success) = 0;
+    virtual ScriptPromise complete(ScriptState*, PaymentComplete result) = 0;
 
 protected:
     virtual ~PaymentCompleter() {}
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
index de2c800..e1a1812 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
@@ -318,13 +318,13 @@
     return ContextLifecycleObserver::getExecutionContext();
 }
 
-ScriptPromise PaymentRequest::complete(ScriptState* scriptState, bool success)
+ScriptPromise PaymentRequest::complete(ScriptState* scriptState, PaymentComplete result)
 {
     if (m_completeResolver)
         return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(InvalidStateError, "Already called complete() once"));
 
     // The payment provider should respond in PaymentRequest::OnComplete().
-    m_paymentProvider->Complete(success);
+    m_paymentProvider->Complete(mojom::blink::PaymentComplete(result));
 
     m_completeResolver = ScriptPromiseResolver::create(scriptState);
     return m_completeResolver->promise();
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequest.h b/third_party/WebKit/Source/modules/payments/PaymentRequest.h
index c150a99c..eaedaf2 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentRequest.h
+++ b/third_party/WebKit/Source/modules/payments/PaymentRequest.h
@@ -64,7 +64,7 @@
     ExecutionContext* getExecutionContext() const override;
 
     // PaymentCompleter:
-    ScriptPromise complete(ScriptState*, bool success) override;
+    ScriptPromise complete(ScriptState*, PaymentComplete result) override;
 
     // PaymentUpdater:
     void onUpdatePaymentDetails(const ScriptValue& detailsScriptValue) override;
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequestTest.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequestTest.cpp
index 7984615..be38125 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentRequestTest.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentRequestTest.cpp
@@ -361,9 +361,9 @@
     EXPECT_FALSE(scope.getExceptionState().hadException());
     request->show(scope.getScriptState());
     static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(buildPaymentResponseForTest());
-    request->complete(scope.getScriptState(), false);
+    request->complete(scope.getScriptState(), Fail);
 
-    request->complete(scope.getScriptState(), true).then(funcs.expectNoCall(), funcs.expectCall());
+    request->complete(scope.getScriptState(), Success).then(funcs.expectNoCall(), funcs.expectCall());
 }
 
 TEST(PaymentRequestTest, RejectShowPromiseOnError)
@@ -389,7 +389,7 @@
     request->show(scope.getScriptState());
     static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(buildPaymentResponseForTest());
 
-    request->complete(scope.getScriptState(), true).then(funcs.expectNoCall(), funcs.expectCall());
+    request->complete(scope.getScriptState(), Success).then(funcs.expectNoCall(), funcs.expectCall());
 
     static_cast<mojom::blink::PaymentRequestClient*>(request)->OnError();
 }
@@ -404,7 +404,7 @@
     request->show(scope.getScriptState());
     static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(buildPaymentResponseForTest());
 
-    request->complete(scope.getScriptState(), true).then(funcs.expectCall(), funcs.expectNoCall());
+    request->complete(scope.getScriptState(), Success).then(funcs.expectCall(), funcs.expectNoCall());
 
     static_cast<mojom::blink::PaymentRequestClient*>(request)->OnComplete();
 }
@@ -432,7 +432,7 @@
     request->show(scope.getScriptState()).then(funcs.expectCall(), funcs.expectNoCall());
     static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(buildPaymentResponseForTest());
 
-    request->complete(scope.getScriptState(), true).then(funcs.expectNoCall(), funcs.expectCall());
+    request->complete(scope.getScriptState(), Success).then(funcs.expectNoCall(), funcs.expectCall());
 
     request->onUpdatePaymentDetailsFailure(ScriptValue::from(scope.getScriptState(), "oops"));
 }
diff --git a/third_party/WebKit/Source/modules/payments/PaymentResponse.cpp b/third_party/WebKit/Source/modules/payments/PaymentResponse.cpp
index e79a75d..a2e498f 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentResponse.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentResponse.cpp
@@ -47,9 +47,14 @@
     return ScriptValue(scriptState, fromJSONString(scriptState, m_stringifiedDetails, exceptionState));
 }
 
-ScriptPromise PaymentResponse::complete(ScriptState* scriptState, bool success)
+ScriptPromise PaymentResponse::complete(ScriptState* scriptState, const String& result)
 {
-    return m_paymentCompleter->complete(scriptState, success);
+    PaymentComplete convertedResult = Unknown;
+    if (result == "success")
+        convertedResult = Success;
+    if (result == "fail")
+        convertedResult = Fail;
+    return m_paymentCompleter->complete(scriptState, convertedResult);
 }
 
 DEFINE_TRACE(PaymentResponse)
diff --git a/third_party/WebKit/Source/modules/payments/PaymentResponse.h b/third_party/WebKit/Source/modules/payments/PaymentResponse.h
index 5f1e70511..8548b617 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentResponse.h
+++ b/third_party/WebKit/Source/modules/payments/PaymentResponse.h
@@ -37,7 +37,7 @@
     const String& payerEmail() const { return m_payerEmail; }
     const String& payerPhone() const { return m_payerPhone; }
 
-    ScriptPromise complete(ScriptState*, bool success);
+    ScriptPromise complete(ScriptState*, const String& result = "");
 
     DECLARE_TRACE();
 
diff --git a/third_party/WebKit/Source/modules/payments/PaymentResponse.idl b/third_party/WebKit/Source/modules/payments/PaymentResponse.idl
index ce9b80d..a24427e 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentResponse.idl
+++ b/third_party/WebKit/Source/modules/payments/PaymentResponse.idl
@@ -2,6 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// https://w3c.github.io/browser-payment-api/#idl-def-paymentcomplete
+
+enum PaymentComplete {
+    "success",
+    "fail",
+    ""
+};
+
 // https://w3c.github.io/browser-payment-api/specs/paymentrequest.html#paymentresponse-interface
 
 [
@@ -14,5 +22,5 @@
     [CallWith=ScriptState, RaisesException] readonly attribute object details;
     readonly attribute PaymentAddress? shippingAddress;
 
-    [CallWith=ScriptState] Promise<void> complete(boolean success);
+    [CallWith=ScriptState] Promise<void> complete(optional PaymentComplete paymentResult = "");
 };
diff --git a/third_party/WebKit/Source/modules/payments/PaymentResponseTest.cpp b/third_party/WebKit/Source/modules/payments/PaymentResponseTest.cpp
index 026fd103..ae633dca 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentResponseTest.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentResponseTest.cpp
@@ -32,7 +32,7 @@
 
     ~MockPaymentCompleter() override {}
 
-    MOCK_METHOD2(complete, ScriptPromise(ScriptState*, bool success));
+    MOCK_METHOD2(complete, ScriptPromise(ScriptState*, PaymentComplete result));
 
     DEFINE_INLINE_TRACE() {}
 
@@ -83,9 +83,9 @@
     MockPaymentCompleter* completeCallback = new MockPaymentCompleter;
     PaymentResponse output(std::move(input), completeCallback);
 
-    EXPECT_CALL(*completeCallback, complete(scope.getScriptState(), true));
+    EXPECT_CALL(*completeCallback, complete(scope.getScriptState(), Success));
 
-    output.complete(scope.getScriptState(), true);
+    output.complete(scope.getScriptState(), "success");
 }
 
 TEST(PaymentResponseTest, CompleteCalledWithFailure)
@@ -97,9 +97,9 @@
     MockPaymentCompleter* completeCallback = new MockPaymentCompleter;
     PaymentResponse output(std::move(input), completeCallback);
 
-    EXPECT_CALL(*completeCallback, complete(scope.getScriptState(), false));
+    EXPECT_CALL(*completeCallback, complete(scope.getScriptState(), Fail));
 
-    output.complete(scope.getScriptState(), false);
+    output.complete(scope.getScriptState(), "fail");
 }
 
 } // namespace
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python.py
index 6356e4a6..dc9cf16 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python.py
@@ -67,7 +67,6 @@
 
     def _check_pylint(self):
         output = self._run_pylint(self._file_path)
-        print output
         errors = self._parse_pylint_output(output)
         for line_number, category, message in errors:
             self._handle_style_error(line_number, category, 5, message)
diff --git a/third_party/WebKit/public/platform/modules/payments/payment_request.mojom b/third_party/WebKit/public/platform/modules/payments/payment_request.mojom
index c21a38a..0f07092 100644
--- a/third_party/WebKit/public/platform/modules/payments/payment_request.mojom
+++ b/third_party/WebKit/public/platform/modules/payments/payment_request.mojom
@@ -109,6 +109,12 @@
   string stringified_data;
 };
 
+enum PaymentComplete {
+  SUCCESS,
+  FAIL,
+  UNKNOWN
+};
+
 interface PaymentRequest {
   SetClient(PaymentRequestClient client);
   Show(array<PaymentMethodData> methodData,
@@ -116,5 +122,5 @@
        PaymentOptions options);
   UpdateWith(PaymentDetails details);
   Abort();
-  Complete(bool success);
+  Complete(PaymentComplete result);
 };
diff --git a/tools/perf/benchmarks/battor.py b/tools/perf/benchmarks/battor.py
index b39d7c7..41c259e 100644
--- a/tools/perf/benchmarks/battor.py
+++ b/tools/perf/benchmarks/battor.py
@@ -40,7 +40,7 @@
 
   @classmethod
   def Name(cls):
-    return 'BattOr.BattOrCases'
+    return 'battor.power_cases'
 
 @benchmark.Disabled('android') # crbug.com/618330
 class BattOrPowerMobileSitesNoChromeTrace(_BattOrBenchmark):
@@ -56,4 +56,4 @@
 
   @classmethod
   def Name(cls):
-    return 'battor.battor_cases.no_chrome_trace'
+    return 'battor.power_cases.no_chrome_trace'
diff --git a/tools/perf/benchmarks/page_cycler_v2.py b/tools/perf/benchmarks/page_cycler_v2.py
index 9678ade..3319c9d6 100644
--- a/tools/perf/benchmarks/page_cycler_v2.py
+++ b/tools/perf/benchmarks/page_cycler_v2.py
@@ -22,13 +22,17 @@
     cat_filter = tracing_category_filter.TracingCategoryFilter(
         filter_string='blink.console,navigation,blink.user_timing,loading')
 
+    # Below categories are needed for first-meaningful-paint computation.
+    cat_filter.AddDisabledByDefault('disabled-by-default-blink.debug.layout')
+    cat_filter.AddIncludedCategory('devtools.timeline')
+
     tbm_options = timeline_based_measurement.Options(
         overhead_level=cat_filter)
     tbm_options.SetTimelineBasedMetric('firstPaintMetric')
     return tbm_options
 
 
-@benchmark.Disabled('win')  # crbug.com/615178
+@benchmark.Disabled('win', 'reference')  # crbug.com/615178, crbug.com/619254
 class PageCyclerV2Typical25(_PageCyclerV2):
   """Page load time benchmark for a 25 typical web pages.
 
diff --git a/ui/accelerated_widget_mac/window_resize_helper_mac.cc b/ui/accelerated_widget_mac/window_resize_helper_mac.cc
index b64e09b..a3b61836 100644
--- a/ui/accelerated_widget_mac/window_resize_helper_mac.cc
+++ b/ui/accelerated_widget_mac/window_resize_helper_mac.cc
@@ -301,10 +301,6 @@
       base::Bind(&WindowResizeHelperMac::EventTimedWait), target_task_runner);
 }
 
-void WindowResizeHelperMac::ShutdownForTests() {
-  task_runner_ = nullptr;
-}
-
 bool WindowResizeHelperMac::WaitForSingleTaskToRun(
     const base::TimeDelta& max_delay) {
   PumpableTaskRunner* pumpable_task_runner =
diff --git a/ui/accelerated_widget_mac/window_resize_helper_mac.h b/ui/accelerated_widget_mac/window_resize_helper_mac.h
index a83034f..f81cdc4 100644
--- a/ui/accelerated_widget_mac/window_resize_helper_mac.h
+++ b/ui/accelerated_widget_mac/window_resize_helper_mac.h
@@ -53,10 +53,6 @@
   void Init(
       const scoped_refptr<base::SingleThreadTaskRunner>& target_task_runner);
 
-  // Because this class is global, many tests may want to do this setup
-  // repeatedly, so need some way to uninitialize as well.
-  void ShutdownForTests();
-
   scoped_refptr<base::SingleThreadTaskRunner> task_runner() const;
 
   // UI THREAD ONLY -----------------------------------------------------------
diff --git a/ui/arc/OWNERS b/ui/arc/OWNERS
index f068aeb..d7d81e7 100644
--- a/ui/arc/OWNERS
+++ b/ui/arc/OWNERS
@@ -1,3 +1,4 @@
 elijahtaylor@chromium.org
 hidehiko@chromium.org
 lhchavez@chromium.org
+yusukes@chromium.org
diff --git a/ui/base/ime/input_method_chromeos.cc b/ui/base/ime/input_method_chromeos.cc
index 924c9cf..03c912751 100644
--- a/ui/base/ime/input_method_chromeos.cc
+++ b/ui/base/ime/input_method_chromeos.cc
@@ -25,6 +25,8 @@
 #include "ui/base/ime/ime_engine_handler_interface.h"
 #include "ui/base/ime/text_input_client.h"
 #include "ui/events/event.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/keycodes/dom/dom_key.h"
 #include "ui/gfx/geometry/rect.h"
 
 namespace {
@@ -361,9 +363,9 @@
   }
   ui::KeyEvent fabricated_event(ET_KEY_PRESSED,
                                 VKEY_PROCESSKEY,
-                                event->code(),
+                                ui::DomCode::NONE,
                                 event->flags(),
-                                event->GetDomKey(),
+                                ui::DomKey::NONE,
                                 event->time_stamp());
   ignore_result(DispatchKeyEventPostIME(&fabricated_event));
   if (fabricated_event.stopped_propagation())
diff --git a/ui/base/ime/input_method_chromeos_unittest.cc b/ui/base/ime/input_method_chromeos_unittest.cc
index 83ae4df..7777d44 100644
--- a/ui/base/ime/input_method_chromeos_unittest.cc
+++ b/ui/base/ime/input_method_chromeos_unittest.cc
@@ -969,9 +969,7 @@
 
   EXPECT_EQ(ET_KEY_PRESSED, key_event.type());
   EXPECT_EQ(VKEY_PROCESSKEY, key_event.key_code());
-  EXPECT_EQ(eventA.code(), key_event.code());
   EXPECT_EQ(eventA.flags(), key_event.flags());
-  EXPECT_EQ(eventA.GetDomKey(), key_event.GetDomKey());
   EXPECT_EQ(eventA.time_stamp(), key_event.time_stamp());
 }
 
diff --git a/ui/events/devices/mojo/input_device.typemap b/ui/events/devices/mojo/input_device.typemap
index 1207467..2296d7a 100644
--- a/ui/events/devices/mojo/input_device.typemap
+++ b/ui/events/devices/mojo/input_device.typemap
@@ -3,11 +3,23 @@
 # found in the LICENSE file.
 
 mojom = "//ui/events/devices/mojo/input_devices.mojom"
-public_headers = [ "//ui/events/devices/input_device.h" ]
-traits_headers = [ 
-  "//ui/events/devices/mojo/input_device_struct_traits.h" 
- ]
+public_headers = [
+  "//ui/events/devices/input_device.h",
+  "//ui/events/devices/touchscreen_device.h",
+]
+traits_headers = [ "//ui/events/devices/mojo/input_device_struct_traits.h" ]
+sources = [
+  "//ui/events/devices/mojo/input_device_struct_traits.cc",
+]
 public_deps = [
   "//ui/events/devices",
 ]
-type_mappings = [ "ui.mojom.InputDevice=ui::InputDevice" ]
+deps = [
+  "//ui/gfx/geometry",
+]
+
+type_mappings = [
+  "ui.mojom.InputDeviceType=ui::InputDeviceType",
+  "ui.mojom.InputDevice=ui::InputDevice",
+  "ui.mojom.TouchscreenDevice=ui::TouchscreenDevice",
+]
diff --git a/ui/events/devices/mojo/input_device_struct_traits.cc b/ui/events/devices/mojo/input_device_struct_traits.cc
new file mode 100644
index 0000000..afab820
--- /dev/null
+++ b/ui/events/devices/mojo/input_device_struct_traits.cc
@@ -0,0 +1,83 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/events/devices/mojo/input_device_struct_traits.h"
+
+#include "base/logging.h"
+#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
+
+namespace mojo {
+
+ui::mojom::InputDeviceType
+EnumTraits<ui::mojom::InputDeviceType, ui::InputDeviceType>::ToMojom(
+    ui::InputDeviceType type) {
+  switch (type) {
+    case ui::INPUT_DEVICE_INTERNAL:
+      return ui::mojom::InputDeviceType::INPUT_DEVICE_INTERNAL;
+    case ui::INPUT_DEVICE_EXTERNAL:
+      return ui::mojom::InputDeviceType::INPUT_DEVICE_EXTERNAL;
+    case ui::INPUT_DEVICE_UNKNOWN:
+      return ui::mojom::InputDeviceType::INPUT_DEVICE_UNKNOWN;
+  }
+  NOTREACHED();
+  return ui::mojom::InputDeviceType::INPUT_DEVICE_UNKNOWN;
+}
+
+bool EnumTraits<ui::mojom::InputDeviceType, ui::InputDeviceType>::FromMojom(
+    ui::mojom::InputDeviceType type,
+    ui::InputDeviceType* output) {
+  switch (type) {
+    case ui::mojom::InputDeviceType::INPUT_DEVICE_INTERNAL:
+      *output = ui::INPUT_DEVICE_INTERNAL;
+      break;
+    case ui::mojom::InputDeviceType::INPUT_DEVICE_EXTERNAL:
+      *output = ui::INPUT_DEVICE_EXTERNAL;
+      break;
+    case ui::mojom::InputDeviceType::INPUT_DEVICE_UNKNOWN:
+      *output = ui::INPUT_DEVICE_UNKNOWN;
+      break;
+    default:
+      // Who knows what values might come over the wire, fail if invalid.
+      return false;
+  }
+  return true;
+}
+
+bool StructTraits<ui::mojom::InputDevice, ui::InputDevice>::Read(
+    ui::mojom::InputDeviceDataView data,
+    ui::InputDevice* out) {
+  out->id = data.id();
+
+  if (!data.ReadType(&out->type))
+    return false;
+
+  if (!data.ReadName(&out->name))
+    return false;
+
+  base::StringPiece sys_path_string;
+  if (!data.ReadSysPath(&sys_path_string))
+    return false;
+  out->sys_path = base::FilePath::FromUTF8Unsafe(sys_path_string);
+
+  out->vendor_id = data.vendor_id();
+  out->product_id = data.product_id();
+
+  return true;
+}
+
+bool StructTraits<ui::mojom::TouchscreenDevice, ui::TouchscreenDevice>::Read(
+    ui::mojom::TouchscreenDeviceDataView data,
+    ui::TouchscreenDevice* out) {
+  if (!data.ReadInputDevice(static_cast<ui::InputDevice*>(out)))
+    return false;
+
+  if (!data.ReadSize(&out->size))
+    return false;
+
+  out->touch_points = data.touch_points();
+
+  return true;
+}
+
+}  // namespace mojo
diff --git a/ui/events/devices/mojo/input_device_struct_traits.h b/ui/events/devices/mojo/input_device_struct_traits.h
index d2945bb..c4f890a 100644
--- a/ui/events/devices/mojo/input_device_struct_traits.h
+++ b/ui/events/devices/mojo/input_device_struct_traits.h
@@ -16,18 +16,18 @@
 namespace mojo {
 
 template <>
+struct EnumTraits<ui::mojom::InputDeviceType, ui::InputDeviceType> {
+  static ui::mojom::InputDeviceType ToMojom(ui::InputDeviceType type);
+  static bool FromMojom(ui::mojom::InputDeviceType type,
+                        ui::InputDeviceType* output);
+};
+
+template <>
 struct StructTraits<ui::mojom::InputDevice, ui::InputDevice> {
   static int32_t id(const ui::InputDevice& device) { return device.id; }
 
-  static ui::mojom::InputDeviceType type(const ui::InputDevice& device) {
-    switch (device.type) {
-      case ui::INPUT_DEVICE_INTERNAL:
-        return ui::mojom::InputDeviceType::INPUT_DEVICE_INTERNAL;
-      case ui::INPUT_DEVICE_EXTERNAL:
-        return ui::mojom::InputDeviceType::INPUT_DEVICE_EXTERNAL;
-      case ui::INPUT_DEVICE_UNKNOWN:
-        return ui::mojom::InputDeviceType::INPUT_DEVICE_UNKNOWN;
-    }
+  static ui::InputDeviceType type(const ui::InputDevice& device) {
+    return device.type;
   }
 
   static const std::string& name(const ui::InputDevice& device) {
@@ -46,37 +46,7 @@
     return device.product_id;
   }
 
-  static bool Read(ui::mojom::InputDeviceDataView data, ui::InputDevice* out) {
-    out->id = data.id();
-
-    switch (data.type()) {
-      case ui::mojom::InputDeviceType::INPUT_DEVICE_INTERNAL:
-        out->type = ui::INPUT_DEVICE_INTERNAL;
-        break;
-      case ui::mojom::InputDeviceType::INPUT_DEVICE_EXTERNAL:
-        out->type = ui::INPUT_DEVICE_EXTERNAL;
-        break;
-      case ui::mojom::InputDeviceType::INPUT_DEVICE_UNKNOWN:
-        out->type = ui::INPUT_DEVICE_UNKNOWN;
-        break;
-      default:
-        // Who knows what values might come over the wire, fail if invalid.
-        return false;
-    }
-
-    if (!data.ReadName(&out->name))
-      return false;
-
-    base::StringPiece sys_path_string;
-    if (!data.ReadSysPath(&sys_path_string))
-      return false;
-    out->sys_path = base::FilePath::FromUTF8Unsafe(sys_path_string);
-
-    out->vendor_id = data.vendor_id();
-    out->product_id = data.product_id();
-
-    return true;
-  }
+  static bool Read(ui::mojom::InputDeviceDataView data, ui::InputDevice* out);
 };
 
 template <>
@@ -95,17 +65,7 @@
   }
 
   static bool Read(ui::mojom::TouchscreenDeviceDataView data,
-                   ui::TouchscreenDevice* out) {
-    if (!data.ReadInputDevice(static_cast<ui::InputDevice*>(out)))
-      return false;
-
-    if (!data.ReadSize(&out->size))
-      return false;
-
-    out->touch_points = data.touch_points();
-
-    return true;
-  }
+                   ui::TouchscreenDevice* out);
 };
 
 }  // namespace mojo
diff --git a/ui/events/devices/mojo/touchscreen_device.typemap b/ui/events/devices/mojo/touchscreen_device.typemap
deleted file mode 100644
index 589312f..0000000
--- a/ui/events/devices/mojo/touchscreen_device.typemap
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//ui/events/devices/mojo/input_devices.mojom"
-public_headers = [ "//ui/events/devices/touchscreen_device.h" ]
-traits_headers = [ 
-  "//ui/events/devices/mojo/input_device_struct_traits.h" 
- ]
-public_deps = [
-  "//ui/events/devices",
-]
-deps = [
-  "//ui/gfx/geometry",
-]
-type_mappings = [ "ui.mojom.TouchscreenDevice=ui::TouchscreenDevice" ]
diff --git a/ui/events/devices/mojo/typemaps.gni b/ui/events/devices/mojo/typemaps.gni
index 996a8a5d..7ce719a 100644
--- a/ui/events/devices/mojo/typemaps.gni
+++ b/ui/events/devices/mojo/typemaps.gni
@@ -2,7 +2,4 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-typemaps = [
-  "//ui/events/devices/mojo/input_device.typemap",
-  "//ui/events/devices/mojo/touchscreen_device.typemap",
-]
+typemaps = [ "//ui/events/devices/mojo/input_device.typemap" ]
diff --git a/ui/gl/gl_switches.cc b/ui/gl/gl_switches.cc
index 31030c4e..23fc099 100644
--- a/ui/gl/gl_switches.cc
+++ b/ui/gl/gl_switches.cc
@@ -93,6 +93,11 @@
 // Disables specified comma separated GL Extensions if found.
 const char kDisableGLExtensions[] = "disable-gl-extensions";
 
+// Enables GL_INTEL_framebuffer_CMAA via shaders. Will be used if the platform
+// does not support GL_INTEL_framebuffer_CMAA and the context is at least
+// OpenGL ES 3.1 or OpenGL 3.0 with the required extensions.
+const char kEnableCMAAShaders[] = "enable-cmaa-shaders";
+
 // This is the list of switches passed from this file that are passed from the
 // GpuProcessHost to the GPU Process. Add your switch to this list if you need
 // to read it in the GPU process, else don't add it.
@@ -107,6 +112,7 @@
     kOverrideUseGLWithOSMesaForTests,
     kUseANGLE,
     kDisableDirectComposition,
+    kEnableCMAAShaders,
 };
 const int kGLSwitchesCopiedFromGpuProcessHostNumSwitches =
     arraysize(kGLSwitchesCopiedFromGpuProcessHost);
diff --git a/ui/gl/gl_switches.h b/ui/gl/gl_switches.h
index 6136460b..8f9dd26e 100644
--- a/ui/gl/gl_switches.h
+++ b/ui/gl/gl_switches.h
@@ -54,6 +54,8 @@
 GL_EXPORT extern const char* kGLSwitchesCopiedFromGpuProcessHost[];
 GL_EXPORT extern const int kGLSwitchesCopiedFromGpuProcessHostNumSwitches;
 
+GL_EXPORT extern const char kEnableCMAAShaders[];
+
 }  // namespace switches
 
 #endif  // UI_GL_GL_SWITCHES_H_