diff --git a/DEPS b/DEPS
index 2703e5eb..ee43e20 100644
--- a/DEPS
+++ b/DEPS
@@ -36,11 +36,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': '7e8cc21d574e00d13391da59f00be6bba62c31cd',
+  'skia_revision': 'c42475cea23bfdb22b5d6cad6042577e47bd6a5c',
   # 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': 'a90e831ead0d9623d7bfb3afc6b4f6c7e800f1a4',
+  'v8_revision': '8e8649093cb16688093b49a7046de3d67b8f3068',
   # 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.
@@ -48,7 +48,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '5695fc990fae1897f31bd418f9278e931776abdf',
+  'angle_revision': '8bad46d40e23671d4a723a2daf4ca1e252bb0617',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -56,7 +56,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': 'cfb31d67a40310ed64d942ba346cf0cd3a01cadf',
+  'pdfium_revision': '3c27a84d15c06f85cc7f455f96dc124673f9f9d2',
   # 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.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': '3cab5572b1fcf5a8f6018529dc30dc8d21b2a4bd',
+  'boringssl_revision': '95c69563dc5422c3b3cd3a0bf435944a7530a12d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
@@ -80,7 +80,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': '0949e1bef9d6b25ee44eb69a54e0cc6f8a677375',
+  'nacl_revision': '4623c4f8a10b85cc3c97f7ecb2f7cb48a1da665e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype-android
   # and whatever else without interference from each other.
@@ -88,7 +88,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '9f8a0a8c0d4522f4014fbdba199222d44d638730',
+  'catapult_revision': '7c4d195ab2d092b848cc05c9bd17b38365959588',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -178,7 +178,7 @@
     Var('chromium_git') + '/external/bidichecker/lib.git' + '@' + '97f2aa645b74c28c57eca56992235c79850fa9e0',
 
   'src/third_party/webgl/src':
-   Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '214fe8f93103621c5103eecfbe547f8a10a423f2',
+   Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'fe43b3cad0afb2c5280ed5d23910a6d744976251',
 
   'src/third_party/webdriver/pylib':
     Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd',
@@ -214,7 +214,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' + '@' + 'd0d6cf9a9a302f1af62d0fd188fade3d205525a4', # commit position 13393
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '05929e21d437bc5f80309455f168a9e4bb2bc94b', # commit position 13407
 
   '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 802ac8a..d2245475 100644
--- a/ash/accelerators/accelerator_controller.cc
+++ b/ash/accelerators/accelerator_controller.cc
@@ -903,8 +903,8 @@
     preferred_actions_.insert(kPreferredActions[i]);
   for (size_t i = 0; i < kReservedActionsLength; ++i)
     reserved_actions_.insert(kReservedActions[i]);
-  for (size_t i = 0; i < kNonrepeatableActionsLength; ++i)
-    nonrepeatable_actions_.insert(kNonrepeatableActions[i]);
+  for (size_t i = 0; i < kRepeatableActionsLength; ++i)
+    repeatable_actions_.insert(kRepeatableActions[i]);
   for (size_t i = 0; i < kActionsAllowedInAppModeOrPinnedModeLength; ++i) {
     actions_allowed_in_app_mode_.insert(
         kActionsAllowedInAppModeOrPinnedMode[i]);
@@ -970,10 +970,8 @@
 bool AcceleratorController::CanPerformAction(
     AcceleratorAction action,
     const ui::Accelerator& accelerator) {
-  if (nonrepeatable_actions_.find(action) != nonrepeatable_actions_.end() &&
-      accelerator.IsRepeat()) {
+  if (accelerator.IsRepeat() && !repeatable_actions_.count(action))
     return false;
-  }
 
   AcceleratorProcessingRestriction restriction =
       GetAcceleratorProcessingRestriction(action);
diff --git a/ash/accelerators/accelerator_controller.h b/ash/accelerators/accelerator_controller.h
index 0e6b12e..2ed610d 100644
--- a/ash/accelerators/accelerator_controller.h
+++ b/ash/accelerators/accelerator_controller.h
@@ -205,8 +205,8 @@
   std::set<int> preferred_actions_;
   // Reserved actions. See accelerator_table.h for details.
   std::set<int> reserved_actions_;
-  // Actions which will not be repeated while holding the accelerator key.
-  std::set<int> nonrepeatable_actions_;
+  // Actions which will be repeated while holding the accelerator key.
+  std::set<int> repeatable_actions_;
   // Actions allowed in app mode.
   std::set<int> actions_allowed_in_app_mode_;
   // Actions allowed in pinned mode.
diff --git a/ash/accelerators/accelerator_table.cc b/ash/accelerators/accelerator_table.cc
index 73f26a0..642ceb7 100644
--- a/ash/accelerators/accelerator_table.cc
+++ b/ash/accelerators/accelerator_table.cc
@@ -403,36 +403,25 @@
 const size_t kActionsAllowedAtModalWindowLength =
     arraysize(kActionsAllowedAtModalWindow);
 
-const AcceleratorAction kNonrepeatableActions[] = {
-    // TODO(mazda): Add other actions which should not be repeated.
-    CYCLE_BACKWARD_MRU,
-    CYCLE_FORWARD_MRU,
-    EXIT,
-    NEXT_IME,
-    PREVIOUS_IME,
-    OPEN_FEEDBACK_PAGE,
-    PRINT_UI_HIERARCHIES,  // Don't fill the logs if the key is held down.
-    ROTATE_SCREEN,
-    ROTATE_WINDOW,
-    SCALE_UI_UP,
-    SCALE_UI_DOWN,
-    SCALE_UI_RESET,
-    TAKE_WINDOW_SCREENSHOT,
-    TAKE_PARTIAL_SCREENSHOT,
-    TAKE_SCREENSHOT,
-    TOGGLE_FULLSCREEN,
-    TOGGLE_MAXIMIZED,
-    TOGGLE_OVERVIEW,
-    WINDOW_MINIMIZE,
+const AcceleratorAction kRepeatableActions[] = {
+    FOCUS_NEXT_PANE,
+    FOCUS_PREVIOUS_PANE,
+    MAGNIFY_SCREEN_ZOOM_IN,
+    MAGNIFY_SCREEN_ZOOM_OUT,
+    MEDIA_NEXT_TRACK,
+    MEDIA_PREV_TRACK,
+    RESTORE_TAB,
 #if defined(OS_CHROMEOS)
-    DEBUG_TOGGLE_TOUCH_PAD,
-    DEBUG_TOGGLE_TOUCH_SCREEN,
-    LOCK_SCREEN,
-    SUSPEND,
-#endif
+    BRIGHTNESS_DOWN,
+    BRIGHTNESS_UP,
+    KEYBOARD_BRIGHTNESS_DOWN,
+    KEYBOARD_BRIGHTNESS_UP,
+    VOLUME_DOWN,
+    VOLUME_UP,
+#endif  // defined(OS_CHROMEOS)
 };
 
-const size_t kNonrepeatableActionsLength = arraysize(kNonrepeatableActions);
+const size_t kRepeatableActionsLength = arraysize(kRepeatableActions);
 
 const AcceleratorAction kActionsAllowedInAppModeOrPinnedMode[] = {
     DEBUG_PRINT_LAYER_HIERARCHY,
diff --git a/ash/accelerators/accelerator_table.h b/ash/accelerators/accelerator_table.h
index 6c4add763..7d40cf6 100644
--- a/ash/accelerators/accelerator_table.h
+++ b/ash/accelerators/accelerator_table.h
@@ -233,9 +233,9 @@
 ASH_EXPORT extern const AcceleratorAction kActionsAllowedAtModalWindow[];
 ASH_EXPORT extern const size_t kActionsAllowedAtModalWindowLength;
 
-// Actions which will not be repeated while holding an accelerator key.
-ASH_EXPORT extern const AcceleratorAction kNonrepeatableActions[];
-ASH_EXPORT extern const size_t kNonrepeatableActionsLength;
+// Actions which may be repeated by holding an accelerator key.
+ASH_EXPORT extern const AcceleratorAction kRepeatableActions[];
+ASH_EXPORT extern const size_t kRepeatableActionsLength;
 
 // Actions allowed in app mode or pinned mode.
 ASH_EXPORT extern const AcceleratorAction
diff --git a/ash/accelerators/accelerator_table_unittest.cc b/ash/accelerators/accelerator_table_unittest.cc
index 95329282..4bb8c86 100644
--- a/ash/accelerators/accelerator_table_unittest.cc
+++ b/ash/accelerators/accelerator_table_unittest.cc
@@ -66,12 +66,11 @@
   }
 }
 
-TEST(AcceleratorTableTest, CheckDuplicatedNonrepeatableActions) {
+TEST(AcceleratorTableTest, CheckDuplicatedRepeatableActions) {
   std::set<AcceleratorAction> actions;
-  for (size_t i = 0; i < kNonrepeatableActionsLength; ++i) {
-    EXPECT_TRUE(actions.insert(kNonrepeatableActions[i]).second)
-        << "Duplicated action: " << kNonrepeatableActions[i]
-        << " at index: " << i;
+  for (size_t i = 0; i < kRepeatableActionsLength; ++i) {
+    EXPECT_TRUE(actions.insert(kRepeatableActions[i]).second)
+        << "Duplicated action: " << kRepeatableActions[i] << " at index: " << i;
   }
 }
 
diff --git a/ash/accelerators/exit_warning_handler.h b/ash/accelerators/exit_warning_handler.h
index 9a4c93f..c678f84d 100644
--- a/ash/accelerators/exit_warning_handler.h
+++ b/ash/accelerators/exit_warning_handler.h
@@ -18,16 +18,15 @@
 
 namespace ash {
 
-// In order to avoid accidental exits when the user presses the exit
-// shortcut by mistake, we require the user press it twice within a
-// period of time. During that time we show a popup informing the
-// user of this.
+// In order to avoid accidental exits when the user presses the exit shortcut by
+// mistake, we require that the user press it twice within a short period of
+// time. During that time we show a popup informing the user of this.
 //
 // Notes:
 //
-// The corresponding accelerator must be non-repeatable (see
-// kNonrepeatableActions in accelerator_table.cc). Otherwise the "Double Press
-// Exit" will be activated just by holding it down, i.e. probably every time.
+// The corresponding accelerator must not be repeatable (see kRepeatableActions
+// in accelerator_table.cc). Otherwise, the "Double Press Exit" will be
+// activated just by holding it down, i.e. probably every time.
 //
 // State Transition Diagrams:
 //
diff --git a/ash/ash.gyp b/ash/ash.gyp
index c352832..d2dce7d 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -77,6 +77,8 @@
       'common/metrics/user_metrics_action.h',
       'common/multi_profile_uma.cc',
       'common/multi_profile_uma.h',
+      'common/popup_message.cc',
+      'common/popup_message.h',
       'common/root_window_controller_common.cc',
       'common/root_window_controller_common.h',
       'common/session/session_state_delegate.cc',
@@ -281,9 +283,15 @@
       'common/system/user/login_status.h',
       'common/system/user/rounded_image_view.cc',
       'common/system/user/rounded_image_view.h',
+      'common/system/user/tray_user.cc',
+      'common/system/user/tray_user.h',
       'common/system/user/tray_user_separator.cc',
       'common/system/user/tray_user_separator.h',
+      'common/system/user/user_card_view.cc',
+      'common/system/user/user_card_view.h',
       'common/system/user/user_observer.h',
+      'common/system/user/user_view.cc',
+      'common/system/user/user_view.h',
       'common/system/volume_control_delegate.h',
       'common/system/web_notification/ash_popup_alignment_delegate.cc',
       'common/system/web_notification/ash_popup_alignment_delegate.h',
@@ -536,8 +544,6 @@
       'pointer_watcher_delegate.h',
       'pointer_watcher_delegate_aura.cc',
       'pointer_watcher_delegate_aura.h',
-      'popup_message.cc',
-      'popup_message.h',
       'root_window_controller.cc',
       'root_window_controller.h',
       'root_window_settings.cc',
@@ -636,12 +642,6 @@
       'system/toast/toast_overlay.h',
       'system/tray/system_tray.cc',
       'system/tray/system_tray.h',
-      'system/user/tray_user.cc',
-      'system/user/tray_user.h',
-      'system/user/user_card_view.cc',
-      'system/user/user_card_view.h',
-      'system/user/user_view.cc',
-      'system/user/user_view.h',
       'touch/touch_hud_debug.cc',
       'touch/touch_hud_debug.h',
       'touch/touch_hud_projection.cc',
@@ -897,6 +897,7 @@
       'autoclick/autoclick_unittest.cc',
       'common/display/display_info_unittest.cc',
       'common/material_design/material_design_controller_unittest.cc',
+      'common/popup_message_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',
@@ -909,6 +910,7 @@
       'common/system/ime/tray_ime_chromeos_unittest.cc',
       'common/system/tray/tray_details_view_unittest.cc',
       'common/system/update/tray_update_unittest.cc',
+      'common/system/user/tray_user_unittest.cc',
       'content/display/screen_orientation_controller_chromeos_unittest.cc',
       'content/keyboard_overlay/keyboard_overlay_delegate_unittest.cc',
       'content/keyboard_overlay/keyboard_overlay_view_unittest.cc',
@@ -945,7 +947,6 @@
       'metrics/task_switch_metrics_recorder_unittest.cc',
       'metrics/task_switch_time_tracker_unittest.cc',
       'metrics/user_metrics_recorder_unittest.cc',
-      'popup_message_unittest.cc',
       'root_window_controller_unittest.cc',
       'rotator/screen_rotation_animation_unittest.cc',
       'screen_util_unittest.cc',
@@ -971,7 +972,6 @@
       'system/overview/overview_button_tray_unittest.cc',
       'system/toast/toast_manager_unittest.cc',
       'system/tray/system_tray_unittest.cc',
-      'system/user/tray_user_unittest.cc',
       'system/web_notification/ash_popup_alignment_delegate_unittest.cc',
       'system/web_notification/web_notification_tray_unittest.cc',
       'test/ash_test_helper_unittest.cc',
diff --git a/ash/ash_touch_exploration_manager_chromeos.cc b/ash/ash_touch_exploration_manager_chromeos.cc
index ff01bd71..7e60f17 100644
--- a/ash/ash_touch_exploration_manager_chromeos.cc
+++ b/ash/ash_touch_exploration_manager_chromeos.cc
@@ -63,8 +63,10 @@
   if (!VolumeAdjustSoundEnabled())
     return;
   if (!audio_handler_->IsOutputMuted() &&
-      audio_handler_->GetOutputVolumePercent() != 100)
-    PlaySystemSoundIfSpokenFeedback(chromeos::SOUND_VOLUME_ADJUST);
+      audio_handler_->GetOutputVolumePercent() != 100) {
+    WmShell::Get()->GetAccessibilityDelegate()->PlayEarcon(
+        chromeos::SOUND_VOLUME_ADJUST);
+  }
 }
 
 void AshTouchExplorationManager::PlayPassthroughEarcon() {
diff --git a/ash/common/DEPS b/ash/common/DEPS
index 1412c1f7..a1417d7 100644
--- a/ash/common/DEPS
+++ b/ash/common/DEPS
@@ -5,3 +5,9 @@
   "+ui",
   "-ui/aura",
 ]
+
+specific_include_rules = {
+  ".*test\.cc": [
+    "+ash/test",
+  ]
+}
\ No newline at end of file
diff --git a/ash/ash_view_ids.h b/ash/common/ash_view_ids.h
similarity index 74%
rename from ash/ash_view_ids.h
rename to ash/common/ash_view_ids.h
index 61bf3cf..ed63b56 100644
--- a/ash/ash_view_ids.h
+++ b/ash/common/ash_view_ids.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_ASH_VIEW_IDS_H_
-#define ASH_ASH_VIEW_IDS_H_
+#ifndef ASH_COMMON_ASH_VIEW_IDS_H_
+#define ASH_COMMON_ASH_VIEW_IDS_H_
 
 namespace ash {
 
@@ -15,4 +15,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_ASH_VIEW_IDS_H_
+#endif  // ASH_COMMON_ASH_VIEW_IDS_H_
diff --git a/ash/popup_message.cc b/ash/common/popup_message.cc
similarity index 93%
rename from ash/popup_message.cc
rename to ash/common/popup_message.cc
index 231e4da..f745499 100644
--- a/ash/popup_message.cc
+++ b/ash/common/popup_message.cc
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/popup_message.h"
+#include "ash/common/popup_message.h"
 
-#include "ash/wm/window_animations.h"
+#include "ash/common/wm_lookup.h"
+#include "ash/common/wm_window.h"
 #include "grit/ash_resources.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/geometry/insets.h"
@@ -14,6 +15,7 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/widget/widget.h"
+#include "ui/wm/core/window_animations.h"
 
 namespace ash {
 namespace {
@@ -199,11 +201,10 @@
   view_ = new MessageBubble(caption, message, message_type, anchor, arrow,
                             size_override, arrow_offset);
   widget_ = view_->GetWidget();
-
-  gfx::NativeView native_view = widget_->GetNativeView();
-  wm::SetWindowVisibilityAnimationType(
-      native_view, wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL);
-  wm::SetWindowVisibilityAnimationTransition(native_view, wm::ANIMATE_HIDE);
+  WmWindow* window = WmLookup::Get()->GetWindowForWidget(widget_);
+  window->SetVisibilityAnimationType(
+      ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL);
+  window->SetVisibilityAnimationTransition(::wm::ANIMATE_HIDE);
   view_->GetWidget()->Show();
 }
 
@@ -221,11 +222,12 @@
 }
 
 void PopupMessage::CancelHidingAnimation() {
-  if (!widget_ || !widget_->GetNativeView())
+  if (!widget_)
     return;
 
-  gfx::NativeView native_view = widget_->GetNativeView();
-  wm::SetWindowVisibilityAnimationTransition(native_view, wm::ANIMATE_NONE);
+  WmWindow* window = WmLookup::Get()->GetWindowForWidget(widget_);
+  if (window)
+    window->SetVisibilityAnimationTransition(::wm::ANIMATE_NONE);
 }
 
 }  // namespace ash
diff --git a/ash/popup_message.h b/ash/common/popup_message.h
similarity index 95%
rename from ash/popup_message.h
rename to ash/common/popup_message.h
index 5da93d0..c31e2c1 100644
--- a/ash/popup_message.h
+++ b/ash/common/popup_message.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_POPUP_MESSAGE_H_
-#define ASH_POPUP_MESSAGE_H_
+#ifndef ASH_COMMON_POPUP_MESSAGE_H_
+#define ASH_COMMON_POPUP_MESSAGE_H_
 
 #include "ash/ash_export.h"
 #include "base/gtest_prod_util.h"
@@ -79,4 +79,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_POPUP_MESSAGE_H_
+#endif  // ASH_COMMON_POPUP_MESSAGE_H_
diff --git a/ash/popup_message_unittest.cc b/ash/common/popup_message_unittest.cc
similarity index 97%
rename from ash/popup_message_unittest.cc
rename to ash/common/popup_message_unittest.cc
index 90559c0e..9bdcce0 100644
--- a/ash/popup_message_unittest.cc
+++ b/ash/common/popup_message_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/popup_message.h"
+#include "ash/common/popup_message.h"
 
 #include "ash/test/ash_test_base.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ash/common/system/DEPS b/ash/common/system/DEPS
index d0d4503..cb8bd0b5 100644
--- a/ash/common/system/DEPS
+++ b/ash/common/system/DEPS
@@ -3,10 +3,4 @@
 include_rules = [
   # TODO(jamescook): Remove this.
   "+ash/system/tray/system_tray.h",
-]
-
-specific_include_rules = {
-  ".*test\.cc": [
-    "+ash/test",
-  ]
-}
+]
\ No newline at end of file
diff --git a/ash/system/user/tray_user.cc b/ash/common/system/user/tray_user.cc
similarity index 98%
rename from ash/system/user/tray_user.cc
rename to ash/common/system/user/tray_user.cc
index e0699c1a..4633076 100644
--- a/ash/system/user/tray_user.cc
+++ b/ash/common/system/user/tray_user.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/user/tray_user.h"
+#include "ash/common/system/user/tray_user.h"
 
 #include "ash/common/ash_switches.h"
 #include "ash/common/session/session_state_delegate.h"
@@ -13,9 +13,9 @@
 #include "ash/common/system/tray/tray_item_view.h"
 #include "ash/common/system/tray/tray_utils.h"
 #include "ash/common/system/user/rounded_image_view.h"
+#include "ash/common/system/user/user_view.h"
 #include "ash/common/wm_shell.h"
 #include "ash/system/tray/system_tray.h"
-#include "ash/system/user/user_view.h"
 #include "base/logging.h"
 #include "base/strings/string16.h"
 #include "components/signin/core/account_id/account_id.h"
diff --git a/ash/system/user/tray_user.h b/ash/common/system/user/tray_user.h
similarity index 95%
rename from ash/system/user/tray_user.h
rename to ash/common/system/user/tray_user.h
index 897cb81..1373db3 100644
--- a/ash/system/user/tray_user.h
+++ b/ash/common/system/user/tray_user.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_USER_TRAY_USER_H_
-#define ASH_SYSTEM_USER_TRAY_USER_H_
+#ifndef ASH_COMMON_SYSTEM_USER_TRAY_USER_H_
+#define ASH_COMMON_SYSTEM_USER_TRAY_USER_H_
 
 #include "ash/ash_export.h"
 #include "ash/common/session/session_types.h"
@@ -93,4 +93,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_SYSTEM_USER_TRAY_USER_H_
+#endif  // ASH_COMMON_SYSTEM_USER_TRAY_USER_H_
diff --git a/ash/system/user/tray_user_unittest.cc b/ash/common/system/user/tray_user_unittest.cc
similarity index 94%
rename from ash/system/user/tray_user_unittest.cc
rename to ash/common/system/user/tray_user_unittest.cc
index 39adf62..b55ab9a 100644
--- a/ash/system/user/tray_user_unittest.cc
+++ b/ash/common/system/user/tray_user_unittest.cc
@@ -6,13 +6,11 @@
 
 #include "ash/common/shell_delegate.h"
 #include "ash/common/system/tray/tray_constants.h"
+#include "ash/common/system/user/tray_user.h"
 #include "ash/common/system/user/tray_user_separator.h"
+#include "ash/common/system/user/user_view.h"
 #include "ash/common/wm_shell.h"
-#include "ash/root_window_controller.h"
-#include "ash/shell.h"
 #include "ash/system/tray/system_tray.h"
-#include "ash/system/user/tray_user.h"
-#include "ash/system/user/user_view.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
 #include "ash/test/test_session_state_delegate.h"
@@ -69,7 +67,7 @@
 
 void TrayUserTest::SetUp() {
   test::AshTestBase::SetUp();
-  tray_ = Shell::GetPrimaryRootWindowController()->GetSystemTray();
+  tray_ = GetPrimarySystemTray();
   delegate_ = test::AshTestHelper::GetTestSessionStateDelegate();
 }
 
@@ -132,7 +130,7 @@
   InitializeParameters(1, false);
 
   // Move the mouse over the status area and click to open the status menu.
-  ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
+  ui::test::EventGenerator& generator = GetEventGenerator();
 
   EXPECT_FALSE(tray()->IsAnyBubbleVisible());
 
@@ -154,7 +152,7 @@
 
 TEST_F(TrayUserTest, AccessibleLabelContainsSingleUserInfo) {
   InitializeParameters(1, false);
-  ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
+  ui::test::EventGenerator& generator = GetEventGenerator();
   ShowTrayMenu(&generator);
 
   views::View* view =
@@ -169,7 +167,7 @@
 
 TEST_F(TrayUserTest, AccessibleLabelContainsMultiUserInfo) {
   InitializeParameters(1, true);
-  ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
+  ui::test::EventGenerator& generator = GetEventGenerator();
   ShowTrayMenu(&generator);
 
   views::View* view =
@@ -191,7 +189,7 @@
   InitializeParameters(1, true);
 
   // Move the mouse over the status area and click to open the status menu.
-  ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
+  ui::test::EventGenerator& generator = GetEventGenerator();
   generator.set_async(false);
 
   int max_users = delegate()->GetMaximumNumberOfLoggedInUsers();
@@ -250,7 +248,7 @@
 TEST_F(TrayUserTest, MutiUserModeButtonClicks) {
   // Have two users.
   InitializeParameters(2, true);
-  ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
+  ui::test::EventGenerator& generator = GetEventGenerator();
   ShowTrayMenu(&generator);
 
   // Switch to a new user - which has a capitalized name.
diff --git a/ash/system/user/user_card_view.cc b/ash/common/system/user/user_card_view.cc
similarity index 99%
rename from ash/system/user/user_card_view.cc
rename to ash/common/system/user/user_card_view.cc
index 8356091..77e228023 100644
--- a/ash/system/user/user_card_view.cc
+++ b/ash/common/system/user/user_card_view.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/user/user_card_view.h"
+#include "ash/common/system/user/user_card_view.h"
 
 #include <algorithm>
 #include <vector>
@@ -39,7 +39,7 @@
 #include "ui/views/layout/box_layout.h"
 
 #if defined(OS_CHROMEOS)
-#include "ash/ash_view_ids.h"
+#include "ash/common/ash_view_ids.h"
 #include "ash/common/media_delegate.h"
 #include "ash/common/system/chromeos/media_security/media_capture_observer.h"
 #include "ui/views/controls/image_view.h"
diff --git a/ash/system/user/user_card_view.h b/ash/common/system/user/user_card_view.h
similarity index 87%
rename from ash/system/user/user_card_view.h
rename to ash/common/system/user/user_card_view.h
index 2d9584b..07504af 100644
--- a/ash/system/user/user_card_view.h
+++ b/ash/common/system/user/user_card_view.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_USER_USER_CARD_VIEW_H_
-#define ASH_SYSTEM_USER_USER_CARD_VIEW_H_
+#ifndef ASH_COMMON_SYSTEM_USER_USER_CARD_VIEW_H_
+#define ASH_COMMON_SYSTEM_USER_USER_CARD_VIEW_H_
 
 #include "base/macros.h"
 #include "ui/views/view.h"
@@ -40,4 +40,4 @@
 }  // namespace tray
 }  // namespace ash
 
-#endif  // ASH_SYSTEM_USER_USER_CARD_VIEW_H_
+#endif  // ASH_COMMON_SYSTEM_USER_USER_CARD_VIEW_H_
diff --git a/ash/system/user/user_view.cc b/ash/common/system/user/user_view.cc
similarity index 99%
rename from ash/system/user/user_view.cc
rename to ash/common/system/user/user_view.cc
index ae1526f..6bbb6a2 100644
--- a/ash/system/user/user_view.cc
+++ b/ash/common/system/user/user_view.cc
@@ -2,12 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/system/user/user_view.h"
+#include "ash/common/system/user/user_view.h"
 
 #include <algorithm>
 #include <utility>
 
 #include "ash/common/multi_profile_uma.h"
+#include "ash/common/popup_message.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/shell_delegate.h"
 #include "ash/common/shell_window_ids.h"
@@ -18,13 +19,12 @@
 #include "ash/common/system/user/button_from_view.h"
 #include "ash/common/system/user/login_status.h"
 #include "ash/common/system/user/rounded_image_view.h"
+#include "ash/common/system/user/user_card_view.h"
 #include "ash/common/wm_lookup.h"
 #include "ash/common/wm_root_window_controller.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/popup_message.h"
 #include "ash/system/tray/system_tray.h"
-#include "ash/system/user/user_card_view.h"
 #include "components/signin/core/account_id/account_id.h"
 #include "components/user_manager/user_info.h"
 #include "grit/ash_resources.h"
diff --git a/ash/system/user/user_view.h b/ash/common/system/user/user_view.h
similarity index 93%
rename from ash/system/user/user_view.h
rename to ash/common/system/user/user_view.h
index 8972db4..69b2673 100644
--- a/ash/system/user/user_view.h
+++ b/ash/common/system/user/user_view.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_SYSTEM_USER_USER_VIEW_H_
-#define ASH_SYSTEM_USER_USER_VIEW_H_
+#ifndef ASH_COMMON_SYSTEM_USER_USER_VIEW_H_
+#define ASH_COMMON_SYSTEM_USER_USER_VIEW_H_
 
 #include <memory>
 
 #include "ash/common/session/session_types.h"
 #include "ash/common/system/tray/tray_constants.h"
-#include "ash/system/user/tray_user.h"
+#include "ash/common/system/user/tray_user.h"
 #include "base/macros.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/focus/focus_manager.h"
@@ -104,4 +104,4 @@
 }  // namespace tray
 }  // namespace ash
 
-#endif  // ASH_SYSTEM_USER_USER_VIEW_H_
+#endif  // ASH_COMMON_SYSTEM_USER_USER_VIEW_H_
diff --git a/ash/display/screen_orientation_controller_chromeos.cc b/ash/display/screen_orientation_controller_chromeos.cc
index 5c11a35..10afdd43 100644
--- a/ash/display/screen_orientation_controller_chromeos.cc
+++ b/ash/display/screen_orientation_controller_chromeos.cc
@@ -112,6 +112,16 @@
   ApplyLockForActiveWindow();
 }
 
+void ScreenOrientationController::UnlockAll() {
+  for (auto pair : locking_windows_)
+    pair.first->RemoveObserver(this);
+  locking_windows_.clear();
+  Shell::GetInstance()->activation_client()->RemoveObserver(this);
+  SetRotationLocked(false);
+  if (user_rotation_ != current_rotation_)
+    SetDisplayRotation(user_rotation_, display::Display::ROTATION_SOURCE_USER);
+}
+
 bool ScreenOrientationController::ScreenOrientationProviderSupported() const {
   return WmShell::Get()
              ->maximize_mode_controller()
@@ -386,11 +396,13 @@
 void ScreenOrientationController::ApplyLockForActiveWindow() {
   aura::Window* active_window =
       Shell::GetInstance()->activation_client()->GetActiveWindow();
-  for (auto const& windows : locking_windows_) {
-    if (windows.first->TargetVisibility() &&
-        active_window->Contains(windows.first)) {
-      LockRotationToOrientation(windows.second);
-      return;
+  if (active_window) {
+    for (auto const& windows : locking_windows_) {
+      if (windows.first->TargetVisibility() &&
+          active_window->Contains(windows.first)) {
+        LockRotationToOrientation(windows.second);
+        return;
+      }
     }
   }
   SetRotationLocked(false);
diff --git a/ash/display/screen_orientation_controller_chromeos.h b/ash/display/screen_orientation_controller_chromeos.h
index 1f1fcff..3b92826 100644
--- a/ash/display/screen_orientation_controller_chromeos.h
+++ b/ash/display/screen_orientation_controller_chromeos.h
@@ -57,6 +57,9 @@
       blink::WebScreenOrientationLockType lock_orientation);
   void UnlockOrientationForWindow(aura::Window* window);
 
+  // Unlock all and set the rotation back to the user specified rotation.
+  void UnlockAll();
+
   bool ScreenOrientationProviderSupported() const;
 
   bool ignore_display_configuration_updates() const {
diff --git a/ash/mus/BUILD.gn b/ash/mus/BUILD.gn
index ff000bed..f9d57e6 100644
--- a/ash/mus/BUILD.gn
+++ b/ash/mus/BUILD.gn
@@ -104,6 +104,10 @@
     "//ui/views",
     "//ui/views/mus:for_mojo_application",
   ]
+
+  if (is_chromeos) {
+    deps += [ "//chromeos" ]
+  }
 }
 
 mojo_native_application("mus") {
@@ -180,7 +184,7 @@
     "//base",
     "//base/test:test_config",
     "//mojo/public/cpp/system",
-    "//services/shell/public/cpp:shell_test_support",
+    "//services/shell/public/cpp:service_test_support",
     "//services/ui/common:mus_common",
     "//services/ui/public/cpp",
     "//services/ui/public/cpp/tests:test_support",
diff --git a/ash/mus/accelerator_registrar_unittest.cc b/ash/mus/accelerator_registrar_unittest.cc
index 3d970eb..97dc91b 100644
--- a/ash/mus/accelerator_registrar_unittest.cc
+++ b/ash/mus/accelerator_registrar_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "mojo/public/cpp/bindings/binding.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_test.h"
 #include "services/ui/common/event_matcher_util.h"
 #include "services/ui/public/cpp/window.h"
 #include "services/ui/public/interfaces/accelerator_registrar.mojom.h"
@@ -67,9 +67,9 @@
   DISALLOW_COPY_AND_ASSIGN(TestAcceleratorHandler);
 };
 
-class AcceleratorRegistrarTest : public shell::test::ShellTest {
+class AcceleratorRegistrarTest : public shell::test::ServiceTest {
  public:
-  AcceleratorRegistrarTest() : shell::test::ShellTest("exe:mash_unittests") {}
+  AcceleratorRegistrarTest() : shell::test::ServiceTest("exe:mash_unittests") {}
   ~AcceleratorRegistrarTest() override {}
 
  protected:
diff --git a/ash/mus/app_launch_unittest.cc b/ash/mus/app_launch_unittest.cc
index 449cbebf..b11bb3b 100644
--- a/ash/mus/app_launch_unittest.cc
+++ b/ash/mus/app_launch_unittest.cc
@@ -5,7 +5,7 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/run_loop.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_test.h"
 #include "services/ui/public/interfaces/window_server_test.mojom.h"
 
 namespace ash {
@@ -16,15 +16,15 @@
   callback.Run();
 }
 
-class AppLaunchTest : public shell::test::ShellTest {
+class AppLaunchTest : public shell::test::ServiceTest {
  public:
-  AppLaunchTest() : ShellTest("exe:mash_unittests") {}
+  AppLaunchTest() : ServiceTest("exe:mash_unittests") {}
   ~AppLaunchTest() override {}
 
  private:
   void SetUp() override {
     base::CommandLine::ForCurrentProcess()->AppendSwitch("use-test-config");
-    ShellTest::SetUp();
+    ServiceTest::SetUp();
   }
 
   DISALLOW_COPY_AND_ASSIGN(AppLaunchTest);
diff --git a/ash/mus/bridge/wm_shell_mus.cc b/ash/mus/bridge/wm_shell_mus.cc
index 6c42ca3..582e750 100644
--- a/ash/mus/bridge/wm_shell_mus.cc
+++ b/ash/mus/bridge/wm_shell_mus.cc
@@ -99,6 +99,8 @@
   client_->AddObserver(this);
   WmShell::Set(this);
 
+  CreateMaximizeModeController();
+
   CreateMruWindowTracker();
 
   accessibility_delegate_.reset(new DefaultAccessibilityDelegate);
@@ -108,6 +110,9 @@
 WmShellMus::~WmShellMus() {
   // This order mirrors that of Shell.
 
+  // Destroy maximize mode controller early on since it has some observers which
+  // need to be removed.
+  DeleteMaximizeModeController();
   DeleteSystemTrayDelegate();
   DeleteWindowSelectorController();
   DeleteMruWindowTracker();
diff --git a/ash/mus/container_ids.cc b/ash/mus/container_ids.cc
index cd724707..e3407fdf 100644
--- a/ash/mus/container_ids.cc
+++ b/ash/mus/container_ids.cc
@@ -36,6 +36,9 @@
 
     case Container::DRAG_AND_TOOLTIPS:
       return kShellWindowId_DragImageAndTooltipContainer;
+
+    case Container::OVERLAY:
+      return kShellWindowId_OverlayContainer;
   }
   return kShellWindowId_Invalid;
 }
diff --git a/ash/mus/window_manager_application.cc b/ash/mus/window_manager_application.cc
index aeef95e..ac84148 100644
--- a/ash/mus/window_manager_application.cc
+++ b/ash/mus/window_manager_application.cc
@@ -23,6 +23,10 @@
 #include "ui/events/event.h"
 #include "ui/views/mus/aura_init.h"
 
+#if defined(OS_CHROMEOS)
+#include "chromeos/dbus/dbus_thread_manager.h"
+#endif
+
 namespace ash {
 namespace mus {
 
@@ -40,6 +44,10 @@
   // Destroy the WindowManager while still valid. This way we ensure
   // OnWillDestroyRootWindowController() is called (if it hasn't been already).
   window_manager_.reset();
+
+#if defined(OS_CHROMEOS)
+  chromeos::DBusThreadManager::Shutdown();
+#endif
 }
 
 void WindowManagerApplication::OnAcceleratorRegistrarDestroyed(
@@ -49,6 +57,11 @@
 
 void WindowManagerApplication::InitWindowManager(
     ::ui::WindowTreeClient* window_tree_client) {
+#if defined(OS_CHROMEOS)
+  // Must occur after mojo::ApplicationRunner has initialized AtExitManager, but
+  // before WindowManager::Init().
+  chromeos::DBusThreadManager::Initialize();
+#endif
   window_manager_->Init(window_tree_client);
   window_manager_->AddObserver(this);
 }
diff --git a/ash/mus/window_manager_unittest.cc b/ash/mus/window_manager_unittest.cc
index 5400deb7d..d084d1d 100644
--- a/ash/mus/window_manager_unittest.cc
+++ b/ash/mus/window_manager_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_test.h"
 #include "services/ui/public/cpp/window.h"
 #include "services/ui/public/cpp/window_tree_client.h"
 #include "services/ui/public/cpp/window_tree_client_delegate.h"
@@ -34,9 +34,9 @@
   DISALLOW_COPY_AND_ASSIGN(WindowTreeClientDelegate);
 };
 
-class WindowManagerTest : public shell::test::ShellTest {
+class WindowManagerTest : public shell::test::ServiceTest {
  public:
-  WindowManagerTest() : shell::test::ShellTest("exe:mash_unittests") {}
+  WindowManagerTest() : shell::test::ServiceTest("exe:mash_unittests") {}
   ~WindowManagerTest() override {}
 
  private:
diff --git a/ash/public/interfaces/OWNERS b/ash/public/interfaces/OWNERS
new file mode 100644
index 0000000..08850f4
--- /dev/null
+++ b/ash/public/interfaces/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/ash/public/interfaces/container.mojom b/ash/public/interfaces/container.mojom
index e0269a1..e49b830 100644
--- a/ash/public/interfaces/container.mojom
+++ b/ash/public/interfaces/container.mojom
@@ -20,6 +20,7 @@
   BUBBLES,
   MENUS,
   DRAG_AND_TOOLTIPS,
+  OVERLAY,
 };
 
 const string kWindowContainer_Property = "ash:window-container";
diff --git a/ash/resources/default_100_percent/common/multi_window_resize_horizontal.png b/ash/resources/default_100_percent/common/multi_window_resize_horizontal.png
index 0f17aa9d..00900cb 100644
--- a/ash/resources/default_100_percent/common/multi_window_resize_horizontal.png
+++ b/ash/resources/default_100_percent/common/multi_window_resize_horizontal.png
Binary files differ
diff --git a/ash/resources/default_100_percent/common/multi_window_resize_vertical.png b/ash/resources/default_100_percent/common/multi_window_resize_vertical.png
index 7dceda4..cc4632a 100644
--- a/ash/resources/default_100_percent/common/multi_window_resize_vertical.png
+++ b/ash/resources/default_100_percent/common/multi_window_resize_vertical.png
Binary files differ
diff --git a/ash/resources/default_200_percent/common/multi_window_resize_horizontal.png b/ash/resources/default_200_percent/common/multi_window_resize_horizontal.png
new file mode 100644
index 0000000..4f1f5b3a
--- /dev/null
+++ b/ash/resources/default_200_percent/common/multi_window_resize_horizontal.png
Binary files differ
diff --git a/ash/resources/default_200_percent/common/multi_window_resize_vertical.png b/ash/resources/default_200_percent/common/multi_window_resize_vertical.png
index 80f7d62e..04f3969 100644
--- a/ash/resources/default_200_percent/common/multi_window_resize_vertical.png
+++ b/ash/resources/default_200_percent/common/multi_window_resize_vertical.png
Binary files differ
diff --git a/ash/shelf/app_list_button.cc b/ash/shelf/app_list_button.cc
index b93bb87..a4b1f37 100644
--- a/ash/shelf/app_list_button.cc
+++ b/ash/shelf/app_list_button.cc
@@ -56,11 +56,17 @@
 AppListButton::~AppListButton() {}
 
 void AppListButton::OnAppListShown() {
-  AnimateInkDrop(views::InkDropState::ACTIVATED, nullptr);
+  if (ash::MaterialDesignController::IsShelfMaterial())
+    AnimateInkDrop(views::InkDropState::ACTIVATED, nullptr);
+  else
+    SchedulePaint();
 }
 
 void AppListButton::OnAppListDismissed() {
-  AnimateInkDrop(views::InkDropState::DEACTIVATED, nullptr);
+  if (ash::MaterialDesignController::IsShelfMaterial())
+    AnimateInkDrop(views::InkDropState::DEACTIVATED, nullptr);
+  else
+    SchedulePaint();
 }
 
 bool AppListButton::OnMousePressed(const ui::MouseEvent& event) {
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 964a8b69..00287912 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -380,7 +380,6 @@
       cancelling_drag_model_changed_(false),
       last_hidden_index_(0),
       closing_event_time_(base::TimeTicks()),
-      got_deleted_(nullptr),
       drag_and_drop_item_pinned_(false),
       drag_and_drop_shelf_id_(0),
       drag_replaced_view_(nullptr),
@@ -403,10 +402,6 @@
 ShelfView::~ShelfView() {
   bounds_animator_->RemoveObserver(this);
   model_->RemoveObserver(this);
-  // If we are inside the MenuRunner, we need to know if we were getting
-  // deleted while it was running.
-  if (got_deleted_)
-    *got_deleted_ = true;
 }
 
 void ShelfView::Init() {
@@ -1593,7 +1588,7 @@
 
 void ShelfView::ShelfItemRemoved(int model_index, ShelfID id) {
   if (id == context_menu_id_)
-    launcher_menu_runner_.reset();
+    launcher_menu_runner_->Cancel();
   {
     base::AutoReset<bool> cancelling_drag(&cancelling_drag_model_changed_,
                                           true);
@@ -1705,57 +1700,58 @@
   last_pressed_index_ = view_model_->GetIndexOfView(sender);
   DCHECK_LT(-1, last_pressed_index_);
 
-  {
-    ScopedTargetRootWindow scoped_target(
-        sender->GetWidget()->GetNativeView()->GetRootWindow());
-    // Slow down activation animations if shift key is pressed.
-    std::unique_ptr<ui::ScopedAnimationDurationScaleMode> slowing_animations;
-    if (event.IsShiftDown()) {
-      slowing_animations.reset(new ui::ScopedAnimationDurationScaleMode(
-          ui::ScopedAnimationDurationScaleMode::SLOW_DURATION));
-    }
-
-    // Collect usage statistics before we decide what to do with the click.
-    switch (model_->items()[last_pressed_index_].type) {
-      case TYPE_APP_SHORTCUT:
-      case TYPE_WINDOWED_APP:
-      case TYPE_PLATFORM_APP:
-      case TYPE_BROWSER_SHORTCUT:
-        WmShell::Get()->RecordUserMetricsAction(UMA_LAUNCHER_CLICK_ON_APP);
-        break;
-
-      case TYPE_APP_LIST:
-        WmShell::Get()->RecordUserMetricsAction(
-            UMA_LAUNCHER_CLICK_ON_APPLIST_BUTTON);
-        break;
-
-      case TYPE_APP_PANEL:
-      case TYPE_DIALOG:
-      case TYPE_IME_MENU:
-        break;
-
-      case TYPE_UNDEFINED:
-        NOTREACHED() << "ShelfItemType must be set.";
-        break;
-    }
-
-    ShelfItemDelegate::PerformedAction performed_action =
-        item_manager_
-            ->GetShelfItemDelegate(model_->items()[last_pressed_index_].id)
-            ->ItemSelected(event);
-
-    shelf_button_pressed_metric_tracker_.ButtonPressed(event, sender,
-                                                       performed_action);
-
-    // For the app list menu no TRIGGERED ink drop effect is needed and it
-    // handles its own ACTIVATED/DEACTIVATED states.
-    if (performed_action == ShelfItemDelegate::kNewWindowCreated ||
-        (performed_action != ShelfItemDelegate::kAppListMenuShown &&
-         !ShowListMenuForView(model_->items()[last_pressed_index_], sender,
-                              event, ink_drop))) {
-      ink_drop->AnimateToState(views::InkDropState::ACTION_TRIGGERED);
-    }
+  scoped_target_root_window_.reset(new ScopedTargetRootWindow(
+      sender->GetWidget()->GetNativeView()->GetRootWindow()));
+  // Slow down activation animations if shift key is pressed.
+  std::unique_ptr<ui::ScopedAnimationDurationScaleMode> slowing_animations;
+  if (event.IsShiftDown()) {
+    slowing_animations.reset(new ui::ScopedAnimationDurationScaleMode(
+        ui::ScopedAnimationDurationScaleMode::SLOW_DURATION));
   }
+
+  // Collect usage statistics before we decide what to do with the click.
+  switch (model_->items()[last_pressed_index_].type) {
+    case TYPE_APP_SHORTCUT:
+    case TYPE_WINDOWED_APP:
+    case TYPE_PLATFORM_APP:
+    case TYPE_BROWSER_SHORTCUT:
+      WmShell::Get()->RecordUserMetricsAction(UMA_LAUNCHER_CLICK_ON_APP);
+      break;
+
+    case TYPE_APP_LIST:
+      WmShell::Get()->RecordUserMetricsAction(
+          UMA_LAUNCHER_CLICK_ON_APPLIST_BUTTON);
+      break;
+
+    case TYPE_APP_PANEL:
+    case TYPE_DIALOG:
+    case TYPE_IME_MENU:
+      break;
+
+    case TYPE_UNDEFINED:
+      NOTREACHED() << "ShelfItemType must be set.";
+      break;
+  }
+
+  ShelfItemDelegate::PerformedAction performed_action =
+      item_manager_
+          ->GetShelfItemDelegate(model_->items()[last_pressed_index_].id)
+          ->ItemSelected(event);
+
+  shelf_button_pressed_metric_tracker_.ButtonPressed(event, sender,
+                                                     performed_action);
+
+  // For the app list menu no TRIGGERED ink drop effect is needed and it
+  // handles its own ACTIVATED/DEACTIVATED states.
+  if (performed_action == ShelfItemDelegate::kNewWindowCreated ||
+      (performed_action != ShelfItemDelegate::kAppListMenuShown &&
+       !ShowListMenuForView(model_->items()[last_pressed_index_], sender, event,
+                            ink_drop))) {
+    ink_drop->AnimateToState(views::InkDropState::ACTION_TRIGGERED);
+  }
+  // Allow the menu to clear |scoped_target_root_window_| during OnMenuClosed.
+  if (!IsShowingMenu())
+    scoped_target_root_window_.reset();
 }
 
 bool ShelfView::ShowListMenuForView(const ShelfItem& item,
@@ -1774,11 +1770,8 @@
 
   ink_drop->AnimateToState(views::InkDropState::ACTIVATED);
   context_menu_id_ = item.id;
-  ShowMenu(list_menu_model.get(), source, gfx::Point(), false,
-           ui::GetMenuSourceTypeForEvent(event));
-  // Menu is run synchronously, the menu is closed now and we need to go to
-  // the deactivated state.
-  ink_drop->AnimateToState(views::InkDropState::DEACTIVATED);
+  ShowMenu(std::move(list_menu_model), source, gfx::Point(), false,
+           ui::GetMenuSourceTypeForEvent(event), ink_drop);
   return true;
 }
 
@@ -1799,20 +1792,31 @@
     return;
 
   context_menu_id_ = item ? item->id : 0;
-  ShowMenu(context_menu_model.get(), source, point, true, source_type);
+  ShowMenu(std::move(context_menu_model), source, point, true, source_type,
+           nullptr);
 }
 
-void ShelfView::ShowMenu(ui::MenuModel* menu_model,
+void ShelfView::ShowMenu(std::unique_ptr<ui::MenuModel> menu_model,
                          views::View* source,
                          const gfx::Point& click_point,
                          bool context_menu,
-                         ui::MenuSourceType source_type) {
+                         ui::MenuSourceType source_type,
+                         views::InkDrop* ink_drop) {
+  menu_model_ = std::move(menu_model);
+  menu_model_adapter_.reset(new views::MenuModelAdapter(
+      menu_model_.get(),
+      base::Bind(&ShelfView::OnMenuClosed, base::Unretained(this), ink_drop)));
+
   closing_event_time_ = base::TimeTicks();
-  launcher_menu_runner_.reset(new views::MenuRunner(
-      menu_model, context_menu ? views::MenuRunner::CONTEXT_MENU : 0));
+  int run_types = views::MenuRunner::ASYNC;
+  if (context_menu)
+    run_types |= views::MenuRunner::CONTEXT_MENU;
+  launcher_menu_runner_.reset(
+      new views::MenuRunner(menu_model_adapter_->CreateMenu(), run_types));
 
   aura::Window* window = source->GetWidget()->GetNativeWindow();
-  ScopedTargetRootWindow scoped_target(window->GetRootWindow());
+  scoped_target_root_window_.reset(
+      new ScopedTargetRootWindow(window->GetRootWindow()));
 
   views::MenuAnchorPosition menu_alignment = views::MENU_ANCHOR_TOPLEFT;
   gfx::Rect anchor = gfx::Rect(click_point, gfx::Size());
@@ -1833,34 +1837,31 @@
         views::MENU_ANCHOR_BUBBLE_ABOVE, views::MENU_ANCHOR_BUBBLE_RIGHT,
         views::MENU_ANCHOR_BUBBLE_LEFT);
   }
-  // If this is deleted while the menu is running, the shelf will also be gone.
-  bool got_deleted = false;
-  got_deleted_ = &got_deleted;
 
-  ShelfWidget* shelf_widget = shelf_->shelf_widget();
-  shelf_widget->ForceUndimming(true);
+  shelf_->shelf_widget()->ForceUndimming(true);
   // NOTE: if you convert to HAS_MNEMONICS be sure to update menu building code.
-  if (launcher_menu_runner_->RunMenuAt(source->GetWidget(), nullptr, anchor,
-                                       menu_alignment, source_type) ==
-      views::MenuRunner::MENU_DELETED) {
-    if (!got_deleted) {
-      got_deleted_ = nullptr;
-      context_menu_id_ = 0;
-      shelf_widget->ForceUndimming(false);
-    }
-    return;
-  }
-  got_deleted_ = nullptr;
+  launcher_menu_runner_->RunMenuAt(source->GetWidget(), nullptr, anchor,
+                                   menu_alignment, source_type);
+}
+
+void ShelfView::OnMenuClosed(views::InkDrop* ink_drop) {
   context_menu_id_ = 0;
-  shelf_widget->ForceUndimming(false);
+  shelf_->shelf_widget()->ForceUndimming(false);
 
   // Hide the hide overflow bubble after showing a context menu for its items.
   if (owner_overflow_bubble_)
     owner_overflow_bubble_->HideBubbleAndRefreshButton();
 
-  // Unpinning an item will reset |launcher_menu_runner_| before coming here.
-  if (launcher_menu_runner_)
-    closing_event_time_ = launcher_menu_runner_->closing_event_time();
+  closing_event_time_ = launcher_menu_runner_->closing_event_time();
+
+  if (ink_drop)
+    ink_drop->AnimateToState(views::InkDropState::DEACTIVATED);
+
+  launcher_menu_runner_.reset();
+  menu_model_adapter_.reset();
+  menu_model_.reset();
+  scoped_target_root_window_.reset();
+
   Shell::GetInstance()->UpdateShelfVisibility();
 }
 
diff --git a/ash/shelf/shelf_view.h b/ash/shelf/shelf_view.h
index dbd1811..64799a19 100644
--- a/ash/shelf/shelf_view.h
+++ b/ash/shelf/shelf_view.h
@@ -33,6 +33,7 @@
 
 namespace views {
 class BoundsAnimator;
+class MenuModelAdapter;
 class MenuRunner;
 }
 
@@ -41,6 +42,7 @@
 class DragImageView;
 class OverflowBubble;
 class OverflowButton;
+class ScopedTargetRootWindow;
 class Shelf;
 class ShelfButton;
 class ShelfDelegate;
@@ -311,11 +313,15 @@
   // If |context_menu| is set, the displayed menu is a context menu and not
   // a menu listing one or more running applications.
   // The |click_point| is only used for |context_menu|'s.
-  void ShowMenu(ui::MenuModel* menu_model,
+  void ShowMenu(std::unique_ptr<ui::MenuModel> menu_model,
                 views::View* source,
                 const gfx::Point& click_point,
                 bool context_menu,
-                ui::MenuSourceType source_type);
+                ui::MenuSourceType source_type,
+                views::InkDrop* ink_drop);
+
+  // Callback for MenuModelAdapter.
+  void OnMenuClosed(views::InkDrop* ink_drop);
 
   // Overridden from views::BoundsAnimatorObserver:
   void OnBoundsAnimatorProgressed(views::BoundsAnimator* animator) override;
@@ -385,7 +391,11 @@
 
   std::unique_ptr<views::FocusSearch> focus_search_;
 
+  // Manages the context menu, and the list menu.
+  std::unique_ptr<ui::MenuModel> menu_model_;
+  std::unique_ptr<views::MenuModelAdapter> menu_model_adapter_;
   std::unique_ptr<views::MenuRunner> launcher_menu_runner_;
+  std::unique_ptr<ScopedTargetRootWindow> scoped_target_root_window_;
 
   base::ObserverList<ShelfIconObserver> observers_;
 
@@ -405,10 +415,6 @@
   // The timestamp of the event which closed the last menu - or 0.
   base::TimeTicks closing_event_time_;
 
-  // When this object gets deleted while a menu is shown, this pointed
-  // element will be set to false.
-  bool* got_deleted_;
-
   // True if a drag and drop operation created/pinned the item in the launcher
   // and it needs to be deleted/unpinned again if the operation gets cancelled.
   bool drag_and_drop_item_pinned_;
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index 40cec06..43eba9d 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -2583,16 +2583,12 @@
   EXPECT_THAT(browser_button_ink_drop_->GetAndResetRequestedStates(),
               ElementsAre(views::InkDropState::ACTION_PENDING));
 
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(&ShelfViewTestAPI::CloseMenu,
-                            base::Unretained(test_api_.get())));
-
-  // Mouse release will spawn a menu which will then get closed by the above
-  // posted task.
+  // Mouse release will spawn a menu which we will then close.
   ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, mouse_location,
                                mouse_location, ui::EventTimeForNow(),
                                ui::EF_LEFT_MOUSE_BUTTON, 0);
   button->OnMouseReleased(release_event);
+  test_api_->CloseMenu();
   EXPECT_EQ(views::InkDropState::HIDDEN,
             browser_button_ink_drop_->GetTargetInkDropState());
   EXPECT_THAT(browser_button_ink_drop_->GetAndResetRequestedStates(),
diff --git a/ash/system/chromeos/media_security/multi_profile_media_tray_item.cc b/ash/system/chromeos/media_security/multi_profile_media_tray_item.cc
index 02b7103..4164e8bf 100644
--- a/ash/system/chromeos/media_security/multi_profile_media_tray_item.cc
+++ b/ash/system/chromeos/media_security/multi_profile_media_tray_item.cc
@@ -4,7 +4,7 @@
 
 #include "ash/system/chromeos/media_security/multi_profile_media_tray_item.h"
 
-#include "ash/ash_view_ids.h"
+#include "ash/common/ash_view_ids.h"
 #include "ash/common/media_delegate.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/system/chromeos/media_security/media_capture_observer.h"
diff --git a/ash/system/chromeos/media_security/multi_profile_media_tray_item_unittest.cc b/ash/system/chromeos/media_security/multi_profile_media_tray_item_unittest.cc
index ea9baffb..15072c7 100644
--- a/ash/system/chromeos/media_security/multi_profile_media_tray_item_unittest.cc
+++ b/ash/system/chromeos/media_security/multi_profile_media_tray_item_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "ash/system/chromeos/media_security/multi_profile_media_tray_item.h"
 
-#include "ash/ash_view_ids.h"
+#include "ash/common/ash_view_ids.h"
 #include "ash/common/system/tray/system_tray_bubble.h"
 #include "ash/common/system/tray/tray_item_view.h"
 #include "ash/system/status_area_widget.h"
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc
index 5526e3fd..8691317 100644
--- a/ash/system/tray/system_tray.cc
+++ b/ash/system/tray/system_tray.cc
@@ -18,13 +18,13 @@
 #include "ash/common/system/tray/tray_constants.h"
 #include "ash/common/system/tray_accessibility.h"
 #include "ash/common/system/update/tray_update.h"
+#include "ash/common/system/user/tray_user.h"
 #include "ash/common/system/user/tray_user_separator.h"
 #include "ash/common/system/web_notification/web_notification_tray.h"
 #include "ash/common/wm_lookup.h"
 #include "ash/common/wm_root_window_controller.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/system/user/tray_user.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ash/system/user/DEPS b/ash/system/user/DEPS
deleted file mode 100644
index a6b411b..0000000
--- a/ash/system/user/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
-  # This directory is being migrated to //ash/common types.
-  "-ui/aura",
-]
diff --git a/ash/sysui/sysui_application.cc b/ash/sysui/sysui_application.cc
index adef771..61e1b9a3 100644
--- a/ash/sysui/sysui_application.cc
+++ b/ash/sysui/sysui_application.cc
@@ -32,7 +32,6 @@
 #include "base/threading/sequenced_worker_pool.h"
 #include "services/catalog/public/cpp/resource_loader.h"
 #include "services/shell/public/cpp/connector.h"
-#include "services/ui/common/gpu_service.h"
 #include "services/ui/public/cpp/property_type_converters.h"
 #include "services/ui/public/interfaces/input_devices/input_device_server.mojom.h"
 #include "ui/aura/env.h"
@@ -309,8 +308,6 @@
 void SysUIApplication::OnStart(::shell::Connector* connector,
                                const ::shell::Identity& identity,
                                uint32_t id) {
-  ui::GpuService::Initialize(connector);
-
   ash_init_.reset(new AshInit());
   ash_init_->Initialize(connector, identity);
 
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 6cd965d..e44570c 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -406,8 +406,6 @@
     "mac/launch_services_util.h",
     "mac/launchd.cc",
     "mac/launchd.h",
-    "mac/libdispatch_task_runner.cc",
-    "mac/libdispatch_task_runner.h",
     "mac/mac_logging.h",
     "mac/mac_logging.mm",
     "mac/mac_util.h",
@@ -1794,7 +1792,6 @@
     "mac/call_with_eh_frame_unittest.mm",
     "mac/dispatch_source_mach_unittest.cc",
     "mac/foundation_util_unittest.mm",
-    "mac/libdispatch_task_runner_unittest.cc",
     "mac/mac_util_unittest.mm",
     "mac/mach_port_broker_unittest.cc",
     "mac/objc_property_releaser_unittest.mm",
diff --git a/base/base.gyp b/base/base.gyp
index f8764797..0c1ad352 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -450,7 +450,6 @@
         'mac/call_with_eh_frame_unittest.mm',
         'mac/dispatch_source_mach_unittest.cc',
         'mac/foundation_util_unittest.mm',
-        'mac/libdispatch_task_runner_unittest.cc',
         'mac/mac_util_unittest.mm',
         'mac/mach_port_broker_unittest.cc',
         'mac/objc_property_releaser_unittest.mm',
diff --git a/base/base.gypi b/base/base.gypi
index d335b97..cb41e79 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -297,8 +297,6 @@
           'mac/launch_services_util.h',
           'mac/launchd.cc',
           'mac/launchd.h',
-          'mac/libdispatch_task_runner.cc',
-          'mac/libdispatch_task_runner.h',
           'mac/mac_logging.h',
           'mac/mac_logging.mm',
           'mac/mac_util.h',
diff --git a/base/bind_internal.h b/base/bind_internal.h
index 6b692a8..41c34ff 100644
--- a/base/bind_internal.h
+++ b/base/bind_internal.h
@@ -46,6 +46,60 @@
 //  BindState<> -- Stores the curried parameters, and is the main entry point
 //                 into the Bind() system.
 
+template <typename...>
+struct make_void {
+  using type = void;
+};
+
+// A clone of C++17 std::void_t.
+// Unlike the original version, we need |make_void| as a helper struct to avoid
+// a C++14 defect.
+// ref: http://en.cppreference.com/w/cpp/types/void_t
+// ref: http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1558
+template <typename... Ts>
+using void_t = typename make_void<Ts...>::type;
+
+template <typename Callable,
+          typename Signature = decltype(&Callable::operator())>
+struct ExtractCallableRunTypeImpl;
+
+template <typename Callable, typename R, typename... Args>
+struct ExtractCallableRunTypeImpl<Callable, R(Callable::*)(Args...) const> {
+  using Type = R(Args...);
+};
+
+// Evaluated to RunType of the given callable type.
+// Example:
+//   auto f = [](int, char*) { return 0.1; };
+//   ExtractCallableRunType<decltype(f)>
+//   is evaluated to
+//   double(int, char*);
+template <typename Callable>
+using ExtractCallableRunType =
+    typename ExtractCallableRunTypeImpl<Callable>::Type;
+
+// IsConvertibleToRunType<Functor> is std::true_type if |Functor| has operator()
+// and convertible to the corresponding function pointer. Otherwise, it's
+// std::false_type.
+// Example:
+//   IsConvertibleToRunType<void(*)()>::value is false.
+//
+//   struct Foo {};
+//   IsConvertibleToRunType<void(Foo::*)()>::value is false.
+//
+//   auto f = []() {};
+//   IsConvertibleToRunType<decltype(f)>::value is true.
+//
+//   int i = 0;
+//   auto g = [i]() {};
+//   IsConvertibleToRunType<decltype(g)>::value is false.
+template <typename Functor, typename SFINAE = void>
+struct IsConvertibleToRunType : std::false_type {};
+
+template <typename Callable>
+struct IsConvertibleToRunType<Callable, void_t<decltype(&Callable::operator())>>
+    : std::is_convertible<Callable, ExtractCallableRunType<Callable>*> {};
+
 // HasRefCountedTypeAsRawPtr selects true_type when any of the |Args| is a raw
 // pointer to a RefCounted type.
 // Implementation note: This non-specialized case handles zero-arity case only.
@@ -76,14 +130,34 @@
 // FunctorTraits<>
 //
 // See description at top of file.
-template <typename Functor>
+template <typename Functor, typename SFINAE = void>
 struct FunctorTraits;
 
+// For a callable type that is convertible to the corresponding function type.
+// This specialization is intended to allow binding captureless lambdas by
+// base::Bind(), based on the fact that captureless lambdas can be convertible
+// to the function type while capturing lambdas can't.
+template <typename Functor>
+struct FunctorTraits<
+    Functor,
+    typename std::enable_if<IsConvertibleToRunType<Functor>::value>::type> {
+  using RunType = ExtractCallableRunType<Functor>;
+  static constexpr bool is_method = false;
+  static constexpr bool is_nullable = false;
+
+  template <typename... RunArgs>
+  static ExtractReturnType<RunType>
+  Invoke(const Functor& functor, RunArgs&&... args) {
+    return functor(std::forward<RunArgs>(args)...);
+  }
+};
+
 // For functions.
 template <typename R, typename... Args>
 struct FunctorTraits<R (*)(Args...)> {
   using RunType = R(Args...);
   static constexpr bool is_method = false;
+  static constexpr bool is_nullable = true;
 
   template <typename... RunArgs>
   static R Invoke(R (*function)(Args...), RunArgs&&... args) {
@@ -98,6 +172,7 @@
 struct FunctorTraits<R(__stdcall*)(Args...)> {
   using RunType = R(Args...);
   static constexpr bool is_method = false;
+  static constexpr bool is_nullable = true;
 
   template <typename... RunArgs>
   static R Invoke(R(__stdcall* function)(Args...), RunArgs&&... args) {
@@ -110,6 +185,7 @@
 struct FunctorTraits<R(__fastcall*)(Args...)> {
   using RunType = R(Args...);
   static constexpr bool is_method = false;
+  static constexpr bool is_nullable = true;
 
   template <typename... RunArgs>
   static R Invoke(R(__fastcall* function)(Args...), RunArgs&&... args) {
@@ -124,6 +200,7 @@
 struct FunctorTraits<R (Receiver::*)(Args...)> {
   using RunType = R(Receiver*, Args...);
   static constexpr bool is_method = true;
+  static constexpr bool is_nullable = true;
 
   template <typename ReceiverPtr, typename... RunArgs>
   static R Invoke(R (Receiver::*method)(Args...),
@@ -143,6 +220,7 @@
 struct FunctorTraits<R (Receiver::*)(Args...) const> {
   using RunType = R(const Receiver*, Args...);
   static constexpr bool is_method = true;
+  static constexpr bool is_nullable = true;
 
   template <typename ReceiverPtr, typename... RunArgs>
   static R Invoke(R (Receiver::*method)(Args...) const,
@@ -176,6 +254,7 @@
 struct FunctorTraits<Callback<R(Args...), copy_mode>> {
   using RunType = R(Args...);
   static constexpr bool is_method = false;
+  static constexpr bool is_nullable = true;
 
   template <typename CallbackType, typename... RunArgs>
   static R Invoke(CallbackType&& callback, RunArgs&&... args) {
@@ -281,6 +360,17 @@
   using UnboundArgs = DropTypeListItem<sizeof...(BoundArgs), Args>;
   using Type = MakeFunctionType<ReturnType, UnboundArgs>;
 };
+template <typename Functor>
+typename std::enable_if<FunctorTraits<Functor>::is_nullable, bool>::type
+IsNull(const Functor& functor) {
+  return !functor;
+}
+
+template <typename Functor>
+typename std::enable_if<!FunctorTraits<Functor>::is_nullable, bool>::type
+IsNull(const Functor&) {
+  return false;
+}
 
 // BindState<>
 //
@@ -292,7 +382,7 @@
       : BindStateBase(&Destroy),
         functor_(std::move(functor)),
         bound_args_(std::forward<ForwardBoundArgs>(bound_args)...) {
-    DCHECK(functor_);
+    DCHECK(!IsNull(functor_));
   }
 
   Functor functor_;
diff --git a/base/bind_unittest.cc b/base/bind_unittest.cc
index 5a7ce386..a14e761 100644
--- a/base/bind_unittest.cc
+++ b/base/bind_unittest.cc
@@ -1038,6 +1038,36 @@
   EXPECT_EQ(0, move_assigns);
 }
 
+TEST_F(BindTest, CapturelessLambda) {
+  EXPECT_FALSE(internal::IsConvertibleToRunType<void>::value);
+  EXPECT_FALSE(internal::IsConvertibleToRunType<int>::value);
+  EXPECT_FALSE(internal::IsConvertibleToRunType<void(*)()>::value);
+  EXPECT_FALSE(internal::IsConvertibleToRunType<void(NoRef::*)()>::value);
+
+  auto f = []() {};
+  EXPECT_TRUE(internal::IsConvertibleToRunType<decltype(f)>::value);
+
+  int i = 0;
+  auto g = [i]() {};
+  EXPECT_FALSE(internal::IsConvertibleToRunType<decltype(g)>::value);
+
+  auto h = [](int, double) { return 'k'; };
+  EXPECT_TRUE((std::is_same<
+      char(int, double),
+      internal::ExtractCallableRunType<decltype(h)>>::value));
+
+  EXPECT_EQ(42, Bind([] { return 42; }).Run());
+  EXPECT_EQ(42, Bind([](int i) { return i * 7; }, 6).Run());
+
+  int x = 1;
+  base::Callback<void(int)> cb =
+      Bind([](int* x, int i) { *x *= i; }, Unretained(&x));
+  cb.Run(6);
+  EXPECT_EQ(6, x);
+  cb.Run(7);
+  EXPECT_EQ(42, x);
+}
+
 // Callback construction and assignment tests.
 //   - Construction from an InvokerStorageHolder should not cause ref/deref.
 //   - Assignment from other callback should only cause one ref
diff --git a/base/bind_unittest.nc b/base/bind_unittest.nc
index bdbcd2f2..e60de076 100644
--- a/base/bind_unittest.nc
+++ b/base/bind_unittest.nc
@@ -201,6 +201,13 @@
   Closure callback_mismatches_bind_type = Bind(&VoidPolymorphic1<int>);
 }
 
+#elif defined(NCTEST_DISALLOW_CAPTURING_LAMBDA)  // [r"fatal error: implicit instantiation of undefined template 'base::internal::FunctorTraits<\(lambda at ../../base/bind_unittest.nc:[0-9]+:[0-9]+\), void>'"]
+
+void WontCompile() {
+  int i = 0;
+  Bind([i]() {});
+}
+
 #endif
 
 }  // namespace base
diff --git a/base/callback_helpers.cc b/base/callback_helpers.cc
index 8fd3dde..838e6c8d 100644
--- a/base/callback_helpers.cc
+++ b/base/callback_helpers.cc
@@ -23,21 +23,18 @@
 
 ScopedClosureRunner& ScopedClosureRunner::operator=(
     ScopedClosureRunner&& other) {
-  Reset(other.Release());
+  ReplaceClosure(other.Release());
   return *this;
 }
 
-void ScopedClosureRunner::Reset() {
+void ScopedClosureRunner::RunAndReset() {
   Closure old_closure = Release();
   if (!old_closure.is_null())
     old_closure.Run();
 }
 
-void ScopedClosureRunner::Reset(const Closure& closure) {
-  Closure old_closure = Release();
+void ScopedClosureRunner::ReplaceClosure(const Closure& closure) {
   closure_ = closure;
-  if (!old_closure.is_null())
-    old_closure.Run();
 }
 
 Closure ScopedClosureRunner::Release() {
diff --git a/base/callback_helpers.h b/base/callback_helpers.h
index c4b0d867..782371f 100644
--- a/base/callback_helpers.h
+++ b/base/callback_helpers.h
@@ -37,15 +37,15 @@
 
   ScopedClosureRunner(ScopedClosureRunner&& other);
 
-  // Calls the current closure if it's set and replaces it with the closure from
-  // |other|.
+  // Releases the current closure if it's set and replaces it with the closure
+  // from |other|.
   ScopedClosureRunner& operator=(ScopedClosureRunner&& other);
 
   // Calls the current closure and resets it, so it wont be called again.
-  void Reset();
+  void RunAndReset();
 
-  // Calls the current closure and replaces it with the new one.
-  void Reset(const Closure& closure);
+  // Replaces closure with the new one releasing the old one without calling it.
+  void ReplaceClosure(const Closure& closure);
 
   // Releases the Closure without calling.
   Closure Release() WARN_UNUSED_RESULT;
diff --git a/base/callback_helpers_unittest.cc b/base/callback_helpers_unittest.cc
index 0e42852..82839963 100644
--- a/base/callback_helpers_unittest.cc
+++ b/base/callback_helpers_unittest.cc
@@ -14,7 +14,7 @@
   (*value)++;
 }
 
-TEST(BindHelpersTest, TestScopedClosureRunnerExitScope) {
+TEST(CallbackHelpersTest, TestScopedClosureRunnerExitScope) {
   int run_count = 0;
   {
     base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count));
@@ -23,7 +23,7 @@
   EXPECT_EQ(1, run_count);
 }
 
-TEST(BindHelpersTest, TestScopedClosureRunnerRelease) {
+TEST(CallbackHelpersTest, TestScopedClosureRunnerRelease) {
   int run_count = 0;
   base::Closure c;
   {
@@ -36,29 +36,32 @@
   EXPECT_EQ(1, run_count);
 }
 
-TEST(BindHelpersTest, TestScopedClosureRunnerReset) {
+TEST(CallbackHelpersTest, TestScopedClosureRunnerReplaceClosure) {
   int run_count_1 = 0;
   int run_count_2 = 0;
   {
     base::ScopedClosureRunner runner;
-    runner.Reset(base::Bind(&Increment, &run_count_1));
-    runner.Reset(base::Bind(&Increment, &run_count_2));
-    EXPECT_EQ(1, run_count_1);
+    runner.ReplaceClosure(base::Bind(&Increment, &run_count_1));
+    runner.ReplaceClosure(base::Bind(&Increment, &run_count_2));
+    EXPECT_EQ(0, run_count_1);
     EXPECT_EQ(0, run_count_2);
   }
+  EXPECT_EQ(0, run_count_1);
   EXPECT_EQ(1, run_count_2);
+}
 
+TEST(CallbackHelpersTest, TestScopedClosureRunnerRunAndReset) {
   int run_count_3 = 0;
   {
     base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count_3));
     EXPECT_EQ(0, run_count_3);
-    runner.Reset();
+    runner.RunAndReset();
     EXPECT_EQ(1, run_count_3);
   }
   EXPECT_EQ(1, run_count_3);
 }
 
-TEST(BindHelpersTest, TestScopedClosureRunnerMoveConstructor) {
+TEST(CallbackHelpersTest, TestScopedClosureRunnerMoveConstructor) {
   int run_count = 0;
   {
     std::unique_ptr<base::ScopedClosureRunner> runner(
@@ -70,35 +73,22 @@
   EXPECT_EQ(1, run_count);
 }
 
-TEST(BindHelpersTest, TestScopedClosureRunnerMoveAssignment) {
-  int run_count = 0;
+TEST(CallbackHelpersTest, TestScopedClosureRunnerMoveAssignment) {
+  int run_count_1 = 0;
+  int run_count_2 = 0;
   {
-    base::ScopedClosureRunner runner;
+    base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count_1));
     {
-      base::ScopedClosureRunner runner2(base::Bind(&Increment, &run_count));
+      base::ScopedClosureRunner runner2(base::Bind(&Increment, &run_count_2));
       runner = std::move(runner2);
+      EXPECT_EQ(0, run_count_1);
+      EXPECT_EQ(0, run_count_2);
     }
-    EXPECT_EQ(0, run_count);
+    EXPECT_EQ(0, run_count_1);
+    EXPECT_EQ(0, run_count_2);
   }
-  EXPECT_EQ(1, run_count);
-}
-
-TEST(BindHelpersTest, TestScopedClosureRunnerRunOnReplace) {
-  int run_count1 = 0;
-  int run_count2 = 0;
-  {
-    base::ScopedClosureRunner runner1(base::Bind(&Increment, &run_count1));
-    {
-      base::ScopedClosureRunner runner2(base::Bind(&Increment, &run_count2));
-      runner1 = std::move(runner2);
-      EXPECT_EQ(1, run_count1);
-      EXPECT_EQ(0, run_count2);
-    }
-    EXPECT_EQ(1, run_count1);
-    EXPECT_EQ(0, run_count2);
-  }
-  EXPECT_EQ(1, run_count1);
-  EXPECT_EQ(1, run_count2);
+  EXPECT_EQ(0, run_count_1);
+  EXPECT_EQ(1, run_count_2);
 }
 
 }  // namespace
diff --git a/base/feature_list.cc b/base/feature_list.cc
index 4673210..435165e1 100644
--- a/base/feature_list.cc
+++ b/base/feature_list.cc
@@ -23,6 +23,9 @@
 // have more control over initialization timing. Leaky.
 FeatureList* g_instance = nullptr;
 
+// Tracks whether the FeatureList instance was initialized via an accessor.
+bool g_initialized_from_accessor = false;
+
 // Some characters are not allowed to appear in feature names or the associated
 // field trial names, as they are used as special characters for command-line
 // serialization. This function checks that the strings are ASCII (since they
@@ -35,10 +38,7 @@
 
 }  // namespace
 
-FeatureList::FeatureList()
-  : initialized_(false),
-    initialized_from_command_line_(false) {
-}
+FeatureList::FeatureList() {}
 
 FeatureList::~FeatureList() {}
 
@@ -133,7 +133,11 @@
 
 // static
 bool FeatureList::IsEnabled(const Feature& feature) {
-  return GetInstance()->IsFeatureEnabled(feature);
+  if (!g_instance) {
+    g_initialized_from_accessor = true;
+    return feature.default_state == FEATURE_ENABLED_BY_DEFAULT;
+  }
+  return g_instance->IsFeatureEnabled(feature);
 }
 
 // static
@@ -158,6 +162,10 @@
   // For example, we initialize an instance in chrome/browser/
   // chrome_browser_main.cc and do not override it in content/browser/
   // browser_main_loop.cc.
+  // If the singleton was previously initialized from within an accessor, we
+  // want to prevent callers from reinitializing the singleton and masking the
+  // accessor call(s) which likely returned incorrect information.
+  CHECK(!g_initialized_from_accessor);
   bool instance_existed_before = false;
   if (g_instance) {
     if (g_instance->initialized_from_command_line_)
@@ -192,6 +200,7 @@
 void FeatureList::ClearInstanceForTesting() {
   delete g_instance;
   g_instance = nullptr;
+  g_initialized_from_accessor = false;
 }
 
 void FeatureList::FinalizeInitialization() {
diff --git a/base/feature_list.h b/base/feature_list.h
index 2a47427f..e9ed00a 100644
--- a/base/feature_list.h
+++ b/base/feature_list.h
@@ -247,10 +247,10 @@
 
   // Whether this object has been fully initialized. This gets set to true as a
   // result of FinalizeInitialization().
-  bool initialized_;
+  bool initialized_ = false;
 
   // Whether this object has been initialized from command line.
-  bool initialized_from_command_line_;
+  bool initialized_from_command_line_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(FeatureList);
 };
diff --git a/base/feature_list_unittest.cc b/base/feature_list_unittest.cc
index a7e7b711..9d1dcb7 100644
--- a/base/feature_list_unittest.cc
+++ b/base/feature_list_unittest.cc
@@ -457,4 +457,15 @@
   EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
 }
 
+TEST_F(FeatureListTest, UninitializedInstance_IsEnabledReturnsFalse) {
+  ClearFeatureListInstance();
+  // This test case simulates the calling pattern found in code which does not
+  // explicitly initialize the features list.
+  // All IsEnabled() calls should return the default value in this scenario.
+  EXPECT_EQ(nullptr, FeatureList::GetInstance());
+  EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
+  EXPECT_EQ(nullptr, FeatureList::GetInstance());
+  EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
+}
+
 }  // namespace base
diff --git a/base/files/file_path.cc b/base/files/file_path.cc
index ca0d1d1b..0b06493 100644
--- a/base/files/file_path.cc
+++ b/base/files/file_path.cc
@@ -537,7 +537,7 @@
 bool FilePath::EndsWithSeparator() const {
   if (empty())
     return false;
-  return IsSeparator(path_[path_.size() - 1]);
+  return IsSeparator(path_.back());
 }
 
 FilePath FilePath::AsEndingWithSeparator() const {
diff --git a/base/files/file_path_watcher_fsevents.cc b/base/files/file_path_watcher_fsevents.cc
index 824e3d8a..e9d2508 100644
--- a/base/files/file_path_watcher_fsevents.cc
+++ b/base/files/file_path_watcher_fsevents.cc
@@ -4,16 +4,18 @@
 
 #include "base/files/file_path_watcher_fsevents.h"
 
+#include <dispatch/dispatch.h>
+
 #include <list>
 
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
-#include "base/mac/libdispatch_task_runner.h"
 #include "base/mac/scoped_cftyperef.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
+#include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
 
 namespace base {
@@ -23,19 +25,6 @@
 // The latency parameter passed to FSEventsStreamCreate().
 const CFAbsoluteTime kEventLatencySeconds = 0.3;
 
-class FSEventsTaskRunner : public mac::LibDispatchTaskRunner {
- public:
-   FSEventsTaskRunner()
-       : mac::LibDispatchTaskRunner("org.chromium.FilePathWatcherFSEvents") {
-   }
-
- protected:
-  ~FSEventsTaskRunner() override {}
-};
-
-static LazyInstance<FSEventsTaskRunner>::Leaky g_task_runner =
-    LAZY_INSTANCE_INITIALIZER;
-
 // Resolve any symlinks in the path.
 FilePath ResolvePath(const FilePath& path) {
   const unsigned kMaxLinksToResolve = 255;
@@ -79,7 +68,12 @@
 
 }  // namespace
 
-FilePathWatcherFSEvents::FilePathWatcherFSEvents() : fsevent_stream_(NULL) {
+FilePathWatcherFSEvents::FilePathWatcherFSEvents()
+    : queue_(dispatch_queue_create(
+          base::StringPrintf(
+              "org.chromium.base.FilePathWatcher.%p", this).c_str(),
+          DISPATCH_QUEUE_SERIAL)),
+      fsevent_stream_(nullptr) {
 }
 
 bool FilePathWatcherFSEvents::Watch(const FilePath& path,
@@ -98,9 +92,14 @@
   callback_ = callback;
 
   FSEventStreamEventId start_event = FSEventsGetCurrentEventId();
-  g_task_runner.Get().PostTask(
-      FROM_HERE, Bind(&FilePathWatcherFSEvents::StartEventStream, this,
-                      start_event, path));
+  // The block runtime would implicitly capture the reference, not the object
+  // it's referencing. Copy the path into a local, so that the value is
+  // captured by the block's scope.
+  const FilePath path_copy(path);
+
+  dispatch_async(queue_, ^{
+      StartEventStream(start_event, path_copy);
+  });
   return true;
 }
 
@@ -108,10 +107,12 @@
   set_cancelled();
   callback_.Reset();
 
-  // Switch to the dispatch queue thread to tear down the event stream.
-  g_task_runner.Get().PostTask(
-      FROM_HERE,
-      Bind(&FilePathWatcherFSEvents::CancelOnMessageLoopThread, this));
+  // Switch to the dispatch queue to tear down the event stream. As the queue
+  // is owned by this object, and this method is called from the destructor,
+  // execute the block synchronously.
+  dispatch_sync(queue_, ^{
+      CancelOnMessageLoopThread();
+  });
 }
 
 // static
@@ -124,8 +125,6 @@
     const FSEventStreamEventId event_ids[]) {
   FilePathWatcherFSEvents* watcher =
       reinterpret_cast<FilePathWatcherFSEvents*>(event_watcher);
-  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
-
   bool root_changed = watcher->ResolveTargetPath();
   std::vector<FilePath> paths;
   FSEventStreamEventId root_change_at = FSEventStreamGetLatestEventId(stream);
@@ -144,10 +143,9 @@
   if (root_changed) {
     // Resetting the event stream from within the callback fails (FSEvents spews
     // bad file descriptor errors), so post a task to do the reset.
-    g_task_runner.Get().PostTask(
-        FROM_HERE,
-        Bind(&FilePathWatcherFSEvents::UpdateEventStream, watcher,
-             root_change_at));
+    dispatch_async(watcher->queue_, ^{
+        watcher->UpdateEventStream(root_change_at);
+    });
   }
 
   watcher->OnFilePathsChanged(paths);
@@ -165,7 +163,6 @@
 
 void FilePathWatcherFSEvents::OnFilePathsChanged(
     const std::vector<FilePath>& paths) {
-  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
   DCHECK(!resolved_target_.empty());
   task_runner()->PostTask(
       FROM_HERE, Bind(&FilePathWatcherFSEvents::DispatchEvents, this, paths,
@@ -194,7 +191,6 @@
   // For all other implementations, the "message loop thread" is the IO thread,
   // as returned by task_runner(). This implementation, however, needs to
   // cancel pending work on the Dispatch Queue thread.
-  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
 
   if (fsevent_stream_) {
     DestroyEventStream();
@@ -205,8 +201,6 @@
 
 void FilePathWatcherFSEvents::UpdateEventStream(
     FSEventStreamEventId start_event) {
-  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
-
   // It can happen that the watcher gets canceled while tasks that call this
   // function are still in flight, so abort if this situation is detected.
   if (resolved_target_.empty())
@@ -237,8 +231,7 @@
                                         start_event,
                                         kEventLatencySeconds,
                                         kFSEventStreamCreateFlagWatchRoot);
-  FSEventStreamSetDispatchQueue(fsevent_stream_,
-                                g_task_runner.Get().GetDispatchQueue());
+  FSEventStreamSetDispatchQueue(fsevent_stream_, queue_);
 
   if (!FSEventStreamStart(fsevent_stream_)) {
     task_runner()->PostTask(
@@ -247,7 +240,6 @@
 }
 
 bool FilePathWatcherFSEvents::ResolveTargetPath() {
-  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
   FilePath resolved = ResolvePath(target_).StripTrailingSeparators();
   bool changed = resolved != resolved_target_;
   resolved_target_ = resolved;
@@ -274,7 +266,6 @@
 
 void FilePathWatcherFSEvents::StartEventStream(FSEventStreamEventId start_event,
                                                const FilePath& path) {
-  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
   DCHECK(resolved_target_.empty());
 
   target_ = path;
diff --git a/base/files/file_path_watcher_fsevents.h b/base/files/file_path_watcher_fsevents.h
index 1ebe463..cfbe020b 100644
--- a/base/files/file_path_watcher_fsevents.h
+++ b/base/files/file_path_watcher_fsevents.h
@@ -12,6 +12,7 @@
 
 #include "base/files/file_path.h"
 #include "base/files/file_path_watcher.h"
+#include "base/mac/scoped_dispatch_object.h"
 #include "base/macros.h"
 
 namespace base {
@@ -76,16 +77,19 @@
   // (Only accessed from the message_loop() thread.)
   FilePathWatcher::Callback callback_;
 
+  // The dispatch queue on which the the event stream is scheduled.
+  ScopedDispatchObject<dispatch_queue_t> queue_;
+
   // Target path to watch (passed to callback).
-  // (Only accessed from the libdispatch thread.)
+  // (Only accessed from the libdispatch queue.)
   FilePath target_;
 
   // Target path with all symbolic links resolved.
-  // (Only accessed from the libdispatch thread.)
+  // (Only accessed from the libdispatch queue.)
   FilePath resolved_target_;
 
   // Backend stream we receive event callbacks from (strong reference).
-  // (Only accessed from the libdispatch thread.)
+  // (Only accessed from the libdispatch queue.)
   FSEventStreamRef fsevent_stream_;
 
   DISALLOW_COPY_AND_ASSIGN(FilePathWatcherFSEvents);
diff --git a/base/files/file_path_watcher_linux.cc b/base/files/file_path_watcher_linux.cc
index ae293fe8..87bddd3 100644
--- a/base/files/file_path_watcher_linux.cc
+++ b/base/files/file_path_watcher_linux.cc
@@ -677,7 +677,7 @@
     if (watches_[i].subdir.empty())
       return false;
   }
-  return watches_[watches_.size() - 1].subdir.empty();
+  return watches_.back().subdir.empty();
 }
 
 }  // namespace
diff --git a/base/logging.h b/base/logging.h
index fd148aa..f06535da 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -456,11 +456,17 @@
 // Make all CHECK functions discard their log strings to reduce code
 // bloat, and improve performance, for official release builds.
 
-// TODO(akalin): This would be more valuable if there were some way to
-// remove BreakDebugger() from the backtrace, perhaps by turning it
-// into a macro (like __debugbreak() on Windows).
+#if defined(COMPILER_GCC) || __clang__
+#define LOGGING_CRASH() __builtin_trap()
+#else
+#define LOGGING_CRASH() ((void)(*(volatile char*)0 = 0))
+#endif
+
+// This is not calling BreakDebugger since this is called frequently, and
+// calling an out-of-line function instead of a noreturn inline macro prevents
+// compiler optimizations.
 #define CHECK(condition)                                                \
-  !(condition) ? ::base::debug::BreakDebugger() : EAT_STREAM_PARAMETERS
+  !(condition) ? LOGGING_CRASH() : EAT_STREAM_PARAMETERS
 
 #define PCHECK(condition) CHECK(condition)
 
diff --git a/base/mac/foundation_util.mm b/base/mac/foundation_util.mm
index d872fc3..4f6fa60a 100644
--- a/base/mac/foundation_util.mm
+++ b/base/mac/foundation_util.mm
@@ -155,7 +155,7 @@
   exec_name.GetComponents(&components);
 
   // It's an error if we don't get any components.
-  if (!components.size())
+  if (components.empty())
     return FilePath();
 
   // Don't prepend '/' to the first component.
diff --git a/base/mac/libdispatch_task_runner.cc b/base/mac/libdispatch_task_runner.cc
deleted file mode 100644
index dcbeecc..0000000
--- a/base/mac/libdispatch_task_runner.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/mac/libdispatch_task_runner.h"
-
-#include <stdint.h>
-
-#include "base/callback.h"
-
-namespace base {
-namespace mac {
-
-LibDispatchTaskRunner::LibDispatchTaskRunner(const char* name)
-    : queue_(dispatch_queue_create(name, NULL)),
-      queue_finalized_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
-                       base::WaitableEvent::InitialState::NOT_SIGNALED) {
-  dispatch_set_context(queue_, this);
-  dispatch_set_finalizer_f(queue_, &LibDispatchTaskRunner::Finalizer);
-}
-
-bool LibDispatchTaskRunner::PostDelayedTask(
-    const tracked_objects::Location& from_here,
-    const Closure& task,
-    base::TimeDelta delay) {
-  if (!queue_)
-    return false;
-
-  // The block runtime would implicitly copy the reference, not the object
-  // it's referencing. Copy the closure into block storage so it's available
-  // to run.
-  __block const Closure task_copy = task;
-  void(^run_task)(void) = ^{
-      task_copy.Run();
-  };
-
-  int64_t delay_nano =
-      delay.InMicroseconds() * base::Time::kNanosecondsPerMicrosecond;
-  if (delay_nano > 0) {
-    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, delay_nano);
-    dispatch_after(time, queue_, run_task);
-  } else {
-    dispatch_async(queue_, run_task);
-  }
-  return true;
-}
-
-bool LibDispatchTaskRunner::RunsTasksOnCurrentThread() const {
-  return queue_ == dispatch_get_current_queue();
-}
-
-bool LibDispatchTaskRunner::PostNonNestableDelayedTask(
-    const tracked_objects::Location& from_here,
-    const Closure& task,
-    base::TimeDelta delay) {
-  return PostDelayedTask(from_here, task, delay);
-}
-
-void LibDispatchTaskRunner::Shutdown() {
-  dispatch_release(queue_);
-  queue_ = NULL;
-  queue_finalized_.Wait();
-}
-
-dispatch_queue_t LibDispatchTaskRunner::GetDispatchQueue() const {
-  return queue_;
-}
-
-LibDispatchTaskRunner::~LibDispatchTaskRunner() {
-  if (queue_) {
-    dispatch_set_context(queue_, NULL);
-    dispatch_set_finalizer_f(queue_, NULL);
-    dispatch_release(queue_);
-  }
-}
-
-void LibDispatchTaskRunner::Finalizer(void* context) {
-  LibDispatchTaskRunner* self = static_cast<LibDispatchTaskRunner*>(context);
-  self->queue_finalized_.Signal();
-}
-
-}  // namespace mac
-}  // namespace base
diff --git a/base/mac/libdispatch_task_runner.h b/base/mac/libdispatch_task_runner.h
deleted file mode 100644
index b479bc7..0000000
--- a/base/mac/libdispatch_task_runner.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (c) 2012 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 BASE_MAC_LIBDISPATCH_TASK_RUNNER_H_
-#define BASE_MAC_LIBDISPATCH_TASK_RUNNER_H_
-
-#include <dispatch/dispatch.h>
-
-#include "base/single_thread_task_runner.h"
-#include "base/synchronization/waitable_event.h"
-
-namespace base {
-namespace mac {
-
-// This is an implementation of the TaskRunner interface that runs closures on
-// a thread managed by Apple's libdispatch. This has the benefit of being able
-// to PostTask() and friends to a dispatch queue, while being reusable as a
-// dispatch_queue_t.
-//
-// One would use this class if an object lives exclusively on one thread but
-// needs a dispatch_queue_t for use in a system API. This ensures all dispatch
-// callbacks happen on the same thread as Closure tasks.
-//
-// A LibDispatchTaskRunner will continue to run until all references to the
-// underlying dispatch queue are released.
-//
-// Important Notes:
-//   - There is no MessageLoop running on this thread, and ::current() returns
-//     NULL.
-//   - No nested loops can be run, and all tasks are run non-nested.
-//   - Work scheduled via libdispatch runs at the same priority as and is
-//     interleaved with posted tasks, though FIFO order is guaranteed.
-//
-class BASE_EXPORT LibDispatchTaskRunner : public base::SingleThreadTaskRunner {
- public:
-  // Starts a new serial dispatch queue with a given name.
-  explicit LibDispatchTaskRunner(const char* name);
-
-  // base::TaskRunner:
-  bool PostDelayedTask(const tracked_objects::Location& from_here,
-                       const Closure& task,
-                       base::TimeDelta delay) override;
-  bool RunsTasksOnCurrentThread() const override;
-
-  // base::SequencedTaskRunner:
-  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
-                                  const Closure& task,
-                                  base::TimeDelta delay) override;
-
-  // This blocks the calling thread until all work on the dispatch queue has
-  // been run and the queue has been destroyed. Destroying a queue requires
-  // ALL retained references to it to be released. Any new tasks posted to
-  // this thread after shutdown are dropped.
-  void Shutdown();
-
-  // Returns the dispatch queue associated with this task runner, for use with
-  // system APIs that take dispatch queues. The caller is responsible for
-  // retaining the result.
-  //
-  // All properties (context, finalizer, etc.) are managed by this class, and
-  // clients should only use the result of this for dispatch_async().
-  dispatch_queue_t GetDispatchQueue() const;
-
- protected:
-  ~LibDispatchTaskRunner() override;
-
- private:
-  static void Finalizer(void* context);
-
-  dispatch_queue_t queue_;
-
-  // The event on which Shutdown waits until Finalizer runs.
-  base::WaitableEvent queue_finalized_;
-};
-
-}  // namespace mac
-}  // namespace base
-
-#endif  // BASE_MAC_LIBDISPATCH_TASK_RUNNER_H_
diff --git a/base/mac/libdispatch_task_runner_unittest.cc b/base/mac/libdispatch_task_runner_unittest.cc
deleted file mode 100644
index a7bc928..0000000
--- a/base/mac/libdispatch_task_runner_unittest.cc
+++ /dev/null
@@ -1,229 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/mac/libdispatch_task_runner.h"
-
-#include <stddef.h>
-
-#include "base/bind.h"
-#include "base/mac/bind_objc_block.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/stringprintf.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class LibDispatchTaskRunnerTest : public testing::Test {
- public:
-  void SetUp() override {
-    task_runner_ = new base::mac::LibDispatchTaskRunner(
-        "org.chromium.LibDispatchTaskRunnerTest");
-  }
-
-  // DispatchLastTask is used to run the main test thread's MessageLoop until
-  // all non-delayed tasks are run on the LibDispatchTaskRunner.
-  void DispatchLastTask() {
-    dispatch_async(task_runner_->GetDispatchQueue(), ^{
-      message_loop_.task_runner()->PostTask(
-          FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
-    });
-    base::RunLoop().Run();
-    task_runner_->Shutdown();
-  }
-
-  // VerifyTaskOrder takes the expectations from TaskOrderMarkers and compares
-  // them against the recorded values.
-  void VerifyTaskOrder(const char* const expectations[],
-                       size_t num_expectations) {
-    size_t actual_size = task_order_.size();
-
-    for (size_t i = 0; i < num_expectations; ++i) {
-      if (i >= actual_size) {
-        EXPECT_LE(i, actual_size) << "Expected " << expectations[i];
-        continue;
-      }
-
-      EXPECT_EQ(expectations[i], task_order_[i]);
-    }
-
-    if (actual_size > num_expectations) {
-      EXPECT_LE(actual_size, num_expectations) << "Extra tasks were run:";
-      for (size_t i = num_expectations; i < actual_size; ++i) {
-        EXPECT_EQ("<none>", task_order_[i]) << " (i=" << i << ")";
-      }
-    }
-  }
-
-  // The message loop for the test main thread.
-  base::MessageLoop message_loop_;
-
-  // The task runner under test.
-  scoped_refptr<base::mac::LibDispatchTaskRunner> task_runner_;
-
-  // Vector that records data from TaskOrderMarker.
-  std::vector<std::string> task_order_;
-};
-
-// Scoper that records the beginning and end of a running task.
-class TaskOrderMarker {
- public:
-  TaskOrderMarker(LibDispatchTaskRunnerTest* test, const std::string& name)
-      : test_(test),
-        name_(name) {
-    test->task_order_.push_back(std::string("BEGIN ") + name);
-  }
-  ~TaskOrderMarker() {
-    test_->task_order_.push_back(std::string("END ") + name_);
-  }
-
- private:
-  LibDispatchTaskRunnerTest* test_;
-  std::string name_;
-};
-
-void RecordTaskOrder(LibDispatchTaskRunnerTest* test, const std::string& name) {
-  TaskOrderMarker marker(test, name);
-}
-
-// Returns a closure that records the task order.
-base::Closure BoundRecordTaskOrder(LibDispatchTaskRunnerTest* test,
-                                   const std::string& name) {
-  return base::Bind(&RecordTaskOrder, base::Unretained(test), name);
-}
-
-TEST_F(LibDispatchTaskRunnerTest, PostTask) {
-  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Basic Task"));
-  DispatchLastTask();
-  const char* const expectations[] = {
-    "BEGIN Basic Task",
-    "END Basic Task"
-  };
-  VerifyTaskOrder(expectations, arraysize(expectations));
-}
-
-TEST_F(LibDispatchTaskRunnerTest, PostTaskWithinTask) {
-  task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
-      TaskOrderMarker marker(this, "Outer");
-      task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Inner"));
-  }));
-  DispatchLastTask();
-
-  const char* const expectations[] = {
-    "BEGIN Outer",
-    "END Outer",
-    "BEGIN Inner",
-    "END Inner"
-  };
-  VerifyTaskOrder(expectations, arraysize(expectations));
-}
-
-TEST_F(LibDispatchTaskRunnerTest, NoMessageLoop) {
-  task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
-      TaskOrderMarker marker(this,
-          base::StringPrintf("MessageLoop = %p", base::MessageLoop::current()));
-  }));
-  DispatchLastTask();
-
-  const char* const expectations[] = {
-    "BEGIN MessageLoop = 0x0",
-    "END MessageLoop = 0x0"
-  };
-  VerifyTaskOrder(expectations, arraysize(expectations));
-}
-
-TEST_F(LibDispatchTaskRunnerTest, DispatchAndPostTasks) {
-  dispatch_async(task_runner_->GetDispatchQueue(), ^{
-      TaskOrderMarker marker(this, "First Block");
-  });
-  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "First Task"));
-  dispatch_async(task_runner_->GetDispatchQueue(), ^{
-      TaskOrderMarker marker(this, "Second Block");
-  });
-  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Second Task"));
-  DispatchLastTask();
-
-  const char* const expectations[] = {
-    "BEGIN First Block",
-    "END First Block",
-    "BEGIN First Task",
-    "END First Task",
-    "BEGIN Second Block",
-    "END Second Block",
-    "BEGIN Second Task",
-    "END Second Task",
-  };
-  VerifyTaskOrder(expectations, arraysize(expectations));
-}
-
-TEST_F(LibDispatchTaskRunnerTest, NonNestable) {
-  task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
-      TaskOrderMarker marker(this, "First");
-      task_runner_->PostNonNestableTask(FROM_HERE, base::BindBlock(^{
-          TaskOrderMarker marker(this, "Second NonNestable");
-          message_loop_.task_runner()->PostTask(
-              FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
-      }));
-  }));
-  base::RunLoop().Run();
-  task_runner_->Shutdown();
-
-  const char* const expectations[] = {
-    "BEGIN First",
-    "END First",
-    "BEGIN Second NonNestable",
-    "END Second NonNestable"
-  };
-  VerifyTaskOrder(expectations, arraysize(expectations));
-}
-
-TEST_F(LibDispatchTaskRunnerTest, PostDelayed) {
-  base::TimeTicks post_time;
-  __block base::TimeTicks run_time;
-  const base::TimeDelta delta = base::TimeDelta::FromMilliseconds(50);
-
-  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "First"));
-  post_time = base::TimeTicks::Now();
-  task_runner_->PostDelayedTask(FROM_HERE, base::BindBlock(^{
-      TaskOrderMarker marker(this, "Timed");
-      run_time = base::TimeTicks::Now();
-      message_loop_.task_runner()->PostTask(
-          FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
-  }), delta);
-  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Second"));
-  base::RunLoop().Run();
-  task_runner_->Shutdown();
-
-  const char* const expectations[] = {
-    "BEGIN First",
-    "END First",
-    "BEGIN Second",
-    "END Second",
-    "BEGIN Timed",
-    "END Timed",
-  };
-  VerifyTaskOrder(expectations, arraysize(expectations));
-
-  EXPECT_GE(run_time, post_time + delta);
-}
-
-TEST_F(LibDispatchTaskRunnerTest, PostAfterShutdown) {
-  EXPECT_TRUE(task_runner_->PostTask(FROM_HERE,
-      BoundRecordTaskOrder(this, "First")));
-  EXPECT_TRUE(task_runner_->PostTask(FROM_HERE,
-      BoundRecordTaskOrder(this, "Second")));
-  task_runner_->Shutdown();
-  EXPECT_FALSE(task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
-      TaskOrderMarker marker(this, "Not Run");
-      ADD_FAILURE() << "Should not run a task after Shutdown";
-  })));
-
-  const char* const expectations[] = {
-    "BEGIN First",
-    "END First",
-    "BEGIN Second",
-    "END Second"
-  };
-  VerifyTaskOrder(expectations, arraysize(expectations));
-}
diff --git a/base/memory/memory_pressure_monitor.h b/base/memory/memory_pressure_monitor.h
index 6073bd3..a4adba4 100644
--- a/base/memory/memory_pressure_monitor.h
+++ b/base/memory/memory_pressure_monitor.h
@@ -6,6 +6,7 @@
 #define BASE_MEMORY_MEMORY_PRESSURE_MONITOR_H_
 
 #include "base/base_export.h"
+#include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/memory_pressure_listener.h"
 
@@ -23,6 +24,7 @@
 class BASE_EXPORT MemoryPressureMonitor {
  public:
   using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel;
+  using DispatchCallback = base::Callback<void(MemoryPressureLevel level)>;
 
   virtual ~MemoryPressureMonitor();
 
@@ -32,6 +34,10 @@
   // Returns the currently observed memory pressure.
   virtual MemoryPressureLevel GetCurrentPressureLevel() const = 0;
 
+  // Sets a notification callback. The default callback invokes
+  // base::MemoryPressureListener::NotifyMemoryPressure.
+  virtual void SetDispatchCallback(const DispatchCallback& callback) = 0;
+
  protected:
   MemoryPressureMonitor();
 
diff --git a/base/memory/memory_pressure_monitor_chromeos.cc b/base/memory/memory_pressure_monitor_chromeos.cc
index 2d0b0a6..5138d01 100644
--- a/base/memory/memory_pressure_monitor_chromeos.cc
+++ b/base/memory/memory_pressure_monitor_chromeos.cc
@@ -113,6 +113,8 @@
       critical_pressure_threshold_percent_(
           GetCriticalMemoryThresholdInPercent(thresholds)),
       low_mem_file_(HANDLE_EINTR(::open(kLowMemFile, O_RDONLY))),
+      dispatch_callback_(
+          base::Bind(&MemoryPressureListener::NotifyMemoryPressure)),
       weak_ptr_factory_(this) {
   StartObserving();
   LOG_IF(ERROR,
@@ -230,7 +232,7 @@
     return;
   }
   moderate_pressure_repeat_count_ = 0;
-  MemoryPressureListener::NotifyMemoryPressure(current_memory_pressure_level_);
+  dispatch_callback_.Run(current_memory_pressure_level_);
 }
 
 // Gets the used ChromeOS memory in percent.
@@ -271,5 +273,10 @@
   return percentage;
 }
 
+void MemoryPressureMonitor::SetDispatchCallback(
+    const DispatchCallback& callback) {
+  dispatch_callback_ = callback;
+}
+
 }  // namespace chromeos
 }  // namespace base
diff --git a/base/memory/memory_pressure_monitor_chromeos.h b/base/memory/memory_pressure_monitor_chromeos.h
index 5529c3b4..1000f300 100644
--- a/base/memory/memory_pressure_monitor_chromeos.h
+++ b/base/memory/memory_pressure_monitor_chromeos.h
@@ -60,6 +60,7 @@
   // Get the current memory pressure level.
   MemoryPressureListener::MemoryPressureLevel GetCurrentPressureLevel() const
       override;
+  void SetDispatchCallback(const DispatchCallback& callback) override;
 
   // Returns a type-casted version of the current memory pressure monitor. A
   // simple wrapper to base::MemoryPressureMonitor::Get.
@@ -107,6 +108,8 @@
   // File descriptor used to detect low memory condition.
   ScopedFD low_mem_file_;
 
+  DispatchCallback dispatch_callback_;
+
   base::WeakPtrFactory<MemoryPressureMonitor> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitor);
diff --git a/base/memory/memory_pressure_monitor_mac.cc b/base/memory/memory_pressure_monitor_mac.cc
index ec807ee..d3430e9 100644
--- a/base/memory/memory_pressure_monitor_mac.cc
+++ b/base/memory/memory_pressure_monitor_mac.cc
@@ -8,6 +8,8 @@
 #include <stddef.h>
 #include <sys/sysctl.h>
 
+#include "base/bind.h"
+#include "base/logging.h"
 #include "base/mac/mac_util.h"
 
 // Redeclare for partial 10.9 availability.
@@ -32,11 +34,12 @@
 }
 
 void MemoryPressureMonitor::NotifyMemoryPressureChanged(
-    dispatch_source_s* event_source) {
+    dispatch_source_s* event_source,
+    const MemoryPressureMonitor::DispatchCallback& dispatch_callback) {
   int mac_memory_pressure = dispatch_source_get_data(event_source);
   MemoryPressureListener::MemoryPressureLevel memory_pressure_level =
       MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure);
-  MemoryPressureListener::NotifyMemoryPressure(memory_pressure_level);
+  dispatch_callback.Run(memory_pressure_level);
 }
 
 MemoryPressureMonitor::MemoryPressureMonitor()
@@ -47,9 +50,12 @@
           DISPATCH_SOURCE_TYPE_MEMORYPRESSURE,
           0,
           DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL,
-          dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0))) {
+          dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0))),
+      dispatch_callback_(
+          base::Bind(&MemoryPressureListener::NotifyMemoryPressure)) {
   dispatch_source_set_event_handler(memory_level_event_source_, ^{
-    NotifyMemoryPressureChanged(memory_level_event_source_.get());
+    NotifyMemoryPressureChanged(memory_level_event_source_.get(),
+                                dispatch_callback_);
   });
   dispatch_resume(memory_level_event_source_);
 }
@@ -67,5 +73,10 @@
   return MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure);
 }
 
+void MemoryPressureMonitor::SetDispatchCallback(
+    const DispatchCallback& callback) {
+  dispatch_callback_ = callback;
+}
+
 }  // namespace mac
 }  // namespace base
diff --git a/base/memory/memory_pressure_monitor_mac.h b/base/memory/memory_pressure_monitor_mac.h
index b975b6e..89794f67 100644
--- a/base/memory/memory_pressure_monitor_mac.h
+++ b/base/memory/memory_pressure_monitor_mac.h
@@ -28,15 +28,21 @@
   // Returns the currently-observed memory pressure.
   MemoryPressureLevel GetCurrentPressureLevel() const override;
 
+  void SetDispatchCallback(const DispatchCallback& callback) override;
+
  private:
   friend TestMemoryPressureMonitor;
 
   static MemoryPressureLevel
       MemoryPressureLevelForMacMemoryPressure(int mac_memory_pressure);
-  static void NotifyMemoryPressureChanged(dispatch_source_s* event_source);
+  static void NotifyMemoryPressureChanged(
+      dispatch_source_s* event_source,
+      const DispatchCallback& dispatch_callback);
 
   ScopedDispatchObject<dispatch_source_t> memory_level_event_source_;
 
+  DispatchCallback dispatch_callback_;
+
   DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitor);
 };
 
diff --git a/base/memory/memory_pressure_monitor_win.cc b/base/memory/memory_pressure_monitor_win.cc
index 8ac66ce..a93b425 100644
--- a/base/memory/memory_pressure_monitor_win.cc
+++ b/base/memory/memory_pressure_monitor_win.cc
@@ -82,6 +82,8 @@
       current_memory_pressure_level_(
           MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
       moderate_pressure_repeat_count_(0),
+      dispatch_callback_(
+          base::Bind(&MemoryPressureListener::NotifyMemoryPressure)),
       weak_ptr_factory_(this) {
   InferThresholds();
   StartObserving();
@@ -94,6 +96,8 @@
       current_memory_pressure_level_(
           MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
       moderate_pressure_repeat_count_(0),
+      dispatch_callback_(
+          base::Bind(&MemoryPressureListener::NotifyMemoryPressure)),
       weak_ptr_factory_(this) {
   DCHECK_GE(moderate_threshold_mb_, critical_threshold_mb_);
   DCHECK_LE(0, critical_threshold_mb_);
@@ -198,7 +202,7 @@
   // happen for moderate and critical pressure levels.
   DCHECK_NE(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
             current_memory_pressure_level_);
-  MemoryPressureListener::NotifyMemoryPressure(current_memory_pressure_level_);
+  dispatch_callback_.Run(current_memory_pressure_level_);
 }
 
 void MemoryPressureMonitor::CheckMemoryPressureAndRecordStatistics() {
@@ -250,5 +254,10 @@
   return true;
 }
 
+void MemoryPressureMonitor::SetDispatchCallback(
+    const DispatchCallback& callback) {
+  dispatch_callback_ = callback;
+}
+
 }  // namespace win
 }  // namespace base
diff --git a/base/memory/memory_pressure_monitor_win.h b/base/memory/memory_pressure_monitor_win.h
index 5689ac6..b52a2d2 100644
--- a/base/memory/memory_pressure_monitor_win.h
+++ b/base/memory/memory_pressure_monitor_win.h
@@ -63,6 +63,7 @@
 
   // Get the current memory pressure level. This can be called from any thread.
   MemoryPressureLevel GetCurrentPressureLevel() const override;
+  void SetDispatchCallback(const DispatchCallback& callback) override;
 
   // Returns the moderate pressure level free memory threshold, in MB.
   int moderate_threshold_mb() const { return moderate_threshold_mb_; }
@@ -132,6 +133,8 @@
   // Ensures that this object is used from a single thread.
   base::ThreadChecker thread_checker_;
 
+  DispatchCallback dispatch_callback_;
+
   // Weak pointer factory to ourself used for scheduling calls to
   // CheckMemoryPressure/CheckMemoryPressureAndRecordStatistics via |timer_|.
   base::WeakPtrFactory<MemoryPressureMonitor> weak_ptr_factory_;
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 9d37691..ee936928 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -464,7 +464,8 @@
   if (deferred_non_nestable_work_queue_.empty())
     return false;
 
-  PendingTask pending_task = deferred_non_nestable_work_queue_.front();
+  PendingTask pending_task =
+      std::move(deferred_non_nestable_work_queue_.front());
   deferred_non_nestable_work_queue_.pop();
 
   RunTask(pending_task);
@@ -497,7 +498,7 @@
   nestable_tasks_allowed_ = true;
 }
 
-bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) {
+bool MessageLoop::DeferOrRunPendingTask(PendingTask pending_task) {
   if (pending_task.nestable || run_loop_->run_depth_ == 1) {
     RunTask(pending_task);
     // Show that we ran a task (Note: a new one might arrive as a
@@ -507,25 +508,25 @@
 
   // We couldn't run the task now because we're in a nested message loop
   // and the task isn't nestable.
-  deferred_non_nestable_work_queue_.push(pending_task);
+  deferred_non_nestable_work_queue_.push(std::move(pending_task));
   return false;
 }
 
-void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) {
+void MessageLoop::AddToDelayedWorkQueue(PendingTask pending_task) {
   // Move to the delayed work queue.
-  delayed_work_queue_.push(pending_task);
+  delayed_work_queue_.push(std::move(pending_task));
 }
 
 bool MessageLoop::DeletePendingTasks() {
   bool did_work = !work_queue_.empty();
   while (!work_queue_.empty()) {
-    PendingTask pending_task = work_queue_.front();
+    PendingTask pending_task = std::move(work_queue_.front());
     work_queue_.pop();
     if (!pending_task.delayed_run_time.is_null()) {
       // We want to delete delayed tasks in the same order in which they would
       // normally be deleted in case of any funny dependencies between delayed
       // tasks.
-      AddToDelayedWorkQueue(pending_task);
+      AddToDelayedWorkQueue(std::move(pending_task));
     }
   }
   did_work |= !deferred_non_nestable_work_queue_.empty();
@@ -613,15 +614,17 @@
 
     // Execute oldest task.
     do {
-      PendingTask pending_task = work_queue_.front();
+      PendingTask pending_task = std::move(work_queue_.front());
       work_queue_.pop();
       if (!pending_task.delayed_run_time.is_null()) {
-        AddToDelayedWorkQueue(pending_task);
+        int sequence_num = pending_task.sequence_num;
+        TimeTicks delayed_run_time = pending_task.delayed_run_time;
+        AddToDelayedWorkQueue(std::move(pending_task));
         // If we changed the topmost task, then it is time to reschedule.
-        if (delayed_work_queue_.top().task.Equals(pending_task.task))
-          pump_->ScheduleDelayedWork(pending_task.delayed_run_time);
+        if (delayed_work_queue_.top().sequence_num == sequence_num)
+          pump_->ScheduleDelayedWork(delayed_run_time);
       } else {
-        if (DeferOrRunPendingTask(pending_task))
+        if (DeferOrRunPendingTask(std::move(pending_task)))
           return true;
       }
     } while (!work_queue_.empty());
@@ -653,13 +656,14 @@
     }
   }
 
-  PendingTask pending_task = delayed_work_queue_.top();
+  PendingTask pending_task =
+      std::move(const_cast<PendingTask&>(delayed_work_queue_.top()));
   delayed_work_queue_.pop();
 
   if (!delayed_work_queue_.empty())
     *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
 
-  return DeferOrRunPendingTask(pending_task);
+  return DeferOrRunPendingTask(std::move(pending_task));
 }
 
 bool MessageLoop::DoIdleWork() {
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index 1230f41..761c18c 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -450,10 +450,10 @@
 
   // Calls RunTask or queues the pending_task on the deferred task list if it
   // cannot be run right now.  Returns true if the task was run.
-  bool DeferOrRunPendingTask(const PendingTask& pending_task);
+  bool DeferOrRunPendingTask(PendingTask pending_task);
 
   // Adds the pending task to delayed_work_queue_.
-  void AddToDelayedWorkQueue(const PendingTask& pending_task);
+  void AddToDelayedWorkQueue(PendingTask pending_task);
 
   // Delete tasks that haven't run yet without running them.  Used in the
   // destructor to make sure all the task's destructors get called.  Returns
diff --git a/base/message_loop/message_pump_perftest.cc b/base/message_loop/message_pump_perftest.cc
index 7bb942f..6cf89bd 100644
--- a/base/message_loop/message_pump_perftest.cc
+++ b/base/message_loop/message_pump_perftest.cc
@@ -271,7 +271,7 @@
         TaskQueue loop_local_queue;
         queue->ReloadWorkQueue(&loop_local_queue);
         while (!loop_local_queue.empty()) {
-          PendingTask t = loop_local_queue.front();
+          PendingTask t = std::move(loop_local_queue.front());
           loop_local_queue.pop();
           loop.RunTask(t);
         }
diff --git a/base/pending_task.cc b/base/pending_task.cc
index c0999bab..73834bd 100644
--- a/base/pending_task.cc
+++ b/base/pending_task.cc
@@ -9,9 +9,9 @@
 namespace base {
 
 PendingTask::PendingTask(const tracked_objects::Location& posted_from,
-                         const base::Closure& task)
+                         base::Closure task)
     : base::TrackingInfo(posted_from, TimeTicks()),
-      task(task),
+      task(std::move(task)),
       posted_from(posted_from),
       sequence_num(0),
       nestable(true),
@@ -19,22 +19,24 @@
 }
 
 PendingTask::PendingTask(const tracked_objects::Location& posted_from,
-                         const base::Closure& task,
+                         base::Closure task,
                          TimeTicks delayed_run_time,
                          bool nestable)
     : base::TrackingInfo(posted_from, delayed_run_time),
-      task(task),
+      task(std::move(task)),
       posted_from(posted_from),
       sequence_num(0),
       nestable(nestable),
       is_high_res(false) {
 }
 
-PendingTask::PendingTask(const PendingTask& other) = default;
+PendingTask::PendingTask(PendingTask&& other) = default;
 
 PendingTask::~PendingTask() {
 }
 
+PendingTask& PendingTask::operator=(PendingTask&& other) = default;
+
 bool PendingTask::operator<(const PendingTask& other) const {
   // Since the top of a priority queue is defined as the "greatest" element, we
   // need to invert the comparison here.  We want the smaller time to be at the
diff --git a/base/pending_task.h b/base/pending_task.h
index c31ab9a..5761653 100644
--- a/base/pending_task.h
+++ b/base/pending_task.h
@@ -19,14 +19,16 @@
 // for use by classes that queue and execute tasks.
 struct BASE_EXPORT PendingTask : public TrackingInfo {
   PendingTask(const tracked_objects::Location& posted_from,
-              const Closure& task);
+              Closure task);
   PendingTask(const tracked_objects::Location& posted_from,
-              const Closure& task,
+              Closure task,
               TimeTicks delayed_run_time,
               bool nestable);
-  PendingTask(const PendingTask& other);
+  PendingTask(PendingTask&& other);
   ~PendingTask();
 
+  PendingTask& operator=(PendingTask&& other);
+
   // Used to support sorting.
   bool operator<(const PendingTask& other) const;
 
diff --git a/base/third_party/symbolize/utilities.h b/base/third_party/symbolize/utilities.h
index 3971145..65c5ba0 100644
--- a/base/third_party/symbolize/utilities.h
+++ b/base/third_party/symbolize/utilities.h
@@ -6,6 +6,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-typedef uint64_t uint64_t;
+
 #define HAVE_SYMBOLIZE 1
 #define ATTRIBUTE_NOINLINE __attribute__ ((noinline))
diff --git a/base/threading/worker_pool_posix.cc b/base/threading/worker_pool_posix.cc
index dcebe0a..b0a2b871 100644
--- a/base/threading/worker_pool_posix.cc
+++ b/base/threading/worker_pool_posix.cc
@@ -150,8 +150,7 @@
   DCHECK(!terminated_)
       << "This thread pool is already terminated.  Do not post new tasks.";
 
-  pending_tasks_.push(*pending_task);
-  pending_task->task.Reset();
+  pending_tasks_.push(std::move(*pending_task));
 
   // We have enough worker threads.
   if (static_cast<size_t>(num_idle_threads_) >= pending_tasks_.size()) {
@@ -186,7 +185,7 @@
     }
   }
 
-  PendingTask pending_task = pending_tasks_.front();
+  PendingTask pending_task = std::move(pending_tasks_.front());
   pending_tasks_.pop();
   return pending_task;
 }
diff --git a/base/trace_event/trace_config.cc b/base/trace_event/trace_config.cc
index d4dc2cc2..ebdddd3 100644
--- a/base/trace_event/trace_config.cc
+++ b/base/trace_event/trace_config.cc
@@ -14,6 +14,7 @@
 #include "base/strings/pattern.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/memory_dump_request_args.h"
@@ -411,7 +412,8 @@
       if (category.empty())
         continue;
       // Synthetic delays are of the form 'DELAY(delay;option;option;...)'.
-      if (category.find(kSyntheticDelayCategoryFilterPrefix) == 0 &&
+      if (base::StartsWith(category, kSyntheticDelayCategoryFilterPrefix,
+                           base::CompareCase::SENSITIVE) &&
           category.at(category.size() - 1) == ')') {
         category = category.substr(
             strlen(kSyntheticDelayCategoryFilterPrefix),
diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc
index 0661caf6..db1db257 100644
--- a/base/trace_event/trace_log.cc
+++ b/base/trace_event/trace_log.cc
@@ -334,7 +334,7 @@
 }
 
 struct TraceLog::RegisteredAsyncObserver {
-  RegisteredAsyncObserver(WeakPtr<AsyncEnabledStateObserver> observer)
+  explicit RegisteredAsyncObserver(WeakPtr<AsyncEnabledStateObserver> observer)
       : observer(observer), task_runner(ThreadTaskRunnerHandle::Get()) {}
   ~RegisteredAsyncObserver() {}
 
@@ -897,7 +897,7 @@
     flush_task_runner_ = ThreadTaskRunnerHandle::IsSet()
                              ? ThreadTaskRunnerHandle::Get()
                              : nullptr;
-    DCHECK(!thread_message_loops_.size() || flush_task_runner_);
+    DCHECK(thread_message_loops_.empty() || flush_task_runner_);
     flush_output_callback_ = cb;
 
     if (thread_shared_chunk_) {
@@ -1354,11 +1354,12 @@
           phase == TRACE_EVENT_PHASE_COMPLETE) {
         AllocationContextTracker::GetInstanceForCurrentThread()
             ->PushPseudoStackFrame(name);
-      } else if (phase == TRACE_EVENT_PHASE_END)
+      } else if (phase == TRACE_EVENT_PHASE_END) {
         // The pop for |TRACE_EVENT_PHASE_COMPLETE| events
         // is in |TraceLog::UpdateTraceEventDuration|.
         AllocationContextTracker::GetInstanceForCurrentThread()
             ->PopPseudoStackFrame(name);
+      }
     }
   }
 
diff --git a/build/android/adb_command_line.py b/build/android/adb_command_line.py
index 72f42b6..e758b09 100755
--- a/build/android/adb_command_line.py
+++ b/build/android/adb_command_line.py
@@ -44,7 +44,7 @@
     def read_flags(device):
       try:
         return device.ReadFile(args.device_path, as_root=as_root).rstrip()
-      except device_errors.AdbCommandFailedError:
+      except device_errors.CommandFailedError:
         return ''  # File might not exist.
 
     descriptions = all_devices.pMap(lambda d: d.build_description).pGet(None)
diff --git a/build/android/gyp/emma_instr.py b/build/android/gyp/emma_instr.py
index 9ba6776..abb5653e 100755
--- a/build/android/gyp/emma_instr.py
+++ b/build/android/gyp/emma_instr.py
@@ -58,6 +58,8 @@
                            help='Space separated list of source files. '
                                 'source-dirs should not be specified if '
                                 'source-files is specified')
+  option_parser.add_option('--java-sources-file',
+                           help='File containing newline-separated .java paths')
   option_parser.add_option('--src-root',
                            help='Root of the src repository.')
   option_parser.add_option('--emma-jar',
@@ -102,17 +104,15 @@
                              build_utils.GetPythonDependencies())
 
 
-def _GetSourceDirsFromSourceFiles(source_files_string):
-  """Returns list of directories for the files in |source_files_string|.
+def _GetSourceDirsFromSourceFiles(source_files):
+  """Returns list of directories for the files in |source_files|.
 
   Args:
-    source_files_string: String generated from GN or GYP containing the list
-      of source files.
+    source_files: List of source files.
 
   Returns:
     List of source directories.
   """
-  source_files = build_utils.ParseGypList(source_files_string)
   return list(set(os.path.dirname(source_file) for source_file in source_files))
 
 
@@ -158,7 +158,8 @@
   """
   if not (options.input_path and options.output_path and
           options.coverage_file and options.sources_list_file and
-          (options.source_files or options.source_dirs) and
+          (options.source_files or options.source_dirs or
+           options.java_sources_file) and
           options.src_root and options.emma_jar):
     option_parser.error('All arguments are required.')
 
@@ -196,7 +197,17 @@
   if options.source_dirs:
     source_dirs = build_utils.ParseGypList(options.source_dirs)
   else:
-    source_dirs = _GetSourceDirsFromSourceFiles(options.source_files)
+    source_files = []
+    if options.source_files:
+      source_files += build_utils.ParseGypList(options.source_files)
+    if options.java_sources_file:
+      with open(options.java_sources_file) as f:
+        source_files.extend(l.strip() for l in f)
+    source_dirs = _GetSourceDirsFromSourceFiles(source_files)
+
+  # TODO(GYP): In GN, we are passed the list of sources, detecting source
+  # directories, then walking them to re-establish the list of sources.
+  # This can obviously be simplified!
   _CreateSourcesListFile(source_dirs, options.sources_list_file,
                          options.src_root)
 
diff --git a/build/android/gyp/javac.py b/build/android/gyp/javac.py
index 6c91424..7b5264d3 100755
--- a/build/android/gyp/javac.py
+++ b/build/android/gyp/javac.py
@@ -324,7 +324,17 @@
   options.javac_includes = build_utils.ParseGypList(options.javac_includes)
   options.jar_excluded_classes = (
       build_utils.ParseGypList(options.jar_excluded_classes))
-  return options, args
+
+  java_files = []
+  for arg in args:
+    # Interpret a path prefixed with @ as a file containing a list of sources.
+    if arg.startswith('@'):
+      with open(arg[1:]) as f:
+        java_files.extend(l.strip() for l in f)
+    else:
+      java_files.append(arg)
+
+  return options, java_files
 
 
 def main(argv):
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index edb1f4b..9f5e3e3 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -131,6 +131,15 @@
     self.all_deps_config_paths.remove(path)
     self.all_deps_configs.remove(GetDepConfig(path))
 
+  def PrebuiltJarPaths(self):
+    ret = []
+    for config in self.Direct('java_library'):
+      if config['is_prebuilt']:
+        ret.append(config['jar_path'])
+        ret.extend(Deps(config['deps_configs']).PrebuiltJarPaths())
+    return ret
+
+
 def _MergeAssets(all_assets):
   """Merges all assets from the given deps.
 
@@ -226,6 +235,7 @@
 
   # java library options
   parser.add_option('--jar-path', help='Path to target\'s jar output.')
+  parser.add_option('--java-sources-file', help='Path to .sources file')
   parser.add_option('--supports-android', action='store_true',
       help='Whether this library supports running on the Android platform.')
   parser.add_option('--requires-android', action='store_true',
@@ -267,6 +277,7 @@
   required_options_map = {
       'java_binary': ['build_config', 'jar_path'],
       'java_library': ['build_config', 'jar_path'],
+      'java_prebuilt': ['build_config', 'jar_path'],
       'android_assets': ['build_config'],
       'android_resources': ['build_config', 'resources_zip'],
       'android_apk': ['build_config', 'jar_path', 'dex_path', 'resources_zip'],
@@ -280,6 +291,11 @@
 
   build_utils.CheckOptions(options, parser, required_options)
 
+  # Java prebuilts are the same as libraries except for in gradle files.
+  is_java_prebuilt = options.type == 'java_prebuilt'
+  if is_java_prebuilt:
+    options.type = 'java_library'
+
   if options.type == 'java_library':
     if options.supports_android and not options.dex_path:
       raise Exception('java_library that supports Android requires a dex path.')
@@ -325,15 +341,33 @@
         d for d in all_resources_deps if not d in tested_apk_resources_deps]
 
   # Initialize some common config.
+  # Any value that needs to be queryable by dependents must go within deps_info.
   config = {
     'deps_info': {
       'name': os.path.basename(options.build_config),
       'path': options.build_config,
       'type': options.type,
       'deps_configs': direct_deps_config_paths
-    }
+    },
+    # Info needed only by generate_gradle.py.
+    'gradle': {}
   }
   deps_info = config['deps_info']
+  gradle = config['gradle']
+
+  # Required for generating gradle files.
+  if options.type == 'java_library':
+    deps_info['is_prebuilt'] = is_java_prebuilt
+
+  if options.android_manifest:
+    gradle['android_manifest'] = options.android_manifest
+  if options.type in ('java_binary', 'java_library', 'android_apk'):
+    if options.java_sources_file:
+      gradle['java_sources_file'] = options.java_sources_file
+    gradle['dependent_prebuilt_jars'] = deps.PrebuiltJarPaths()
+    gradle['dependent_projects'] = (
+        [c['path'] for c in direct_library_deps if not c['is_prebuilt']])
+
 
   if (options.type in ('java_binary', 'java_library') and
       not options.bypass_platform_checks):
@@ -367,6 +401,7 @@
     # Classpath values filled in below (after applying tested_apk_config).
     config['javac'] = {}
 
+
   if options.type in ('java_binary', 'java_library'):
     # Only resources might have srcjars (normal srcjar targets are listed in
     # srcjar_deps). A resource's srcjar contains the R.java file for those
diff --git a/build/common.gypi b/build/common.gypi
index 7120836..66f152d 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -4634,19 +4634,20 @@
 
             'target_conditions': [
               ['_toolset=="target"', {
-                'ldflags': [
-                  # Experimentation found that using four linking threads
-                  # saved ~20% of link time.
-                  # https://groups.google.com/a/chromium.org/group/chromium-dev/browse_thread/thread/281527606915bb36
-                  # Only apply this to the target linker, since the host
-                  # linker might not be gold, but isn't used much anyway.
-                  # TODO(raymes): Disable threading because gold is frequently
-                  # crashing on the bots: crbug.com/161942.
-                  # '-Wl,--threads',
-                  # '-Wl,--thread-count=4',
-                ],
                 'conditions': [
                   # TODO(thestig): Enable this for disabled cases.
+                  [ 'linux_use_bundled_binutils==1', {
+                    'ldflags': [
+                      # Experimentation found that using four linking threads
+                      # saved ~20% of link time.
+                      # https://groups.google.com/a/chromium.org/group/chromium-dev/browse_thread/thread/281527606915bb36
+                      # Only apply this to the target linker, since the host
+                      # linker might not be gold, but isn't used much anyway.
+                      '-Wl,--threads',
+                      '-Wl,--thread-count=4',
+                    ],
+                  }],
+                  # TODO(thestig): Enable this for disabled cases.
                   [ 'buildtype!="Official" and chromeos==0 and release_valgrind_build==0 and asan==0 and lsan==0 and tsan==0 and msan==0 and ubsan==0 and ubsan_security==0 and ubsan_vptr==0', {
                     'ldflags': [
                       '-Wl,--detect-odr-violations',
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index d177932..363a53a 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -102,7 +102,7 @@
     assert(type == "android_apk" || type == "java_library" ||
            type == "android_resources" || type == "deps_dex" ||
            type == "android_assets" || type == "resource_rewriter" ||
-           type == "java_binary" || type == "group")
+           type == "java_binary" || type == "group" || type == "java_prebuilt")
 
     forward_variables_from(invoker,
                            [
@@ -159,7 +159,8 @@
       rebase_path(build_config, root_build_dir),
     ]
 
-    is_java = type == "java_library" || type == "java_binary"
+    is_java = type == "java_library" || type == "java_binary" ||
+              type == "java_prebuilt"
     is_apk = type == "android_apk"
     is_android_assets = type == "android_assets"
     is_android_resources = type == "android_resources"
@@ -314,6 +315,12 @@
       }
     }
 
+    if (defined(invoker.java_sources_file)) {
+      args += [
+        "--java-sources-file",
+        rebase_path(invoker.java_sources_file, root_build_dir),
+      ]
+    }
     if (defined(invoker.srcjar)) {
       args += [
         "--srcjar",
@@ -1039,77 +1046,56 @@
   }
 
   template("emma_instr") {
-    set_sources_assignment_filter([])
-    forward_variables_from(invoker, [ "testonly" ])
+    action(target_name) {
+      forward_variables_from(invoker,
+                             [
+                               "deps",
+                               "testonly",
+                             ])
 
-    assert(invoker.source_files != [] || true)  # Mark as used
-
-    if (invoker.emma_instrument) {
-      _output_jar_target = "${target_name}__process"
       _coverage_file = "$target_out_dir/${target_name}.em"
       _source_dirs_listing_file = "$target_out_dir/${target_name}_sources.txt"
       _emma_jar = "${android_sdk_root}/tools/lib/emma.jar"
-      _rebased_source_files = rebase_path(invoker.source_files, root_build_dir)
-      action(_output_jar_target) {
-        forward_variables_from(invoker, [ "deps" ])
 
-        script = "//build/android/gyp/emma_instr.py"
-        depfile = "${target_gen_dir}/${target_name}.d"
-        inputs = [
-          _emma_jar,
-          invoker.input_jar_path,
-        ]
-        outputs = [
-          depfile,
-          _coverage_file,
-          _source_dirs_listing_file,
-          invoker.output_jar_path,
-        ]
-        args = [
-          "instrument_jar",
-          "--input-path",
-          rebase_path(invoker.input_jar_path, root_build_dir),
-          "--output-path",
-          rebase_path(invoker.output_jar_path, root_build_dir),
-          "--depfile",
-          rebase_path(depfile, root_build_dir),
-          "--coverage-file",
-          rebase_path(_coverage_file, root_build_dir),
-          "--sources-list-file",
-          rebase_path(_source_dirs_listing_file, root_build_dir),
-          "--source-files=$_rebased_source_files",
-          "--src-root",
-          rebase_path("//", root_build_dir),
-          "--emma-jar",
-          rebase_path(_emma_jar, root_build_dir),
-        ]
-
-        if (emma_filter != "") {
-          args += [
-            "--filter-string",
-            emma_filter,
-          ]
-        }
-      }
-    } else {
-      _output_jar_target = "${target_name}__copy_jar"
-      copy(_output_jar_target) {
-        forward_variables_from(invoker, [ "deps" ])
-
-        sources = [
-          invoker.input_jar_path,
-        ]
-        outputs = [
-          invoker.output_jar_path,
-        ]
-      }
-    }
-
-    group(target_name) {
-      forward_variables_from(invoker, [ "visibility" ])
-      public_deps = [
-        ":$_output_jar_target",
+      script = "//build/android/gyp/emma_instr.py"
+      depfile = "${target_gen_dir}/${target_name}.d"
+      inputs = invoker.java_files + [
+                 _emma_jar,
+                 invoker.input_jar_path,
+               ]
+      outputs = [
+        depfile,
+        _coverage_file,
+        _source_dirs_listing_file,
+        invoker.output_jar_path,
       ]
+      args = [
+        "instrument_jar",
+        "--input-path",
+        rebase_path(invoker.input_jar_path, root_build_dir),
+        "--output-path",
+        rebase_path(invoker.output_jar_path, root_build_dir),
+        "--depfile",
+        rebase_path(depfile, root_build_dir),
+        "--coverage-file",
+        rebase_path(_coverage_file, root_build_dir),
+        "--sources-list-file",
+        rebase_path(_source_dirs_listing_file, root_build_dir),
+        "--src-root",
+        rebase_path("//", root_build_dir),
+        "--emma-jar",
+        rebase_path(_emma_jar, root_build_dir),
+      ]
+      _rebased_java_sources_file =
+          rebase_path(invoker.java_sources_file, root_build_dir)
+      args += [ "--java-sources-file=$_rebased_java_sources_file" ]
+
+      if (emma_filter != "") {
+        args += [
+          "--filter-string",
+          emma_filter,
+        ]
+      }
     }
   }
 
@@ -1688,7 +1674,7 @@
     }
 
     write_build_config(_build_config_target_name) {
-      type = "java_library"
+      type = "java_prebuilt"
       supports_android = _supports_android
       requires_android =
           defined(invoker.requires_android) && invoker.requires_android
@@ -1797,7 +1783,8 @@
   #  $jar_path.interface.jar
   #
   # Variables
-  #   java_files: List of .java files to compile.
+  #   java_files: List of .java files to compile (same as exists in java_sources_file)
+  #   java_sources_file: Path to file containing list of files to compile.
   #   chromium_code: If true, enable extra warnings.
   #   srcjar_deps: List of srcjar dependencies. The .java files contained in the
   #     dependencies srcjar outputs will be compiled and added to the output jar.
@@ -1807,18 +1794,9 @@
     set_sources_assignment_filter([])
     forward_variables_from(invoker, [ "testonly" ])
 
-    assert(defined(invoker.java_files))
     assert(defined(invoker.build_config))
     assert(defined(invoker.jar_path))
 
-    _java_files = invoker.java_files
-    _final_jar_path = invoker.jar_path
-    _javac_jar_path = "$target_gen_dir/$target_name.javac.jar"
-    _process_prebuilt_jar_path =
-        "$target_gen_dir/$target_name.process_prebuilt.jar"
-    _final_ijar_path = get_path_info(_final_jar_path, "dir") + "/" +
-                       get_path_info(_final_jar_path, "name") + ".interface.jar"
-
     _build_config = invoker.build_config
 
     _input_jars_paths = []
@@ -1891,15 +1869,28 @@
     # Mark srcjar_deps as used.
     assert(_srcjar_deps == [] || true)
 
-    _rebased_build_config = rebase_path(_build_config, root_build_dir)
-    _rebased_jar_path = rebase_path(_javac_jar_path, root_build_dir)
-
     _javac_target_name = "${target_name}__javac"
     _process_prebuilt_target_name = "${target_name}__process_prebuilt"
-    _emma_instr_target_name = "${target_name}__emma_instr"
     _ijar_target_name = "${target_name}__ijar"
     _final_target_name = target_name
 
+    _final_jar_path = invoker.jar_path
+    _javac_jar_path = "$target_gen_dir/$target_name.javac.jar"
+    _process_prebuilt_jar_path = _final_jar_path
+    _final_ijar_path = get_path_info(_final_jar_path, "dir") + "/" +
+                       get_path_info(_final_jar_path, "name") + ".interface.jar"
+
+    _emma_instrument = defined(invoker.emma_instrument) &&
+                       invoker.emma_instrument && invoker.java_files != []
+    if (_emma_instrument) {
+      _emma_instr_target_name = "${target_name}__emma_instr"
+      _process_prebuilt_jar_path =
+          "$target_gen_dir/$target_name.process_prebuilt.jar"
+    }
+
+    _rebased_build_config = rebase_path(_build_config, root_build_dir)
+    _rebased_jar_path = rebase_path(_javac_jar_path, root_build_dir)
+
     action(_javac_target_name) {
       script = "//build/android/gyp/javac.py"
       depfile = "$target_gen_dir/$target_name.d"
@@ -1913,10 +1904,13 @@
         _javac_jar_path,
         _javac_jar_path + ".md5.stamp",
       ]
-      sources = _java_files + _java_srcjars
+      sources = invoker.java_files + _java_srcjars
       inputs = [
         _build_config,
       ]
+      if (invoker.java_files != []) {
+        inputs += [ invoker.java_sources_file ]
+      }
 
       _rebased_java_srcjars = rebase_path(_java_srcjars, root_build_dir)
       _rebased_depfile = rebase_path(depfile, root_build_dir)
@@ -1976,7 +1970,9 @@
       foreach(e, _processor_args) {
         args += [ "--processor-arg=" + e ]
       }
-      args += rebase_path(_java_files, root_build_dir)
+      if (invoker.java_files != []) {
+        args += [ "@" + rebase_path(invoker.java_sources_file, root_build_dir) ]
+      }
     }
 
     process_java_prebuilt(_process_prebuilt_target_name) {
@@ -1996,37 +1992,47 @@
       }
     }
 
-    emma_instr(_emma_instr_target_name) {
-      visibility = [
-        ":$_ijar_target_name",
-        ":$_final_target_name",
-      ]
+    if (_emma_instrument) {
+      emma_instr(_emma_instr_target_name) {
+        forward_variables_from(invoker,
+                               [
+                                 "java_files",
+                                 "java_sources_file",
+                               ])
 
-      forward_variables_from(invoker, [ "emma_instrument" ])
+        input_jar_path = _process_prebuilt_jar_path
+        output_jar_path = _final_jar_path
 
-      input_jar_path = _process_prebuilt_jar_path
-      output_jar_path = _final_jar_path
-      source_files = _java_files
-
-      deps = [
-        ":$_process_prebuilt_target_name",
-      ]
+        deps = [
+          ":$_process_prebuilt_target_name",
+        ]
+      }
     }
 
     generate_interface_jar(_ijar_target_name) {
       input_jar = _final_jar_path
       output_jar = _final_ijar_path
-      deps = [
-        ":$_emma_instr_target_name",
-      ]
+      if (_emma_instrument) {
+        deps = [
+          ":$_emma_instr_target_name",
+        ]
+      } else {
+        deps = [
+          ":$_process_prebuilt_target_name",
+        ]
+      }
     }
 
     group(_final_target_name) {
       forward_variables_from(invoker, [ "visibility" ])
       public_deps = [
-        ":$_emma_instr_target_name",
         ":$_ijar_target_name",
       ]
+      if (_emma_instrument) {
+        public_deps += [ ":$_emma_instr_target_name" ]
+      } else {
+        public_deps += [ ":$_process_prebuilt_target_name" ]
+      }
     }
   }
 
@@ -2112,6 +2118,15 @@
       }
     }
 
+    _java_files = []
+    if (defined(invoker.java_files)) {
+      _java_files += invoker.java_files
+    }
+    if (_java_files != []) {
+      _java_sources_file = "$_base_path.sources"
+      write_file(_java_sources_file, rebase_path(_java_files, root_build_dir))
+    }
+
     # Define build_config_deps which will be a list of targets required to
     # build the _build_config.
     if (defined(invoker.override_build_config)) {
@@ -2139,6 +2154,9 @@
         if (_supports_android) {
           dex_path = _dex_path
         }
+        if (_java_files != []) {
+          java_sources_file = _java_sources_file
+        }
       }
       _accumulated_deps += [ ":$build_config_target_name" ]
     }
@@ -2153,10 +2171,6 @@
       _srcjars = invoker.srcjars
     }
 
-    _java_files = []
-    if (defined(invoker.java_files)) {
-      _java_files += invoker.java_files
-    }
     assert(_java_files != [] || _srcjar_deps != [] || _srcjars != [])
 
     _compile_java_target = "${_template_name}__compile_java"
@@ -2181,6 +2195,9 @@
       jar_path = _jar_path
       build_config = _build_config
       java_files = _java_files
+      if (_java_files != []) {
+        java_sources_file = _java_sources_file
+      }
       srcjar_deps = _srcjar_deps
       srcjars = _srcjars
       chromium_code = _chromium_code
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 7b1bbed..a6cc4fe 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1676,6 +1676,9 @@
       if (defined(invoker.deps)) {
         deps += invoker.deps
       }
+      if (defined(invoker.alternative_locale_resource_dep)) {
+        deps += [ invoker.alternative_locale_resource_dep ]
+      }
     }
     _srcjar_deps += [ ":$process_resources_target" ]
 
@@ -1783,6 +1786,9 @@
       if (defined(invoker.apk_under_test)) {
         deps += [ "${invoker.apk_under_test}__java" ]
       }
+      if (emma_coverage && !_emma_never_instrument) {
+        deps += [ "//third_party/android_tools:emma_device" ]
+      }
     }
 
     # TODO(cjhopman): This is only ever needed to calculate the list of tests to
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 15ff58c..30d8017 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -208,8 +208,7 @@
     }
 
     # Linker warnings.
-    if ( fatal_linker_warnings &&
-        !(is_chromeos && current_cpu == "arm") &&
+    if (fatal_linker_warnings && !(is_chromeos && current_cpu == "arm") &&
         !(is_android && use_order_profiling) && !is_mac && !is_ios) {
       # TODO(jochen): Enable this on chromeos on arm. http://crbug.com/356580
       # TODO(lizeb,pasko): Fix link errors when linking with order_profiling=1
@@ -318,18 +317,19 @@
         cflags += [ "-mstackrealign" ]
       }
     } else {
-      ldflags += [
-        "-B$gold_path",
-        # Experimentation found that using four linking threads
-        # saved ~20% of link time.
-        # https://groups.google.com/a/chromium.org/group/chromium-dev/browse_thread/thread/281527606915bb36
-        # Only apply this to the target linker, since the host
-        # linker might not be gold, but isn't used much anyway.
-        # TODO(raymes): Disable threading because gold is frequently
-        # crashing on the bots: crbug.com/161942.
-        #"-Wl,--threads",
-        #"-Wl,--thread-count=4",
-      ]
+      ldflags += [ "-B$gold_path" ]
+
+      if (linux_use_bundled_binutils) {
+        ldflags += [
+          # Experimentation found that using four linking threads
+          # saved ~20% of link time.
+          # https://groups.google.com/a/chromium.org/group/chromium-dev/browse_thread/thread/281527606915bb36
+          # Only apply this to the target linker, since the host
+          # linker might not be gold, but isn't used much anyway.
+          "-Wl,--threads",
+          "-Wl,--thread-count=4",
+        ]
+      }
     }
 
     if (gdb_index) {
diff --git a/build/config/ios/rules.gni b/build/config/ios/rules.gni
index ac2c61ac..219b580b 100644
--- a/build/config/ios/rules.gni
+++ b/build/config/ios/rules.gni
@@ -377,6 +377,58 @@
   }
 }
 
+# Compile a strings file and add it to a bundle_data so that it is available
+# at runtime in the bundle.
+#
+# Arguments
+#
+#   source:
+#       string, path of the strings file to compile.
+#
+#   output:
+#       string, path of the compiled file in the final bundle.
+#
+# Forwards all variables to the bundle_data target.
+template("bundle_data_strings") {
+  assert(defined(invoker.source), "source needs to be defined for $target_name")
+  assert(defined(invoker.output), "output needs to be defined for $target_name")
+
+  _source_extension = get_path_info(invoker.source, "extension")
+  assert(_source_extension == "strings",
+         "source must be a .strings for $target_name")
+
+  _target_name = target_name
+  _convert_target = target_name + "_compile_strings"
+
+  convert_plist(_convert_target) {
+    visibility = [ ":$_target_name" ]
+    source = invoker.source
+    output =
+        "$target_gen_dir/$_target_name/" + get_path_info(invoker.source, "file")
+    format = "binary1"
+  }
+
+  bundle_data(_target_name) {
+    forward_variables_from(invoker,
+                           "*",
+                           [
+                             "source",
+                             "output",
+                           ])
+
+    if (!defined(public_deps)) {
+      public_deps = []
+    }
+    public_deps += [ ":$_convert_target" ]
+
+    sources = get_target_outputs(":$_convert_target")
+
+    outputs = [
+      invoker.output,
+    ]
+  }
+}
+
 # Template to package a shared library into an iOS framework bundle.
 #
 # This template provides two targets to control whether the framework is
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi
index 29336ce2..8cf538d3 100644
--- a/build/gn_migration.gypi
+++ b/build/gn_migration.gypi
@@ -76,32 +76,6 @@
         '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_platform_unittests',
         '../third_party/WebKit/Source/web/web_tests.gyp:webkit_unit_tests',
         '../third_party/WebKit/Source/wtf/wtf_tests.gyp:wtf_unittests',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_ecdsa_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_bn_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_pqueue_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_digest_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_cipher_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_hkdf_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_constant_time_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_thread_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_base64_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_gcm_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_bytestring_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_evp_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_dsa_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_rsa_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_hmac_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_aead_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_ssl_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_err_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_lhash_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_pbkdf_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_dh_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_pkcs12_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_example_mul',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_ec_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_bio_test',
-        '../third_party/boringssl/boringssl_tests.gyp:boringssl_pkcs7_test',
         '../third_party/boringssl/boringssl_tests.gyp:boringssl_unittests',
         '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests',
         '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests',
diff --git a/build/linux/sysroot_scripts/install-sysroot.py b/build/linux/sysroot_scripts/install-sysroot.py
index 2003ff6..d1aa1aac 100755
--- a/build/linux/sysroot_scripts/install-sysroot.py
+++ b/build/linux/sysroot_scripts/install-sysroot.py
@@ -36,22 +36,26 @@
 URL_PATH = 'chrome-linux-sysroot/toolchain'
 REVISION_AMD64 = 'c52471d9dec240c8d0a88fa98aa1eefeee32e22f'
 REVISION_ARM = 'c52471d9dec240c8d0a88fa98aa1eefeee32e22f'
+REVISION_ARM64 = 'bd10c315594d2a20e31a94a7a6c7adb9a0961c56'
 REVISION_I386 = 'c52471d9dec240c8d0a88fa98aa1eefeee32e22f'
 REVISION_MIPS = 'c52471d9dec240c8d0a88fa98aa1eefeee32e22f'
 TARBALL_AMD64 = 'debian_wheezy_amd64_sysroot.tgz'
 TARBALL_ARM = 'debian_wheezy_arm_sysroot.tgz'
+TARBALL_ARM64 = 'debian_jessie_arm64_sysroot.tgz'
 TARBALL_I386 = 'debian_wheezy_i386_sysroot.tgz'
 TARBALL_MIPS = 'debian_wheezy_mips_sysroot.tgz'
 TARBALL_AMD64_SHA1SUM = 'ca4ed6e7c9e333b046be19d38584a11f6785eea6'
 TARBALL_ARM_SHA1SUM = '1fab0c2b1e93a933ddc593df3b43872b0ba5ded2'
+TARBALL_ARM64_SHA1SUM = '0db3be51912e0be46bb1b906fc196c5c1dfc090f'
 TARBALL_I386_SHA1SUM = '80c48c303319af2284e4a104c882d888af75ba81'
 TARBALL_MIPS_SHA1SUM = '01da32a35288627e05cfca193b7f3659531c6f7d'
 SYSROOT_DIR_AMD64 = 'debian_wheezy_amd64-sysroot'
 SYSROOT_DIR_ARM = 'debian_wheezy_arm-sysroot'
+SYSROOT_DIR_ARM64 = 'debian_jessie_arm64-sysroot'
 SYSROOT_DIR_I386 = 'debian_wheezy_i386-sysroot'
 SYSROOT_DIR_MIPS = 'debian_wheezy_mips-sysroot'
 
-valid_archs = ('arm', 'i386', 'amd64', 'mips')
+valid_archs = ('arm', 'arm64', 'i386', 'amd64', 'mips')
 
 
 class Error(Exception):
@@ -129,7 +133,7 @@
   # Don't attampt to install arm64 since this is currently and android-only
   # architecture.
   target_arch = DetectTargetArch()
-  if target_arch and target_arch not in (host_arch, 'i386', 'arm64'):
+  if target_arch and target_arch not in (host_arch, 'i386'):
     InstallSysroot(target_arch)
 
 
@@ -170,6 +174,11 @@
     tarball_filename = TARBALL_ARM
     tarball_sha1sum = TARBALL_ARM_SHA1SUM
     revision = REVISION_ARM
+  elif target_arch == 'arm64':
+    sysroot = os.path.join(linux_dir, SYSROOT_DIR_ARM64)
+    tarball_filename = TARBALL_ARM64
+    tarball_sha1sum = TARBALL_ARM64_SHA1SUM
+    revision = REVISION_ARM64
   elif target_arch == 'i386':
     sysroot = os.path.join(linux_dir, SYSROOT_DIR_I386)
     tarball_filename = TARBALL_I386
diff --git a/build/linux/sysroot_scripts/packagelist.jessie.arm64 b/build/linux/sysroot_scripts/packagelist.jessie.arm64
index c95cbf0d..7a3358cc 100644
--- a/build/linux/sysroot_scripts/packagelist.jessie.arm64
+++ b/build/linux/sysroot_scripts/packagelist.jessie.arm64
@@ -20,8 +20,8 @@
 main/e/e2fsprogs/libcomerr2_1.42.12-1.1_arm64.deb
 main/e/elfutils/libelf1_0.159-4.2_arm64.deb
 main/e/elfutils/libelf-dev_0.159-4.2_arm64.deb
-main/e/expat/libexpat1_2.1.0-6+deb8u1_arm64.deb
-main/e/expat/libexpat1-dev_2.1.0-6+deb8u1_arm64.deb
+main/e/expat/libexpat1_2.1.0-6+deb8u2_arm64.deb
+main/e/expat/libexpat1-dev_2.1.0-6+deb8u2_arm64.deb
 main/f/fontconfig/libfontconfig1_2.11.0-6.3_arm64.deb
 main/f/fontconfig/libfontconfig1-dev_2.11.0-6.3_arm64.deb
 main/f/freetype/libfreetype6_2.5.2-3+deb8u1_arm64.deb
@@ -86,7 +86,7 @@
 main/libp/libpng/libpng12-dev_1.2.50-2+deb8u2_arm64.deb
 main/libp/libpthread-stubs/libpthread-stubs0-dev_0.3-4_arm64.deb
 main/libs/libselinux/libselinux1_2.3-2_arm64.deb
-main/libt/libtasn1-6/libtasn1-6_4.2-3+deb8u1_arm64.deb
+main/libt/libtasn1-6/libtasn1-6_4.2-3+deb8u2_arm64.deb
 main/libt/libthai/libthai0_0.1.21-1_arm64.deb
 main/libx/libx11/libx11-6_1.6.2-3_arm64.deb
 main/libx/libx11/libx11-dev_1.6.2-3_arm64.deb
@@ -127,7 +127,7 @@
 main/libx/libxtst/libxtst6_1.2.2-1+b1_arm64.deb
 main/libx/libxtst/libxtst-dev_1.2.2-1+b1_arm64.deb
 main/libx/libxxf86vm/libxxf86vm1_1.1.3-1+b1_arm64.deb
-main/l/linux/linux-libc-dev_3.16.7-ckt25-1_arm64.deb
+main/l/linux/linux-libc-dev_3.16.7-ckt25-2_arm64.deb
 main/m/mesa/libgl1-mesa-dev_10.3.2-1+deb8u1_arm64.deb
 main/m/mesa/libgl1-mesa-glx_10.3.2-1+deb8u1_arm64.deb
 main/m/mesa/libglapi-mesa_10.3.2-1+deb8u1_arm64.deb
@@ -138,8 +138,8 @@
 main/n/nspr/libnspr4-dev_4.10.7-1+deb8u1_arm64.deb
 main/n/nss/libnss3_3.17.2-1.1+deb8u2_arm64.deb
 main/n/nss/libnss3-dev_3.17.2-1.1+deb8u2_arm64.deb
-main/o/openssl/libssl1.0.0_1.0.1k-3+deb8u4_arm64.deb
-main/o/openssl/libssl-dev_1.0.1k-3+deb8u4_arm64.deb
+main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u2_arm64.deb
+main/o/openssl/libssl-dev_1.0.1t-1+deb8u2_arm64.deb
 main/o/orbit2/liborbit2_2.14.19-0.3_arm64.deb
 main/p/p11-kit/libp11-kit0_0.20.7-1_arm64.deb
 main/p/pam/libpam0g_1.1.8-3.1+deb8u1+b1_arm64.deb
diff --git a/build/linux/unbundle/zlib.gn b/build/linux/unbundle/zlib.gn
index ecde1c9..020fc7e 100644
--- a/build/linux/unbundle/zlib.gn
+++ b/build/linux/unbundle/zlib.gn
@@ -9,11 +9,16 @@
   headers = [ "zlib.h" ]
 }
 
+config("system_zlib") {
+  defines = [ "USE_SYSTEM_ZLIB=1" ]
+}
+
 source_set("zlib") {
   deps = [
     ":zlib_shim",
   ]
   libs = [ "z" ]
+  public_configs = [ ":system_zlib" ]
 }
 
 shim_headers("minizip_shim") {
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 4886d7b..f1be4f7 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -484,11 +484,15 @@
     "trees/blocking_task_runner.h",
     "trees/channel_impl.h",
     "trees/channel_main.h",
+    "trees/clip_node.cc",
+    "trees/clip_node.h",
     "trees/compositor_mode.h",
     "trees/damage_tracker.cc",
     "trees/damage_tracker.h",
     "trees/draw_property_utils.cc",
     "trees/draw_property_utils.h",
+    "trees/effect_node.cc",
+    "trees/effect_node.h",
     "trees/latency_info_swap_promise_monitor.cc",
     "trees/latency_info_swap_promise_monitor.h",
     "trees/layer_tree_host.cc",
@@ -525,6 +529,8 @@
     "trees/remote_channel_main.h",
     "trees/remote_proto_channel.h",
     "trees/scoped_abort_remaining_swap_promises.h",
+    "trees/scroll_node.cc",
+    "trees/scroll_node.h",
     "trees/single_thread_proxy.cc",
     "trees/single_thread_proxy.h",
     "trees/swap_promise_monitor.cc",
@@ -533,6 +539,8 @@
     "trees/task_runner_provider.h",
     "trees/threaded_channel.cc",
     "trees/threaded_channel.h",
+    "trees/transform_node.cc",
+    "trees/transform_node.h",
     "trees/tree_synchronizer.cc",
     "trees/tree_synchronizer.h",
   ]
@@ -657,6 +665,8 @@
     "test/fake_video_frame_provider.h",
     "test/geometry_test_utils.cc",
     "test/geometry_test_utils.h",
+    "test/layer_internals_for_test.cc",
+    "test/layer_internals_for_test.h",
     "test/layer_test_common.cc",
     "test/layer_test_common.h",
     "test/layer_tree_host_common_test.cc",
@@ -995,7 +1005,7 @@
 test("cc_perftests") {
   sources = [
     "animation/animation_host_perftest.cc",
-    "ipc/cc_param_traits_perftest.cc",
+    "ipc/cc_serialization_perftest.cc",
     "layers/layer_perftest.cc",
     "layers/picture_layer_impl_perftest.cc",
     "quads/draw_quad_perftest.cc",
@@ -1016,12 +1026,15 @@
     "//base",
     "//base/test:test_support",
     "//cc/ipc",
+    "//cc/ipc:interfaces",
     "//cc/surfaces",
     "//cc/surfaces:surface_id",
     "//gpu",
     "//gpu:test_support",
     "//gpu/command_buffer/common:gles2_utils",
     "//media",
+    "//mojo/edk/system",
+    "//mojo/public/cpp/bindings",
     "//skia",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 3d0394e8..ef836c9c 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -545,11 +545,15 @@
         'trees/blocking_task_runner.h',
         'trees/channel_impl.h',
         'trees/channel_main.h',
+        'trees/clip_node.cc',
+        'trees/clip_node.h',
         'trees/compositor_mode.h',
         'trees/damage_tracker.cc',
         'trees/damage_tracker.h',
         'trees/draw_property_utils.cc',
         'trees/draw_property_utils.h',
+        'trees/effect_node.cc',
+        'trees/effect_node.h',
         'trees/latency_info_swap_promise_monitor.cc',
         'trees/latency_info_swap_promise_monitor.h',
         'trees/layer_tree_host.cc',
@@ -586,6 +590,8 @@
         'trees/remote_channel_main.h',
         'trees/remote_proto_channel.h',
         'trees/scoped_abort_remaining_swap_promises.h',
+        'trees/scroll_node.cc',
+        'trees/scroll_node.h',
         'trees/single_thread_proxy.cc',
         'trees/single_thread_proxy.h',
         'trees/swap_promise_monitor.cc',
@@ -594,6 +600,8 @@
         'trees/task_runner_provider.h',
         'trees/threaded_channel.cc',
         'trees/threaded_channel.h',
+        'trees/transform_node.cc',
+        'trees/transform_node.h',
         'trees/tree_synchronizer.cc',
         'trees/tree_synchronizer.h',
       ],
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index 271c2c4f..2b5c33e 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -243,6 +243,8 @@
       'test/fake_video_frame_provider.h',
       'test/geometry_test_utils.cc',
       'test/geometry_test_utils.h',
+      'test/layer_internals_for_test.cc',
+      'test/layer_internals_for_test.h',
       'test/layer_test_common.cc',
       'test/layer_test_common.h',
       'test/layer_tree_host_common_test.cc',
@@ -403,7 +405,6 @@
       'sources': [
         # Note: sources list duplicated in GN build.
         'animation/animation_host_perftest.cc',
-        'ipc/cc_param_traits_perftest.cc',
         'layers/layer_perftest.cc',
         'layers/picture_layer_impl_perftest.cc',
         'quads/draw_quad_perftest.cc',
diff --git a/cc/input/scroll_state.cc b/cc/input/scroll_state.cc
index f0c0d7e..8b6a140 100644
--- a/cc/input/scroll_state.cc
+++ b/cc/input/scroll_state.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/scroll_node.h"
 
 namespace cc {
 
diff --git a/cc/input/scroll_state_data.cc b/cc/input/scroll_state_data.cc
index 1ba778d9..567a024 100644
--- a/cc/input/scroll_state_data.cc
+++ b/cc/input/scroll_state_data.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "cc/input/scroll_state_data.h"
+#include "cc/trees/scroll_node.h"
 
 namespace cc {
 
@@ -39,7 +40,7 @@
 
 ElementId ScrollStateData::current_native_scrolling_element() const {
   if (current_native_scrolling_node_)
-    return current_native_scrolling_node_->data.element_id;
+    return current_native_scrolling_node_->element_id;
   return current_native_scrolling_element_;
 }
 
diff --git a/cc/input/scroll_state_unittest.cc b/cc/input/scroll_state_unittest.cc
index b7299007..1a3a8965 100644
--- a/cc/input/scroll_state_unittest.cc
+++ b/cc/input/scroll_state_unittest.cc
@@ -10,6 +10,7 @@
 #include "cc/test/test_shared_bitmap_manager.h"
 #include "cc/test/test_task_graph_runner.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/scroll_node.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/cc/ipc/cc_param_traits_macros.h b/cc/ipc/cc_param_traits_macros.h
index 753f6e71..43431c6 100644
--- a/cc/ipc/cc_param_traits_macros.h
+++ b/cc/ipc/cc_param_traits_macros.h
@@ -184,6 +184,8 @@
   IPC_STRUCT_TRAITS_MEMBER(max_page_scale_factor)
   IPC_STRUCT_TRAITS_MEMBER(root_overflow_x_hidden)
   IPC_STRUCT_TRAITS_MEMBER(root_overflow_y_hidden)
+  IPC_STRUCT_TRAITS_MEMBER(
+      is_resourceless_software_draw_with_scroll_or_animation)
   IPC_STRUCT_TRAITS_MEMBER(location_bar_offset)
   IPC_STRUCT_TRAITS_MEMBER(location_bar_content_translation)
   IPC_STRUCT_TRAITS_MEMBER(root_background_color)
diff --git a/cc/ipc/cc_param_traits_perftest.cc b/cc/ipc/cc_param_traits_perftest.cc
deleted file mode 100644
index 1cf40f1a..0000000
--- a/cc/ipc/cc_param_traits_perftest.cc
+++ /dev/null
@@ -1,155 +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 <utility>
-
-#include "base/test/launcher/unit_test_launcher.h"
-#include "base/test/test_suite.h"
-#include "cc/ipc/cc_param_traits.h"
-#include "cc/output/compositor_frame.h"
-#include "cc/quads/picture_draw_quad.h"
-#include "ipc/ipc_message.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/perf/perf_test.h"
-
-using cc::CompositorFrame;
-using cc::DelegatedFrameData;
-using cc::DrawQuad;
-using cc::PictureDrawQuad;
-using cc::RenderPass;
-using cc::SharedQuadState;
-
-namespace content {
-namespace {
-
-static const int kTimeLimitMillis = 2000;
-static const int kNumWarmupRuns = 20;
-static const int kTimeCheckInterval = 10;
-
-class CCParamTraitsPerfTest : public testing::Test {
- protected:
-  static void RunTest(const std::string& test_name,
-                      const CompositorFrame& frame) {
-    for (int i = 0; i < kNumWarmupRuns; ++i) {
-      IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
-      IPC::ParamTraits<CompositorFrame>::Write(&msg, frame);
-    }
-
-    base::TimeTicks start = base::TimeTicks::Now();
-    base::TimeTicks end =
-        start + base::TimeDelta::FromMilliseconds(kTimeLimitMillis);
-    base::TimeDelta min_time;
-    int count = 0;
-    while (start < end) {
-      for (int i = 0; i < kTimeCheckInterval; ++i) {
-        IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
-        IPC::ParamTraits<CompositorFrame>::Write(&msg, frame);
-        ++count;
-      }
-
-      base::TimeTicks now = base::TimeTicks::Now();
-      if (now - start < min_time || min_time.is_zero())
-        min_time = now - start;
-      start = base::TimeTicks::Now();
-    }
-
-    perf_test::PrintResult(
-        "min_frame_serialization_time", "", test_name,
-        min_time.InMillisecondsF() / kTimeCheckInterval * 1000, "us", true);
-  }
-};
-
-TEST_F(CCParamTraitsPerfTest, DelegatedFrame_ManyQuads_1_4000) {
-  std::unique_ptr<CompositorFrame> frame(new CompositorFrame);
-
-  std::unique_ptr<RenderPass> render_pass = RenderPass::Create();
-  render_pass->CreateAndAppendSharedQuadState();
-  for (int i = 0; i < 4000; ++i) {
-    PictureDrawQuad* quad =
-        render_pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
-    quad->shared_quad_state = render_pass->shared_quad_state_list.back();
-  }
-
-  frame->delegated_frame_data.reset(new DelegatedFrameData);
-  frame->delegated_frame_data->render_pass_list.push_back(
-      std::move(render_pass));
-
-  RunTest("DelegatedFrame_ManyQuads_1_4000", *frame);
-}
-
-TEST_F(CCParamTraitsPerfTest, DelegatedFrame_ManyQuads_1_100000) {
-  std::unique_ptr<CompositorFrame> frame(new CompositorFrame);
-
-  std::unique_ptr<RenderPass> render_pass = RenderPass::Create();
-  render_pass->CreateAndAppendSharedQuadState();
-  for (int i = 0; i < 100000; ++i) {
-    PictureDrawQuad* quad =
-        render_pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
-    quad->shared_quad_state = render_pass->shared_quad_state_list.back();
-  }
-
-  frame->delegated_frame_data.reset(new DelegatedFrameData);
-  frame->delegated_frame_data->render_pass_list.push_back(
-      std::move(render_pass));
-
-  RunTest("DelegatedFrame_ManyQuads_1_100000", *frame);
-}
-
-TEST_F(CCParamTraitsPerfTest, DelegatedFrame_ManyQuads_4000_4000) {
-  std::unique_ptr<CompositorFrame> frame(new CompositorFrame);
-
-  std::unique_ptr<RenderPass> render_pass = RenderPass::Create();
-  for (int i = 0; i < 4000; ++i) {
-    render_pass->CreateAndAppendSharedQuadState();
-    PictureDrawQuad* quad =
-        render_pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
-    quad->shared_quad_state = render_pass->shared_quad_state_list.back();
-  }
-
-  frame->delegated_frame_data.reset(new DelegatedFrameData);
-  frame->delegated_frame_data->render_pass_list.push_back(
-      std::move(render_pass));
-
-  RunTest("DelegatedFrame_ManyQuads_4000_4000", *frame);
-}
-
-TEST_F(CCParamTraitsPerfTest, DelegatedFrame_ManyQuads_100000_100000) {
-  std::unique_ptr<CompositorFrame> frame(new CompositorFrame);
-
-  std::unique_ptr<RenderPass> render_pass = RenderPass::Create();
-  for (int i = 0; i < 100000; ++i) {
-    render_pass->CreateAndAppendSharedQuadState();
-    PictureDrawQuad* quad =
-        render_pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
-    quad->shared_quad_state = render_pass->shared_quad_state_list.back();
-  }
-
-  frame->delegated_frame_data.reset(new DelegatedFrameData);
-  frame->delegated_frame_data->render_pass_list.push_back(
-      std::move(render_pass));
-
-  RunTest("DelegatedFrame_ManyQuads_100000_100000", *frame);
-}
-
-TEST_F(CCParamTraitsPerfTest, DelegatedFrame_ManyRenderPasses_10000_100) {
-  std::unique_ptr<CompositorFrame> frame(new CompositorFrame);
-  frame->delegated_frame_data.reset(new DelegatedFrameData);
-
-  for (int i = 0; i < 1000; ++i) {
-    std::unique_ptr<RenderPass> render_pass = RenderPass::Create();
-    for (int j = 0; j < 100; ++j) {
-      render_pass->CreateAndAppendSharedQuadState();
-      PictureDrawQuad* quad =
-          render_pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
-      quad->shared_quad_state = render_pass->shared_quad_state_list.back();
-    }
-    frame->delegated_frame_data->render_pass_list.push_back(
-        std::move(render_pass));
-  }
-
-  RunTest("DelegatedFrame_ManyRenderPasses_10000_100", *frame);
-}
-
-}  // namespace
-}  // namespace content
diff --git a/cc/ipc/cc_serialization_perftest.cc b/cc/ipc/cc_serialization_perftest.cc
new file mode 100644
index 0000000..cad0894
--- /dev/null
+++ b/cc/ipc/cc_serialization_perftest.cc
@@ -0,0 +1,217 @@
+// 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 <utility>
+
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "cc/ipc/cc_param_traits.h"
+#include "cc/ipc/compositor_frame.mojom.h"
+#include "cc/ipc/compositor_frame_metadata_struct_traits.h"
+#include "cc/ipc/compositor_frame_struct_traits.h"
+#include "cc/ipc/render_pass_struct_traits.h"
+#include "cc/ipc/selection_struct_traits.h"
+#include "cc/ipc/shared_quad_state_struct_traits.h"
+#include "cc/ipc/surface_id_struct_traits.h"
+#include "cc/ipc/transferable_resource_struct_traits.h"
+#include "cc/output/compositor_frame.h"
+#include "cc/quads/picture_draw_quad.h"
+#include "gpu/ipc/common/mailbox_holder_struct_traits.h"
+#include "gpu/ipc/common/mailbox_struct_traits.h"
+#include "gpu/ipc/common/sync_token_struct_traits.h"
+#include "ipc/ipc_message.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+#include "ui/events/mojo/latency_info_struct_traits.h"
+#include "ui/gfx/geometry/mojo/geometry.mojom.h"
+#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
+#include "ui/gfx/mojo/selection_bound_struct_traits.h"
+
+namespace cc {
+namespace {
+
+static const int kTimeLimitMillis = 2000;
+static const int kNumWarmupRuns = 20;
+static const int kTimeCheckInterval = 10;
+
+class CCSerializationPerfTest : public testing::Test {
+ protected:
+  static void RunTestParamTraits(const std::string& test_name,
+                                 const CompositorFrame& frame) {
+    for (int i = 0; i < kNumWarmupRuns; ++i) {
+      IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+      IPC::ParamTraits<CompositorFrame>::Write(&msg, frame);
+    }
+
+    base::TimeTicks start = base::TimeTicks::Now();
+    base::TimeTicks end =
+        start + base::TimeDelta::FromMilliseconds(kTimeLimitMillis);
+    base::TimeDelta min_time;
+    size_t count = 0;
+    while (start < end) {
+      for (int i = 0; i < kTimeCheckInterval; ++i) {
+        IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+        IPC::ParamTraits<CompositorFrame>::Write(&msg, frame);
+        ++count;
+      }
+
+      base::TimeTicks now = base::TimeTicks::Now();
+      if (now - start < min_time || min_time.is_zero())
+        min_time = now - start;
+      start = base::TimeTicks::Now();
+    }
+
+    perf_test::PrintResult(
+        "ParamTraits: min_frame_serialization_time", "", test_name,
+        min_time.InMillisecondsF() / kTimeCheckInterval * 1000, "us", true);
+    perf_test::PrintResult("ParamTraits: num runs in 2 seconds", "", test_name,
+                           count, "", true);
+  }
+
+  static void RunTestStructTraits(const std::string& test_name,
+                                  const CompositorFrame& frame) {
+    for (int i = 0; i < kNumWarmupRuns; ++i) {
+      mojo::Array<uint8_t> data = mojom::CompositorFrame::Serialize(&frame);
+      DCHECK_GT(data.size(), 0u);
+    }
+
+    base::TimeTicks start = base::TimeTicks::Now();
+    base::TimeTicks end =
+        start + base::TimeDelta::FromMilliseconds(kTimeLimitMillis);
+    base::TimeDelta min_time;
+    size_t count = 0;
+    while (start < end) {
+      for (int i = 0; i < kTimeCheckInterval; ++i) {
+        mojo::Array<uint8_t> data = mojom::CompositorFrame::Serialize(&frame);
+        DCHECK_GT(data.size(), 0u);
+        ++count;
+      }
+
+      base::TimeTicks now = base::TimeTicks::Now();
+      if (now - start < min_time || min_time.is_zero())
+        min_time = now - start;
+      start = base::TimeTicks::Now();
+    }
+
+    perf_test::PrintResult(
+        "StructTraits min_frame_serialization_time", "", test_name,
+        min_time.InMillisecondsF() / kTimeCheckInterval * 1000, "us", true);
+    perf_test::PrintResult("StructTraits: num runs in 2 seconds", "", test_name,
+                           count, "", true);
+  }
+
+  static void RunTest(const std::string& test_name, CompositorFrame frame) {
+    RunTestStructTraits(test_name, frame);
+    RunTestParamTraits(test_name, frame);
+  }
+};
+
+TEST_F(CCSerializationPerfTest, DelegatedFrame_ManyQuads_1_4000) {
+  CompositorFrame frame;
+
+  std::unique_ptr<RenderPass> render_pass = RenderPass::Create();
+  render_pass->CreateAndAppendSharedQuadState();
+  for (int i = 0; i < 4000; ++i) {
+    const gfx::Rect bounds(100, 100, 100, 100);
+    const bool kForceAntiAliasingOff = true;
+    SolidColorDrawQuad* quad =
+        render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+    quad->SetNew(render_pass->shared_quad_state_list.back(), bounds, bounds,
+                 SK_ColorRED, kForceAntiAliasingOff);
+  }
+
+  frame.delegated_frame_data.reset(new DelegatedFrameData);
+  frame.delegated_frame_data->render_pass_list.push_back(
+      std::move(render_pass));
+
+  RunTest("DelegatedFrame_ManyQuads_1_4000", std::move(frame));
+}
+
+TEST_F(CCSerializationPerfTest, DelegatedFrame_ManyQuads_1_100000) {
+  CompositorFrame frame;
+
+  std::unique_ptr<RenderPass> render_pass = RenderPass::Create();
+  render_pass->CreateAndAppendSharedQuadState();
+  for (int i = 0; i < 100000; ++i) {
+    const gfx::Rect bounds(100, 100, 100, 100);
+    const bool kForceAntiAliasingOff = true;
+    SolidColorDrawQuad* quad =
+        render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+    quad->SetNew(render_pass->shared_quad_state_list.back(), bounds, bounds,
+                 SK_ColorRED, kForceAntiAliasingOff);
+  }
+
+  frame.delegated_frame_data.reset(new DelegatedFrameData);
+  frame.delegated_frame_data->render_pass_list.push_back(
+      std::move(render_pass));
+
+  RunTest("DelegatedFrame_ManyQuads_1_100000", std::move(frame));
+}
+
+TEST_F(CCSerializationPerfTest, DelegatedFrame_ManyQuads_4000_4000) {
+  CompositorFrame frame;
+
+  std::unique_ptr<RenderPass> render_pass = RenderPass::Create();
+  for (int i = 0; i < 4000; ++i) {
+    const gfx::Rect bounds(100, 100, 100, 100);
+    const bool kForceAntiAliasingOff = true;
+    render_pass->CreateAndAppendSharedQuadState();
+    SolidColorDrawQuad* quad =
+        render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+    quad->SetNew(render_pass->shared_quad_state_list.back(), bounds, bounds,
+                 SK_ColorRED, kForceAntiAliasingOff);
+  }
+
+  frame.delegated_frame_data.reset(new DelegatedFrameData);
+  frame.delegated_frame_data->render_pass_list.push_back(
+      std::move(render_pass));
+
+  RunTest("DelegatedFrame_ManyQuads_4000_4000", std::move(frame));
+}
+
+TEST_F(CCSerializationPerfTest, DelegatedFrame_ManyQuads_100000_100000) {
+  CompositorFrame frame;
+
+  std::unique_ptr<RenderPass> render_pass = RenderPass::Create();
+  for (int i = 0; i < 100000; ++i) {
+    render_pass->CreateAndAppendSharedQuadState();
+    const gfx::Rect bounds(100, 100, 100, 100);
+    const bool kForceAntiAliasingOff = true;
+    SolidColorDrawQuad* quad =
+        render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+    quad->SetNew(render_pass->shared_quad_state_list.back(), bounds, bounds,
+                 SK_ColorRED, kForceAntiAliasingOff);
+  }
+
+  frame.delegated_frame_data.reset(new DelegatedFrameData);
+  frame.delegated_frame_data->render_pass_list.push_back(
+      std::move(render_pass));
+
+  RunTest("DelegatedFrame_ManyQuads_100000_100000", std::move(frame));
+}
+
+TEST_F(CCSerializationPerfTest, DelegatedFrame_ManyRenderPasses_10000_100) {
+  CompositorFrame frame;
+  frame.delegated_frame_data.reset(new DelegatedFrameData);
+
+  for (int i = 0; i < 1000; ++i) {
+    std::unique_ptr<RenderPass> render_pass = RenderPass::Create();
+    for (int j = 0; j < 100; ++j) {
+      render_pass->CreateAndAppendSharedQuadState();
+      const gfx::Rect bounds(100, 100, 100, 100);
+      const bool kForceAntiAliasingOff = true;
+      SolidColorDrawQuad* quad =
+          render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+      quad->SetNew(render_pass->shared_quad_state_list.back(), bounds, bounds,
+                   SK_ColorRED, kForceAntiAliasingOff);
+    }
+    frame.delegated_frame_data->render_pass_list.push_back(
+        std::move(render_pass));
+  }
+
+  RunTest("DelegatedFrame_ManyRenderPasses_10000_100", std::move(frame));
+}
+
+}  // namespace
+}  // namespace cc
diff --git a/cc/ipc/compositor_frame_metadata.mojom b/cc/ipc/compositor_frame_metadata.mojom
index 8db3460..93d1ca9f 100644
--- a/cc/ipc/compositor_frame_metadata.mojom
+++ b/cc/ipc/compositor_frame_metadata.mojom
@@ -20,6 +20,7 @@
   float max_page_scale_factor;
   bool root_overflow_x_hidden;
   bool root_overflow_y_hidden;
+  bool is_resourceless_software_draw_with_scroll_or_animation;
   gfx.mojom.Vector2dF location_bar_offset;
   gfx.mojom.Vector2dF location_bar_content_translation;
   uint32 root_background_color;
diff --git a/cc/ipc/compositor_frame_metadata_struct_traits.cc b/cc/ipc/compositor_frame_metadata_struct_traits.cc
index 5294bde..177abbb 100644
--- a/cc/ipc/compositor_frame_metadata_struct_traits.cc
+++ b/cc/ipc/compositor_frame_metadata_struct_traits.cc
@@ -29,6 +29,8 @@
   out->max_page_scale_factor = data.max_page_scale_factor();
   out->root_overflow_x_hidden = data.root_overflow_x_hidden();
   out->root_overflow_y_hidden = data.root_overflow_y_hidden();
+  out->is_resourceless_software_draw_with_scroll_or_animation =
+      data.is_resourceless_software_draw_with_scroll_or_animation();
   if (!data.ReadLocationBarOffset(&out->location_bar_offset) ||
       !data.ReadLocationBarContentTranslation(
           &out->location_bar_content_translation)) {
diff --git a/cc/ipc/compositor_frame_metadata_struct_traits.h b/cc/ipc/compositor_frame_metadata_struct_traits.h
index fedd13e..9bf8c07 100644
--- a/cc/ipc/compositor_frame_metadata_struct_traits.h
+++ b/cc/ipc/compositor_frame_metadata_struct_traits.h
@@ -57,6 +57,11 @@
     return metadata.root_overflow_y_hidden;
   }
 
+  static bool is_resourceless_software_draw_with_scroll_or_animation(
+      const cc::CompositorFrameMetadata& metadata) {
+    return metadata.is_resourceless_software_draw_with_scroll_or_animation;
+  }
+
   static gfx::Vector2dF location_bar_offset(
       const cc::CompositorFrameMetadata& metadata) {
     return metadata.location_bar_offset;
diff --git a/cc/ipc/struct_traits_unittest.cc b/cc/ipc/struct_traits_unittest.cc
index 248ea4c..f74f10ad 100644
--- a/cc/ipc/struct_traits_unittest.cc
+++ b/cc/ipc/struct_traits_unittest.cc
@@ -267,6 +267,7 @@
   const float max_page_scale_factor = 4.6f;
   const bool root_overflow_x_hidden = true;
   const bool root_overflow_y_hidden = true;
+  const bool is_resourceless_software_draw_with_scroll_or_animation = true;
   const gfx::Vector2dF location_bar_offset(1234.5f, 5432.1f);
   const gfx::Vector2dF location_bar_content_translation(1234.5f, 5432.1f);
   const uint32_t root_background_color = 1337;
@@ -300,6 +301,8 @@
   input.max_page_scale_factor = max_page_scale_factor;
   input.root_overflow_x_hidden = root_overflow_x_hidden;
   input.root_overflow_y_hidden = root_overflow_y_hidden;
+  input.is_resourceless_software_draw_with_scroll_or_animation =
+      is_resourceless_software_draw_with_scroll_or_animation;
   input.location_bar_offset = location_bar_offset;
   input.location_bar_content_translation = location_bar_content_translation;
   input.root_background_color = root_background_color;
@@ -320,6 +323,8 @@
   EXPECT_EQ(max_page_scale_factor, output.max_page_scale_factor);
   EXPECT_EQ(root_overflow_x_hidden, output.root_overflow_x_hidden);
   EXPECT_EQ(root_overflow_y_hidden, output.root_overflow_y_hidden);
+  EXPECT_EQ(is_resourceless_software_draw_with_scroll_or_animation,
+            output.is_resourceless_software_draw_with_scroll_or_animation);
   EXPECT_EQ(location_bar_offset, output.location_bar_offset);
   EXPECT_EQ(location_bar_content_translation,
             output.location_bar_content_translation);
diff --git a/cc/layers/heads_up_display_layer.cc b/cc/layers/heads_up_display_layer.cc
index 0492cb0a..2feb1fa 100644
--- a/cc/layers/heads_up_display_layer.cc
+++ b/cc/layers/heads_up_display_layer.cc
@@ -63,7 +63,7 @@
 
 std::unique_ptr<LayerImpl> HeadsUpDisplayLayer::CreateLayerImpl(
     LayerTreeImpl* tree_impl) {
-  return HeadsUpDisplayLayerImpl::Create(tree_impl, layer_id_);
+  return HeadsUpDisplayLayerImpl::Create(tree_impl, id());
 }
 
 void HeadsUpDisplayLayer::SetTypeForProtoSerialization(
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 60afdfb..30c110e 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -31,8 +31,10 @@
 #include "cc/proto/layer.pb.h"
 #include "cc/proto/skia_conversions.h"
 #include "cc/trees/draw_property_utils.h"
+#include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/transform_node.h"
 #include "third_party/skia/include/core/SkImageFilter.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
@@ -41,55 +43,60 @@
 
 base::StaticAtomicSequenceNumber g_next_layer_id;
 
+Layer::Inputs::Inputs()
+    :  // Layer IDs start from 1.
+      layer_id(g_next_layer_id.GetNext() + 1),
+      masks_to_bounds(false),
+      mask_layer(nullptr),
+      replica_layer(nullptr),
+      opacity(1.f),
+      blend_mode(SkXfermode::kSrcOver_Mode),
+      is_root_for_isolated_group(false),
+      contents_opaque(false),
+      is_drawable(false),
+      double_sided(true),
+      should_flatten_transform(true),
+      sorting_context_id(0),
+      use_parent_backface_visibility(false),
+      background_color(0),
+      scroll_clip_layer_id(INVALID_ID),
+      user_scrollable_horizontal(true),
+      user_scrollable_vertical(true),
+      main_thread_scrolling_reasons(
+          MainThreadScrollingReason::kNotScrollingOnMain),
+      is_container_for_fixed_position_layers(false),
+      mutable_properties(MutableProperty::kNone),
+      scroll_parent(nullptr),
+      clip_parent(nullptr),
+      has_will_change_transform_hint(false),
+      hide_layer_and_subtree(false),
+      client(nullptr) {}
+
+Layer::Inputs::~Inputs() {}
+
 scoped_refptr<Layer> Layer::Create() {
   return make_scoped_refptr(new Layer());
 }
 
 Layer::Layer()
-    :  // Layer IDs start from 1.
-      layer_id_(g_next_layer_id.GetNext() + 1),
-      ignore_set_needs_commit_(false),
-      sorting_context_id_(0),
+    : ignore_set_needs_commit_(false),
       parent_(nullptr),
       layer_tree_host_(nullptr),
-      scroll_clip_layer_id_(INVALID_ID),
       num_descendants_that_draw_content_(0),
       transform_tree_index_(-1),
       effect_tree_index_(-1),
       clip_tree_index_(-1),
       scroll_tree_index_(-1),
       property_tree_sequence_number_(-1),
-      mutable_properties_(MutableProperty::kNone),
-      main_thread_scrolling_reasons_(
-          MainThreadScrollingReason::kNotScrollingOnMain),
       should_flatten_transform_from_property_tree_(false),
-      user_scrollable_horizontal_(true),
-      user_scrollable_vertical_(true),
-      is_root_for_isolated_group_(false),
-      is_container_for_fixed_position_layers_(false),
-      is_drawable_(false),
       draws_content_(false),
-      hide_layer_and_subtree_(false),
-      masks_to_bounds_(false),
-      contents_opaque_(false),
-      double_sided_(true),
-      should_flatten_transform_(true),
-      use_parent_backface_visibility_(false),
       use_local_transform_for_backface_visibility_(false),
       should_check_backface_visibility_(false),
       force_render_surface_for_testing_(false),
       subtree_property_changed_(false),
       layer_property_changed_(false),
-      has_will_change_transform_hint_(false),
-      background_color_(0),
       safe_opaque_background_color_(0),
-      opacity_(1.f),
-      blend_mode_(SkXfermode::kSrcOver_Mode),
       draw_blend_mode_(SkXfermode::kSrcOver_Mode),
-      scroll_parent_(nullptr),
-      clip_parent_(nullptr),
-      replica_layer_(nullptr),
-      client_(nullptr),
       num_unclipped_descendants_(0) {}
 
 Layer::~Layer() {
@@ -105,13 +112,13 @@
 
   // Remove the parent reference from all children and dependents.
   RemoveAllChildren();
-  if (mask_layer_.get()) {
-    DCHECK_EQ(this, mask_layer_->parent());
-    mask_layer_->RemoveFromParent();
+  if (inputs_.mask_layer.get()) {
+    DCHECK_EQ(this, inputs_.mask_layer->parent());
+    inputs_.mask_layer->RemoveFromParent();
   }
-  if (replica_layer_.get()) {
-    DCHECK_EQ(this, replica_layer_->parent());
-    replica_layer_->RemoveFromParent();
+  if (inputs_.replica_layer.get()) {
+    DCHECK_EQ(this, inputs_.replica_layer->parent());
+    inputs_.replica_layer->RemoveFromParent();
   }
 }
 
@@ -123,18 +130,18 @@
     layer_tree_host_->property_trees()->RemoveIdFromIdToIndexMaps(id());
     layer_tree_host_->property_trees()->needs_rebuild = true;
     layer_tree_host_->UnregisterLayer(this);
-    if (element_id_) {
+    if (inputs_.element_id) {
       layer_tree_host_->animation_host()->UnregisterElement(
-          element_id_, ElementListType::ACTIVE);
+          inputs_.element_id, ElementListType::ACTIVE);
       layer_tree_host_->RemoveFromElementMap(this);
     }
   }
   if (host) {
     host->property_trees()->needs_rebuild = true;
     host->RegisterLayer(this);
-    if (element_id_) {
+    if (inputs_.element_id) {
       host->AddToElementMap(this);
-      host->animation_host()->RegisterElement(element_id_,
+      host->animation_host()->RegisterElement(inputs_.element_id,
                                               ElementListType::ACTIVE);
     }
   }
@@ -146,13 +153,13 @@
   // side for the new host.
   SetNeedsPushProperties();
 
-  for (size_t i = 0; i < children_.size(); ++i)
-    children_[i]->SetLayerTreeHost(host);
+  for (size_t i = 0; i < inputs_.children.size(); ++i)
+    inputs_.children[i]->SetLayerTreeHost(host);
 
-  if (mask_layer_.get())
-    mask_layer_->SetLayerTreeHost(host);
-  if (replica_layer_.get())
-    replica_layer_->SetLayerTreeHost(host);
+  if (inputs_.mask_layer.get())
+    inputs_.mask_layer->SetLayerTreeHost(host);
+  if (inputs_.replica_layer.get())
+    inputs_.replica_layer->SetLayerTreeHost(host);
 
   const bool has_any_animation =
       layer_tree_host_ ? layer_tree_host_->HasAnyAnimation(this) : false;
@@ -238,7 +245,7 @@
 }
 
 void Layer::AddChild(scoped_refptr<Layer> child) {
-  InsertChild(child, children_.size());
+  InsertChild(child, inputs_.children.size());
 }
 
 void Layer::InsertChild(scoped_refptr<Layer> child, size_t index) {
@@ -249,8 +256,8 @@
   child->SetParent(this);
   child->SetSubtreePropertyChanged();
 
-  index = std::min(index, children_.size());
-  children_.insert(children_.begin() + index, child);
+  index = std::min(index, inputs_.children.size());
+  inputs_.children.insert(inputs_.children.begin() + index, child);
   SetNeedsFullTreeSync();
 }
 
@@ -261,29 +268,28 @@
 }
 
 void Layer::RemoveChildOrDependent(Layer* child) {
-  if (mask_layer_.get() == child) {
-    mask_layer_->SetParent(nullptr);
-    mask_layer_ = nullptr;
+  if (inputs_.mask_layer.get() == child) {
+    inputs_.mask_layer->SetParent(nullptr);
+    inputs_.mask_layer = nullptr;
     SetNeedsFullTreeSync();
     return;
   }
-  if (replica_layer_.get() == child) {
-    replica_layer_->SetParent(nullptr);
-    replica_layer_ = nullptr;
+  if (inputs_.replica_layer.get() == child) {
+    inputs_.replica_layer->SetParent(nullptr);
+    inputs_.replica_layer = nullptr;
     SetNeedsFullTreeSync();
     return;
   }
 
-  for (LayerList::iterator iter = children_.begin();
-       iter != children_.end();
-       ++iter) {
+  for (LayerList::iterator iter = inputs_.children.begin();
+       iter != inputs_.children.end(); ++iter) {
     if (iter->get() != child)
       continue;
 
     child->SetParent(nullptr);
     AddDrawableDescendants(-child->NumDescendantsThatDrawContent() -
                            (child->DrawsContent() ? 1 : 0));
-    children_.erase(iter);
+    inputs_.children.erase(iter);
     SetNeedsFullTreeSync();
     return;
   }
@@ -299,12 +305,12 @@
 
   // Find the index of |reference| in |children_|.
   auto reference_it =
-      std::find_if(children_.begin(), children_.end(),
+      std::find_if(inputs_.children.begin(), inputs_.children.end(),
                    [reference](const scoped_refptr<Layer>& layer) {
                      return layer.get() == reference;
                    });
-  DCHECK(reference_it != children_.end());
-  size_t reference_index = reference_it - children_.begin();
+  DCHECK(reference_it != inputs_.children.end());
+  size_t reference_index = reference_it - inputs_.children.begin();
   reference->RemoveFromParent();
 
   if (new_layer.get()) {
@@ -317,7 +323,7 @@
   DCHECK(IsPropertyChangeAllowed());
   if (bounds() == size)
     return;
-  bounds_ = size;
+  inputs_.bounds = size;
 
   if (!layer_tree_host_)
     return;
@@ -336,8 +342,8 @@
 
 void Layer::RemoveAllChildren() {
   DCHECK(IsPropertyChangeAllowed());
-  while (children_.size()) {
-    Layer* layer = children_[0].get();
+  while (inputs_.children.size()) {
+    Layer* layer = inputs_.children[0].get();
     DCHECK_EQ(this, layer->parent());
     layer->RemoveFromParent();
   }
@@ -345,7 +351,7 @@
 
 void Layer::SetChildren(const LayerList& children) {
   DCHECK(IsPropertyChangeAllowed());
-  if (children == children_)
+  if (children == inputs_.children)
     return;
 
   RemoveAllChildren();
@@ -365,25 +371,25 @@
   DCHECK(IsPropertyChangeAllowed());
   if (void* source = request->source()) {
     auto it =
-        std::find_if(copy_requests_.begin(), copy_requests_.end(),
+        std::find_if(inputs_.copy_requests.begin(), inputs_.copy_requests.end(),
                      [source](const std::unique_ptr<CopyOutputRequest>& x) {
                        return x->source() == source;
                      });
-    if (it != copy_requests_.end())
-      copy_requests_.erase(it);
+    if (it != inputs_.copy_requests.end())
+      inputs_.copy_requests.erase(it);
   }
   if (request->IsEmpty())
     return;
-  copy_requests_.push_back(std::move(request));
+  inputs_.copy_requests.push_back(std::move(request));
   SetSubtreePropertyChanged();
   SetNeedsCommit();
 }
 
 void Layer::SetBackgroundColor(SkColor background_color) {
   DCHECK(IsPropertyChangeAllowed());
-  if (background_color_ == background_color)
+  if (inputs_.background_color == background_color)
     return;
-  background_color_ = background_color;
+  inputs_.background_color = background_color;
   SetNeedsCommit();
 }
 
@@ -406,27 +412,27 @@
 
 void Layer::SetMasksToBounds(bool masks_to_bounds) {
   DCHECK(IsPropertyChangeAllowed());
-  if (masks_to_bounds_ == masks_to_bounds)
+  if (inputs_.masks_to_bounds == masks_to_bounds)
     return;
-  masks_to_bounds_ = masks_to_bounds;
+  inputs_.masks_to_bounds = masks_to_bounds;
   SetNeedsCommit();
   SetSubtreePropertyChanged();
 }
 
 void Layer::SetMaskLayer(Layer* mask_layer) {
   DCHECK(IsPropertyChangeAllowed());
-  if (mask_layer_.get() == mask_layer)
+  if (inputs_.mask_layer.get() == mask_layer)
     return;
-  if (mask_layer_.get()) {
-    DCHECK_EQ(this, mask_layer_->parent());
-    mask_layer_->RemoveFromParent();
+  if (inputs_.mask_layer.get()) {
+    DCHECK_EQ(this, inputs_.mask_layer->parent());
+    inputs_.mask_layer->RemoveFromParent();
   }
-  mask_layer_ = mask_layer;
-  if (mask_layer_.get()) {
-    mask_layer_->RemoveFromParent();
-    DCHECK(!mask_layer_->parent());
-    mask_layer_->SetParent(this);
-    mask_layer_->SetIsMask(true);
+  inputs_.mask_layer = mask_layer;
+  if (inputs_.mask_layer.get()) {
+    inputs_.mask_layer->RemoveFromParent();
+    DCHECK(!inputs_.mask_layer->parent());
+    inputs_.mask_layer->SetParent(this);
+    inputs_.mask_layer->SetIsMask(true);
   }
   SetSubtreePropertyChanged();
   SetNeedsFullTreeSync();
@@ -434,17 +440,17 @@
 
 void Layer::SetReplicaLayer(Layer* layer) {
   DCHECK(IsPropertyChangeAllowed());
-  if (replica_layer_.get() == layer)
+  if (inputs_.replica_layer.get() == layer)
     return;
-  if (replica_layer_.get()) {
-    DCHECK_EQ(this, replica_layer_->parent());
-    replica_layer_->RemoveFromParent();
+  if (inputs_.replica_layer.get()) {
+    DCHECK_EQ(this, inputs_.replica_layer->parent());
+    inputs_.replica_layer->RemoveFromParent();
   }
-  replica_layer_ = layer;
-  if (replica_layer_.get()) {
-    DCHECK(!replica_layer_->parent());
-    replica_layer_->RemoveFromParent();
-    replica_layer_->SetParent(this);
+  inputs_.replica_layer = layer;
+  if (inputs_.replica_layer.get()) {
+    DCHECK(!inputs_.replica_layer->parent());
+    inputs_.replica_layer->RemoveFromParent();
+    inputs_.replica_layer->SetParent(this);
   }
   SetSubtreePropertyChanged();
   SetNeedsFullTreeSync();
@@ -452,9 +458,9 @@
 
 void Layer::SetFilters(const FilterOperations& filters) {
   DCHECK(IsPropertyChangeAllowed());
-  if (filters_ == filters)
+  if (inputs_.filters == filters)
     return;
-  filters_ = filters;
+  inputs_.filters = filters;
   SetSubtreePropertyChanged();
   SetNeedsCommit();
 }
@@ -470,9 +476,9 @@
 
 void Layer::SetBackgroundFilters(const FilterOperations& filters) {
   DCHECK(IsPropertyChangeAllowed());
-  if (background_filters_ == filters)
+  if (inputs_.background_filters == filters)
     return;
-  background_filters_ = filters;
+  inputs_.background_filters = filters;
   SetLayerPropertyChanged();
   SetNeedsCommit();
 }
@@ -482,12 +488,12 @@
   DCHECK_GE(opacity, 0.f);
   DCHECK_LE(opacity, 1.f);
 
-  if (opacity_ == opacity)
+  if (inputs_.opacity == opacity)
     return;
   // We need to force a property tree rebuild when opacity changes from 1 to a
   // non-1 value or vice-versa as render surfaces can change.
-  bool force_rebuild = opacity == 1.f || opacity_ == 1.f;
-  opacity_ = opacity;
+  bool force_rebuild = opacity == 1.f || inputs_.opacity == 1.f;
+  inputs_.opacity = opacity;
   SetSubtreePropertyChanged();
   if (layer_tree_host_ && !force_rebuild) {
     PropertyTrees* property_trees = layer_tree_host_->property_trees();
@@ -495,8 +501,8 @@
     if (effect_id_to_index != property_trees->effect_id_to_index_map.end()) {
       EffectNode* node =
           property_trees->effect_tree.Node(effect_id_to_index->second);
-      node->data.opacity = opacity;
-      node->data.effect_changed = true;
+      node->opacity = opacity;
+      node->effect_changed = true;
       property_trees->effect_tree.set_needs_update(true);
       SetNeedsCommitNoRebuild();
       return;
@@ -506,7 +512,7 @@
 }
 
 float Layer::EffectiveOpacity() const {
-  return hide_layer_and_subtree_ ? 0.f : opacity_;
+  return inputs_.hide_layer_and_subtree ? 0.f : inputs_.opacity;
 }
 
 bool Layer::OpacityIsAnimating() const {
@@ -528,7 +534,7 @@
 
 void Layer::SetBlendMode(SkXfermode::Mode blend_mode) {
   DCHECK(IsPropertyChangeAllowed());
-  if (blend_mode_ == blend_mode)
+  if (inputs_.blend_mode == blend_mode)
     return;
 
   // Allowing only blend modes that are defined in the CSS Compositing standard:
@@ -571,33 +577,33 @@
       return;
   }
 
-  blend_mode_ = blend_mode;
+  inputs_.blend_mode = blend_mode;
   SetNeedsCommit();
   SetSubtreePropertyChanged();
 }
 
 void Layer::SetIsRootForIsolatedGroup(bool root) {
   DCHECK(IsPropertyChangeAllowed());
-  if (is_root_for_isolated_group_ == root)
+  if (inputs_.is_root_for_isolated_group == root)
     return;
-  is_root_for_isolated_group_ = root;
+  inputs_.is_root_for_isolated_group = root;
   SetNeedsCommit();
 }
 
 void Layer::SetContentsOpaque(bool opaque) {
   DCHECK(IsPropertyChangeAllowed());
-  if (contents_opaque_ == opaque)
+  if (inputs_.contents_opaque == opaque)
     return;
-  contents_opaque_ = opaque;
+  inputs_.contents_opaque = opaque;
   SetNeedsCommit();
   SetSubtreePropertyChanged();
 }
 
 void Layer::SetPosition(const gfx::PointF& position) {
   DCHECK(IsPropertyChangeAllowed());
-  if (position_ == position)
+  if (inputs_.position == position)
     return;
-  position_ = position;
+  inputs_.position = position;
 
   if (!layer_tree_host_)
     return;
@@ -610,10 +616,9 @@
               property_trees->transform_id_to_index_map[id()]);
     TransformNode* transform_node =
         property_trees->transform_tree.Node(transform_tree_index());
-    transform_node->data.update_post_local_transform(position,
-                                                     transform_origin());
-    transform_node->data.needs_local_transform_update = true;
-    transform_node->data.transform_changed = true;
+    transform_node->update_post_local_transform(position, transform_origin());
+    transform_node->needs_local_transform_update = true;
+    transform_node->transform_changed = true;
     layer_tree_host_->property_trees()->transform_tree.set_needs_update(true);
     SetNeedsCommitNoRebuild();
     return;
@@ -623,11 +628,11 @@
 }
 
 bool Layer::IsContainerForFixedPositionLayers() const {
-  if (!transform_.IsIdentityOrTranslation())
+  if (!inputs_.transform.IsIdentityOrTranslation())
     return true;
-  if (parent_ && !parent_->transform_.IsIdentityOrTranslation())
+  if (parent_ && !parent_->inputs_.transform.IsIdentityOrTranslation())
     return true;
-  return is_container_for_fixed_position_layers_;
+  return inputs_.is_container_for_fixed_position_layers;
 }
 
 bool Are2dAxisAligned(const gfx::Transform& a, const gfx::Transform& b) {
@@ -647,7 +652,7 @@
 
 void Layer::SetTransform(const gfx::Transform& transform) {
   DCHECK(IsPropertyChangeAllowed());
-  if (transform_ == transform)
+  if (inputs_.transform == transform)
     return;
 
   SetSubtreePropertyChanged();
@@ -656,37 +661,38 @@
     if (property_trees->IsInIdToIndexMap(PropertyTrees::TreeType::TRANSFORM,
                                          id())) {
       // We need to trigger a rebuild if we could have affected 2d axis
-      // alignment. We'll check to see if transform and transform_ are axis
+      // alignment. We'll check to see if transform and inputs_.transform
+      // are axis
       // align with respect to one another.
       DCHECK_EQ(transform_tree_index(),
                 property_trees->transform_id_to_index_map[id()]);
       TransformNode* transform_node =
           property_trees->transform_tree.Node(transform_tree_index());
       bool preserves_2d_axis_alignment =
-          Are2dAxisAligned(transform_, transform);
-      transform_node->data.local = transform;
-      transform_node->data.needs_local_transform_update = true;
-      transform_node->data.transform_changed = true;
+          Are2dAxisAligned(inputs_.transform, transform);
+      transform_node->local = transform;
+      transform_node->needs_local_transform_update = true;
+      transform_node->transform_changed = true;
       layer_tree_host_->property_trees()->transform_tree.set_needs_update(true);
       if (preserves_2d_axis_alignment)
         SetNeedsCommitNoRebuild();
       else
         SetNeedsCommit();
-      transform_ = transform;
+      inputs_.transform = transform;
       return;
     }
   }
 
-  transform_ = transform;
+  inputs_.transform = transform;
 
   SetNeedsCommit();
 }
 
 void Layer::SetTransformOrigin(const gfx::Point3F& transform_origin) {
   DCHECK(IsPropertyChangeAllowed());
-  if (transform_origin_ == transform_origin)
+  if (inputs_.transform_origin == transform_origin)
     return;
-  transform_origin_ = transform_origin;
+  inputs_.transform_origin = transform_origin;
 
   if (!layer_tree_host_)
     return;
@@ -699,11 +705,10 @@
               property_trees->transform_id_to_index_map[id()]);
     TransformNode* transform_node =
         property_trees->transform_tree.Node(transform_tree_index());
-    transform_node->data.update_pre_local_transform(transform_origin);
-    transform_node->data.update_post_local_transform(position(),
-                                                     transform_origin);
-    transform_node->data.needs_local_transform_update = true;
-    transform_node->data.transform_changed = true;
+    transform_node->update_pre_local_transform(transform_origin);
+    transform_node->update_post_local_transform(position(), transform_origin);
+    transform_node->needs_local_transform_update = true;
+    transform_node->transform_changed = true;
     layer_tree_host_->property_trees()->transform_tree.set_needs_update(true);
     SetNeedsCommitNoRebuild();
     return;
@@ -750,16 +755,16 @@
 
 void Layer::SetScrollParent(Layer* parent) {
   DCHECK(IsPropertyChangeAllowed());
-  if (scroll_parent_ == parent)
+  if (inputs_.scroll_parent == parent)
     return;
 
-  if (scroll_parent_)
-    scroll_parent_->RemoveScrollChild(this);
+  if (inputs_.scroll_parent)
+    inputs_.scroll_parent->RemoveScrollChild(this);
 
-  scroll_parent_ = parent;
+  inputs_.scroll_parent = parent;
 
-  if (scroll_parent_)
-    scroll_parent_->AddScrollChild(this);
+  if (inputs_.scroll_parent)
+    inputs_.scroll_parent->AddScrollChild(this);
 
   SetNeedsCommit();
 }
@@ -780,16 +785,16 @@
 
 void Layer::SetClipParent(Layer* ancestor) {
   DCHECK(IsPropertyChangeAllowed());
-  if (clip_parent_ == ancestor)
+  if (inputs_.clip_parent == ancestor)
     return;
 
-  if (clip_parent_)
-    clip_parent_->RemoveClipChild(this);
+  if (inputs_.clip_parent)
+    inputs_.clip_parent->RemoveClipChild(this);
 
-  clip_parent_ = ancestor;
+  inputs_.clip_parent = ancestor;
 
-  if (clip_parent_)
-    clip_parent_->AddClipChild(this);
+  if (inputs_.clip_parent)
+    inputs_.clip_parent->AddClipChild(this);
 
   SetNeedsCommit();
   if (layer_tree_host_)
@@ -813,9 +818,9 @@
 void Layer::SetScrollOffset(const gfx::ScrollOffset& scroll_offset) {
   DCHECK(IsPropertyChangeAllowed());
 
-  if (scroll_offset_ == scroll_offset)
+  if (inputs_.scroll_offset == scroll_offset)
     return;
-  scroll_offset_ = scroll_offset;
+  inputs_.scroll_offset = scroll_offset;
 
   if (!layer_tree_host_)
     return;
@@ -830,8 +835,8 @@
               property_trees->transform_id_to_index_map[id()]);
     TransformNode* transform_node =
         property_trees->transform_tree.Node(transform_tree_index());
-    transform_node->data.scroll_offset = CurrentScrollOffset();
-    transform_node->data.needs_local_transform_update = true;
+    transform_node->scroll_offset = CurrentScrollOffset();
+    transform_node->needs_local_transform_update = true;
     property_trees->transform_tree.set_needs_update(true);
     SetNeedsCommitNoRebuild();
     return;
@@ -846,9 +851,9 @@
   // This function only gets called during a BeginMainFrame, so there
   // is no need to call SetNeedsUpdate here.
   DCHECK(layer_tree_host_ && layer_tree_host_->CommitRequested());
-  if (scroll_offset_ == scroll_offset)
+  if (inputs_.scroll_offset == scroll_offset)
     return;
-  scroll_offset_ = scroll_offset;
+  inputs_.scroll_offset = scroll_offset;
   SetNeedsPushProperties();
 
   bool needs_rebuild = true;
@@ -863,8 +868,8 @@
               property_trees->transform_id_to_index_map[id()]);
     TransformNode* transform_node =
         property_trees->transform_tree.Node(transform_tree_index());
-    transform_node->data.scroll_offset = CurrentScrollOffset();
-    transform_node->data.needs_local_transform_update = true;
+    transform_node->scroll_offset = CurrentScrollOffset();
+    transform_node->needs_local_transform_update = true;
     property_trees->transform_tree.set_needs_update(true);
     needs_rebuild = false;
   }
@@ -872,31 +877,31 @@
   if (needs_rebuild)
     property_trees->needs_rebuild = true;
 
-  if (!did_scroll_callback_.is_null())
-    did_scroll_callback_.Run();
+  if (!inputs_.did_scroll_callback.is_null())
+    inputs_.did_scroll_callback.Run();
   // The callback could potentially change the layer structure:
   // "this" may have been destroyed during the process.
 }
 
 void Layer::SetScrollClipLayerId(int clip_layer_id) {
   DCHECK(IsPropertyChangeAllowed());
-  if (scroll_clip_layer_id_ == clip_layer_id)
+  if (inputs_.scroll_clip_layer_id == clip_layer_id)
     return;
-  scroll_clip_layer_id_ = clip_layer_id;
+  inputs_.scroll_clip_layer_id = clip_layer_id;
   SetNeedsCommit();
 }
 
 Layer* Layer::scroll_clip_layer() const {
-  return layer_tree_host()->LayerById(scroll_clip_layer_id_);
+  return layer_tree_host()->LayerById(inputs_.scroll_clip_layer_id);
 }
 
 void Layer::SetUserScrollable(bool horizontal, bool vertical) {
   DCHECK(IsPropertyChangeAllowed());
-  if (user_scrollable_horizontal_ == horizontal &&
-      user_scrollable_vertical_ == vertical)
+  if (inputs_.user_scrollable_horizontal == horizontal &&
+      inputs_.user_scrollable_vertical == vertical)
     return;
-  user_scrollable_horizontal_ = horizontal;
-  user_scrollable_vertical_ = vertical;
+  inputs_.user_scrollable_horizontal = horizontal;
+  inputs_.user_scrollable_vertical = vertical;
   SetNeedsCommit();
 }
 
@@ -905,10 +910,10 @@
   DCHECK(IsPropertyChangeAllowed());
   DCHECK(main_thread_scrolling_reasons);
   uint32_t new_reasons =
-      main_thread_scrolling_reasons_ | main_thread_scrolling_reasons;
-  if (main_thread_scrolling_reasons_ == new_reasons)
+      inputs_.main_thread_scrolling_reasons | main_thread_scrolling_reasons;
+  if (inputs_.main_thread_scrolling_reasons == new_reasons)
     return;
-  main_thread_scrolling_reasons_ = new_reasons;
+  inputs_.main_thread_scrolling_reasons = new_reasons;
   SetNeedsCommit();
 }
 
@@ -916,28 +921,28 @@
     uint32_t main_thread_scrolling_reasons_to_clear) {
   DCHECK(IsPropertyChangeAllowed());
   DCHECK(main_thread_scrolling_reasons_to_clear);
-  uint32_t new_reasons =
-      ~main_thread_scrolling_reasons_to_clear & main_thread_scrolling_reasons_;
-  if (new_reasons == main_thread_scrolling_reasons_)
+  uint32_t new_reasons = ~main_thread_scrolling_reasons_to_clear &
+                         inputs_.main_thread_scrolling_reasons;
+  if (new_reasons == inputs_.main_thread_scrolling_reasons)
     return;
-  main_thread_scrolling_reasons_ = new_reasons;
+  inputs_.main_thread_scrolling_reasons = new_reasons;
   SetNeedsCommit();
 }
 
 void Layer::SetNonFastScrollableRegion(const Region& region) {
   DCHECK(IsPropertyChangeAllowed());
-  if (non_fast_scrollable_region_ == region)
+  if (inputs_.non_fast_scrollable_region == region)
     return;
-  non_fast_scrollable_region_ = region;
+  inputs_.non_fast_scrollable_region = region;
   SetNeedsCommit();
 }
 
 void Layer::SetTouchEventHandlerRegion(const Region& region) {
   DCHECK(IsPropertyChangeAllowed());
-  if (touch_event_handler_region_ == region)
+  if (inputs_.touch_event_handler_region == region)
     return;
 
-  touch_event_handler_region_ = region;
+  inputs_.touch_event_handler_region = region;
   SetNeedsCommit();
 }
 
@@ -951,18 +956,18 @@
 
 void Layer::SetDoubleSided(bool double_sided) {
   DCHECK(IsPropertyChangeAllowed());
-  if (double_sided_ == double_sided)
+  if (inputs_.double_sided == double_sided)
     return;
-  double_sided_ = double_sided;
+  inputs_.double_sided = double_sided;
   SetNeedsCommit();
   SetSubtreePropertyChanged();
 }
 
 void Layer::Set3dSortingContextId(int id) {
   DCHECK(IsPropertyChangeAllowed());
-  if (id == sorting_context_id_)
+  if (id == inputs_.sorting_context_id)
     return;
-  sorting_context_id_ = id;
+  inputs_.sorting_context_id = id;
   SetNeedsCommit();
   SetSubtreePropertyChanged();
 }
@@ -1044,18 +1049,18 @@
 
 void Layer::SetShouldFlattenTransform(bool should_flatten) {
   DCHECK(IsPropertyChangeAllowed());
-  if (should_flatten_transform_ == should_flatten)
+  if (inputs_.should_flatten_transform == should_flatten)
     return;
-  should_flatten_transform_ = should_flatten;
+  inputs_.should_flatten_transform = should_flatten;
   SetNeedsCommit();
   SetSubtreePropertyChanged();
 }
 
 void Layer::SetUseParentBackfaceVisibility(bool use) {
   DCHECK(IsPropertyChangeAllowed());
-  if (use_parent_backface_visibility_ == use)
+  if (inputs_.use_parent_backface_visibility == use)
     return;
-  use_parent_backface_visibility_ = use;
+  inputs_.use_parent_backface_visibility = use;
   SetNeedsPushProperties();
 }
 
@@ -1076,19 +1081,19 @@
 
 void Layer::SetIsDrawable(bool is_drawable) {
   DCHECK(IsPropertyChangeAllowed());
-  if (is_drawable_ == is_drawable)
+  if (inputs_.is_drawable == is_drawable)
     return;
 
-  is_drawable_ = is_drawable;
+  inputs_.is_drawable = is_drawable;
   UpdateDrawsContent(HasDrawableContent());
 }
 
 void Layer::SetHideLayerAndSubtree(bool hide) {
   DCHECK(IsPropertyChangeAllowed());
-  if (hide_layer_and_subtree_ == hide)
+  if (inputs_.hide_layer_and_subtree == hide)
     return;
 
-  hide_layer_and_subtree_ = hide;
+  inputs_.hide_layer_and_subtree = hide;
   SetNeedsCommit();
   SetSubtreePropertyChanged();
 }
@@ -1098,25 +1103,25 @@
     return;
 
   SetNeedsPushProperties();
-  update_rect_.Union(dirty_rect);
+  inputs_.update_rect.Union(dirty_rect);
 
   if (DrawsContent())
     SetNeedsUpdate();
 }
 
 bool Layer::DescendantIsFixedToContainerLayer() const {
-  for (size_t i = 0; i < children_.size(); ++i) {
-    if (children_[i]->position_constraint_.is_fixed_position() ||
-        children_[i]->DescendantIsFixedToContainerLayer())
+  for (size_t i = 0; i < inputs_.children.size(); ++i) {
+    if (inputs_.children[i]->inputs_.position_constraint.is_fixed_position() ||
+        inputs_.children[i]->DescendantIsFixedToContainerLayer())
       return true;
   }
   return false;
 }
 
 void Layer::SetIsContainerForFixedPositionLayers(bool container) {
-  if (is_container_for_fixed_position_layers_ == container)
+  if (inputs_.is_container_for_fixed_position_layers == container)
     return;
-  is_container_for_fixed_position_layers_ = container;
+  inputs_.is_container_for_fixed_position_layers = container;
 
   if (layer_tree_host_ && layer_tree_host_->CommitRequested())
     return;
@@ -1128,9 +1133,9 @@
 
 void Layer::SetPositionConstraint(const LayerPositionConstraint& constraint) {
   DCHECK(IsPropertyChangeAllowed());
-  if (position_constraint_ == constraint)
+  if (inputs_.position_constraint == constraint)
     return;
-  position_constraint_ = constraint;
+  inputs_.position_constraint = constraint;
   SetNeedsCommit();
 }
 
@@ -1159,10 +1164,10 @@
   bool use_paint_properties = paint_properties_.source_frame_number ==
                               layer_tree_host_->source_frame_number();
 
-  layer->SetBackgroundColor(background_color_);
+  layer->SetBackgroundColor(inputs_.background_color);
   layer->SetSafeOpaqueBackgroundColor(safe_opaque_background_color_);
   layer->SetBounds(use_paint_properties ? paint_properties_.bounds
-                                        : bounds_);
+                                        : inputs_.bounds);
 
 #if defined(NDEBUG)
   if (frame_viewer_instrumentation::IsTracingLayerTreeSnapshots())
@@ -1182,30 +1187,31 @@
   if (subtree_property_changed_ || layer_property_changed_)
     layer->NoteLayerPropertyChanged();
   if (!FilterIsAnimating())
-    layer->SetFilters(filters_);
-  layer->SetMasksToBounds(masks_to_bounds_);
-  layer->set_main_thread_scrolling_reasons(main_thread_scrolling_reasons_);
-  layer->SetNonFastScrollableRegion(non_fast_scrollable_region_);
-  layer->SetTouchEventHandlerRegion(touch_event_handler_region_);
-  layer->SetContentsOpaque(contents_opaque_);
-  layer->SetBlendMode(blend_mode_);
-  layer->SetPosition(position_);
+    layer->SetFilters(inputs_.filters);
+  layer->SetMasksToBounds(inputs_.masks_to_bounds);
+  layer->set_main_thread_scrolling_reasons(
+      inputs_.main_thread_scrolling_reasons);
+  layer->SetNonFastScrollableRegion(inputs_.non_fast_scrollable_region);
+  layer->SetTouchEventHandlerRegion(inputs_.touch_event_handler_region);
+  layer->SetContentsOpaque(inputs_.contents_opaque);
+  layer->SetBlendMode(inputs_.blend_mode);
+  layer->SetPosition(inputs_.position);
   layer->set_should_flatten_transform_from_property_tree(
       should_flatten_transform_from_property_tree_);
   layer->set_draw_blend_mode(draw_blend_mode_);
-  layer->SetUseParentBackfaceVisibility(use_parent_backface_visibility_);
+  layer->SetUseParentBackfaceVisibility(inputs_.use_parent_backface_visibility);
   layer->SetUseLocalTransformForBackfaceVisibility(
       use_local_transform_for_backface_visibility_);
   layer->SetShouldCheckBackfaceVisibility(should_check_backface_visibility_);
   if (!TransformIsAnimating())
-    layer->SetTransform(transform_);
-  layer->Set3dSortingContextId(sorting_context_id_);
+    layer->SetTransform(inputs_.transform);
+  layer->Set3dSortingContextId(inputs_.sorting_context_id);
 
-  layer->SetScrollClipLayer(scroll_clip_layer_id_);
-  layer->set_user_scrollable_horizontal(user_scrollable_horizontal_);
-  layer->set_user_scrollable_vertical(user_scrollable_vertical_);
-  layer->SetElementId(element_id_);
-  layer->SetMutableProperties(mutable_properties_);
+  layer->SetScrollClipLayer(inputs_.scroll_clip_layer_id);
+  layer->set_user_scrollable_horizontal(inputs_.user_scrollable_horizontal);
+  layer->set_user_scrollable_vertical(inputs_.user_scrollable_vertical);
+  layer->SetElementId(inputs_.element_id);
+  layer->SetMutableProperties(inputs_.mutable_properties);
 
   // When a scroll offset animation is interrupted the new scroll position on
   // the pending tree will clobber any impl-side scrolling occuring on the
@@ -1220,8 +1226,8 @@
   // draws, then damage tracking will become incorrect if we simply clobber the
   // update_rect here. The LayerImpl's update_rect needs to accumulate (i.e.
   // union) any update changes that have occurred on the main thread.
-  update_rect_.Union(layer->update_rect());
-  layer->SetUpdateRect(update_rect_);
+  inputs_.update_rect.Union(layer->update_rect());
+  layer->SetUpdateRect(inputs_.update_rect);
 
   layer->SetHasWillChangeTransformHint(has_will_change_transform_hint());
   layer->SetNeedsPushProperties();
@@ -1229,14 +1235,14 @@
   // Reset any state that should be cleared for the next update.
   subtree_property_changed_ = false;
   layer_property_changed_ = false;
-  update_rect_ = gfx::Rect();
+  inputs_.update_rect = gfx::Rect();
 
   layer_tree_host()->RemoveLayerShouldPushProperties(this);
 }
 
 void Layer::TakeCopyRequests(
     std::vector<std::unique_ptr<CopyOutputRequest>>* requests) {
-  for (auto& it : copy_requests_) {
+  for (auto& it : inputs_.copy_requests) {
     scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner =
         layer_tree_host()->task_runner_provider()->MainThreadTaskRunner();
     std::unique_ptr<CopyOutputRequest> original_request = std::move(it);
@@ -1253,7 +1259,7 @@
     requests->push_back(std::move(main_thread_request));
   }
 
-  copy_requests_.clear();
+  inputs_.copy_requests.clear();
 }
 
 void Layer::SetTypeForProtoSerialization(proto::LayerNode* proto) const {
@@ -1261,26 +1267,26 @@
 }
 
 void Layer::ToLayerNodeProto(proto::LayerNode* proto) const {
-  proto->set_id(layer_id_);
+  proto->set_id(inputs_.layer_id);
   SetTypeForProtoSerialization(proto);
 
   if (parent_)
     proto->set_parent_id(parent_->id());
 
   DCHECK_EQ(0, proto->children_size());
-  for (const auto& child : children_) {
+  for (const auto& child : inputs_.children) {
     child->ToLayerNodeProto(proto->add_children());
   }
 
-  if (mask_layer_)
-    mask_layer_->ToLayerNodeProto(proto->mutable_mask_layer());
-  if (replica_layer_)
-    replica_layer_->ToLayerNodeProto(proto->mutable_replica_layer());
+  if (inputs_.mask_layer)
+    inputs_.mask_layer->ToLayerNodeProto(proto->mutable_mask_layer());
+  if (inputs_.replica_layer)
+    inputs_.replica_layer->ToLayerNodeProto(proto->mutable_replica_layer());
 }
 
 void Layer::ClearLayerTreePropertiesForDeserializationAndAddToMap(
     LayerIdMap* layer_map) {
-  (*layer_map)[layer_id_] = this;
+  (*layer_map)[inputs_.layer_id] = this;
 
   if (layer_tree_host_)
     layer_tree_host_->UnregisterLayer(this);
@@ -1289,22 +1295,22 @@
   parent_ = nullptr;
 
   // Clear these properties for all the children and add them to the map.
-  for (auto& child : children_) {
+  for (auto& child : inputs_.children) {
     child->ClearLayerTreePropertiesForDeserializationAndAddToMap(layer_map);
   }
 
-  children_.clear();
+  inputs_.children.clear();
 
-  if (mask_layer_) {
-    mask_layer_->ClearLayerTreePropertiesForDeserializationAndAddToMap(
+  if (inputs_.mask_layer) {
+    inputs_.mask_layer->ClearLayerTreePropertiesForDeserializationAndAddToMap(
         layer_map);
-    mask_layer_ = nullptr;
+    inputs_.mask_layer = nullptr;
   }
 
-  if (replica_layer_) {
-    replica_layer_->ClearLayerTreePropertiesForDeserializationAndAddToMap(
-        layer_map);
-    replica_layer_ = nullptr;
+  if (inputs_.replica_layer) {
+    inputs_.replica_layer
+        ->ClearLayerTreePropertiesForDeserializationAndAddToMap(layer_map);
+    inputs_.replica_layer = nullptr;
   }
 }
 
@@ -1312,13 +1318,13 @@
                                const LayerIdMap& layer_map,
                                LayerTreeHost* layer_tree_host) {
   DCHECK(!layer_tree_host_);
-  DCHECK(children_.empty());
-  DCHECK(!mask_layer_);
-  DCHECK(!replica_layer_);
+  DCHECK(inputs_.children.empty());
+  DCHECK(!inputs_.mask_layer);
+  DCHECK(!inputs_.replica_layer);
   DCHECK(layer_tree_host);
   DCHECK(proto.has_id());
 
-  layer_id_ = proto.id();
+  inputs_.layer_id = proto.id();
 
   layer_tree_host_ = layer_tree_host;
   layer_tree_host_->RegisterLayer(this);
@@ -1333,36 +1339,36 @@
     DCHECK(!child->parent_);
     child->parent_ = this;
     child->FromLayerNodeProto(child_proto, layer_map, layer_tree_host_);
-    children_.push_back(child);
+    inputs_.children.push_back(child);
   }
 
   if (proto.has_mask_layer()) {
-    mask_layer_ = LayerProtoConverter::FindOrAllocateAndConstruct(
+    inputs_.mask_layer = LayerProtoConverter::FindOrAllocateAndConstruct(
         proto.mask_layer(), layer_map);
-    mask_layer_->parent_ = this;
-    mask_layer_->FromLayerNodeProto(proto.mask_layer(), layer_map,
-                                    layer_tree_host_);
+    inputs_.mask_layer->parent_ = this;
+    inputs_.mask_layer->FromLayerNodeProto(proto.mask_layer(), layer_map,
+                                           layer_tree_host_);
   }
 
   if (proto.has_replica_layer()) {
-    replica_layer_ = LayerProtoConverter::FindOrAllocateAndConstruct(
+    inputs_.replica_layer = LayerProtoConverter::FindOrAllocateAndConstruct(
         proto.replica_layer(), layer_map);
-    replica_layer_->parent_ = this;
-    replica_layer_->FromLayerNodeProto(proto.replica_layer(), layer_map,
-                                       layer_tree_host_);
+    inputs_.replica_layer->parent_ = this;
+    inputs_.replica_layer->FromLayerNodeProto(proto.replica_layer(), layer_map,
+                                              layer_tree_host_);
   }
 }
 
 void Layer::ToLayerPropertiesProto(proto::LayerUpdate* layer_update) {
   // Always set properties metadata for serialized layers.
   proto::LayerProperties* proto = layer_update->add_layers();
-  proto->set_id(layer_id_);
+  proto->set_id(inputs_.layer_id);
   LayerSpecificPropertiesToProto(proto);
 }
 
 void Layer::FromLayerPropertiesProto(const proto::LayerProperties& proto) {
   DCHECK(proto.has_id());
-  DCHECK_EQ(layer_id_, proto.id());
+  DCHECK_EQ(inputs_.layer_id, proto.id());
   FromLayerSpecificPropertiesProto(proto);
 }
 
@@ -1373,10 +1379,10 @@
                               paint_properties_.source_frame_number ==
                                   layer_tree_host_->source_frame_number();
 
-  Point3FToProto(transform_origin_, base->mutable_transform_origin());
-  base->set_background_color(background_color_);
+  Point3FToProto(inputs_.transform_origin, base->mutable_transform_origin());
+  base->set_background_color(inputs_.background_color);
   base->set_safe_opaque_background_color(safe_opaque_background_color_);
-  SizeToProto(use_paint_properties ? paint_properties_.bounds : bounds_,
+  SizeToProto(use_paint_properties ? paint_properties_.bounds : inputs_.bounds,
               base->mutable_bounds());
 
   // TODO(nyquist): Figure out what to do with debug info. See crbug.com/570372.
@@ -1387,44 +1393,47 @@
   base->set_scroll_tree_index(scroll_tree_index_);
   Vector2dFToProto(offset_to_transform_parent_,
                    base->mutable_offset_to_transform_parent());
-  base->set_double_sided(double_sided_);
+  base->set_double_sided(inputs_.double_sided);
   base->set_draws_content(draws_content_);
-  base->set_hide_layer_and_subtree(hide_layer_and_subtree_);
+  base->set_hide_layer_and_subtree(inputs_.hide_layer_and_subtree);
   base->set_subtree_property_changed(subtree_property_changed_);
   base->set_layer_property_changed(layer_property_changed_);
 
   // TODO(nyquist): Add support for serializing FilterOperations for
   // |filters_| and |background_filters_|. See crbug.com/541321.
 
-  base->set_masks_to_bounds(masks_to_bounds_);
-  base->set_main_thread_scrolling_reasons(main_thread_scrolling_reasons_);
-  RegionToProto(non_fast_scrollable_region_,
+  base->set_masks_to_bounds(inputs_.masks_to_bounds);
+  base->set_main_thread_scrolling_reasons(
+      inputs_.main_thread_scrolling_reasons);
+  RegionToProto(inputs_.non_fast_scrollable_region,
                 base->mutable_non_fast_scrollable_region());
-  RegionToProto(touch_event_handler_region_,
+  RegionToProto(inputs_.touch_event_handler_region,
                 base->mutable_touch_event_handler_region());
-  base->set_contents_opaque(contents_opaque_);
-  base->set_opacity(opacity_);
-  base->set_blend_mode(SkXfermodeModeToProto(blend_mode_));
-  base->set_is_root_for_isolated_group(is_root_for_isolated_group_);
-  PointFToProto(position_, base->mutable_position());
+  base->set_contents_opaque(inputs_.contents_opaque);
+  base->set_opacity(inputs_.opacity);
+  base->set_blend_mode(SkXfermodeModeToProto(inputs_.blend_mode));
+  base->set_is_root_for_isolated_group(inputs_.is_root_for_isolated_group);
+  PointFToProto(inputs_.position, base->mutable_position());
   base->set_is_container_for_fixed_position_layers(
-      is_container_for_fixed_position_layers_);
-  position_constraint_.ToProtobuf(base->mutable_position_constraint());
-  base->set_should_flatten_transform(should_flatten_transform_);
+      inputs_.is_container_for_fixed_position_layers);
+  inputs_.position_constraint.ToProtobuf(base->mutable_position_constraint());
+  base->set_should_flatten_transform(inputs_.should_flatten_transform);
   base->set_should_flatten_transform_from_property_tree(
       should_flatten_transform_from_property_tree_);
   base->set_draw_blend_mode(SkXfermodeModeToProto(draw_blend_mode_));
-  base->set_use_parent_backface_visibility(use_parent_backface_visibility_);
-  TransformToProto(transform_, base->mutable_transform());
-  base->set_sorting_context_id(sorting_context_id_);
+  base->set_use_parent_backface_visibility(
+      inputs_.use_parent_backface_visibility);
+  TransformToProto(inputs_.transform, base->mutable_transform());
+  base->set_sorting_context_id(inputs_.sorting_context_id);
   base->set_num_descendants_that_draw_content(
       num_descendants_that_draw_content_);
 
-  base->set_scroll_clip_layer_id(scroll_clip_layer_id_);
-  base->set_user_scrollable_horizontal(user_scrollable_horizontal_);
-  base->set_user_scrollable_vertical(user_scrollable_vertical_);
+  base->set_scroll_clip_layer_id(inputs_.scroll_clip_layer_id);
+  base->set_user_scrollable_horizontal(inputs_.user_scrollable_horizontal);
+  base->set_user_scrollable_vertical(inputs_.user_scrollable_vertical);
 
-  int scroll_parent_id = scroll_parent_ ? scroll_parent_->id() : INVALID_ID;
+  int scroll_parent_id =
+      inputs_.scroll_parent ? inputs_.scroll_parent->id() : INVALID_ID;
   base->set_scroll_parent_id(scroll_parent_id);
 
   if (scroll_children_) {
@@ -1432,7 +1441,8 @@
       base->add_scroll_children_ids(child->id());
   }
 
-  int clip_parent_id = clip_parent_ ? clip_parent_->id() : INVALID_ID;
+  int clip_parent_id =
+      inputs_.clip_parent ? inputs_.clip_parent->id() : INVALID_ID;
   base->set_clip_parent_id(clip_parent_id);
 
   if (clip_children_) {
@@ -1440,19 +1450,20 @@
       base->add_clip_children_ids(child->id());
   }
 
-  ScrollOffsetToProto(scroll_offset_, base->mutable_scroll_offset());
+  ScrollOffsetToProto(inputs_.scroll_offset, base->mutable_scroll_offset());
 
   // TODO(nyquist): Figure out what to do with CopyRequests.
   // See crbug.com/570374.
 
-  RectToProto(update_rect_, base->mutable_update_rect());
+  RectToProto(inputs_.update_rect, base->mutable_update_rect());
 
   // TODO(nyquist): Figure out what to do with ElementAnimations.
   // See crbug.com/570376.
 
-  update_rect_ = gfx::Rect();
+  inputs_.update_rect = gfx::Rect();
 
-  base->set_has_will_change_transform_hint(has_will_change_transform_hint_);
+  base->set_has_will_change_transform_hint(
+      inputs_.has_will_change_transform_hint);
 }
 
 void Layer::FromLayerSpecificPropertiesProto(
@@ -1461,10 +1472,10 @@
   DCHECK(layer_tree_host_);
   const proto::BaseLayerProperties& base = proto.base();
 
-  transform_origin_ = ProtoToPoint3F(base.transform_origin());
-  background_color_ = base.background_color();
+  inputs_.transform_origin = ProtoToPoint3F(base.transform_origin());
+  inputs_.background_color = base.background_color();
   safe_opaque_background_color_ = base.safe_opaque_background_color();
-  bounds_ = ProtoToSize(base.bounds());
+  inputs_.bounds = ProtoToSize(base.bounds());
 
   transform_tree_index_ = base.transform_free_index();
   effect_tree_index_ = base.effect_tree_index();
@@ -1472,41 +1483,43 @@
   scroll_tree_index_ = base.scroll_tree_index();
   offset_to_transform_parent_ =
       ProtoToVector2dF(base.offset_to_transform_parent());
-  double_sided_ = base.double_sided();
+  inputs_.double_sided = base.double_sided();
   draws_content_ = base.draws_content();
-  hide_layer_and_subtree_ = base.hide_layer_and_subtree();
+  inputs_.hide_layer_and_subtree = base.hide_layer_and_subtree();
   subtree_property_changed_ = base.subtree_property_changed();
   layer_property_changed_ = base.layer_property_changed();
-  masks_to_bounds_ = base.masks_to_bounds();
-  main_thread_scrolling_reasons_ = base.main_thread_scrolling_reasons();
-  non_fast_scrollable_region_ =
+  inputs_.masks_to_bounds = base.masks_to_bounds();
+  inputs_.main_thread_scrolling_reasons = base.main_thread_scrolling_reasons();
+  inputs_.non_fast_scrollable_region =
       RegionFromProto(base.non_fast_scrollable_region());
-  touch_event_handler_region_ =
+  inputs_.touch_event_handler_region =
       RegionFromProto(base.touch_event_handler_region());
-  contents_opaque_ = base.contents_opaque();
-  opacity_ = base.opacity();
-  blend_mode_ = SkXfermodeModeFromProto(base.blend_mode());
-  is_root_for_isolated_group_ = base.is_root_for_isolated_group();
-  position_ = ProtoToPointF(base.position());
-  is_container_for_fixed_position_layers_ =
+  inputs_.contents_opaque = base.contents_opaque();
+  inputs_.opacity = base.opacity();
+  inputs_.blend_mode = SkXfermodeModeFromProto(base.blend_mode());
+  inputs_.is_root_for_isolated_group = base.is_root_for_isolated_group();
+  inputs_.position = ProtoToPointF(base.position());
+  inputs_.is_container_for_fixed_position_layers =
       base.is_container_for_fixed_position_layers();
-  position_constraint_.FromProtobuf(base.position_constraint());
-  should_flatten_transform_ = base.should_flatten_transform();
+  inputs_.position_constraint.FromProtobuf(base.position_constraint());
+  inputs_.should_flatten_transform = base.should_flatten_transform();
   should_flatten_transform_from_property_tree_ =
       base.should_flatten_transform_from_property_tree();
   draw_blend_mode_ = SkXfermodeModeFromProto(base.draw_blend_mode());
-  use_parent_backface_visibility_ = base.use_parent_backface_visibility();
-  transform_ = ProtoToTransform(base.transform());
-  sorting_context_id_ = base.sorting_context_id();
+  inputs_.use_parent_backface_visibility =
+      base.use_parent_backface_visibility();
+  inputs_.transform = ProtoToTransform(base.transform());
+  inputs_.sorting_context_id = base.sorting_context_id();
   num_descendants_that_draw_content_ = base.num_descendants_that_draw_content();
 
-  scroll_clip_layer_id_ = base.scroll_clip_layer_id();
-  user_scrollable_horizontal_ = base.user_scrollable_horizontal();
-  user_scrollable_vertical_ = base.user_scrollable_vertical();
+  inputs_.scroll_clip_layer_id = base.scroll_clip_layer_id();
+  inputs_.user_scrollable_horizontal = base.user_scrollable_horizontal();
+  inputs_.user_scrollable_vertical = base.user_scrollable_vertical();
 
-  scroll_parent_ = base.scroll_parent_id() == INVALID_ID
-                       ? nullptr
-                       : layer_tree_host_->LayerById(base.scroll_parent_id());
+  inputs_.scroll_parent =
+      base.scroll_parent_id() == INVALID_ID
+          ? nullptr
+          : layer_tree_host_->LayerById(base.scroll_parent_id());
 
   // If there have been scroll children entries in previous deserializations,
   // clear out the set. If there have been none, initialize the set of children.
@@ -1523,9 +1536,10 @@
     scroll_children_->insert(child.get());
   }
 
-  clip_parent_ = base.clip_parent_id() == INVALID_ID
-                     ? nullptr
-                     : layer_tree_host_->LayerById(base.clip_parent_id());
+  inputs_.clip_parent =
+      base.clip_parent_id() == INVALID_ID
+          ? nullptr
+          : layer_tree_host_->LayerById(base.clip_parent_id());
 
   // If there have been clip children entries in previous deserializations,
   // clear out the set. If there have been none, initialize the set of children.
@@ -1542,15 +1556,16 @@
     clip_children_->insert(child.get());
   }
 
-  scroll_offset_ = ProtoToScrollOffset(base.scroll_offset());
+  inputs_.scroll_offset = ProtoToScrollOffset(base.scroll_offset());
 
-  update_rect_.Union(ProtoToRect(base.update_rect()));
+  inputs_.update_rect.Union(ProtoToRect(base.update_rect()));
 
-  has_will_change_transform_hint_ = base.has_will_change_transform_hint();
+  inputs_.has_will_change_transform_hint =
+      base.has_will_change_transform_hint();
 }
 
 std::unique_ptr<LayerImpl> Layer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
-  return LayerImpl::Create(tree_impl, layer_id_);
+  return LayerImpl::Create(tree_impl, inputs_.layer_id);
 }
 
 bool Layer::DrawsContent() const {
@@ -1558,12 +1573,12 @@
 }
 
 bool Layer::HasDrawableContent() const {
-  return is_drawable_;
+  return inputs_.is_drawable;
 }
 
 void Layer::UpdateDrawsContent(bool has_drawable_content) {
   bool draws_content = has_drawable_content;
-  DCHECK(is_drawable_ || !has_drawable_content);
+  DCHECK(inputs_.is_drawable || !has_drawable_content);
   if (draws_content == draws_content_)
     return;
 
@@ -1583,7 +1598,7 @@
 
   // TODO(reveman): Save all layer properties that we depend on not
   // changing until PushProperties() has been called. crbug.com/231016
-  paint_properties_.bounds = bounds_;
+  paint_properties_.bounds = inputs_.bounds;
   paint_properties_.source_frame_number =
       layer_tree_host_->source_frame_number();
 }
@@ -1602,8 +1617,8 @@
 
 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
 Layer::TakeDebugInfo() {
-  if (client_)
-    return client_->TakeDebugInfo(this);
+  if (inputs_.client)
+    return inputs_.client->TakeDebugInfo(this);
   else
     return nullptr;
 }
@@ -1631,16 +1646,16 @@
 // is no need to request a commit to push this value over, so the value is
 // set directly rather than by calling Set<Property>.
 void Layer::OnFilterAnimated(const FilterOperations& filters) {
-  filters_ = filters;
+  inputs_.filters = filters;
 }
 
 void Layer::OnOpacityAnimated(float opacity) {
   DCHECK_GE(opacity, 0.f);
   DCHECK_LE(opacity, 1.f);
 
-  if (opacity_ == opacity)
+  if (inputs_.opacity == opacity)
     return;
-  opacity_ = opacity;
+  inputs_.opacity = opacity;
   // Changing the opacity may make a previously hidden layer visible, so a new
   // recording may be needed.
   SetNeedsUpdate();
@@ -1651,16 +1666,16 @@
       DCHECK_EQ(effect_tree_index(),
                 property_trees->effect_id_to_index_map[id()]);
       EffectNode* node = property_trees->effect_tree.Node(effect_tree_index());
-      node->data.opacity = opacity;
+      node->opacity = opacity;
       property_trees->effect_tree.set_needs_update(true);
     }
   }
 }
 
 void Layer::OnTransformAnimated(const gfx::Transform& transform) {
-  if (transform_ == transform)
+  if (inputs_.transform == transform)
     return;
-  transform_ = transform;
+  inputs_.transform = transform;
   // Changing the transform may change the visible part of this layer, so a new
   // recording may be needed.
   SetNeedsUpdate();
@@ -1672,9 +1687,9 @@
                 property_trees->transform_id_to_index_map[id()]);
       TransformNode* node =
           property_trees->transform_tree.Node(transform_tree_index());
-      node->data.local = transform;
-      node->data.needs_local_transform_update = true;
-      node->data.has_potential_animation = true;
+      node->local = transform;
+      node->needs_local_transform_update = true;
+      node->has_potential_animation = true;
       property_trees->transform_tree.set_needs_update(true);
     }
   }
@@ -1697,7 +1712,7 @@
             property_trees->transform_id_to_index_map[id()]);
   TransformNode* node =
       property_trees->transform_tree.Node(transform_tree_index());
-  node->data.is_currently_animating = is_currently_animating;
+  node->is_currently_animating = is_currently_animating;
 }
 
 void Layer::OnTransformIsPotentiallyAnimatingChanged(
@@ -1713,11 +1728,11 @@
   TransformNode* node =
       property_trees->transform_tree.Node(transform_tree_index());
 
-  node->data.has_potential_animation = has_potential_animation;
+  node->has_potential_animation = has_potential_animation;
   if (has_potential_animation) {
-    node->data.has_only_translation_animations = HasOnlyTranslationTransforms();
+    node->has_only_translation_animations = HasOnlyTranslationTransforms();
   } else {
-    node->data.has_only_translation_animations = true;
+    node->has_only_translation_animations = true;
   }
   property_trees->transform_tree.set_needs_update(true);
 }
@@ -1729,7 +1744,7 @@
     return;
   DCHECK_EQ(effect_tree_index(), property_trees->effect_id_to_index_map[id()]);
   EffectNode* node = property_trees->effect_tree.Node(effect_tree_index());
-  node->data.is_currently_animating_opacity = is_currently_animating;
+  node->is_currently_animating_opacity = is_currently_animating;
 }
 
 void Layer::OnOpacityIsPotentiallyAnimatingChanged(
@@ -1740,7 +1755,7 @@
     return;
   DCHECK_EQ(effect_tree_index(), property_trees->effect_id_to_index_map[id()]);
   EffectNode* node = property_trees->effect_tree.Node(effect_tree_index());
-  node->data.has_potential_opacity_animation =
+  node->has_potential_opacity_animation =
       has_potential_animation || OpacityCanAnimateOnImplThread();
   property_trees->effect_tree.set_needs_update(true);
 }
@@ -1751,9 +1766,9 @@
 }
 
 void Layer::SetHasWillChangeTransformHint(bool has_will_change) {
-  if (has_will_change_transform_hint_ == has_will_change)
+  if (inputs_.has_will_change_transform_hint == has_will_change)
     return;
-  has_will_change_transform_hint_ = has_will_change;
+  inputs_.has_will_change_transform_hint = has_will_change;
   SetNeedsCommit();
 }
 
@@ -1804,21 +1819,21 @@
 
 void Layer::SetElementId(ElementId id) {
   DCHECK(IsPropertyChangeAllowed());
-  if (element_id_ == id)
+  if (inputs_.element_id == id)
     return;
   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("compositor-worker"),
                "Layer::SetElementId", "element", id.AsValue().release());
-  if (element_id_ && layer_tree_host()) {
+  if (inputs_.element_id && layer_tree_host()) {
     layer_tree_host()->animation_host()->UnregisterElement(
-        element_id_, ElementListType::ACTIVE);
+        inputs_.element_id, ElementListType::ACTIVE);
     layer_tree_host()->RemoveFromElementMap(this);
   }
 
-  element_id_ = id;
+  inputs_.element_id = id;
 
-  if (element_id_ && layer_tree_host()) {
+  if (inputs_.element_id && layer_tree_host()) {
     layer_tree_host()->animation_host()->RegisterElement(
-        element_id_, ElementListType::ACTIVE);
+        inputs_.element_id, ElementListType::ACTIVE);
     layer_tree_host()->AddToElementMap(this);
   }
 
@@ -1827,11 +1842,11 @@
 
 void Layer::SetMutableProperties(uint32_t properties) {
   DCHECK(IsPropertyChangeAllowed());
-  if (mutable_properties_ == properties)
+  if (inputs_.mutable_properties == properties)
     return;
   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("compositor-worker"),
                "Layer::SetMutableProperties", "properties", properties);
-  mutable_properties_ = properties;
+  inputs_.mutable_properties = properties;
   SetNeedsCommit();
 }
 
@@ -1847,7 +1862,7 @@
   return layer_tree_host()
       ->property_trees()
       ->effect_tree.Node(effect_tree_index())
-      ->data.num_copy_requests_in_subtree;
+      ->num_copy_requests_in_subtree;
 }
 
 gfx::Transform Layer::screen_space_transform() const {
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 7718e00f..addb510 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -81,7 +81,7 @@
 
   static scoped_refptr<Layer> Create();
 
-  int id() const { return layer_id_; }
+  int id() const { return inputs_.layer_id; }
 
   Layer* RootLayer();
   Layer* parent() { return parent_; }
@@ -94,8 +94,8 @@
   void SetChildren(const LayerList& children);
   bool HasAncestor(const Layer* ancestor) const;
 
-  const LayerList& children() const { return children_; }
-  Layer* child_at(size_t index) { return children_[index].get(); }
+  const LayerList& children() const { return inputs_.children; }
+  Layer* child_at(size_t index) { return inputs_.children[index].get(); }
 
   // This requests the layer and its subtree be rendered and given to the
   // callback. If the copy is unable to be produced (the layer is destroyed
@@ -103,15 +103,13 @@
   // request's source property is set, any prior uncommitted requests having the
   // same source will be aborted.
   void RequestCopyOfOutput(std::unique_ptr<CopyOutputRequest> request);
-  bool HasCopyRequest() const {
-    return !copy_requests_.empty();
-  }
+  bool HasCopyRequest() const { return !inputs_.copy_requests.empty(); }
 
   void TakeCopyRequests(
       std::vector<std::unique_ptr<CopyOutputRequest>>* requests);
 
   virtual void SetBackgroundColor(SkColor background_color);
-  SkColor background_color() const { return background_color_; }
+  SkColor background_color() const { return inputs_.background_color; }
   void SetSafeOpaqueBackgroundColor(SkColor background_color);
   // If contents_opaque(), return an opaque color else return a
   // non-opaque color.  Tries to return background_color(), if possible.
@@ -120,20 +118,20 @@
   // A layer's bounds are in logical, non-page-scaled pixels (however, the
   // root layer's bounds are in physical pixels).
   void SetBounds(const gfx::Size& bounds);
-  gfx::Size bounds() const { return bounds_; }
+  gfx::Size bounds() const { return inputs_.bounds; }
 
   void SetMasksToBounds(bool masks_to_bounds);
-  bool masks_to_bounds() const { return masks_to_bounds_; }
+  bool masks_to_bounds() const { return inputs_.masks_to_bounds; }
 
   void SetMaskLayer(Layer* mask_layer);
-  Layer* mask_layer() { return mask_layer_.get(); }
-  const Layer* mask_layer() const { return mask_layer_.get(); }
+  Layer* mask_layer() { return inputs_.mask_layer.get(); }
+  const Layer* mask_layer() const { return inputs_.mask_layer.get(); }
 
   virtual void SetNeedsDisplayRect(const gfx::Rect& dirty_rect);
   void SetNeedsDisplay() { SetNeedsDisplayRect(gfx::Rect(bounds())); }
 
   virtual void SetOpacity(float opacity);
-  float opacity() const { return opacity_; }
+  float opacity() const { return inputs_.opacity; }
   float EffectiveOpacity() const;
   bool OpacityIsAnimating() const;
   bool HasPotentiallyRunningOpacityAnimation() const;
@@ -142,7 +140,7 @@
   virtual bool AlwaysUseActiveTreeOpacity() const;
 
   void SetBlendMode(SkXfermode::Mode blend_mode);
-  SkXfermode::Mode blend_mode() const { return blend_mode_; }
+  SkXfermode::Mode blend_mode() const { return inputs_.blend_mode; }
 
   void set_draw_blend_mode(SkXfermode::Mode blend_mode) {
     if (draw_blend_mode_ == blend_mode)
@@ -153,7 +151,7 @@
   SkXfermode::Mode draw_blend_mode() const { return draw_blend_mode_; }
 
   bool uses_default_blend_mode() const {
-    return blend_mode_ == SkXfermode::kSrcOver_Mode;
+    return inputs_.blend_mode == SkXfermode::kSrcOver_Mode;
   }
 
   // A layer is root for an isolated group when it and all its descendants are
@@ -162,11 +160,11 @@
   // layers within the group to blend with layers outside this group.
   void SetIsRootForIsolatedGroup(bool root);
   bool is_root_for_isolated_group() const {
-    return is_root_for_isolated_group_;
+    return inputs_.is_root_for_isolated_group;
   }
 
   void SetFilters(const FilterOperations& filters);
-  const FilterOperations& filters() const { return filters_; }
+  const FilterOperations& filters() const { return inputs_.filters; }
   bool FilterIsAnimating() const;
   bool HasPotentiallyRunningFilterAnimation() const;
 
@@ -175,14 +173,14 @@
   // through the WebLayer interface, and are not exposed to HTML.
   void SetBackgroundFilters(const FilterOperations& filters);
   const FilterOperations& background_filters() const {
-    return background_filters_;
+    return inputs_.background_filters;
   }
 
   virtual void SetContentsOpaque(bool opaque);
-  bool contents_opaque() const { return contents_opaque_; }
+  bool contents_opaque() const { return inputs_.contents_opaque; }
 
   void SetPosition(const gfx::PointF& position);
-  gfx::PointF position() const { return position_; }
+  gfx::PointF position() const { return inputs_.position; }
 
   // A layer that is a container for fixed position layers cannot be both
   // scrollable and have a non-identity transform.
@@ -195,11 +193,11 @@
 
   void SetPositionConstraint(const LayerPositionConstraint& constraint);
   const LayerPositionConstraint& position_constraint() const {
-    return position_constraint_;
+    return inputs_.position_constraint;
   }
 
   void SetTransform(const gfx::Transform& transform);
-  const gfx::Transform& transform() const { return transform_; }
+  const gfx::Transform& transform() const { return inputs_.transform; }
   bool TransformIsAnimating() const;
   bool HasPotentiallyRunningTransformAnimation() const;
   bool HasOnlyTranslationTransforms() const;
@@ -209,7 +207,7 @@
   bool AnimationStartScale(float* start_scale) const;
 
   void SetTransformOrigin(const gfx::Point3F&);
-  gfx::Point3F transform_origin() const { return transform_origin_; }
+  gfx::Point3F transform_origin() const { return inputs_.transform_origin; }
 
   bool HasAnyAnimationTargetingProperty(TargetProperty::Type property) const;
 
@@ -217,8 +215,8 @@
 
   void SetScrollParent(Layer* parent);
 
-  Layer* scroll_parent() { return scroll_parent_; }
-  const Layer* scroll_parent() const { return scroll_parent_; }
+  Layer* scroll_parent() { return inputs_.scroll_parent; }
+  const Layer* scroll_parent() const { return inputs_.scroll_parent; }
 
   void AddScrollChild(Layer* child);
   void RemoveScrollChild(Layer* child);
@@ -230,10 +228,8 @@
 
   void SetClipParent(Layer* ancestor);
 
-  Layer* clip_parent() { return clip_parent_; }
-  const Layer* clip_parent() const {
-    return clip_parent_;
-  }
+  Layer* clip_parent() { return inputs_.clip_parent; }
+  const Layer* clip_parent() const { return inputs_.clip_parent; }
 
   void AddClipChild(Layer* child);
   void RemoveClipChild(Layer* child);
@@ -255,41 +251,43 @@
 
   void SetScrollOffset(const gfx::ScrollOffset& scroll_offset);
 
-  gfx::ScrollOffset scroll_offset() const { return scroll_offset_; }
+  gfx::ScrollOffset scroll_offset() const { return inputs_.scroll_offset; }
   void SetScrollOffsetFromImplSide(const gfx::ScrollOffset& scroll_offset);
 
   void SetScrollClipLayerId(int clip_layer_id);
-  bool scrollable() const { return scroll_clip_layer_id_ != INVALID_ID; }
+  bool scrollable() const { return inputs_.scroll_clip_layer_id != INVALID_ID; }
   Layer* scroll_clip_layer() const;
 
   void SetUserScrollable(bool horizontal, bool vertical);
   bool user_scrollable_horizontal() const {
-    return user_scrollable_horizontal_;
+    return inputs_.user_scrollable_horizontal;
   }
-  bool user_scrollable_vertical() const { return user_scrollable_vertical_; }
+  bool user_scrollable_vertical() const {
+    return inputs_.user_scrollable_vertical;
+  }
 
   void AddMainThreadScrollingReasons(uint32_t main_thread_scrolling_reasons);
   void ClearMainThreadScrollingReasons(
       uint32_t main_thread_scrolling_reasons_to_clear);
   uint32_t main_thread_scrolling_reasons() const {
-    return main_thread_scrolling_reasons_;
+    return inputs_.main_thread_scrolling_reasons;
   }
   bool should_scroll_on_main_thread() const {
-    return !!main_thread_scrolling_reasons_;
+    return !!inputs_.main_thread_scrolling_reasons;
   }
 
   void SetNonFastScrollableRegion(const Region& non_fast_scrollable_region);
   const Region& non_fast_scrollable_region() const {
-    return non_fast_scrollable_region_;
+    return inputs_.non_fast_scrollable_region;
   }
 
   void SetTouchEventHandlerRegion(const Region& touch_event_handler_region);
   const Region& touch_event_handler_region() const {
-    return touch_event_handler_region_;
+    return inputs_.touch_event_handler_region;
   }
 
   void set_did_scroll_callback(const base::Closure& callback) {
-    did_scroll_callback_ = callback;
+    inputs_.did_scroll_callback = callback;
   }
 
   void SetForceRenderSurfaceForTesting(bool force_render_surface);
@@ -297,19 +295,23 @@
     return force_render_surface_for_testing_;
   }
 
-  gfx::ScrollOffset CurrentScrollOffset() const { return scroll_offset_; }
+  gfx::ScrollOffset CurrentScrollOffset() const {
+    return inputs_.scroll_offset;
+  }
 
   void SetDoubleSided(bool double_sided);
-  bool double_sided() const { return double_sided_; }
+  bool double_sided() const { return inputs_.double_sided; }
 
   void SetShouldFlattenTransform(bool flatten);
-  bool should_flatten_transform() const { return should_flatten_transform_; }
+  bool should_flatten_transform() const {
+    return inputs_.should_flatten_transform;
+  }
 
-  bool Is3dSorted() const { return sorting_context_id_ != 0; }
+  bool Is3dSorted() const { return inputs_.sorting_context_id != 0; }
 
   void SetUseParentBackfaceVisibility(bool use);
   bool use_parent_backface_visibility() const {
-    return use_parent_backface_visibility_;
+    return inputs_.use_parent_backface_visibility;
   }
 
   void SetUseLocalTransformForBackfaceVisibility(bool use_local);
@@ -327,17 +329,18 @@
   void SetIsDrawable(bool is_drawable);
 
   void SetHideLayerAndSubtree(bool hide);
-  bool hide_layer_and_subtree() const { return hide_layer_and_subtree_; }
+  bool hide_layer_and_subtree() const { return inputs_.hide_layer_and_subtree; }
 
   void SetReplicaLayer(Layer* layer);
-  Layer* replica_layer() { return replica_layer_.get(); }
-  const Layer* replica_layer() const { return replica_layer_.get(); }
+  Layer* replica_layer() { return inputs_.replica_layer.get(); }
+  const Layer* replica_layer() const { return inputs_.replica_layer.get(); }
 
-  bool has_mask() const { return !!mask_layer_.get(); }
-  bool has_replica() const { return !!replica_layer_.get(); }
+  bool has_mask() const { return !!inputs_.mask_layer.get(); }
+  bool has_replica() const { return !!inputs_.replica_layer.get(); }
   bool replica_has_mask() const {
-    return replica_layer_.get() &&
-           (mask_layer_.get() || replica_layer_->mask_layer_.get());
+    return inputs_.replica_layer.get() &&
+           (inputs_.mask_layer.get() ||
+            inputs_.replica_layer->inputs_.mask_layer.get());
   }
 
   int NumDescendantsThatDrawContent() const;
@@ -358,7 +361,7 @@
   virtual std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
   TakeDebugInfo();
 
-  void SetLayerClient(LayerClient* client) { client_ = client; }
+  void SetLayerClient(LayerClient* client) { inputs_.client = client; }
 
   virtual void PushPropertiesTo(LayerImpl* layer);
 
@@ -416,8 +419,8 @@
   // Constructs a LayerImpl of the correct runtime type for this Layer type.
   virtual std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl);
 
-  bool NeedsDisplayForTesting() const { return !update_rect_.IsEmpty(); }
-  void ResetNeedsDisplayForTesting() { update_rect_ = gfx::Rect(); }
+  bool NeedsDisplayForTesting() const { return !inputs_.update_rect.IsEmpty(); }
+  void ResetNeedsDisplayForTesting() { inputs_.update_rect = gfx::Rect(); }
 
   RenderingStatsInstrumentation* rendering_stats_instrumentation() const;
 
@@ -431,7 +434,7 @@
   virtual void RunMicroBenchmark(MicroBenchmark* benchmark);
 
   void Set3dSortingContextId(int id);
-  int sorting_context_id() const { return sorting_context_id_; }
+  int sorting_context_id() const { return inputs_.sorting_context_id; }
 
   void set_property_tree_sequence_number(int sequence_number) {
     property_tree_sequence_number_ = sequence_number;
@@ -493,26 +496,16 @@
   int num_copy_requests_in_target_subtree();
 
   void SetElementId(ElementId id);
-  ElementId element_id() const { return element_id_; }
+  ElementId element_id() const { return inputs_.element_id; }
 
   void SetMutableProperties(uint32_t properties);
-  uint32_t mutable_properties() const { return mutable_properties_; }
+  uint32_t mutable_properties() const { return inputs_.mutable_properties; }
 
-  // Interactions with attached animations.
-  gfx::ScrollOffset ScrollOffsetForAnimation() const;
-  void OnFilterAnimated(const FilterOperations& filters);
-  void OnOpacityAnimated(float opacity);
-  void OnTransformAnimated(const gfx::Transform& transform);
-  void OnScrollOffsetAnimated(const gfx::ScrollOffset& scroll_offset);
-  void OnTransformIsCurrentlyAnimatingChanged(bool is_animating);
-  void OnTransformIsPotentiallyAnimatingChanged(bool is_animating);
-  void OnOpacityIsCurrentlyAnimatingChanged(bool is_currently_animating);
-  void OnOpacityIsPotentiallyAnimatingChanged(bool has_potential_animation);
   bool HasActiveAnimationForTesting() const;
 
   void SetHasWillChangeTransformHint(bool has_will_change);
   bool has_will_change_transform_hint() const {
-    return has_will_change_transform_hint_;
+    return inputs_.has_will_change_transform_hint;
   }
 
  protected:
@@ -564,30 +557,29 @@
   virtual void FromLayerSpecificPropertiesProto(
       const proto::LayerProperties& proto);
 
-  // The update rect is the region of the compositor resource that was
-  // actually updated by the compositor. For layers that may do updating
-  // outside the compositor's control (i.e. plugin layers), this information
-  // is not available and the update rect will remain empty.
-  // Note this rect is in layer space (not content space).
-  gfx::Rect update_rect_;
-
-  scoped_refptr<Layer> mask_layer_;
-
-  int layer_id_;
+  gfx::Rect& update_rect() { return inputs_.update_rect; }
 
   // When true, the layer is about to perform an update. Any commit requests
   // will be handled implicitly after the update completes.
   bool ignore_set_needs_commit_;
 
-  // Layers that share a sorting context id will be sorted together in 3d
-  // space.  0 is a special value that means this layer will not be sorted and
-  // will be drawn in paint order.
-  int sorting_context_id_;
-
  private:
   friend class base::RefCounted<Layer>;
   friend class LayerSerializationTest;
   friend class LayerTreeHostCommon;
+  friend class LayerTreeHost;
+  friend class LayerInternalsForTest;
+
+  // Interactions with attached animations.
+  gfx::ScrollOffset ScrollOffsetForAnimation() const;
+  void OnFilterAnimated(const FilterOperations& filters);
+  void OnOpacityAnimated(float opacity);
+  void OnTransformAnimated(const gfx::Transform& transform);
+  void OnScrollOffsetAnimated(const gfx::ScrollOffset& scroll_offset);
+  void OnTransformIsCurrentlyAnimatingChanged(bool is_animating);
+  void OnTransformIsPotentiallyAnimatingChanged(bool is_animating);
+  void OnOpacityIsCurrentlyAnimatingChanged(bool is_currently_animating);
+  void OnOpacityIsPotentiallyAnimatingChanged(bool has_potential_animation);
 
   void SetParent(Layer* layer);
   bool DescendantIsFixedToContainerLayer() const;
@@ -607,7 +599,95 @@
   // indices becomes invalid.
   void InvalidatePropertyTreesIndices();
 
-  LayerList children_;
+  // Encapsulates all data, callbacks or interfaces received from the embedder.
+  // TODO(khushalsagar): This is only valid when PropertyTrees are built
+  // internally in cc. Update this for the SPv2 path where blink generates
+  // PropertyTrees.
+  struct Inputs {
+    Inputs();
+    ~Inputs();
+
+    int layer_id;
+
+    LayerList children;
+
+    // The update rect is the region of the compositor resource that was
+    // actually updated by the compositor. For layers that may do updating
+    // outside the compositor's control (i.e. plugin layers), this information
+    // is not available and the update rect will remain empty.
+    // Note this rect is in layer space (not content space).
+    gfx::Rect update_rect;
+
+    gfx::Size bounds;
+    bool masks_to_bounds;
+
+    scoped_refptr<Layer> mask_layer;
+
+    // Replica layer used for reflections.
+    scoped_refptr<Layer> replica_layer;
+
+    float opacity;
+    SkXfermode::Mode blend_mode;
+
+    bool is_root_for_isolated_group : 1;
+
+    bool contents_opaque : 1;
+
+    gfx::PointF position;
+    gfx::Transform transform;
+    gfx::Point3F transform_origin;
+
+    bool is_drawable : 1;
+
+    bool double_sided : 1;
+    bool should_flatten_transform : 1;
+
+    // Layers that share a sorting context id will be sorted together in 3d
+    // space.  0 is a special value that means this layer will not be sorted
+    // and will be drawn in paint order.
+    int sorting_context_id;
+
+    bool use_parent_backface_visibility : 1;
+
+    SkColor background_color;
+
+    FilterOperations filters;
+    FilterOperations background_filters;
+
+    gfx::ScrollOffset scroll_offset;
+
+    // This variable indicates which ancestor layer (if any) whose size,
+    // transformed relative to this layer, defines the maximum scroll offset
+    // for this layer.
+    int scroll_clip_layer_id;
+    bool user_scrollable_horizontal : 1;
+    bool user_scrollable_vertical : 1;
+
+    uint32_t main_thread_scrolling_reasons;
+    Region non_fast_scrollable_region;
+
+    Region touch_event_handler_region;
+
+    bool is_container_for_fixed_position_layers : 1;
+    LayerPositionConstraint position_constraint;
+
+    ElementId element_id;
+
+    uint32_t mutable_properties;
+
+    Layer* scroll_parent;
+    Layer* clip_parent;
+
+    bool has_will_change_transform_hint : 1;
+
+    bool hide_layer_and_subtree : 1;
+
+    // The following elements can not and are not serialized.
+    LayerClient* client;
+    base::Closure did_scroll_callback;
+    std::vector<std::unique_ptr<CopyOutputRequest>> copy_requests;
+  };
+
   Layer* parent_;
 
   // Layer instances have a weak pointer to their LayerTreeHost.
@@ -615,74 +695,30 @@
   // updated via SetLayerTreeHost() if a layer moves between trees.
   LayerTreeHost* layer_tree_host_;
 
-  // Layer properties.
-  gfx::Size bounds_;
+  Inputs inputs_;
 
-  gfx::ScrollOffset scroll_offset_;
-  // This variable indicates which ancestor layer (if any) whose size,
-  // transformed relative to this layer, defines the maximum scroll offset for
-  // this layer.
-  int scroll_clip_layer_id_;
   int num_descendants_that_draw_content_;
   int transform_tree_index_;
   int effect_tree_index_;
   int clip_tree_index_;
   int scroll_tree_index_;
   int property_tree_sequence_number_;
-  ElementId element_id_;
-  uint32_t mutable_properties_;
   gfx::Vector2dF offset_to_transform_parent_;
-  uint32_t main_thread_scrolling_reasons_;
   bool should_flatten_transform_from_property_tree_ : 1;
-  bool user_scrollable_horizontal_ : 1;
-  bool user_scrollable_vertical_ : 1;
-  bool is_root_for_isolated_group_ : 1;
-  bool is_container_for_fixed_position_layers_ : 1;
-  bool is_drawable_ : 1;
   bool draws_content_ : 1;
-  bool hide_layer_and_subtree_ : 1;
-  bool masks_to_bounds_ : 1;
-  bool contents_opaque_ : 1;
-  bool double_sided_ : 1;
-  bool should_flatten_transform_ : 1;
-  bool use_parent_backface_visibility_ : 1;
   bool use_local_transform_for_backface_visibility_ : 1;
   bool should_check_backface_visibility_ : 1;
   bool force_render_surface_for_testing_ : 1;
   bool subtree_property_changed_ : 1;
   bool layer_property_changed_ : 1;
-  bool has_will_change_transform_hint_ : 1;
-  Region non_fast_scrollable_region_;
-  Region touch_event_handler_region_;
-  gfx::PointF position_;
-  SkColor background_color_;
   SkColor safe_opaque_background_color_;
-  float opacity_;
-  SkXfermode::Mode blend_mode_;
   // draw_blend_mode may be different than blend_mode_,
   // when a RenderSurface re-parents the layer's blend_mode.
   SkXfermode::Mode draw_blend_mode_;
-  FilterOperations filters_;
-  FilterOperations background_filters_;
-  LayerPositionConstraint position_constraint_;
-  Layer* scroll_parent_;
   std::unique_ptr<std::set<Layer*>> scroll_children_;
 
-  Layer* clip_parent_;
   std::unique_ptr<std::set<Layer*>> clip_children_;
 
-  gfx::Transform transform_;
-  gfx::Point3F transform_origin_;
-
-  // Replica layer used for reflections.
-  scoped_refptr<Layer> replica_layer_;
-
-  LayerClient* client_;
-
-  std::vector<std::unique_ptr<CopyOutputRequest>> copy_requests_;
-
-  base::Closure did_scroll_callback_;
-
   PaintProperties paint_properties_;
 
   // These all act like draw properties, so don't need push properties.
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 9a1b979..163ee3a5 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -30,11 +30,15 @@
 #include "cc/output/copy_output_request.h"
 #include "cc/quads/debug_border_draw_quad.h"
 #include "cc/quads/render_pass.h"
+#include "cc/trees/clip_node.h"
 #include "cc/trees/draw_property_utils.h"
+#include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_host_common.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/layer_tree_settings.h"
 #include "cc/trees/proxy.h"
+#include "cc/trees/scroll_node.h"
+#include "cc/trees/transform_node.h"
 #include "ui/gfx/geometry/box_f.h"
 #include "ui/gfx/geometry/point_conversions.h"
 #include "ui/gfx/geometry/quad_f.h"
@@ -378,7 +382,7 @@
   TransformTree& transform_tree =
       layer_tree_impl()->property_trees()->transform_tree;
   return transform_tree.Node(transform_tree_index())
-      ->data.in_subtree_of_page_scale_layer;
+      ->in_subtree_of_page_scale_layer;
 }
 
 gfx::Vector2dF LayerImpl::FixedContainerSizeDelta() const {
@@ -444,14 +448,14 @@
   TransformNode* transform_node =
       layer_tree_impl()->property_trees()->transform_tree.Node(
           transform_tree_index());
-  if (transform_node && transform_node->data.transform_changed)
+  if (transform_node && transform_node->transform_changed)
     return true;
   if (effect_tree_index() == -1)
     return false;
   EffectNode* effect_node =
       layer_tree_impl()->property_trees()->effect_tree.Node(
           effect_tree_index());
-  if (effect_node && effect_node->data.effect_changed)
+  if (effect_node && effect_node->effect_changed)
     return true;
   return false;
 }
@@ -490,7 +494,7 @@
   return layer_tree_impl()
       ->property_trees()
       ->effect_tree.Node(effect_tree_index())
-      ->data.num_copy_requests_in_subtree;
+      ->num_copy_requests_in_subtree;
 }
 
 void LayerImpl::UpdatePropertyTreeTransform() {
@@ -505,10 +509,10 @@
     // thread.
     TransformNode* node = property_trees->transform_tree.Node(
         property_trees->transform_id_to_index_map[id()]);
-    if (node->data.local != transform_) {
-      node->data.local = transform_;
-      node->data.needs_local_transform_update = true;
-      node->data.transform_changed = true;
+    if (node->local != transform_) {
+      node->local = transform_;
+      node->needs_local_transform_update = true;
+      node->transform_changed = true;
       property_trees->changed = true;
       property_trees->transform_tree.set_needs_update(true);
       // TODO(ajuma): The current criteria for creating clip nodes means that
@@ -536,13 +540,12 @@
     // activation (and, in that case, the LayerImpl will no longer own a
     // TransformNode, unless it has non-animation-related reasons for owning a
     // node).
-    if (node->data.has_potential_animation != is_animated) {
-      node->data.has_potential_animation = is_animated;
+    if (node->has_potential_animation != is_animated) {
+      node->has_potential_animation = is_animated;
       if (is_animated) {
-        node->data.has_only_translation_animations =
-            HasOnlyTranslationTransforms();
+        node->has_only_translation_animations = HasOnlyTranslationTransforms();
       } else {
-        node->data.has_only_translation_animations = true;
+        node->has_only_translation_animations = true;
       }
 
       property_trees->transform_tree.set_needs_update(true);
@@ -561,10 +564,10 @@
     // started, but might have finished since then on the compositor thread.
     EffectNode* node = property_trees->effect_tree.Node(
         property_trees->effect_id_to_index_map[id()]);
-    if (node->data.opacity == opacity)
+    if (node->opacity == opacity)
       return;
-    node->data.opacity = opacity;
-    node->data.effect_changed = true;
+    node->opacity = opacity;
+    node->effect_changed = true;
     property_trees->changed = true;
     property_trees->effect_tree.set_needs_update(true);
   }
@@ -593,7 +596,7 @@
     EffectNode* node = effect_tree.Node(effect_tree_index_);
     DCHECK(layer_tree_impl()->property_trees()->IsInIdToIndexMap(
         PropertyTrees::TreeType::EFFECT, id()));
-    node->data.effect_changed = true;
+    node->effect_changed = true;
     layer_tree_impl()->property_trees()->changed = true;
     effect_tree.set_needs_update(true);
   }
@@ -639,7 +642,7 @@
     return;
   TransformNode* node = property_trees->transform_tree.Node(
       property_trees->transform_id_to_index_map[id()]);
-  node->data.is_currently_animating = is_currently_animating;
+  node->is_currently_animating = is_currently_animating;
 }
 
 void LayerImpl::OnTransformIsPotentiallyAnimatingChanged(
@@ -657,7 +660,7 @@
   EffectNode* node = property_trees->effect_tree.Node(
       property_trees->effect_id_to_index_map[id()]);
 
-  node->data.is_currently_animating_opacity = is_currently_animating;
+  node->is_currently_animating_opacity = is_currently_animating;
 }
 
 void LayerImpl::OnOpacityIsPotentiallyAnimatingChanged(
@@ -668,7 +671,7 @@
     return;
   EffectNode* node = property_trees->effect_tree.Node(
       property_trees->effect_id_to_index_map[id()]);
-  node->data.has_potential_opacity_animation = has_potential_animation;
+  node->has_potential_opacity_animation = has_potential_animation;
   property_trees->effect_tree.set_needs_update(true);
 }
 
@@ -721,8 +724,8 @@
     if (clip_node) {
       DCHECK(property_trees->IsInIdToIndexMap(PropertyTrees::TreeType::CLIP,
                                               id()));
-      clip_node->data.clip = gfx::RectF(
-          gfx::PointF() + offset_to_transform_parent(), gfx::SizeF(bounds()));
+      clip_node->clip = gfx::RectF(gfx::PointF() + offset_to_transform_parent(),
+                                   gfx::SizeF(bounds()));
       property_trees->clip_tree.set_needs_update(true);
     }
     property_trees->full_tree_damaged = true;
@@ -791,7 +794,7 @@
     return 1.f;
   EffectNode* node = property_trees->effect_tree.Node(
       property_trees->effect_id_to_index_map[id()]);
-  return node->data.opacity;
+  return node->opacity;
 }
 
 bool LayerImpl::OpacityIsAnimating() const {
@@ -924,9 +927,9 @@
       layer_tree_impl()->property_trees()->transform_tree;
   TransformNode* node = transform_tree.Node(transform_tree_index_);
   gfx::ScrollOffset current_offset = CurrentScrollOffset();
-  if (node->data.scroll_offset != current_offset) {
-    node->data.scroll_offset = current_offset;
-    node->data.needs_local_transform_update = true;
+  if (node->scroll_offset != current_offset) {
+    node->scroll_offset = current_offset;
+    node->needs_local_transform_update = true;
     transform_tree.set_needs_update(true);
   }
 }
@@ -1108,12 +1111,12 @@
   if (layer_tree_impl()
           ->property_trees()
           ->effect_tree.Node(effect_tree_index())
-          ->data.screen_space_opacity != 1.f)
+          ->screen_space_opacity != 1.f)
     return false;
   if (!layer_tree_impl()
            ->property_trees()
            ->transform_tree.Node(transform_tree_index())
-           ->data.node_and_ancestors_have_only_integer_translation)
+           ->node_and_ancestors_have_only_integer_translation)
     return false;
   if (static_cast<int>(offset_to_transform_parent().x()) !=
       offset_to_transform_parent().x())
@@ -1145,10 +1148,10 @@
   EffectTree& effect_tree = layer_tree_impl_->property_trees()->effect_tree;
   EffectNode* node = effect_tree.Node(effect_tree_index_);
 
-  if (node->data.render_surface)
-    return node->data.render_surface;
+  if (node->render_surface)
+    return node->render_surface;
   else
-    return effect_tree.Node(node->data.target_id)->data.render_surface;
+    return effect_tree.Node(node->target_id)->render_surface;
 }
 
 const RenderSurfaceImpl* LayerImpl::render_target() const {
@@ -1156,16 +1159,16 @@
       layer_tree_impl_->property_trees()->effect_tree;
   const EffectNode* node = effect_tree.Node(effect_tree_index_);
 
-  if (node->data.render_surface)
-    return node->data.render_surface;
+  if (node->render_surface)
+    return node->render_surface;
   else
-    return effect_tree.Node(node->data.target_id)->data.render_surface;
+    return effect_tree.Node(node->target_id)->render_surface;
 }
 
 bool LayerImpl::IsHidden() const {
   EffectTree& effect_tree = layer_tree_impl_->property_trees()->effect_tree;
   EffectNode* node = effect_tree.Node(effect_tree_index_);
-  return node->data.screen_space_opacity == 0.f;
+  return node->screen_space_opacity == 0.f;
 }
 
 bool LayerImpl::InsideReplica() const {
@@ -1175,9 +1178,9 @@
   EffectNode* node = effect_tree.Node(effect_tree_index_);
 
   while (node->id > 0) {
-    if (node->data.replica_layer_id != -1)
+    if (node->replica_layer_id != -1)
       return true;
-    node = effect_tree.Node(node->data.target_id);
+    node = effect_tree.Node(node->target_id);
   }
 
   return false;
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index 6f9dfbf..179e0a5 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -24,12 +24,14 @@
 #include "cc/test/fake_layer_tree_host_client.h"
 #include "cc/test/fake_layer_tree_host_impl.h"
 #include "cc/test/geometry_test_utils.h"
+#include "cc/test/layer_internals_for_test.h"
 #include "cc/test/layer_test_common.h"
 #include "cc/test/test_gpu_memory_buffer_manager.h"
 #include "cc/test/test_shared_bitmap_manager.h"
 #include "cc/test/test_task_graph_runner.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/single_thread_proxy.h"
+#include "cc/trees/transform_node.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -129,7 +131,7 @@
 
     // The following member is reset during serialization, so store the original
     // values.
-    gfx::Rect update_rect = src->update_rect_;
+    gfx::Rect update_rect = src->inputs_.update_rect;
 
     // Serialize |src| to protobuf and read the first entry in the
     // LayerUpdate. There are no descendants, so the serialization
@@ -140,14 +142,14 @@
     proto::LayerProperties props = layer_update.layers(0);
 
     // The |dest| layer needs to be able to lookup the scroll and clip parents.
-    if (src->scroll_parent_)
-      layer_tree_host_->RegisterLayer(src->scroll_parent_);
+    if (src->inputs_.scroll_parent)
+      layer_tree_host_->RegisterLayer(src->inputs_.scroll_parent);
     if (src->scroll_children_) {
       for (auto* child : *(src->scroll_children_))
         layer_tree_host_->RegisterLayer(child);
     }
-    if (src->clip_parent_)
-      layer_tree_host_->RegisterLayer(src->clip_parent_);
+    if (src->inputs_.clip_parent)
+      layer_tree_host_->RegisterLayer(src->inputs_.clip_parent);
     if (src->clip_children_) {
       for (auto* child : *(src->clip_children_))
         layer_tree_host_->RegisterLayer(child);
@@ -157,60 +159,67 @@
     src->SetLayerTreeHost(nullptr);
 
     scoped_refptr<Layer> dest = Layer::Create();
-    dest->layer_id_ = src->layer_id_;
+    dest->inputs_.layer_id = src->inputs_.layer_id;
     dest->SetLayerTreeHost(layer_tree_host_.get());
     dest->FromLayerPropertiesProto(props);
 
     // Verify that both layers are equal.
-    EXPECT_EQ(src->transform_origin_, dest->transform_origin_);
-    EXPECT_EQ(src->background_color_, dest->background_color_);
-    EXPECT_EQ(src->bounds_, dest->bounds_);
+    EXPECT_EQ(src->inputs_.transform_origin, dest->inputs_.transform_origin);
+    EXPECT_EQ(src->inputs_.background_color, dest->inputs_.background_color);
+    EXPECT_EQ(src->inputs_.bounds, dest->inputs_.bounds);
     EXPECT_EQ(src->transform_tree_index_, dest->transform_tree_index_);
     EXPECT_EQ(src->effect_tree_index_, dest->effect_tree_index_);
     EXPECT_EQ(src->clip_tree_index_, dest->clip_tree_index_);
     EXPECT_EQ(src->offset_to_transform_parent_,
               dest->offset_to_transform_parent_);
-    EXPECT_EQ(src->double_sided_, dest->double_sided_);
+    EXPECT_EQ(src->inputs_.double_sided, dest->inputs_.double_sided);
     EXPECT_EQ(src->draws_content_, dest->draws_content_);
-    EXPECT_EQ(src->hide_layer_and_subtree_, dest->hide_layer_and_subtree_);
-    EXPECT_EQ(src->masks_to_bounds_, dest->masks_to_bounds_);
-    EXPECT_EQ(src->main_thread_scrolling_reasons_,
-              dest->main_thread_scrolling_reasons_);
-    EXPECT_EQ(src->non_fast_scrollable_region_,
-              dest->non_fast_scrollable_region_);
-    EXPECT_EQ(src->touch_event_handler_region_,
-              dest->touch_event_handler_region_);
-    EXPECT_EQ(src->contents_opaque_, dest->contents_opaque_);
-    EXPECT_EQ(src->opacity_, dest->opacity_);
-    EXPECT_EQ(src->blend_mode_, dest->blend_mode_);
-    EXPECT_EQ(src->is_root_for_isolated_group_,
-              dest->is_root_for_isolated_group_);
-    EXPECT_EQ(src->position_, dest->position_);
-    EXPECT_EQ(src->is_container_for_fixed_position_layers_,
-              dest->is_container_for_fixed_position_layers_);
-    EXPECT_EQ(src->position_constraint_, dest->position_constraint_);
-    EXPECT_EQ(src->should_flatten_transform_, dest->should_flatten_transform_);
+    EXPECT_EQ(src->inputs_.hide_layer_and_subtree,
+              dest->inputs_.hide_layer_and_subtree);
+    EXPECT_EQ(src->inputs_.masks_to_bounds, dest->inputs_.masks_to_bounds);
+    EXPECT_EQ(src->inputs_.main_thread_scrolling_reasons,
+              dest->inputs_.main_thread_scrolling_reasons);
+    EXPECT_EQ(src->inputs_.non_fast_scrollable_region,
+              dest->inputs_.non_fast_scrollable_region);
+    EXPECT_EQ(src->inputs_.touch_event_handler_region,
+              dest->inputs_.touch_event_handler_region);
+    EXPECT_EQ(src->inputs_.contents_opaque, dest->inputs_.contents_opaque);
+    EXPECT_EQ(src->inputs_.opacity, dest->inputs_.opacity);
+    EXPECT_EQ(src->inputs_.blend_mode, dest->inputs_.blend_mode);
+    EXPECT_EQ(src->inputs_.is_root_for_isolated_group,
+              dest->inputs_.is_root_for_isolated_group);
+    EXPECT_EQ(src->inputs_.position, dest->inputs_.position);
+    EXPECT_EQ(src->inputs_.is_container_for_fixed_position_layers,
+              dest->inputs_.is_container_for_fixed_position_layers);
+    EXPECT_EQ(src->inputs_.position_constraint,
+              dest->inputs_.position_constraint);
+    EXPECT_EQ(src->inputs_.should_flatten_transform,
+              dest->inputs_.should_flatten_transform);
     EXPECT_EQ(src->should_flatten_transform_from_property_tree_,
               dest->should_flatten_transform_from_property_tree_);
     EXPECT_EQ(src->draw_blend_mode_, dest->draw_blend_mode_);
-    EXPECT_EQ(src->use_parent_backface_visibility_,
-              dest->use_parent_backface_visibility_);
-    EXPECT_EQ(src->transform_, dest->transform_);
-    EXPECT_EQ(src->sorting_context_id_, dest->sorting_context_id_);
+    EXPECT_EQ(src->inputs_.use_parent_backface_visibility,
+              dest->inputs_.use_parent_backface_visibility);
+    EXPECT_EQ(src->inputs_.transform, dest->inputs_.transform);
+    EXPECT_EQ(src->inputs_.sorting_context_id,
+              dest->inputs_.sorting_context_id);
     EXPECT_EQ(src->num_descendants_that_draw_content_,
               dest->num_descendants_that_draw_content_);
-    EXPECT_EQ(src->scroll_clip_layer_id_, dest->scroll_clip_layer_id_);
-    EXPECT_EQ(src->user_scrollable_horizontal_,
-              dest->user_scrollable_horizontal_);
-    EXPECT_EQ(src->user_scrollable_vertical_, dest->user_scrollable_vertical_);
-    EXPECT_EQ(src->scroll_offset_, dest->scroll_offset_);
-    EXPECT_EQ(update_rect, dest->update_rect_);
+    EXPECT_EQ(src->inputs_.scroll_clip_layer_id,
+              dest->inputs_.scroll_clip_layer_id);
+    EXPECT_EQ(src->inputs_.user_scrollable_horizontal,
+              dest->inputs_.user_scrollable_horizontal);
+    EXPECT_EQ(src->inputs_.user_scrollable_vertical,
+              dest->inputs_.user_scrollable_vertical);
+    EXPECT_EQ(src->inputs_.scroll_offset, dest->inputs_.scroll_offset);
+    EXPECT_EQ(update_rect, dest->inputs_.update_rect);
 
-    if (src->scroll_parent_) {
-      ASSERT_TRUE(dest->scroll_parent_);
-      EXPECT_EQ(src->scroll_parent_->id(), dest->scroll_parent_->id());
+    if (src->inputs_.scroll_parent) {
+      ASSERT_TRUE(dest->inputs_.scroll_parent);
+      EXPECT_EQ(src->inputs_.scroll_parent->id(),
+                dest->inputs_.scroll_parent->id());
     } else {
-      EXPECT_FALSE(dest->scroll_parent_);
+      EXPECT_FALSE(dest->inputs_.scroll_parent);
     }
     if (src->scroll_children_) {
       ASSERT_TRUE(dest->scroll_children_);
@@ -219,11 +228,12 @@
       EXPECT_FALSE(dest->scroll_children_);
     }
 
-    if (src->clip_parent_) {
-      ASSERT_TRUE(dest->clip_parent_);
-      EXPECT_EQ(src->clip_parent_->id(), dest->clip_parent_->id());
+    if (src->inputs_.clip_parent) {
+      ASSERT_TRUE(dest->inputs_.clip_parent);
+      EXPECT_EQ(src->inputs_.clip_parent->id(),
+                dest->inputs_.clip_parent->id());
     } else {
-      ASSERT_FALSE(dest->clip_parent_);
+      ASSERT_FALSE(dest->inputs_.clip_parent);
     }
     if (src->clip_children_) {
       ASSERT_TRUE(dest->clip_children_);
@@ -233,16 +243,16 @@
     }
 
     // The following member should have been reset during serialization.
-    EXPECT_EQ(gfx::Rect(), src->update_rect_);
+    EXPECT_EQ(gfx::Rect(), src->inputs_.update_rect);
 
     // Before deleting |dest|, the LayerTreeHost must be unset.
     dest->SetLayerTreeHost(nullptr);
 
     // Cleanup scroll tree.
-    if (src->scroll_parent_)
-      layer_tree_host_->UnregisterLayer(src->scroll_parent_);
-    src->scroll_parent_ = nullptr;
-    dest->scroll_parent_ = nullptr;
+    if (src->inputs_.scroll_parent)
+      layer_tree_host_->UnregisterLayer(src->inputs_.scroll_parent);
+    src->inputs_.scroll_parent = nullptr;
+    dest->inputs_.scroll_parent = nullptr;
     if (src->scroll_children_) {
       for (auto* child : *(src->scroll_children_))
         layer_tree_host_->UnregisterLayer(child);
@@ -251,10 +261,10 @@
     }
 
     // Cleanup clip tree.
-    if (src->clip_parent_)
-      layer_tree_host_->UnregisterLayer(src->clip_parent_);
-    src->clip_parent_ = nullptr;
-    dest->clip_parent_ = nullptr;
+    if (src->inputs_.clip_parent)
+      layer_tree_host_->UnregisterLayer(src->inputs_.clip_parent);
+    src->inputs_.clip_parent = nullptr;
+    dest->inputs_.clip_parent = nullptr;
     if (src->clip_children_) {
       for (auto* child : *(src->clip_children_))
         layer_tree_host_->UnregisterLayer(child);
@@ -270,91 +280,96 @@
 
   void RunArbitraryMembersChangedTest() {
     scoped_refptr<Layer> layer = Layer::Create();
-    layer->transform_origin_ = gfx::Point3F(3.0f, 1.0f, 4.0f);
-    layer->background_color_ = SK_ColorRED;
-    layer->bounds_ = gfx::Size(3, 14);
+    layer->inputs_.transform_origin = gfx::Point3F(3.0f, 1.0f, 4.0f);
+    layer->inputs_.background_color = SK_ColorRED;
+    layer->inputs_.bounds = gfx::Size(3, 14);
     layer->transform_tree_index_ = -1;
     layer->effect_tree_index_ = -1;
     layer->clip_tree_index_ = 71;
     layer->offset_to_transform_parent_ = gfx::Vector2dF(3.14f, 1.618f);
-    layer->double_sided_ = true;
+    layer->inputs_.double_sided = true;
     layer->draws_content_ = true;
-    layer->hide_layer_and_subtree_ = false;
-    layer->masks_to_bounds_ = true;
-    layer->main_thread_scrolling_reasons_ =
+    layer->inputs_.hide_layer_and_subtree = false;
+    layer->inputs_.masks_to_bounds = true;
+    layer->inputs_.main_thread_scrolling_reasons =
         MainThreadScrollingReason::kNotScrollingOnMain;
-    layer->non_fast_scrollable_region_ = Region(gfx::Rect(5, 1, 14, 3));
-    layer->touch_event_handler_region_ = Region(gfx::Rect(3, 14, 1, 5));
-    layer->contents_opaque_ = true;
-    layer->opacity_ = 1.f;
-    layer->blend_mode_ = SkXfermode::kSrcOver_Mode;
-    layer->is_root_for_isolated_group_ = true;
-    layer->position_ = gfx::PointF(3.14f, 6.28f);
-    layer->is_container_for_fixed_position_layers_ = true;
+    layer->inputs_.non_fast_scrollable_region = Region(gfx::Rect(5, 1, 14, 3));
+    layer->inputs_.touch_event_handler_region = Region(gfx::Rect(3, 14, 1, 5));
+    layer->inputs_.contents_opaque = true;
+    layer->inputs_.opacity = 1.f;
+    layer->inputs_.blend_mode = SkXfermode::kSrcOver_Mode;
+    layer->inputs_.is_root_for_isolated_group = true;
+    layer->inputs_.position = gfx::PointF(3.14f, 6.28f);
+    layer->inputs_.is_container_for_fixed_position_layers = true;
     LayerPositionConstraint pos_con;
     pos_con.set_is_fixed_to_bottom_edge(true);
-    layer->position_constraint_ = pos_con;
-    layer->should_flatten_transform_ = true;
+    layer->inputs_.position_constraint = pos_con;
+    layer->inputs_.should_flatten_transform = true;
     layer->should_flatten_transform_from_property_tree_ = true;
     layer->draw_blend_mode_ = SkXfermode::kSrcOut_Mode;
-    layer->use_parent_backface_visibility_ = true;
+    layer->inputs_.use_parent_backface_visibility = true;
     gfx::Transform transform;
     transform.Rotate(90);
-    layer->transform_ = transform;
-    layer->sorting_context_id_ = 0;
+    layer->inputs_.transform = transform;
+    layer->inputs_.sorting_context_id = 0;
     layer->num_descendants_that_draw_content_ = 5;
-    layer->scroll_clip_layer_id_ = Layer::INVALID_ID;
-    layer->user_scrollable_horizontal_ = false;
-    layer->user_scrollable_vertical_ = true;
-    layer->scroll_offset_ = gfx::ScrollOffset(3, 14);
-    layer->update_rect_ = gfx::Rect(14, 15);
+    layer->inputs_.scroll_clip_layer_id = Layer::INVALID_ID;
+    layer->inputs_.user_scrollable_horizontal = false;
+    layer->inputs_.user_scrollable_vertical = true;
+    layer->inputs_.scroll_offset = gfx::ScrollOffset(3, 14);
+    layer->inputs_.update_rect = gfx::Rect(14, 15);
 
     VerifyBaseLayerPropertiesSerializationAndDeserialization(layer.get());
   }
 
   void RunAllMembersChangedTest() {
     scoped_refptr<Layer> layer = Layer::Create();
-    layer->transform_origin_ = gfx::Point3F(3.0f, 1.0f, 4.0f);
-    layer->background_color_ = SK_ColorRED;
-    layer->bounds_ = gfx::Size(3, 14);
+    layer->inputs_.transform_origin = gfx::Point3F(3.0f, 1.0f, 4.0f);
+    layer->inputs_.background_color = SK_ColorRED;
+    layer->inputs_.bounds = gfx::Size(3, 14);
     layer->transform_tree_index_ = 39;
     layer->effect_tree_index_ = 17;
     layer->clip_tree_index_ = 71;
     layer->offset_to_transform_parent_ = gfx::Vector2dF(3.14f, 1.618f);
-    layer->double_sided_ = !layer->double_sided_;
+    layer->inputs_.double_sided = !layer->inputs_.double_sided;
     layer->draws_content_ = !layer->draws_content_;
-    layer->hide_layer_and_subtree_ = !layer->hide_layer_and_subtree_;
-    layer->masks_to_bounds_ = !layer->masks_to_bounds_;
-    layer->main_thread_scrolling_reasons_ =
+    layer->inputs_.hide_layer_and_subtree =
+        !layer->inputs_.hide_layer_and_subtree;
+    layer->inputs_.masks_to_bounds = !layer->inputs_.masks_to_bounds;
+    layer->inputs_.main_thread_scrolling_reasons =
         MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects;
-    layer->non_fast_scrollable_region_ = Region(gfx::Rect(5, 1, 14, 3));
-    layer->touch_event_handler_region_ = Region(gfx::Rect(3, 14, 1, 5));
-    layer->contents_opaque_ = !layer->contents_opaque_;
-    layer->opacity_ = 3.14f;
-    layer->blend_mode_ = SkXfermode::kSrcIn_Mode;
-    layer->is_root_for_isolated_group_ = !layer->is_root_for_isolated_group_;
-    layer->position_ = gfx::PointF(3.14f, 6.28f);
-    layer->is_container_for_fixed_position_layers_ =
-        !layer->is_container_for_fixed_position_layers_;
+    layer->inputs_.non_fast_scrollable_region = Region(gfx::Rect(5, 1, 14, 3));
+    layer->inputs_.touch_event_handler_region = Region(gfx::Rect(3, 14, 1, 5));
+    layer->inputs_.contents_opaque = !layer->inputs_.contents_opaque;
+    layer->inputs_.opacity = 3.14f;
+    layer->inputs_.blend_mode = SkXfermode::kSrcIn_Mode;
+    layer->inputs_.is_root_for_isolated_group =
+        !layer->inputs_.is_root_for_isolated_group;
+    layer->inputs_.position = gfx::PointF(3.14f, 6.28f);
+    layer->inputs_.is_container_for_fixed_position_layers =
+        !layer->inputs_.is_container_for_fixed_position_layers;
     LayerPositionConstraint pos_con;
     pos_con.set_is_fixed_to_bottom_edge(true);
-    layer->position_constraint_ = pos_con;
-    layer->should_flatten_transform_ = !layer->should_flatten_transform_;
+    layer->inputs_.position_constraint = pos_con;
+    layer->inputs_.should_flatten_transform =
+        !layer->inputs_.should_flatten_transform;
     layer->should_flatten_transform_from_property_tree_ =
         !layer->should_flatten_transform_from_property_tree_;
     layer->draw_blend_mode_ = SkXfermode::kSrcOut_Mode;
-    layer->use_parent_backface_visibility_ =
-        !layer->use_parent_backface_visibility_;
+    layer->inputs_.use_parent_backface_visibility =
+        !layer->inputs_.use_parent_backface_visibility;
     gfx::Transform transform;
     transform.Rotate(90);
-    layer->transform_ = transform;
-    layer->sorting_context_id_ = 42;
+    layer->inputs_.transform = transform;
+    layer->inputs_.sorting_context_id = 42;
     layer->num_descendants_that_draw_content_ = 5;
-    layer->scroll_clip_layer_id_ = 17;
-    layer->user_scrollable_horizontal_ = !layer->user_scrollable_horizontal_;
-    layer->user_scrollable_vertical_ = !layer->user_scrollable_vertical_;
-    layer->scroll_offset_ = gfx::ScrollOffset(3, 14);
-    layer->update_rect_ = gfx::Rect(14, 15);
+    layer->inputs_.scroll_clip_layer_id = 17;
+    layer->inputs_.user_scrollable_horizontal =
+        !layer->inputs_.user_scrollable_horizontal;
+    layer->inputs_.user_scrollable_vertical =
+        !layer->inputs_.user_scrollable_vertical;
+    layer->inputs_.scroll_offset = gfx::ScrollOffset(3, 14);
+    layer->inputs_.update_rect = gfx::Rect(14, 15);
 
     VerifyBaseLayerPropertiesSerializationAndDeserialization(layer.get());
   }
@@ -367,7 +382,8 @@
     scoped_refptr<SolidColorScrollbarLayer> deserialized_scrollbar =
         SolidColorScrollbarLayer::Create(ScrollbarOrientation::HORIZONTAL, -1,
                                          -1, false, Layer::INVALID_ID);
-    deserialized_scrollbar->layer_id_ = source_scrollbar->layer_id_;
+    deserialized_scrollbar->inputs_.layer_id =
+        source_scrollbar->inputs_.layer_id;
 
     // FromLayerSpecificPropertiesProto expects a non-null LayerTreeHost to be
     // set.
@@ -393,13 +409,13 @@
     scoped_refptr<Layer> layer = Layer::Create();
 
     scoped_refptr<Layer> scroll_parent = Layer::Create();
-    layer->scroll_parent_ = scroll_parent.get();
+    layer->inputs_.scroll_parent = scroll_parent.get();
     scoped_refptr<Layer> scroll_child = Layer::Create();
     layer->scroll_children_.reset(new std::set<Layer*>);
     layer->scroll_children_->insert(scroll_child.get());
 
     scoped_refptr<Layer> clip_parent = Layer::Create();
-    layer->clip_parent_ = clip_parent.get();
+    layer->inputs_.clip_parent = clip_parent.get();
     layer->clip_children_.reset(new std::set<Layer*>);
     scoped_refptr<Layer> clip_child1 = Layer::Create();
     layer->clip_children_->insert(clip_child1.get());
@@ -542,9 +558,9 @@
     EXPECT_EQ(layer_src_b->id(), layer_dest_b->id());
 
     // Swap order of the children.
-    scoped_refptr<Layer> tmp_a = layer_src_root->children_[0];
-    layer_src_root->children_[0] = layer_src_root->children_[1];
-    layer_src_root->children_[1] = tmp_a;
+    scoped_refptr<Layer> tmp_a = layer_src_root->inputs_.children[0];
+    layer_src_root->inputs_.children[0] = layer_src_root->inputs_.children[1];
+    layer_src_root->inputs_.children[1] = tmp_a;
 
     // Fake the fact that the destination layers have valid indexes.
     layer_dest_root->transform_tree_index_ = 33;
@@ -1138,41 +1154,41 @@
   root->SetPosition(arbitrary_point_f);
   TransformNode* node = layer_tree_host_->property_trees()->transform_tree.Node(
       root->transform_tree_index());
-  EXPECT_TRUE(node->data.transform_changed);
+  EXPECT_TRUE(node->transform_changed);
   EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET(
       root->PushPropertiesTo(root_impl.get());
       child->PushPropertiesTo(child_impl.get());
       child2->PushPropertiesTo(child2_impl.get());
       grand_child->PushPropertiesTo(grand_child_impl.get());
       layer_tree_host_->property_trees()->ResetAllChangeTracking());
-  EXPECT_FALSE(node->data.transform_changed);
+  EXPECT_FALSE(node->transform_changed);
 
   EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1);
   child->SetPosition(arbitrary_point_f);
   node = layer_tree_host_->property_trees()->transform_tree.Node(
       child->transform_tree_index());
-  EXPECT_TRUE(node->data.transform_changed);
+  EXPECT_TRUE(node->transform_changed);
   // child2 is not in the subtree of child, but its scroll parent is. So, its
   // to_screen will be effected by change in position of child2.
   layer_tree_host_->property_trees()->transform_tree.UpdateTransforms(
       child2->transform_tree_index());
   node = layer_tree_host_->property_trees()->transform_tree.Node(
       child2->transform_tree_index());
-  EXPECT_TRUE(node->data.transform_changed);
+  EXPECT_TRUE(node->transform_changed);
   EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET(
       child->PushPropertiesTo(child_impl.get());
       grand_child->PushPropertiesTo(grand_child_impl.get());
       layer_tree_host_->property_trees()->ResetAllChangeTracking());
   node = layer_tree_host_->property_trees()->transform_tree.Node(
       child->transform_tree_index());
-  EXPECT_FALSE(node->data.transform_changed);
+  EXPECT_FALSE(node->transform_changed);
 
   gfx::Point3F arbitrary_point_3f = gfx::Point3F(0.125f, 0.25f, 0.f);
   EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1);
   root->SetTransformOrigin(arbitrary_point_3f);
   node = layer_tree_host_->property_trees()->transform_tree.Node(
       root->transform_tree_index());
-  EXPECT_TRUE(node->data.transform_changed);
+  EXPECT_TRUE(node->transform_changed);
   EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET(
       root->PushPropertiesTo(root_impl.get());
       child->PushPropertiesTo(child_impl.get());
@@ -1186,7 +1202,7 @@
   root->SetTransform(arbitrary_transform);
   node = layer_tree_host_->property_trees()->transform_tree.Node(
       root->transform_tree_index());
-  EXPECT_TRUE(node->data.transform_changed);
+  EXPECT_TRUE(node->transform_changed);
 }
 
 TEST_F(LayerTest, AddAndRemoveChild) {
@@ -2192,20 +2208,22 @@
   scoped_refptr<Layer> layer = Layer::Create();
   EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(layer));
 
+  LayerInternalsForTest layer_internals(layer.get());
+
   EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers()).Times(1);
-  layer->OnOpacityAnimated(0.5f);
+  layer_internals.OnOpacityAnimated(0.5f);
   Mock::VerifyAndClearExpectations(layer_tree_host_.get());
 
   EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers()).Times(1);
   gfx::Transform transform;
   transform.Rotate(45.0);
-  layer->OnTransformAnimated(transform);
+  layer_internals.OnTransformAnimated(transform);
   Mock::VerifyAndClearExpectations(layer_tree_host_.get());
 
   // Scroll offset animation should not schedule a layer update since it is
   // handled similarly to normal compositor scroll updates.
   EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers()).Times(0);
-  layer->OnScrollOffsetAnimated(gfx::ScrollOffset(10, 10));
+  layer_internals.OnScrollOffsetAnimated(gfx::ScrollOffset(10, 10));
   Mock::VerifyAndClearExpectations(layer_tree_host_.get());
 }
 
diff --git a/cc/layers/layer_utils.cc b/cc/layers/layer_utils.cc
index 0eeab138..b3b6d53 100644
--- a/cc/layers/layer_utils.cc
+++ b/cc/layers/layer_utils.cc
@@ -7,6 +7,7 @@
 #include "cc/layers/layer_impl.h"
 #include "cc/trees/layer_tree_host_common.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/transform_node.h"
 #include "ui/gfx/geometry/box_f.h"
 
 namespace cc {
@@ -18,7 +19,7 @@
 }
 
 inline bool HasAncestorTransformAnimation(const TransformNode* transform_node) {
-  return transform_node->data.to_screen_is_potentially_animated;
+  return transform_node->to_screen_is_potentially_animated;
 }
 
 inline bool HasAncestorFilterAnimation(const LayerImpl& layer) {
@@ -92,7 +93,7 @@
     // HasAncestorFilterAnimation() for reference.
 
     if (HasTransformAnimationThatInflatesBounds(*layer)) {
-      coalesced_transform.ConcatTransform(transform_node->data.pre_local);
+      coalesced_transform.ConcatTransform(transform_node->pre_local);
       coalesced_transform.TransformBox(&box);
       coalesced_transform.MakeIdentity();
 
@@ -101,9 +102,9 @@
         return false;
       box = inflated;
 
-      coalesced_transform.ConcatTransform(transform_node->data.post_local);
+      coalesced_transform.ConcatTransform(transform_node->post_local);
     } else {
-      coalesced_transform.ConcatTransform(transform_node->data.to_parent);
+      coalesced_transform.ConcatTransform(transform_node->to_parent);
     }
   }
 
diff --git a/cc/layers/painted_scrollbar_layer.cc b/cc/layers/painted_scrollbar_layer.cc
index 6bbcf107..09bb588b 100644
--- a/cc/layers/painted_scrollbar_layer.cc
+++ b/cc/layers/painted_scrollbar_layer.cc
@@ -245,7 +245,7 @@
     updated = true;
   }
 
-  if (update_rect_.IsEmpty() && track_resource_)
+  if (update_rect().IsEmpty() && track_resource_)
     return updated;
 
   if (!track_resource_ || scrollbar_->NeedsPaintPart(TRACK)) {
diff --git a/cc/layers/render_surface_impl.cc b/cc/layers/render_surface_impl.cc
index 1a742f9..a2d128ca 100644
--- a/cc/layers/render_surface_impl.cc
+++ b/cc/layers/render_surface_impl.cc
@@ -21,6 +21,7 @@
 #include "cc/quads/shared_quad_state.h"
 #include "cc/trees/damage_tracker.h"
 #include "cc/trees/draw_property_utils.h"
+#include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/occlusion.h"
 #include "third_party/skia/include/core/SkImageFilter.h"
@@ -45,9 +46,9 @@
   EffectTree& effect_tree =
       owning_layer_->layer_tree_impl()->property_trees()->effect_tree;
   EffectNode* node = effect_tree.Node(EffectTreeIndex());
-  EffectNode* target_node = effect_tree.Node(node->data.target_id);
+  EffectNode* target_node = effect_tree.Node(node->target_id);
   if (target_node->id != 0)
-    return target_node->data.render_surface;
+    return target_node->render_surface;
   else
     return this;
 }
@@ -56,9 +57,9 @@
   const EffectTree& effect_tree =
       owning_layer_->layer_tree_impl()->property_trees()->effect_tree;
   const EffectNode* node = effect_tree.Node(EffectTreeIndex());
-  const EffectNode* target_node = effect_tree.Node(node->data.target_id);
+  const EffectNode* target_node = effect_tree.Node(node->target_id);
   if (target_node->id != 0)
-    return target_node->data.render_surface;
+    return target_node->render_surface;
   else
     return this;
 }
@@ -125,43 +126,43 @@
 }
 
 bool RenderSurfaceImpl::HasReplica() const {
-  return OwningEffectNode()->data.replica_layer_id != -1;
+  return OwningEffectNode()->replica_layer_id != -1;
 }
 
 const LayerImpl* RenderSurfaceImpl::ReplicaLayer() const {
-  int replica_layer_id = OwningEffectNode()->data.replica_layer_id;
+  int replica_layer_id = OwningEffectNode()->replica_layer_id;
   return owning_layer_->layer_tree_impl()->LayerById(replica_layer_id);
 }
 
 LayerImpl* RenderSurfaceImpl::ReplicaLayer() {
-  int replica_layer_id = OwningEffectNode()->data.replica_layer_id;
+  int replica_layer_id = OwningEffectNode()->replica_layer_id;
   return owning_layer_->layer_tree_impl()->LayerById(replica_layer_id);
 }
 
 LayerImpl* RenderSurfaceImpl::MaskLayer() {
-  int mask_layer_id = OwningEffectNode()->data.mask_layer_id;
+  int mask_layer_id = OwningEffectNode()->mask_layer_id;
   return owning_layer_->layer_tree_impl()->LayerById(mask_layer_id);
 }
 
 bool RenderSurfaceImpl::HasMask() const {
-  return OwningEffectNode()->data.mask_layer_id != -1;
+  return OwningEffectNode()->mask_layer_id != -1;
 }
 
 LayerImpl* RenderSurfaceImpl::ReplicaMaskLayer() {
-  int replica_mask_layer_id = OwningEffectNode()->data.replica_mask_layer_id;
+  int replica_mask_layer_id = OwningEffectNode()->replica_mask_layer_id;
   return owning_layer_->layer_tree_impl()->LayerById(replica_mask_layer_id);
 }
 
 bool RenderSurfaceImpl::HasReplicaMask() const {
-  return OwningEffectNode()->data.replica_mask_layer_id != -1;
+  return OwningEffectNode()->replica_mask_layer_id != -1;
 }
 
 const FilterOperations& RenderSurfaceImpl::BackgroundFilters() const {
-  return OwningEffectNode()->data.background_filters;
+  return OwningEffectNode()->background_filters;
 }
 
 bool RenderSurfaceImpl::HasCopyRequest() const {
-  return OwningEffectNode()->data.has_copy_request;
+  return OwningEffectNode()->has_copy_request;
 }
 
 int RenderSurfaceImpl::TransformTreeIndex() const {
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc
index ef16f8b4..6852fee 100644
--- a/cc/layers/scrollbar_layer_unittest.cc
+++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -27,9 +27,11 @@
 #include "cc/test/mock_occlusion_tracker.h"
 #include "cc/test/test_task_graph_runner.h"
 #include "cc/test/test_web_graphics_context_3d.h"
+#include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/occlusion_tracker.h"
+#include "cc/trees/scroll_node.h"
 #include "cc/trees/single_thread_proxy.h"
 #include "cc/trees/tree_synchronizer.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -543,7 +545,7 @@
   layer_tree_host_->UpdateLayers();
   EffectNode* node = layer_tree_host_->property_trees()->effect_tree.Node(
       scrollbar_layer->effect_tree_index());
-  EXPECT_EQ(node->data.opacity, 0.f);
+  EXPECT_EQ(node->opacity, 0.f);
 
   // This tests that the initial opacity(0) of the scrollbar gets pushed onto
   // the pending tree and then onto the active tree.
@@ -555,12 +557,12 @@
   EXPECT_TRUE(layer_tree_impl->IsPendingTree());
   node = layer_tree_impl->property_trees()->effect_tree.Node(
       scrollbar_layer->effect_tree_index());
-  EXPECT_EQ(node->data.opacity, 0.f);
+  EXPECT_EQ(node->opacity, 0.f);
   host_impl->ActivateSyncTree();
   layer_tree_impl = host_impl->active_tree();
   node = layer_tree_impl->property_trees()->effect_tree.Node(
       scrollbar_layer->effect_tree_index());
-  EXPECT_EQ(node->data.opacity, 0.f);
+  EXPECT_EQ(node->opacity, 0.f);
 
   // This tests that activation does not change the opacity of scrollbar layer.
   LayerImpl* scrollbar_layer_impl =
@@ -572,12 +574,12 @@
   EXPECT_TRUE(layer_tree_impl->IsPendingTree());
   node = layer_tree_impl->property_trees()->effect_tree.Node(
       scrollbar_layer->effect_tree_index());
-  EXPECT_EQ(node->data.opacity, 0.f);
+  EXPECT_EQ(node->opacity, 0.f);
   host_impl->ActivateSyncTree();
   layer_tree_impl = host_impl->active_tree();
   node = layer_tree_impl->property_trees()->effect_tree.Node(
       scrollbar_layer->effect_tree_index());
-  EXPECT_EQ(node->data.opacity, 0.25f);
+  EXPECT_EQ(node->opacity, 0.25f);
 }
 
 TEST_F(ScrollbarLayerTest, ScrollbarLayerPushProperties) {
@@ -621,7 +623,7 @@
   EffectNode* node =
       host_impl->active_tree()->property_trees()->effect_tree.Node(
           scrollbar_layer->effect_tree_index());
-  EXPECT_EQ(node->data.opacity, 1.f);
+  EXPECT_EQ(node->opacity, 1.f);
 }
 
 class ScrollbarLayerSolidColorThumbTest : public testing::Test {
diff --git a/cc/layers/texture_layer.cc b/cc/layers/texture_layer.cc
index eab540e..7d1e142 100644
--- a/cc/layers/texture_layer.cc
+++ b/cc/layers/texture_layer.cc
@@ -201,7 +201,7 @@
   // SetTextureMailbox could be called externally and the same mailbox used for
   // different textures.  Such callers notify this layer that the texture has
   // changed by calling SetNeedsDisplay, so check for that here.
-  return updated || !update_rect_.IsEmpty();
+  return updated || !update_rect().IsEmpty();
 }
 
 void TextureLayer::PushPropertiesTo(LayerImpl* layer) {
diff --git a/cc/layers/video_layer.cc b/cc/layers/video_layer.cc
index fe4f2ed..177721b 100644
--- a/cc/layers/video_layer.cc
+++ b/cc/layers/video_layer.cc
@@ -35,7 +35,7 @@
   //
   // This is the inefficient legacy redraw path for videos.  It's better to
   // communicate this directly to the VideoLayerImpl.
-  updated |= !update_rect_.IsEmpty();
+  updated |= !update_rect().IsEmpty();
 
   return updated;
 }
diff --git a/cc/layers/viewport.cc b/cc/layers/viewport.cc
index d80d40c..d4c3fd5 100644
--- a/cc/layers/viewport.cc
+++ b/cc/layers/viewport.cc
@@ -9,6 +9,7 @@
 #include "cc/input/top_controls_manager.h"
 #include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/scroll_node.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
 #include "ui/gfx/geometry/vector2d_f.h"
 
diff --git a/cc/output/compositor_frame_metadata.cc b/cc/output/compositor_frame_metadata.cc
index a98eee2..afd9741 100644
--- a/cc/output/compositor_frame_metadata.cc
+++ b/cc/output/compositor_frame_metadata.cc
@@ -6,14 +6,7 @@
 
 namespace cc {
 
-CompositorFrameMetadata::CompositorFrameMetadata()
-    : device_scale_factor(0.f),
-      page_scale_factor(0.f),
-      min_page_scale_factor(0.f),
-      max_page_scale_factor(0.f),
-      root_overflow_x_hidden(false),
-      root_overflow_y_hidden(false),
-      root_background_color(SK_ColorWHITE) {}
+CompositorFrameMetadata::CompositorFrameMetadata() = default;
 
 CompositorFrameMetadata::CompositorFrameMetadata(
     CompositorFrameMetadata&& other) = default;
diff --git a/cc/output/compositor_frame_metadata.h b/cc/output/compositor_frame_metadata.h
index c2e13fe..d6f0e60 100644
--- a/cc/output/compositor_frame_metadata.h
+++ b/cc/output/compositor_frame_metadata.h
@@ -31,21 +31,27 @@
   CompositorFrameMetadata Clone() const;
 
   // The device scale factor used to generate this compositor frame.
-  float device_scale_factor;
+  float device_scale_factor = 0.f;
 
   // Scroll offset and scale of the root layer. This can be used for tasks
   // like positioning windowed plugins.
   gfx::Vector2dF root_scroll_offset;
-  float page_scale_factor;
+  float page_scale_factor = 0.f;
 
   // These limits can be used together with the scroll/scale fields above to
   // determine if scrolling/scaling in a particular direction is possible.
   gfx::SizeF scrollable_viewport_size;
   gfx::SizeF root_layer_size;
-  float min_page_scale_factor;
-  float max_page_scale_factor;
-  bool root_overflow_x_hidden;
-  bool root_overflow_y_hidden;
+  float min_page_scale_factor = 0.f;
+  float max_page_scale_factor = 0.f;
+  bool root_overflow_x_hidden = false;
+  bool root_overflow_y_hidden = false;
+
+  // WebView makes quality decisions for rastering resourceless software frames
+  // based on information that a scroll or animation is active.
+  // TODO(aelias): Remove this and always enable filtering if there aren't apps
+  // depending on this anymore.
+  bool is_resourceless_software_draw_with_scroll_or_animation = false;
 
   // Used to position the Android location top bar and page content, whose
   // precise position is computed by the renderer compositor.
@@ -55,7 +61,7 @@
   // This color is usually obtained from the background color of the <body>
   // element. It can be used for filling in gutter areas around the frame when
   // it's too small to fill the box the parent reserved for it.
-  SkColor root_background_color;
+  SkColor root_background_color = SK_ColorWHITE;
 
   // Provides selection region updates relative to the current viewport. If the
   // selection is empty or otherwise unused, the bound types will indicate such.
diff --git a/cc/output/delegating_renderer.cc b/cc/output/delegating_renderer.cc
index 9d80336..06aee77 100644
--- a/cc/output/delegating_renderer.cc
+++ b/cc/output/delegating_renderer.cc
@@ -77,8 +77,7 @@
                                    float device_scale_factor,
                                    const gfx::ColorSpace& device_color_space,
                                    const gfx::Rect& device_viewport_rect,
-                                   const gfx::Rect& device_clip_rect,
-                                   bool disable_picture_quad_image_filtering) {
+                                   const gfx::Rect& device_clip_rect) {
   TRACE_EVENT0("cc", "DelegatingRenderer::DrawFrame");
 
   DCHECK(!delegated_frame_data_);
diff --git a/cc/output/delegating_renderer.h b/cc/output/delegating_renderer.h
index 831f943..eeec14a 100644
--- a/cc/output/delegating_renderer.h
+++ b/cc/output/delegating_renderer.h
@@ -32,8 +32,7 @@
                  float device_scale_factor,
                  const gfx::ColorSpace& device_color_space,
                  const gfx::Rect& device_viewport_rect,
-                 const gfx::Rect& device_clip_rect,
-                 bool disable_picture_quad_image_filtering) override;
+                 const gfx::Rect& device_clip_rect) override;
 
   void Finish() override {}
 
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index a677f0e..61865b1d 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -200,8 +200,7 @@
                                float device_scale_factor,
                                const gfx::ColorSpace& device_color_space,
                                const gfx::Rect& device_viewport_rect,
-                               const gfx::Rect& device_clip_rect,
-                               bool disable_picture_quad_image_filtering) {
+                               const gfx::Rect& device_clip_rect) {
   TRACE_EVENT0("cc", "DirectRenderer::DrawFrame");
   UMA_HISTOGRAM_COUNTS(
       "Renderer4.renderPassCount",
@@ -218,8 +217,6 @@
   frame.root_damage_rect.Intersect(gfx::Rect(device_viewport_rect.size()));
   frame.device_viewport_rect = device_viewport_rect;
   frame.device_clip_rect = device_clip_rect;
-  frame.disable_picture_quad_image_filtering =
-      disable_picture_quad_image_filtering;
 
   EnsureBackbuffer();
 
diff --git a/cc/output/direct_renderer.h b/cc/output/direct_renderer.h
index 63d40af..d0687cd 100644
--- a/cc/output/direct_renderer.h
+++ b/cc/output/direct_renderer.h
@@ -38,8 +38,7 @@
                  float device_scale_factor,
                  const gfx::ColorSpace& device_color_space,
                  const gfx::Rect& device_viewport_rect,
-                 const gfx::Rect& device_clip_rect,
-                 bool disable_picture_quad_image_filtering) override;
+                 const gfx::Rect& device_clip_rect) override;
   virtual void SwapBuffersComplete() {}
   virtual void DidReceiveTextureInUseResponses(
       const gpu::TextureInUseResponses& responses) {}
@@ -65,8 +64,6 @@
     gfx::Transform projection_matrix;
     gfx::Transform window_matrix;
 
-    bool disable_picture_quad_image_filtering;
-
     OverlayCandidateList overlay_list;
     CALayerOverlayList ca_layer_overlay_list;
   };
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc
index 51377a35..e8dbf43 100644
--- a/cc/output/gl_renderer_unittest.cc
+++ b/cc/output/gl_renderer_unittest.cc
@@ -66,13 +66,13 @@
   }
   void DrawFrame(Renderer* renderer, const gfx::Rect& viewport_rect) {
     renderer->DrawFrame(&render_passes_in_draw_order_, 1.f, gfx::ColorSpace(),
-                        viewport_rect, viewport_rect, false);
+                        viewport_rect, viewport_rect);
   }
   void DrawFrame(Renderer* renderer,
                  const gfx::Rect& viewport_rect,
                  const gfx::Rect& clip_rect) {
     renderer->DrawFrame(&render_passes_in_draw_order_, 1.f, gfx::ColorSpace(),
-                        viewport_rect, clip_rect, false);
+                        viewport_rect, clip_rect);
   }
 
   RenderPassList render_passes_in_draw_order_;
@@ -1693,7 +1693,7 @@
                     bool has_alpha));
   MOCK_METHOD0(BindFramebuffer, void());
   MOCK_METHOD0(GetFramebufferCopyTextureFormat, GLenum());
-  MOCK_METHOD1(SwapBuffers_, void(CompositorFrame& frame));
+  MOCK_METHOD1(SwapBuffers_, void(CompositorFrame& frame));  // NOLINT
   void SwapBuffers(CompositorFrame frame) override { SwapBuffers_(frame); }
 };
 
@@ -1739,7 +1739,7 @@
         render_passes_in_draw_order_);
     renderer_->DrawFrame(&render_passes_in_draw_order_, device_scale_factor,
                          gfx::ColorSpace(), device_viewport_rect,
-                         device_viewport_rect, false);
+                         device_viewport_rect);
   }
 
   OutputSurfaceMockContext* Context() {
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc
index 2e7ccc755..3c7e16b 100644
--- a/cc/output/overlay_unittest.cc
+++ b/cc/output/overlay_unittest.cc
@@ -1222,7 +1222,7 @@
 
   void DrawFrame(RenderPassList* pass_list, const gfx::Rect& viewport_rect) {
     renderer_->DrawFrame(pass_list, 1.f, gfx::ColorSpace(), viewport_rect,
-                         viewport_rect, false);
+                         viewport_rect);
   }
   void SwapBuffers() {
     renderer_->SwapBuffers(CompositorFrameMetadata());
diff --git a/cc/output/renderer.h b/cc/output/renderer.h
index 2b5a52c9..f349295c 100644
--- a/cc/output/renderer.h
+++ b/cc/output/renderer.h
@@ -73,8 +73,7 @@
                          float device_scale_factor,
                          const gfx::ColorSpace& device_color_space,
                          const gfx::Rect& device_viewport_rect,
-                         const gfx::Rect& device_clip_rect,
-                         bool disable_picture_quad_image_filtering) = 0;
+                         const gfx::Rect& device_clip_rect) = 0;
 
   // Waits for rendering to finish.
   virtual void Finish() = 0;
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc
index 0368ad9..ee169b7 100644
--- a/cc/output/software_renderer.cc
+++ b/cc/output/software_renderer.cc
@@ -56,24 +56,20 @@
     RendererClient* client,
     const RendererSettings* settings,
     OutputSurface* output_surface,
-    ResourceProvider* resource_provider,
-    bool use_image_hijack_canvas) {
+    ResourceProvider* resource_provider) {
   return base::WrapUnique(new SoftwareRenderer(client, settings, output_surface,
-                                               resource_provider,
-                                               use_image_hijack_canvas));
+                                               resource_provider));
 }
 
 SoftwareRenderer::SoftwareRenderer(RendererClient* client,
                                    const RendererSettings* settings,
                                    OutputSurface* output_surface,
-                                   ResourceProvider* resource_provider,
-                                   bool use_image_hijack_canvas)
+                                   ResourceProvider* resource_provider)
     : DirectRenderer(client, settings, output_surface, resource_provider),
       is_scissor_enabled_(false),
       is_backbuffer_discarded_(false),
       output_device_(output_surface->software_device()),
-      current_canvas_(nullptr),
-      use_image_hijack_canvas_(use_image_hijack_canvas) {
+      current_canvas_(nullptr) {
   if (resource_provider_) {
     capabilities_.max_texture_size = resource_provider_->max_texture_size();
     capabilities_.best_texture_format =
@@ -366,13 +362,19 @@
   const bool needs_transparency =
       SkScalarRoundToInt(quad->shared_quad_state->opacity * 255) < 255;
   const bool disable_image_filtering =
-      frame->disable_picture_quad_image_filtering || quad->nearest_neighbor;
+      disable_picture_quad_image_filtering_ || quad->nearest_neighbor;
 
   TRACE_EVENT0("cc", "SoftwareRenderer::DrawPictureQuad");
 
   RasterSource::PlaybackSettings playback_settings;
   playback_settings.playback_to_shared_canvas = true;
-  playback_settings.use_image_hijack_canvas = use_image_hijack_canvas_;
+  // Indicates whether content rasterization should happen through an
+  // ImageHijackCanvas, which causes image decodes to be managed by an
+  // ImageDecodeController. PictureDrawQuads are used for resourceless software
+  // draws, while a GPU ImageDecodeController may be in use by the compositor
+  // providing the RasterSource. So we disable the image hijack canvas to avoid
+  // trying to use the GPU ImageDecodeController while doing a software draw.
+  playback_settings.use_image_hijack_canvas = false;
   if (needs_transparency || disable_image_filtering) {
     // TODO(aelias): This isn't correct in all cases. We should detect these
     // cases and fall back to a persistent bitmap backing
diff --git a/cc/output/software_renderer.h b/cc/output/software_renderer.h
index 5a0bb04..c7e0f809 100644
--- a/cc/output/software_renderer.h
+++ b/cc/output/software_renderer.h
@@ -30,8 +30,7 @@
       RendererClient* client,
       const RendererSettings* settings,
       OutputSurface* output_surface,
-      ResourceProvider* resource_provider,
-      bool use_image_hijack_canvas);
+      ResourceProvider* resource_provider);
 
   ~SoftwareRenderer() override;
   const RendererCapabilitiesImpl& Capabilities() const override;
@@ -40,6 +39,10 @@
   void DiscardBackbuffer() override;
   void EnsureBackbuffer() override;
 
+  void SetDisablePictureQuadImageFiltering(bool disable) {
+    disable_picture_quad_image_filtering_ = disable;
+  }
+
  protected:
   void BindFramebufferToOutputSurface(DrawingFrame* frame) override;
   bool BindFramebufferToTexture(DrawingFrame* frame,
@@ -64,8 +67,7 @@
   SoftwareRenderer(RendererClient* client,
                    const RendererSettings* settings,
                    OutputSurface* output_surface,
-                   ResourceProvider* resource_provider,
-                   bool use_image_hijack_canvas);
+                   ResourceProvider* resource_provider);
 
   void DidChangeVisibility() override;
 
@@ -104,6 +106,8 @@
       const RenderPassDrawQuad* quad,
       SkShader::TileMode content_tile_mode) const;
 
+  bool disable_picture_quad_image_filtering_ = false;
+
   RendererCapabilitiesImpl capabilities_;
   bool is_scissor_enabled_;
   bool is_backbuffer_discarded_;
@@ -117,13 +121,6 @@
       current_framebuffer_lock_;
   sk_sp<SkCanvas> current_framebuffer_canvas_;
 
-  // Indicates whether content rasterization should happen through an
-  // ImageHijackCanvas, which causes image decodes to be managed by an
-  // ImageDecodeController. We set this to false during resourceless software
-  // draw when a GPU ImageDecodeController is in use, as software rasterization
-  // cannot use the GPU IDC.
-  const bool use_image_hijack_canvas_;
-
   DISALLOW_COPY_AND_ASSIGN(SoftwareRenderer);
 };
 
diff --git a/cc/output/software_renderer_unittest.cc b/cc/output/software_renderer_unittest.cc
index 087db9b..be76d35 100644
--- a/cc/output/software_renderer_unittest.cc
+++ b/cc/output/software_renderer_unittest.cc
@@ -42,8 +42,7 @@
     resource_provider_ = FakeResourceProvider::Create(
         output_surface_.get(), shared_bitmap_manager_.get());
     renderer_ = SoftwareRenderer::Create(
-        this, &settings_, output_surface_.get(), resource_provider(),
-        true /* use_image_hijack_canvas */);
+        this, &settings_, output_surface_.get(), resource_provider());
   }
 
   ResourceProvider* resource_provider() const {
@@ -68,7 +67,7 @@
                        loop.QuitClosure())));
 
     renderer()->DrawFrame(list, device_scale_factor, gfx::ColorSpace(),
-                          device_viewport_rect, device_viewport_rect, false);
+                          device_viewport_rect, device_viewport_rect);
     loop.Run();
     return bitmap_result;
   }
diff --git a/cc/proto/property_tree.proto b/cc/proto/property_tree.proto
index afdd13e..230c62e 100644
--- a/cc/proto/property_tree.proto
+++ b/cc/proto/property_tree.proto
@@ -85,7 +85,7 @@
 }
 
 // Proto for struct EffectNodeData.
-// NEXT ID: 20
+// NEXT ID: 21
 message EffectNodeData {
   optional float opacity = 1;
   optional float screen_space_opacity = 2;
@@ -105,6 +105,7 @@
   optional int64 mask_layer_id = 17;
   optional int64 replica_layer_id = 18;
   optional int64 replica_mask_layer_id = 19;
+  optional Vector2dF sublayer_scale = 20;
 }
 
 // Proto for struct ScrollNodeData
diff --git a/cc/raster/bitmap_raster_buffer_provider.cc b/cc/raster/bitmap_raster_buffer_provider.cc
index 56e4b57..1bc2e04 100644
--- a/cc/raster/bitmap_raster_buffer_provider.cc
+++ b/cc/raster/bitmap_raster_buffer_provider.cc
@@ -103,11 +103,15 @@
   return resource_provider_->best_texture_format();
 }
 
-bool BitmapRasterBufferProvider::GetResourceRequiresSwizzle(
+bool BitmapRasterBufferProvider::IsResourceSwizzleRequired(
     bool must_support_alpha) const {
   return ResourceFormatRequiresSwizzle(GetResourceFormat(must_support_alpha));
 }
 
+bool BitmapRasterBufferProvider::IsPartialRasterSupported() const {
+  return true;
+}
+
 void BitmapRasterBufferProvider::Shutdown() {}
 
 }  // namespace cc
diff --git a/cc/raster/bitmap_raster_buffer_provider.h b/cc/raster/bitmap_raster_buffer_provider.h
index 045622626..182be515 100644
--- a/cc/raster/bitmap_raster_buffer_provider.h
+++ b/cc/raster/bitmap_raster_buffer_provider.h
@@ -35,7 +35,8 @@
   void ReleaseBufferForRaster(std::unique_ptr<RasterBuffer> buffer) override;
   void OrderingBarrier() override;
   ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
-  bool GetResourceRequiresSwizzle(bool must_support_alpha) const override;
+  bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
+  bool IsPartialRasterSupported() const override;
   void Shutdown() override;
 
  protected:
diff --git a/cc/raster/gpu_raster_buffer_provider.cc b/cc/raster/gpu_raster_buffer_provider.cc
index 0cd802b1..adeddbd 100644
--- a/cc/raster/gpu_raster_buffer_provider.cc
+++ b/cc/raster/gpu_raster_buffer_provider.cc
@@ -188,12 +188,16 @@
   return resource_provider_->best_render_buffer_format();
 }
 
-bool GpuRasterBufferProvider::GetResourceRequiresSwizzle(
+bool GpuRasterBufferProvider::IsResourceSwizzleRequired(
     bool must_support_alpha) const {
   // This doesn't require a swizzle because we rasterize to the correct format.
   return false;
 }
 
+bool GpuRasterBufferProvider::IsPartialRasterSupported() const {
+  return true;
+}
+
 void GpuRasterBufferProvider::Shutdown() {
   pending_raster_buffers_.clear();
 }
diff --git a/cc/raster/gpu_raster_buffer_provider.h b/cc/raster/gpu_raster_buffer_provider.h
index ef69754..dc4fb61d 100644
--- a/cc/raster/gpu_raster_buffer_provider.h
+++ b/cc/raster/gpu_raster_buffer_provider.h
@@ -33,7 +33,8 @@
   void ReleaseBufferForRaster(std::unique_ptr<RasterBuffer> buffer) override;
   void OrderingBarrier() override;
   ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
-  bool GetResourceRequiresSwizzle(bool must_support_alpha) const override;
+  bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
+  bool IsPartialRasterSupported() const override;
   void Shutdown() override;
 
   void PlaybackOnWorkerThread(
diff --git a/cc/raster/one_copy_raster_buffer_provider.cc b/cc/raster/one_copy_raster_buffer_provider.cc
index a9ff50f..44e3845 100644
--- a/cc/raster/one_copy_raster_buffer_provider.cc
+++ b/cc/raster/one_copy_raster_buffer_provider.cc
@@ -148,11 +148,15 @@
   return resource_provider_->best_texture_format();
 }
 
-bool OneCopyRasterBufferProvider::GetResourceRequiresSwizzle(
+bool OneCopyRasterBufferProvider::IsResourceSwizzleRequired(
     bool must_support_alpha) const {
   return ResourceFormatRequiresSwizzle(GetResourceFormat(must_support_alpha));
 }
 
+bool OneCopyRasterBufferProvider::IsPartialRasterSupported() const {
+  return true;
+}
+
 void OneCopyRasterBufferProvider::Shutdown() {
   staging_pool_.Shutdown();
   pending_raster_buffers_.clear();
diff --git a/cc/raster/one_copy_raster_buffer_provider.h b/cc/raster/one_copy_raster_buffer_provider.h
index 44ceb7a..008a5bd4 100644
--- a/cc/raster/one_copy_raster_buffer_provider.h
+++ b/cc/raster/one_copy_raster_buffer_provider.h
@@ -40,7 +40,8 @@
   void ReleaseBufferForRaster(std::unique_ptr<RasterBuffer> buffer) override;
   void OrderingBarrier() override;
   ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
-  bool GetResourceRequiresSwizzle(bool must_support_alpha) const override;
+  bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
+  bool IsPartialRasterSupported() const override;
   void Shutdown() override;
 
   // Playback raster source and copy result into |resource|.
diff --git a/cc/raster/raster_buffer_provider.h b/cc/raster/raster_buffer_provider.h
index 1cdfba2..616d123 100644
--- a/cc/raster/raster_buffer_provider.h
+++ b/cc/raster/raster_buffer_provider.h
@@ -60,7 +60,11 @@
   virtual ResourceFormat GetResourceFormat(bool must_support_alpha) const = 0;
 
   // Determine if the resource requires swizzling.
-  virtual bool GetResourceRequiresSwizzle(bool must_support_alpha) const = 0;
+  virtual bool IsResourceSwizzleRequired(bool must_support_alpha) const = 0;
+
+  // Determine if the RasterBufferProvider can handle partial raster into
+  // resources.
+  virtual bool IsPartialRasterSupported() const = 0;
 
   // Shutdown for doing cleanup.
   virtual void Shutdown() = 0;
diff --git a/cc/raster/zero_copy_raster_buffer_provider.cc b/cc/raster/zero_copy_raster_buffer_provider.cc
index b89b45b..e33bb43 100644
--- a/cc/raster/zero_copy_raster_buffer_provider.cc
+++ b/cc/raster/zero_copy_raster_buffer_provider.cc
@@ -111,11 +111,15 @@
   return resource_provider_->best_texture_format();
 }
 
-bool ZeroCopyRasterBufferProvider::GetResourceRequiresSwizzle(
+bool ZeroCopyRasterBufferProvider::IsResourceSwizzleRequired(
     bool must_support_alpha) const {
   return ResourceFormatRequiresSwizzle(GetResourceFormat(must_support_alpha));
 }
 
+bool ZeroCopyRasterBufferProvider::IsPartialRasterSupported() const {
+  return false;
+}
+
 void ZeroCopyRasterBufferProvider::Shutdown() {}
 
 }  // namespace cc
diff --git a/cc/raster/zero_copy_raster_buffer_provider.h b/cc/raster/zero_copy_raster_buffer_provider.h
index f813a59b..67262c7 100644
--- a/cc/raster/zero_copy_raster_buffer_provider.h
+++ b/cc/raster/zero_copy_raster_buffer_provider.h
@@ -37,7 +37,8 @@
   void ReleaseBufferForRaster(std::unique_ptr<RasterBuffer> buffer) override;
   void OrderingBarrier() override;
   ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
-  bool GetResourceRequiresSwizzle(bool must_support_alpha) const override;
+  bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
+  bool IsPartialRasterSupported() const override;
   void Shutdown() override;
 
  protected:
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index e9803961..d38110e 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -1184,7 +1184,9 @@
     sk_bitmap.setImmutable();
     sk_image_ = SkImage::MakeFromBitmap(sk_bitmap);
   } else {
-    NOTREACHED() << "Image not valid";
+    // TODO(enne): fix race condition of shared bitmap manager going away
+    // that can cause this to happen.  This will cause the read lock
+    // to not be valid.
   }
 }
 
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc
index e4ad249b..d20f8f82 100644
--- a/cc/surfaces/display.cc
+++ b/cc/surfaces/display.cc
@@ -52,7 +52,6 @@
       texture_mailbox_deleter_(std::move(texture_mailbox_deleter)) {
   DCHECK(surface_manager_);
   DCHECK(output_surface_);
-  DCHECK(texture_mailbox_deleter_);
   DCHECK_EQ(!scheduler_, !begin_frame_source_);
 
   surface_manager_->AddObserver(this);
@@ -163,6 +162,7 @@
                             GL_TEXTURE_2D)));
 
   if (output_surface_->context_provider()) {
+    DCHECK(texture_mailbox_deleter_);
     std::unique_ptr<GLRenderer> renderer = GLRenderer::Create(
         this, &settings_, output_surface_.get(), resource_provider.get(),
         texture_mailbox_deleter_.get(), settings_.highp_threshold_min);
@@ -171,6 +171,7 @@
     renderer_ = std::move(renderer);
   } else if (output_surface_->vulkan_context_provider()) {
 #if defined(ENABLE_VULKAN)
+    DCHECK(texture_mailbox_deleter_);
     std::unique_ptr<VulkanRenderer> renderer = VulkanRenderer::Create(
         this, &settings_, output_surface_.get(), resource_provider.get(),
         texture_mailbox_deleter_.get(), settings_.highp_threshold_min);
@@ -182,10 +183,10 @@
 #endif
   } else {
     std::unique_ptr<SoftwareRenderer> renderer = SoftwareRenderer::Create(
-        this, &settings_, output_surface_.get(), resource_provider.get(),
-        true /* use_image_hijack_canvas */);
+        this, &settings_, output_surface_.get(), resource_provider.get());
     if (!renderer)
       return;
+    software_renderer_ = renderer.get();
     renderer_ = std::move(renderer);
   }
 
@@ -290,14 +291,22 @@
     gfx::Rect device_viewport_rect = gfx::Rect(current_surface_size_);
     gfx::Rect device_clip_rect =
         external_clip_.IsEmpty() ? device_viewport_rect : external_clip_;
-    bool disable_picture_quad_image_filtering = false;
+
+    bool disable_image_filtering =
+        frame.metadata.is_resourceless_software_draw_with_scroll_or_animation;
+    if (software_renderer_) {
+      software_renderer_->SetDisablePictureQuadImageFiltering(
+          disable_image_filtering);
+    } else {
+      // This should only be set for software draws in synchronous compositor.
+      DCHECK(!disable_image_filtering);
+    }
 
     renderer_->DecideRenderPassAllocationsForFrame(
         frame_data->render_pass_list);
     renderer_->DrawFrame(&frame_data->render_pass_list, device_scale_factor_,
                          device_color_space_, device_viewport_rect,
-                         device_clip_rect,
-                         disable_picture_quad_image_filtering);
+                         device_clip_rect);
   } else {
     TRACE_EVENT_INSTANT0("cc", "Draw skipped.", TRACE_EVENT_SCOPE_THREAD);
   }
diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h
index 5d477ff..9df93d41 100644
--- a/cc/surfaces/display.h
+++ b/cc/surfaces/display.h
@@ -39,6 +39,7 @@
 class RendererSettings;
 class ResourceProvider;
 class SharedBitmapManager;
+class SoftwareRenderer;
 class Surface;
 class SurfaceAggregator;
 class SurfaceIdAllocator;
@@ -142,6 +143,7 @@
   std::unique_ptr<SurfaceAggregator> aggregator_;
   std::unique_ptr<TextureMailboxDeleter> texture_mailbox_deleter_;
   std::unique_ptr<DirectRenderer> renderer_;
+  SoftwareRenderer* software_renderer_ = nullptr;
   std::vector<ui::LatencyInfo> stored_latency_info_;
 
  private:
diff --git a/cc/test/fake_output_surface.h b/cc/test/fake_output_surface.h
index 23f2123..8fcc04a 100644
--- a/cc/test/fake_output_surface.h
+++ b/cc/test/fake_output_surface.h
@@ -57,13 +57,6 @@
         new FakeOutputSurface(std::move(software_device), false));
   }
 
-  static std::unique_ptr<FakeOutputSurface>
-  Create3dWithResourcelessSoftwareSupport() {
-    return base::WrapUnique(new FakeOutputSurface(
-        TestContextProvider::Create(), TestContextProvider::CreateWorker(),
-        base::WrapUnique(new SoftwareOutputDevice), false));
-  }
-
   static std::unique_ptr<FakeOutputSurface> CreateDelegating3d() {
     return base::WrapUnique(
         new FakeOutputSurface(TestContextProvider::Create(),
diff --git a/cc/test/fake_picture_layer.cc b/cc/test/fake_picture_layer.cc
index 291342cd..a4e9e8f4 100644
--- a/cc/test/fake_picture_layer.cc
+++ b/cc/test/fake_picture_layer.cc
@@ -32,8 +32,8 @@
 std::unique_ptr<LayerImpl> FakePictureLayer::CreateLayerImpl(
     LayerTreeImpl* tree_impl) {
   if (is_mask())
-    return FakePictureLayerImpl::CreateMask(tree_impl, layer_id_);
-  return FakePictureLayerImpl::Create(tree_impl, layer_id_);
+    return FakePictureLayerImpl::CreateMask(tree_impl, id());
+  return FakePictureLayerImpl::Create(tree_impl, id());
 }
 
 bool FakePictureLayer::Update() {
diff --git a/cc/test/fake_raster_buffer_provider.cc b/cc/test/fake_raster_buffer_provider.cc
index 9657b6be..9c24db2 100644
--- a/cc/test/fake_raster_buffer_provider.cc
+++ b/cc/test/fake_raster_buffer_provider.cc
@@ -28,11 +28,15 @@
   return ResourceFormat::RGBA_8888;
 }
 
-bool FakeRasterBufferProviderImpl::GetResourceRequiresSwizzle(
+bool FakeRasterBufferProviderImpl::IsResourceSwizzleRequired(
     bool must_support_alpha) const {
   return ResourceFormatRequiresSwizzle(GetResourceFormat(must_support_alpha));
 }
 
+bool FakeRasterBufferProviderImpl::IsPartialRasterSupported() const {
+  return true;
+}
+
 void FakeRasterBufferProviderImpl::Shutdown() {}
 
 }  // namespace cc
diff --git a/cc/test/fake_raster_buffer_provider.h b/cc/test/fake_raster_buffer_provider.h
index 00ab04a6..37738a55 100644
--- a/cc/test/fake_raster_buffer_provider.h
+++ b/cc/test/fake_raster_buffer_provider.h
@@ -23,7 +23,8 @@
   void ReleaseBufferForRaster(std::unique_ptr<RasterBuffer> buffer) override;
   void OrderingBarrier() override;
   ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
-  bool GetResourceRequiresSwizzle(bool must_support_alpha) const override;
+  bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
+  bool IsPartialRasterSupported() const override;
   void Shutdown() override;
 };
 
diff --git a/cc/test/layer_internals_for_test.cc b/cc/test/layer_internals_for_test.cc
new file mode 100644
index 0000000..321330c
--- /dev/null
+++ b/cc/test/layer_internals_for_test.cc
@@ -0,0 +1,27 @@
+// 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 "cc/test/layer_internals_for_test.h"
+
+#include "cc/layers/layer.h"
+
+namespace cc {
+
+LayerInternalsForTest::LayerInternalsForTest(Layer* layer) : layer_(layer) {}
+
+void LayerInternalsForTest::OnOpacityAnimated(float opacity) {
+  layer_->OnOpacityAnimated(opacity);
+}
+
+void LayerInternalsForTest::OnTransformAnimated(
+    const gfx::Transform& transform) {
+  layer_->OnTransformAnimated(transform);
+}
+
+void LayerInternalsForTest::OnScrollOffsetAnimated(
+    const gfx::ScrollOffset& scroll_offset) {
+  layer_->OnScrollOffsetAnimated(scroll_offset);
+}
+
+}  // namespace cc
diff --git a/cc/test/layer_internals_for_test.h b/cc/test/layer_internals_for_test.h
new file mode 100644
index 0000000..58fce8c
--- /dev/null
+++ b/cc/test/layer_internals_for_test.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 CC_TEST_LAYER_INTERNALS_FOR_TEST_H_
+#define CC_TEST_LAYER_INTERNALS_FOR_TEST_H_
+
+#include "base/macros.h"
+#include "cc/layers/layer.h"
+
+namespace cc {
+
+// Utility class to give tests access to Layer private methods.
+class LayerInternalsForTest {
+ public:
+  explicit LayerInternalsForTest(Layer* layer);
+
+  void OnOpacityAnimated(float opacity);
+  void OnTransformAnimated(const gfx::Transform& transform);
+  void OnScrollOffsetAnimated(const gfx::ScrollOffset& scroll_offset);
+
+ private:
+  Layer* layer_;
+};
+
+}  // namespace cc
+
+#endif  // CC_TEST_LAYER_INTERNALS_FOR_TEST_H_
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index b20ef02..13fc919 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -80,10 +80,15 @@
   gfx::Rect device_clip_rect = external_device_clip_rect_.IsEmpty()
                                    ? device_viewport_rect
                                    : external_device_clip_rect_;
+
+  if (software_renderer_) {
+    software_renderer_->SetDisablePictureQuadImageFiltering(
+        disable_picture_quad_image_filtering_);
+  }
+
   renderer_->DecideRenderPassAllocationsForFrame(*pass_list);
   renderer_->DrawFrame(pass_list, device_scale_factor, gfx::ColorSpace(),
-                       device_viewport_rect, device_clip_rect,
-                       disable_picture_quad_image_filtering_);
+                       device_viewport_rect, device_clip_rect);
 
   // Wait for the readback to complete.
   if (output_surface_->context_provider())
@@ -182,9 +187,11 @@
       main_thread_task_runner_.get(), 0, 1, delegated_sync_points_required,
       settings_.renderer_settings.use_gpu_memory_buffer_resources,
       settings_.use_image_texture_targets);
-  renderer_ = SoftwareRenderer::Create(
-      this, &settings_.renderer_settings, output_surface_.get(),
-      resource_provider_.get(), true /* use_image_hijack_canvas */);
+  std::unique_ptr<SoftwareRenderer> renderer =
+      SoftwareRenderer::Create(this, &settings_.renderer_settings,
+                               output_surface_.get(), resource_provider_.get());
+  software_renderer_ = renderer.get();
+  renderer_ = std::move(renderer);
 }
 
 }  // namespace cc
diff --git a/cc/test/pixel_test.h b/cc/test/pixel_test.h
index 90f349b0..4f9eb6e 100644
--- a/cc/test/pixel_test.h
+++ b/cc/test/pixel_test.h
@@ -58,6 +58,7 @@
   std::unique_ptr<ResourceProvider> resource_provider_;
   std::unique_ptr<TextureMailboxDeleter> texture_mailbox_deleter_;
   std::unique_ptr<DirectRenderer> renderer_;
+  SoftwareRenderer* software_renderer_ = nullptr;
   std::unique_ptr<SkBitmap> result_bitmap_;
   gfx::Vector2d external_device_viewport_offset_;
   gfx::Rect external_device_clip_rect_;
@@ -118,11 +119,7 @@
                                        const RendererSettings* settings,
                                        OutputSurface* output_surface,
                                        ResourceProvider* resource_provider)
-      : SoftwareRenderer(client,
-                         settings,
-                         output_surface,
-                         resource_provider,
-                         true /* use_image_hijack_canvas */) {}
+      : SoftwareRenderer(client, settings, output_surface, resource_provider) {}
 };
 
 class GLRendererWithFlippedSurface : public GLRenderer {
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index 3f83286..950f8f0 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -932,7 +932,7 @@
   // Get the resource.
   uint64_t resource_content_id = 0;
   Resource* resource = nullptr;
-  if (use_partial_raster_ && tile->invalidated_id()) {
+  if (UsePartialRaster() && tile->invalidated_id()) {
     // TODO(danakj): For resources that are in use, we should still grab them
     // and copy from them instead of rastering everything. crbug.com/492754
     resource =
@@ -1229,8 +1229,7 @@
 }
 
 bool TileManager::DetermineResourceRequiresSwizzle(const Tile* tile) const {
-  return raster_buffer_provider_->GetResourceRequiresSwizzle(
-      !tile->is_opaque());
+  return raster_buffer_provider_->IsResourceSwizzleRequired(!tile->is_opaque());
 }
 
 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
@@ -1246,6 +1245,11 @@
   return std::move(state);
 }
 
+bool TileManager::UsePartialRaster() const {
+  return use_partial_raster_ &&
+         raster_buffer_provider_->IsPartialRasterSupported();
+}
+
 // Utility function that can be used to create a "Task set finished" task that
 // posts |callback| to |task_runner| when run.
 scoped_refptr<TileTask> TileManager::CreateTaskSetFinishedTask(
diff --git a/cc/tiles/tile_manager.h b/cc/tiles/tile_manager.h
index 87a8e5c..ce69a7d 100644
--- a/cc/tiles/tile_manager.h
+++ b/cc/tiles/tile_manager.h
@@ -293,6 +293,8 @@
   std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
   ScheduledTasksStateAsValue() const;
 
+  bool UsePartialRaster() const;
+
   TileManagerClient* client_;
   base::SequencedTaskRunner* task_runner_;
   ResourcePool* resource_pool_;
diff --git a/cc/trees/clip_node.cc b/cc/trees/clip_node.cc
new file mode 100644
index 0000000..b5efb98f
--- /dev/null
+++ b/cc/trees/clip_node.cc
@@ -0,0 +1,111 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_argument.h"
+#include "cc/base/math_util.h"
+#include "cc/proto/gfx_conversions.h"
+#include "cc/proto/property_tree.pb.h"
+#include "cc/trees/clip_node.h"
+
+namespace cc {
+
+ClipNode::ClipNode()
+    : id(-1),
+      parent_id(-1),
+      owner_id(-1),
+      transform_id(-1),
+      target_id(-1),
+      applies_local_clip(true),
+      layer_clipping_uses_only_local_clip(false),
+      target_is_clipped(false),
+      layers_are_clipped(false),
+      layers_are_clipped_when_surfaces_disabled(false),
+      resets_clip(false) {}
+
+ClipNode::ClipNode(const ClipNode& other) = default;
+
+bool ClipNode::operator==(const ClipNode& other) const {
+  return id == other.id && parent_id == other.parent_id &&
+         owner_id == other.owner_id && clip == other.clip &&
+         combined_clip_in_target_space == other.combined_clip_in_target_space &&
+         clip_in_target_space == other.clip_in_target_space &&
+         transform_id == other.transform_id && target_id == other.target_id &&
+         applies_local_clip == other.applies_local_clip &&
+         layer_clipping_uses_only_local_clip ==
+             other.layer_clipping_uses_only_local_clip &&
+         target_is_clipped == other.target_is_clipped &&
+         layers_are_clipped == other.layers_are_clipped &&
+         layers_are_clipped_when_surfaces_disabled ==
+             other.layers_are_clipped_when_surfaces_disabled &&
+         resets_clip == other.resets_clip;
+}
+
+void ClipNode::ToProtobuf(proto::TreeNode* proto) const {
+  proto->set_id(id);
+  proto->set_parent_id(parent_id);
+  proto->set_owner_id(owner_id);
+
+  DCHECK(!proto->has_clip_node_data());
+  proto::ClipNodeData* data = proto->mutable_clip_node_data();
+
+  RectFToProto(clip, data->mutable_clip());
+  RectFToProto(combined_clip_in_target_space,
+               data->mutable_combined_clip_in_target_space());
+  RectFToProto(clip_in_target_space, data->mutable_clip_in_target_space());
+
+  data->set_transform_id(transform_id);
+  data->set_target_id(target_id);
+  data->set_applies_local_clip(applies_local_clip);
+  data->set_layer_clipping_uses_only_local_clip(
+      layer_clipping_uses_only_local_clip);
+  data->set_target_is_clipped(target_is_clipped);
+  data->set_layers_are_clipped(layers_are_clipped);
+  data->set_layers_are_clipped_when_surfaces_disabled(
+      layers_are_clipped_when_surfaces_disabled);
+  data->set_resets_clip(resets_clip);
+}
+
+void ClipNode::FromProtobuf(const proto::TreeNode& proto) {
+  id = proto.id();
+  parent_id = proto.parent_id();
+  owner_id = proto.owner_id();
+
+  DCHECK(proto.has_clip_node_data());
+  const proto::ClipNodeData& data = proto.clip_node_data();
+
+  clip = ProtoToRectF(data.clip());
+  combined_clip_in_target_space =
+      ProtoToRectF(data.combined_clip_in_target_space());
+  clip_in_target_space = ProtoToRectF(data.clip_in_target_space());
+
+  transform_id = data.transform_id();
+  target_id = data.target_id();
+  applies_local_clip = data.applies_local_clip();
+  layer_clipping_uses_only_local_clip =
+      data.layer_clipping_uses_only_local_clip();
+  target_is_clipped = data.target_is_clipped();
+  layers_are_clipped = data.layers_are_clipped();
+  layers_are_clipped_when_surfaces_disabled =
+      data.layers_are_clipped_when_surfaces_disabled();
+  resets_clip = data.resets_clip();
+}
+
+void ClipNode::AsValueInto(base::trace_event::TracedValue* value) const {
+  value->SetInteger("id", id);
+  value->SetInteger("parent_id", parent_id);
+  value->SetInteger("owner_id", owner_id);
+  MathUtil::AddToTracedValue("clip", clip, value);
+  value->SetInteger("transform_id", transform_id);
+  value->SetInteger("target_id", target_id);
+  value->SetBoolean("applies_local_clip", applies_local_clip);
+  value->SetBoolean("layer_clipping_uses_only_local_clip",
+                    layer_clipping_uses_only_local_clip);
+  value->SetBoolean("target_is_clipped", target_is_clipped);
+  value->SetBoolean("layers_are_clipped", layers_are_clipped);
+  value->SetBoolean("layers_are_clipped_when_surfaces_disabled",
+                    layers_are_clipped_when_surfaces_disabled);
+  value->SetBoolean("resets_clip", resets_clip);
+}
+
+}  // namespace cc
diff --git a/cc/trees/clip_node.h b/cc/trees/clip_node.h
new file mode 100644
index 0000000..289930b
--- /dev/null
+++ b/cc/trees/clip_node.h
@@ -0,0 +1,82 @@
+// 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 CC_TREES_CLIP_NODE_H_
+#define CC_TREES_CLIP_NODE_H_
+
+#include "cc/base/cc_export.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace base {
+namespace trace_event {
+class TracedValue;
+}  // namespace trace_event
+}  // namespace base
+
+namespace cc {
+
+namespace proto {
+class TreeNode;
+}  // namespace proto
+
+struct CC_EXPORT ClipNode {
+  ClipNode();
+  ClipNode(const ClipNode& other);
+
+  int id;
+  int parent_id;
+  int owner_id;
+
+  // The clip rect that this node contributes, expressed in the space of its
+  // transform node.
+  gfx::RectF clip;
+
+  // Clip nodes are uses for two reasons. First, they are used for determining
+  // which parts of each layer are visible. Second, they are used for
+  // determining whether a clip needs to be applied when drawing a layer, and if
+  // so, the rect that needs to be used. These can be different since not all
+  // clips need to be applied directly to each layer. For example, a layer is
+  // implicitly clipped by the bounds of its target render surface and by clips
+  // applied to this surface. |combined_clip_in_target_space| is used for
+  // computing visible rects, and |clip_in_target_space| is used for computing
+  // clips applied at draw time. Both rects are expressed in the space of the
+  // target transform node, and may include clips contributed by ancestors.
+  gfx::RectF combined_clip_in_target_space;
+  gfx::RectF clip_in_target_space;
+
+  // The id of the transform node that defines the clip node's local space.
+  int transform_id;
+
+  // The id of the transform node that defines the clip node's target space.
+  int target_id;
+
+  // Whether this node contributes a new clip (that is, whether |clip| needs to
+  // be applied), rather than only inheriting ancestor clips.
+  bool applies_local_clip : 1;
+
+  // When true, |clip_in_target_space| does not include clips from ancestor
+  // nodes.
+  bool layer_clipping_uses_only_local_clip : 1;
+
+  // True if target surface needs to be drawn with a clip applied.
+  bool target_is_clipped : 1;
+
+  // True if layers with this clip tree node need to be drawn with a clip
+  // applied.
+  bool layers_are_clipped : 1;
+  bool layers_are_clipped_when_surfaces_disabled : 1;
+
+  // Nodes that correspond to unclipped surfaces disregard ancestor clips.
+  bool resets_clip : 1;
+
+  bool operator==(const ClipNode& other) const;
+
+  void ToProtobuf(proto::TreeNode* proto) const;
+  void FromProtobuf(const proto::TreeNode& proto);
+  void AsValueInto(base::trace_event::TracedValue* value) const;
+};
+
+}  // namespace cc
+
+#endif  // CC_TREES_CLIP_NODE_H_
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc
index f2c7022..612c9a9 100644
--- a/cc/trees/draw_property_utils.cc
+++ b/cc/trees/draw_property_utils.cc
@@ -12,10 +12,13 @@
 #include "cc/layers/draw_properties.h"
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_impl.h"
+#include "cc/trees/clip_node.h"
+#include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/property_tree.h"
 #include "cc/trees/property_tree_builder.h"
+#include "cc/trees/transform_node.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 
 namespace cc {
@@ -46,45 +49,89 @@
           layer->effect_tree_index());
   if (effect_node->owner_id != layer->id())
     return;
-  DCHECK_EQ(effect_node->data.mask_layer_id, -1) << "layer: " << layer->id();
-  DCHECK_EQ(effect_node->data.replica_layer_id, -1) << "layer: " << layer->id();
-  DCHECK(effect_node->data.background_filters.IsEmpty());
+  DCHECK_EQ(effect_node->mask_layer_id, -1) << "layer: " << layer->id();
+  DCHECK_EQ(effect_node->replica_layer_id, -1) << "layer: " << layer->id();
+  DCHECK(effect_node->background_filters.IsEmpty());
 }
 
 #endif
 
+static void AddSublayerScaleToTransform(const int effect_node_id,
+                                        const EffectTree& effect_tree,
+                                        gfx::Transform* transform) {
+  const EffectNode* effect_node = effect_tree.Node(effect_node_id);
+  const EffectNode* target_effect_node =
+      effect_node->has_render_surface
+          ? effect_node
+          : effect_tree.Node(effect_node->target_id);
+  transform->matrix().postScale(target_effect_node->sublayer_scale.x(),
+                                target_effect_node->sublayer_scale.y(), 1.f);
+}
+
+#if DCHECK_IS_ON()
+void VerifySublayerScalesMatch(const int effect_node_id,
+                               const int target_transform_id,
+                               const EffectTree& effect_tree,
+                               const TransformTree& transform_tree) {
+  const TransformNode* target_transform_node =
+      transform_tree.Node(target_transform_id);
+  const EffectNode* effect_node = effect_tree.Node(effect_node_id);
+  const EffectNode* target_effect_node =
+      effect_node->has_render_surface
+          ? effect_node
+          : effect_tree.Node(effect_node->target_id);
+  DCHECK(target_transform_node->sublayer_scale ==
+         target_effect_node->sublayer_scale)
+      << " sublayer scale from transform tree: "
+      << target_transform_node->sublayer_scale.ToString()
+      << " sublayer scale from effect tree: "
+      << target_effect_node->sublayer_scale.ToString();
+}
+#endif
+
 template <typename LayerType>
 bool ComputeClipRectInTargetSpace(const LayerType* layer,
                                   const ClipNode* clip_node,
                                   const TransformTree& transform_tree,
+                                  const EffectTree& effect_tree,
                                   int target_node_id,
                                   gfx::RectF* clip_rect_in_target_space) {
   DCHECK(layer->clip_tree_index() == clip_node->id);
-  DCHECK(clip_node->data.target_id != target_node_id);
+  DCHECK(clip_node->target_id != target_node_id);
 
   gfx::Transform clip_to_target;
-  if (clip_node->data.target_id > target_node_id) {
+  if (clip_node->target_id > target_node_id) {
     // In this case, layer has a scroll parent. We need to keep the scale
     // at the layer's target but remove the scale at the scroll parent's
     // target.
-    if (transform_tree.ComputeTransformWithDestinationSublayerScale(
-            clip_node->data.target_id, target_node_id, &clip_to_target)) {
+    if (transform_tree.ComputeTransform(clip_node->target_id, target_node_id,
+                                        &clip_to_target)) {
+      // We don't have to apply sublayer scale when target is root.
+      if (target_node_id != 0) {
+        AddSublayerScaleToTransform(layer->effect_tree_index(), effect_tree,
+                                    &clip_to_target);
+#if DCHECK_IS_ON()
+        VerifySublayerScalesMatch(layer->effect_tree_index(), target_node_id,
+                                  effect_tree, transform_tree);
+#endif
+      }
+
       const TransformNode* source_node =
-          transform_tree.Node(clip_node->data.target_id);
-      if (source_node->data.sublayer_scale.x() != 0.f &&
-          source_node->data.sublayer_scale.y() != 0.f)
-        clip_to_target.Scale(1.0f / source_node->data.sublayer_scale.x(),
-                             1.0f / source_node->data.sublayer_scale.y());
+          transform_tree.Node(clip_node->target_id);
+      if (source_node->sublayer_scale.x() != 0.f &&
+          source_node->sublayer_scale.y() != 0.f)
+        clip_to_target.Scale(1.0f / source_node->sublayer_scale.x(),
+                             1.0f / source_node->sublayer_scale.y());
       *clip_rect_in_target_space = MathUtil::MapClippedRect(
-          clip_to_target, clip_node->data.clip_in_target_space);
+          clip_to_target, clip_node->clip_in_target_space);
     } else {
       return false;
     }
   } else {
-    if (transform_tree.ComputeTransform(clip_node->data.target_id,
-                                        target_node_id, &clip_to_target)) {
+    if (transform_tree.ComputeTransform(clip_node->target_id, target_node_id,
+                                        &clip_to_target)) {
       *clip_rect_in_target_space = MathUtil::ProjectClippedRect(
-          clip_to_target, clip_node->data.clip_in_target_space);
+          clip_to_target, clip_node->clip_in_target_space);
     } else {
       return false;
     }
@@ -138,14 +185,14 @@
 static ConditionalClip ComputeCurrentClip(const ClipNode* clip_node,
                                           const TransformTree& transform_tree,
                                           int target_transform_id) {
-  if (clip_node->data.transform_id != target_transform_id)
-    return ComputeLocalRectInTargetSpace(clip_node->data.clip, transform_tree,
-                                         clip_node->data.transform_id,
+  if (clip_node->transform_id != target_transform_id)
+    return ComputeLocalRectInTargetSpace(clip_node->clip, transform_tree,
+                                         clip_node->transform_id,
                                          target_transform_id);
 
-  gfx::RectF current_clip = clip_node->data.clip;
+  gfx::RectF current_clip = clip_node->clip;
   gfx::Vector2dF sublayer_scale =
-      transform_tree.Node(target_transform_id)->data.sublayer_scale;
+      transform_tree.Node(target_transform_id)->sublayer_scale;
   if (sublayer_scale.x() > 0 && sublayer_scale.y() > 0)
     current_clip.Scale(sublayer_scale.x(), sublayer_scale.y());
   return ConditionalClip{true /* is_clipped */, current_clip};
@@ -159,7 +206,7 @@
     const TransformTree& transform_tree) {
   const ClipNode* clip_node = clip_tree.Node(local_clip_id);
   const EffectNode* target_node = effect_tree.Node(target_id);
-  int target_transform_id = target_node->data.transform_id;
+  int target_transform_id = target_node->transform_id;
   bool is_clipped = false;
 
   // Collect all the clips that need to be accumulated.
@@ -168,17 +215,17 @@
   // If target is not direct ancestor of clip, this will find least common
   // ancestor between the target and the clip.
   while (target_node->id >= 0 && clip_node->id >= 0) {
-    while (target_node->data.clip_id > clip_node->id ||
-           target_node->data.has_unclipped_descendants) {
-      target_node = effect_tree.Node(target_node->data.target_id);
+    while (target_node->clip_id > clip_node->id ||
+           target_node->has_unclipped_descendants) {
+      target_node = effect_tree.Node(target_node->target_id);
     }
-    if (target_node->data.clip_id == clip_node->id)
+    if (target_node->clip_id == clip_node->id)
       break;
-    while (target_node->data.clip_id < clip_node->id) {
+    while (target_node->clip_id < clip_node->id) {
       parent_chain.push(clip_node);
       clip_node = clip_tree.parent(clip_node);
     }
-    if (target_node->data.clip_id == clip_node->id) {
+    if (target_node->clip_id == clip_node->id) {
       // Target is responsible for applying this clip_node (id equals to
       // target_node's clip id), no need to accumulate this as part of clip
       // rect.
@@ -190,12 +237,12 @@
 
   // TODO(weiliangc): If we don't create clip for render surface, we don't need
   // to check applies_local_clip.
-  while (!clip_node->data.applies_local_clip && parent_chain.size() > 0) {
+  while (!clip_node->applies_local_clip && parent_chain.size() > 0) {
     clip_node = parent_chain.top();
     parent_chain.pop();
   }
 
-  if (!clip_node->data.applies_local_clip)
+  if (!clip_node->applies_local_clip)
     // No clip node applying clip in between.
     return ConditionalClip{false, gfx::RectF()};
 
@@ -207,7 +254,7 @@
   while (parent_chain.size() > 0) {
     clip_node = parent_chain.top();
     parent_chain.pop();
-    if (!clip_node->data.applies_local_clip) {
+    if (!clip_node->applies_local_clip) {
       continue;
     }
     ConditionalClip current_clip =
@@ -237,14 +284,14 @@
     const ClipNode* clip_node = clip_tree.Node(layer->clip_tree_index());
     if (!non_root_surfaces_enabled) {
       layer->set_clip_rect(
-          gfx::ToEnclosingRect(clip_node->data.clip_in_target_space));
+          gfx::ToEnclosingRect(clip_node->clip_in_target_space));
       continue;
     }
 
     // When both the layer and the target are unclipped, the entire layer
     // content rect is visible.
-    const bool fully_visible = !clip_node->data.layers_are_clipped &&
-                               !clip_node->data.target_is_clipped;
+    const bool fully_visible =
+        !clip_node->layers_are_clipped && !clip_node->target_is_clipped;
 
     if (!fully_visible) {
       const TransformNode* transform_node =
@@ -252,22 +299,21 @@
       int target_node_id = transform_tree.ContentTargetId(transform_node->id);
 
       // The clip node stores clip rect in its target space.
-      gfx::RectF clip_rect_in_target_space =
-          clip_node->data.clip_in_target_space;
+      gfx::RectF clip_rect_in_target_space = clip_node->clip_in_target_space;
 
       // If required, this clip rect should be mapped to the current layer's
       // target space.
-      if (clip_node->data.target_id != target_node_id) {
+      if (clip_node->target_id != target_node_id) {
         // In this case, layer has a clip parent or scroll parent (or shares the
         // target with an ancestor layer that has clip parent) and the clip
         // parent's target is different from the layer's target. As the layer's
         // target has unclippped descendants, it is unclippped.
-        if (!clip_node->data.layers_are_clipped)
+        if (!clip_node->layers_are_clipped)
           continue;
 
         // Compute the clip rect in target space and store it.
         if (!ComputeClipRectInTargetSpace(layer, clip_node, transform_tree,
-                                          target_node_id,
+                                          effect_tree, target_node_id,
                                           &clip_rect_in_target_space))
           continue;
       }
@@ -284,21 +330,23 @@
 bool GetLayerClipRect(const scoped_refptr<Layer> layer,
                       const ClipNode* clip_node,
                       const TransformTree& transform_tree,
+                      const EffectTree& effect_tree,
                       int target_node_id,
                       gfx::RectF* clip_rect_in_target_space) {
   return ComputeClipRectInTargetSpace(layer.get(), clip_node, transform_tree,
-                                      target_node_id,
+                                      effect_tree, target_node_id,
                                       clip_rect_in_target_space);
 }
 
 bool GetLayerClipRect(const LayerImpl* layer,
                       const ClipNode* clip_node,
                       const TransformTree& transform_tree,
+                      const EffectTree& effect_tree,
                       int target_node_id,
                       gfx::RectF* clip_rect_in_target_space) {
   // This is equivalent of calling ComputeClipRectInTargetSpace.
   *clip_rect_in_target_space = gfx::RectF(layer->clip_rect());
-  return transform_tree.Node(target_node_id)->data.ancestors_are_invertible;
+  return transform_tree.Node(target_node_id)->ancestors_are_invertible;
 }
 
 template <typename LayerType>
@@ -330,7 +378,7 @@
           effect_tree.Node(effect_ancestor_with_copy_request);
       ConditionalClip clip_in_layer_space = ComputeTargetRectInLocalSpace(
           accumulated_clip_in_copy_request_space, transform_tree,
-          copy_request_effect_node->data.transform_id,
+          copy_request_effect_node->transform_id,
           layer->transform_tree_index());
 
       if (clip_in_layer_space.is_clipped) {
@@ -351,9 +399,9 @@
     if (!non_root_surfaces_enabled) {
       // When we only have a root surface, the clip node and the layer must
       // necessarily have the same target (the root).
-      if (transform_node->data.ancestors_are_invertible) {
+      if (transform_node->ancestors_are_invertible) {
         gfx::RectF combined_clip_rect_in_target_space =
-            clip_node->data.combined_clip_in_target_space;
+            clip_node->combined_clip_in_target_space;
         gfx::Transform target_to_content;
         target_to_content.Translate(-layer->offset_to_transform_parent().x(),
                                     -layer->offset_to_transform_parent().y());
@@ -373,8 +421,8 @@
 
     // When both the layer and the target are unclipped, the entire layer
     // content rect is visible.
-    const bool fully_visible = !clip_node->data.layers_are_clipped &&
-                               !clip_node->data.target_is_clipped;
+    const bool fully_visible =
+        !clip_node->layers_are_clipped && !clip_node->target_is_clipped;
 
     if (fully_visible) {
       layer->set_visible_layer_rect(gfx::Rect(layer_bounds));
@@ -387,12 +435,12 @@
     // this clip rect should be mapped to the current layer's target space.
     gfx::RectF combined_clip_rect_in_target_space;
 
-    if (clip_node->data.target_id != target_node_id) {
+    if (clip_node->target_id != target_node_id) {
       // In this case, layer has a clip parent or scroll parent (or shares the
       // target with an ancestor layer that has clip parent) and the clip
       // parent's target is different from the layer's target. As the layer's
       // target has unclippped descendants, it is unclippped.
-      if (!clip_node->data.layers_are_clipped) {
+      if (!clip_node->layers_are_clipped) {
         layer->set_visible_layer_rect(gfx::Rect(layer_bounds));
         continue;
       }
@@ -403,18 +451,18 @@
       // the combined clip has even the clip parent's target's clip baked into
       // it and as our target is different, we don't want to use it in our
       // visible rect computation.
-      if (!GetLayerClipRect(layer, clip_node, transform_tree, target_node_id,
+      if (!GetLayerClipRect(layer, clip_node, transform_tree, effect_tree,
+                            target_node_id,
                             &combined_clip_rect_in_target_space)) {
         layer->set_visible_layer_rect(gfx::Rect(layer_bounds));
         continue;
       }
     } else {
-      if (clip_node->data.target_is_clipped) {
+      if (clip_node->target_is_clipped) {
         combined_clip_rect_in_target_space =
-            clip_node->data.combined_clip_in_target_space;
+            clip_node->combined_clip_in_target_space;
       } else {
-        combined_clip_rect_in_target_space =
-            clip_node->data.clip_in_target_space;
+        combined_clip_rect_in_target_space = clip_node->clip_in_target_space;
       }
     }
 
@@ -443,7 +491,7 @@
     }
 
     gfx::Transform target_to_layer;
-    if (transform_node->data.ancestors_are_invertible) {
+    if (transform_node->ancestors_are_invertible) {
       target_to_layer = transform_tree.FromTarget(transform_node->id);
     } else {
       if (!transform_tree.ComputeTransformWithSourceSublayerScale(
@@ -471,7 +519,7 @@
 static bool HasSingularTransform(int transform_tree_index,
                                  const TransformTree& tree) {
   const TransformNode* node = tree.Node(transform_tree_index);
-  return !node->data.is_invertible || !node->data.ancestors_are_invertible;
+  return !node->is_invertible || !node->ancestors_are_invertible;
 }
 
 template <typename LayerType>
@@ -489,7 +537,7 @@
                                    const TransformTree& tree) {
   const TransformNode* node = tree.Node(transform_tree_index);
   return layer->use_local_transform_for_backface_visibility()
-             ? node->data.local.IsBackFaceVisible()
+             ? node->local.IsBackFaceVisible()
              : tree.ToTarget(transform_tree_index).IsBackFaceVisible();
 }
 
@@ -497,7 +545,7 @@
                                             int transform_tree_index,
                                             const TransformTree& tree) {
   const TransformNode* node = tree.Node(transform_tree_index);
-  return !node->data.to_screen_is_potentially_animated;
+  return !node->to_screen_is_potentially_animated;
 }
 
 static inline bool TransformToScreenIsKnown(LayerImpl* layer,
@@ -554,7 +602,7 @@
                                std::vector<LayerImpl*>* visible_layer_list) {
   for (auto* layer_impl : *layer_tree_impl) {
     bool layer_is_drawn =
-        effect_tree.Node(layer_impl->effect_tree_index())->data.is_drawn;
+        effect_tree.Node(layer_impl->effect_tree_index())->is_drawn;
 
     if (!IsRootLayer(layer_impl) &&
         LayerShouldBeSkipped(layer_impl, layer_is_drawn, transform_tree,
@@ -576,7 +624,7 @@
 
   EffectNode* node = effect_tree->Node(layer->effect_tree_index());
 
-  if (node->owner_id == layer->id() && node->data.has_render_surface)
+  if (node->owner_id == layer->id() && node->has_render_surface)
     layer->SetHasRenderSurface(true);
   else
     layer->SetHasRenderSurface(false);
@@ -593,16 +641,15 @@
       transform_tree.Node(layer->transform_tree_index());
   const EffectNode* effect_node = effect_tree.Node(layer->effect_tree_index());
 
-  if (effect_node->data.has_render_surface &&
-      effect_node->data.num_copy_requests_in_subtree > 0)
+  if (effect_node->has_render_surface &&
+      effect_node->num_copy_requests_in_subtree > 0)
     return false;
   // If the layer transform is not invertible, it should be skipped.
   // TODO(ajuma): Correctly process subtrees with singular transform for the
   // case where we may animate to a non-singular transform and wish to
   // pre-raster.
-  return !transform_node->data.node_and_ancestors_are_animated_or_invertible ||
-         effect_node->data.hidden_by_backface_visibility ||
-         !effect_node->data.is_drawn;
+  return !transform_node->node_and_ancestors_are_animated_or_invertible ||
+         effect_node->hidden_by_backface_visibility || !effect_node->is_drawn;
 }
 
 bool LayerShouldBeSkipped(LayerImpl* layer,
@@ -627,7 +674,7 @@
                                LayerList* update_layer_list) {
   for (auto* layer : *layer_tree_host) {
     bool layer_is_drawn =
-        effect_tree.Node(layer->effect_tree_index())->data.is_drawn;
+        effect_tree.Node(layer->effect_tree_index())->is_drawn;
 
     if (!IsRootLayer(layer) &&
         LayerShouldBeSkipped(layer, layer_is_drawn, transform_tree,
@@ -665,18 +712,18 @@
     ClipNode* clip_node = clip_tree->Node(i);
 
     if (clip_node->id == 1) {
-      ResetIfHasNanCoordinate(&clip_node->data.clip);
-      clip_node->data.clip_in_target_space = clip_node->data.clip;
-      clip_node->data.combined_clip_in_target_space = clip_node->data.clip;
+      ResetIfHasNanCoordinate(&clip_node->clip);
+      clip_node->clip_in_target_space = clip_node->clip;
+      clip_node->combined_clip_in_target_space = clip_node->clip;
       continue;
     }
     const TransformNode* transform_node =
-        transform_tree.Node(clip_node->data.transform_id);
+        transform_tree.Node(clip_node->transform_id);
     ClipNode* parent_clip_node = clip_tree->parent(clip_node);
 
     gfx::Transform parent_to_current;
     const TransformNode* parent_target_transform_node =
-        transform_tree.Node(parent_clip_node->data.target_id);
+        transform_tree.Node(parent_clip_node->target_id);
     bool success = true;
 
     // Clips must be combined in target space. We cannot, for example, combine
@@ -690,110 +737,105 @@
     // target space. So, we need to get the ancestor clip rect in the current
     // clip node's target space.
     gfx::RectF parent_combined_clip_in_target_space =
-        parent_clip_node->data.combined_clip_in_target_space;
+        parent_clip_node->combined_clip_in_target_space;
     gfx::RectF parent_clip_in_target_space =
-        parent_clip_node->data.clip_in_target_space;
+        parent_clip_node->clip_in_target_space;
     if (parent_target_transform_node &&
-        parent_target_transform_node->id != clip_node->data.target_id &&
+        parent_target_transform_node->id != clip_node->target_id &&
         non_root_surfaces_enabled) {
       success &= transform_tree.ComputeTransformWithDestinationSublayerScale(
-          parent_target_transform_node->id, clip_node->data.target_id,
+          parent_target_transform_node->id, clip_node->target_id,
           &parent_to_current);
-      if (parent_target_transform_node->data.sublayer_scale.x() > 0 &&
-          parent_target_transform_node->data.sublayer_scale.y() > 0)
+      if (parent_target_transform_node->sublayer_scale.x() > 0 &&
+          parent_target_transform_node->sublayer_scale.y() > 0)
         parent_to_current.Scale(
-            1.f / parent_target_transform_node->data.sublayer_scale.x(),
-            1.f / parent_target_transform_node->data.sublayer_scale.y());
+            1.f / parent_target_transform_node->sublayer_scale.x(),
+            1.f / parent_target_transform_node->sublayer_scale.y());
       // If we can't compute a transform, it's because we had to use the inverse
       // of a singular transform. We won't draw in this case, so there's no need
       // to compute clips.
       if (!success)
         continue;
       parent_combined_clip_in_target_space = MathUtil::ProjectClippedRect(
-          parent_to_current,
-          parent_clip_node->data.combined_clip_in_target_space);
+          parent_to_current, parent_clip_node->combined_clip_in_target_space);
       parent_clip_in_target_space = MathUtil::ProjectClippedRect(
-          parent_to_current, parent_clip_node->data.clip_in_target_space);
+          parent_to_current, parent_clip_node->clip_in_target_space);
     }
     // Only nodes affected by ancestor clips will have their clip adjusted due
     // to intersecting with an ancestor clip. But, we still need to propagate
     // the combined clip to our children because if they are clipped, they may
     // need to clip using our parent clip and if we don't propagate it here,
     // it will be lost.
-    if (clip_node->data.resets_clip && non_root_surfaces_enabled) {
-      if (clip_node->data.applies_local_clip) {
-        clip_node->data.clip_in_target_space = MathUtil::MapClippedRect(
-            transform_tree.ToTarget(clip_node->data.transform_id),
-            clip_node->data.clip);
-        ResetIfHasNanCoordinate(&clip_node->data.clip_in_target_space);
-        clip_node->data.combined_clip_in_target_space =
-            gfx::IntersectRects(clip_node->data.clip_in_target_space,
+    if (clip_node->resets_clip && non_root_surfaces_enabled) {
+      if (clip_node->applies_local_clip) {
+        clip_node->clip_in_target_space = MathUtil::MapClippedRect(
+            transform_tree.ToTarget(clip_node->transform_id), clip_node->clip);
+        ResetIfHasNanCoordinate(&clip_node->clip_in_target_space);
+        clip_node->combined_clip_in_target_space =
+            gfx::IntersectRects(clip_node->clip_in_target_space,
                                 parent_combined_clip_in_target_space);
       } else {
-        DCHECK(!clip_node->data.target_is_clipped);
-        DCHECK(!clip_node->data.layers_are_clipped);
-        clip_node->data.combined_clip_in_target_space =
+        DCHECK(!clip_node->target_is_clipped);
+        DCHECK(!clip_node->layers_are_clipped);
+        clip_node->combined_clip_in_target_space =
             parent_combined_clip_in_target_space;
       }
-      ResetIfHasNanCoordinate(&clip_node->data.combined_clip_in_target_space);
+      ResetIfHasNanCoordinate(&clip_node->combined_clip_in_target_space);
       continue;
     }
-    bool use_only_parent_clip = !clip_node->data.applies_local_clip;
+    bool use_only_parent_clip = !clip_node->applies_local_clip;
     if (use_only_parent_clip) {
-      clip_node->data.combined_clip_in_target_space =
+      clip_node->combined_clip_in_target_space =
           parent_combined_clip_in_target_space;
       if (!non_root_surfaces_enabled) {
-        clip_node->data.clip_in_target_space =
-            parent_clip_node->data.clip_in_target_space;
-      } else if (!clip_node->data.target_is_clipped) {
-        clip_node->data.clip_in_target_space = parent_clip_in_target_space;
+        clip_node->clip_in_target_space =
+            parent_clip_node->clip_in_target_space;
+      } else if (!clip_node->target_is_clipped) {
+        clip_node->clip_in_target_space = parent_clip_in_target_space;
       } else {
         // Render Surface applies clip and the owning layer itself applies
         // no clip. So, clip_in_target_space is not used and hence we can set
         // it to an empty rect.
-        clip_node->data.clip_in_target_space = gfx::RectF();
+        clip_node->clip_in_target_space = gfx::RectF();
       }
     } else {
       gfx::Transform source_to_target;
 
       if (!non_root_surfaces_enabled) {
-        source_to_target =
-            transform_tree.ToScreen(clip_node->data.transform_id);
+        source_to_target = transform_tree.ToScreen(clip_node->transform_id);
       } else if (transform_tree.ContentTargetId(transform_node->id) ==
-                 clip_node->data.target_id) {
-        source_to_target =
-            transform_tree.ToTarget(clip_node->data.transform_id);
+                 clip_node->target_id) {
+        source_to_target = transform_tree.ToTarget(clip_node->transform_id);
       } else {
         success = transform_tree.ComputeTransformWithDestinationSublayerScale(
-            transform_node->id, clip_node->data.target_id, &source_to_target);
+            transform_node->id, clip_node->target_id, &source_to_target);
         // source_to_target computation should be successful as target is an
         // ancestor of the transform node.
         DCHECK(success);
       }
 
       gfx::RectF source_clip_in_target_space =
-          MathUtil::MapClippedRect(source_to_target, clip_node->data.clip);
+          MathUtil::MapClippedRect(source_to_target, clip_node->clip);
 
       // With surfaces disabled, the only case where we use only the local clip
       // for layer clipping is the case where no non-viewport ancestor node
       // applies a local clip.
       bool layer_clipping_uses_only_local_clip =
           non_root_surfaces_enabled
-              ? clip_node->data.layer_clipping_uses_only_local_clip
-              : !parent_clip_node->data
-                     .layers_are_clipped_when_surfaces_disabled;
+              ? clip_node->layer_clipping_uses_only_local_clip
+              : !parent_clip_node->layers_are_clipped_when_surfaces_disabled;
       if (!layer_clipping_uses_only_local_clip) {
-        clip_node->data.clip_in_target_space = gfx::IntersectRects(
+        clip_node->clip_in_target_space = gfx::IntersectRects(
             parent_clip_in_target_space, source_clip_in_target_space);
       } else {
-        clip_node->data.clip_in_target_space = source_clip_in_target_space;
+        clip_node->clip_in_target_space = source_clip_in_target_space;
       }
 
-      clip_node->data.combined_clip_in_target_space = gfx::IntersectRects(
+      clip_node->combined_clip_in_target_space = gfx::IntersectRects(
           parent_combined_clip_in_target_space, source_clip_in_target_space);
     }
-    ResetIfHasNanCoordinate(&clip_node->data.clip_in_target_space);
-    ResetIfHasNanCoordinate(&clip_node->data.combined_clip_in_target_space);
+    ResetIfHasNanCoordinate(&clip_node->clip_in_target_space);
+    ResetIfHasNanCoordinate(&clip_node->combined_clip_in_target_space);
   }
   clip_tree->set_needs_update(false);
 }
@@ -812,13 +854,13 @@
     EffectNode* node = effect_tree->Node(i);
     if (i == 1) {
       // Render target on the first effect node is root.
-      node->data.target_id = 0;
+      node->target_id = 0;
     } else if (!can_render_to_separate_surface) {
-      node->data.target_id = 1;
-    } else if (effect_tree->parent(node)->data.has_render_surface) {
-      node->data.target_id = node->parent_id;
+      node->target_id = 1;
+    } else if (effect_tree->parent(node)->has_render_surface) {
+      node->target_id = node->parent_id;
     } else {
-      node->data.target_id = effect_tree->parent(node)->data.target_id;
+      node->target_id = effect_tree->parent(node)->target_id;
     }
   }
 }
@@ -837,9 +879,9 @@
   const TransformTree* transform_tree = &property_trees->transform_tree;
   EffectNode* root_effect_node = effect_tree->Node(1);
   const RenderSurfaceImpl* root_render_surface =
-      root_effect_node->data.render_surface;
-  gfx::Rect root_clip = gfx::ToEnclosingRect(
-      clip_tree->Node(root_effect_node->data.clip_id)->data.clip);
+      root_effect_node->render_surface;
+  gfx::Rect root_clip =
+      gfx::ToEnclosingRect(clip_tree->Node(root_effect_node->clip_id)->clip);
   if (root_render_surface->is_clipped())
     DCHECK(root_clip == root_render_surface->clip_rect())
         << "clip on root render surface: "
@@ -847,13 +889,12 @@
         << " v.s. root effect node's clip: " << root_clip.ToString();
   for (int i = 2; i < static_cast<int>(effect_tree->size()); ++i) {
     EffectNode* effect_node = effect_tree->Node(i);
-    const EffectNode* target_node =
-        effect_tree->Node(effect_node->data.target_id);
+    const EffectNode* target_node = effect_tree->Node(effect_node->target_id);
     ConditionalClip accumulated_clip_rect =
-        ComputeAccumulatedClip(*clip_tree, effect_node->data.clip_id,
-                               *effect_tree, target_node->id, *transform_tree);
+        ComputeAccumulatedClip(*clip_tree, effect_node->clip_id, *effect_tree,
+                               target_node->id, *transform_tree);
     gfx::RectF accumulated_clip = accumulated_clip_rect.clip_rect;
-    const RenderSurfaceImpl* render_surface = effect_node->data.render_surface;
+    const RenderSurfaceImpl* render_surface = effect_node->render_surface;
     if (render_surface && render_surface->is_clipped()) {
       DCHECK(gfx::ToEnclosingRect(accumulated_clip) ==
              render_surface->clip_rect())
@@ -872,9 +913,9 @@
   const TransformTree* transform_tree = &property_trees->transform_tree;
   const EffectNode* effect_node = effect_tree->Node(layer->effect_tree_index());
   const EffectNode* target_node =
-      effect_node->data.has_render_surface
+      effect_node->has_render_surface
           ? effect_node
-          : effect_tree->Node(effect_node->data.target_id);
+          : effect_tree->Node(effect_node->target_id);
   // TODO(weiliangc): When effect node has up to date render surface info on
   // compositor thread, no need to check for resourceless draw mode
   if (!property_trees->non_root_surfaces_enabled) {
@@ -889,15 +930,15 @@
 
   if ((!property_trees->non_root_surfaces_enabled &&
        clip_tree->Node(layer->clip_tree_index())
-           ->data.layers_are_clipped_when_surfaces_disabled) ||
-      clip_tree->Node(layer->clip_tree_index())->data.layers_are_clipped) {
+           ->layers_are_clipped_when_surfaces_disabled) ||
+      clip_tree->Node(layer->clip_tree_index())->layers_are_clipped) {
     DCHECK(layer->clip_rect() == gfx::ToEnclosingRect(accumulated_clip))
         << " layer: " << layer->id() << " clip id: " << layer->clip_tree_index()
         << " layer clip: " << layer->clip_rect().ToString() << " v.s. "
         << gfx::ToEnclosingRect(accumulated_clip).ToString()
         << " and clip node clip: "
-        << gfx::ToEnclosingRect(clip_tree->Node(layer->clip_tree_index())
-                                    ->data.clip_in_target_space)
+        << gfx::ToEnclosingRect(
+               clip_tree->Node(layer->clip_tree_index())->clip_in_target_space)
                .ToString();
   }
 }
@@ -906,10 +947,10 @@
     const EffectTree& effect_tree,
     const int effect_tree_index) {
   const EffectNode* node = effect_tree.Node(effect_tree_index);
-  if (node->data.has_render_surface)
-    return node->data.transform_id;
-  node = effect_tree.Node(node->data.target_id);
-  return node->data.transform_id;
+  if (node->has_render_surface)
+    return node->transform_id;
+  node = effect_tree.Node(node->target_id);
+  return node->transform_id;
 }
 
 static void VerifyDrawTransformsMatch(LayerImpl* layer,
@@ -917,17 +958,19 @@
   const int source_id = layer->transform_tree_index();
   int destination_id = FindTargetTransformTreeIndexFromEffectTree(
       property_trees->effect_tree, layer->effect_tree_index());
-  // TODO(jaydasika) : Remove this after sorting out how sublayer scale works
-  // for these ids.
-  if (destination_id == 0 || destination_id == 1)
-    return;
   gfx::Transform draw_transform;
   property_trees->transform_tree.ComputeTransform(source_id, destination_id,
                                                   &draw_transform);
-  TransformNode* target_node =
-      property_trees->transform_tree.Node(destination_id);
-  draw_transform.matrix().postScale(target_node->data.sublayer_scale.x(),
-                                    target_node->data.sublayer_scale.y(), 1.f);
+  // We don't have to apply sublayer scale when target is root.
+  if (destination_id != 0) {
+    AddSublayerScaleToTransform(layer->effect_tree_index(),
+                                property_trees->effect_tree, &draw_transform);
+#if DCHECK_IS_ON()
+    VerifySublayerScalesMatch(layer->effect_tree_index(), destination_id,
+                              property_trees->effect_tree,
+                              property_trees->transform_tree);
+#endif
+  }
   if (layer->should_flatten_transform_from_property_tree())
     draw_transform.FlattenTo2d();
   draw_transform.Translate(layer->offset_to_transform_parent().x(),
@@ -1049,7 +1092,7 @@
     EffectNode* node =
         property_trees->effect_tree.Node(layer->effect_tree_index());
     if (node->owner_id == layer->id())
-      node->data.render_surface = layer->render_surface();
+      node->render_surface = layer->render_surface();
 #if DCHECK_IS_ON()
     if (can_render_to_separate_surface)
       ValidateRenderSurfaceForLayer(layer);
@@ -1088,28 +1131,44 @@
                     layer->offset_to_transform_parent().y());
   } else {
     // Surfaces need to apply their sublayer scale.
-    xform.Scale(node->data.sublayer_scale.x(), node->data.sublayer_scale.y());
+    xform.Scale(node->sublayer_scale.x(), node->sublayer_scale.y());
   }
   return xform;
 }
 
-static void SetSurfaceDrawTransform(const TransformTree& tree,
+static void SetSurfaceDrawTransform(const TransformTree& transform_tree,
+                                    const EffectTree& effect_tree,
                                     RenderSurfaceImpl* render_surface) {
-  const TransformNode* node = tree.Node(render_surface->TransformTreeIndex());
+  const TransformNode* transform_node =
+      transform_tree.Node(render_surface->TransformTreeIndex());
+  const EffectNode* effect_node =
+      effect_tree.Node(render_surface->EffectTreeIndex());
   // The draw transform of root render surface is identity tranform.
-  if (node->id == 1) {
+  if (transform_node->id == 1) {
     render_surface->SetDrawTransform(gfx::Transform());
     return;
   }
 
   gfx::Transform render_surface_transform;
-  const TransformNode* target_node = tree.Node(tree.TargetId(node->id));
-  tree.ComputeTransformWithDestinationSublayerScale(node->id, target_node->id,
-                                                    &render_surface_transform);
-  if (node->data.sublayer_scale.x() != 0.0 &&
-      node->data.sublayer_scale.y() != 0.0)
-    render_surface_transform.Scale(1.0 / node->data.sublayer_scale.x(),
-                                   1.0 / node->data.sublayer_scale.y());
+  const TransformNode* target_transform_node =
+      transform_tree.Node(transform_tree.TargetId(transform_node->id));
+  transform_tree.ComputeTransform(transform_node->id, target_transform_node->id,
+                                  &render_surface_transform);
+  // We don't have to apply sublayer scale when target is root.
+  if (target_transform_node->id != 0) {
+    AddSublayerScaleToTransform(effect_node->target_id, effect_tree,
+                                &render_surface_transform);
+#if DCHECK_IS_ON()
+    VerifySublayerScalesMatch(effect_node->target_id, target_transform_node->id,
+                              effect_tree, transform_tree);
+#endif
+  }
+
+  DCHECK(transform_node->sublayer_scale == effect_node->sublayer_scale);
+  if (effect_node->sublayer_scale.x() != 0.0 &&
+      effect_node->sublayer_scale.y() != 0.0)
+    render_surface_transform.Scale(1.0 / effect_node->sublayer_scale.x(),
+                                   1.0 / effect_node->sublayer_scale.y());
   render_surface->SetDrawTransform(render_surface_transform);
 }
 
@@ -1118,7 +1177,7 @@
   DCHECK(render_surface->OwningLayerId() == clip_node->owner_id)
       << "we now create clip node for every render surface";
 
-  render_surface->SetIsClipped(clip_node->data.target_is_clipped);
+  render_surface->SetIsClipped(clip_node->target_is_clipped);
 }
 
 static void SetSurfaceClipRect(const ClipNode* parent_clip_node,
@@ -1132,9 +1191,9 @@
   const TransformNode* transform_node =
       transform_tree.Node(render_surface->TransformTreeIndex());
   if (transform_tree.TargetId(transform_node->id) ==
-      parent_clip_node->data.target_id) {
+      parent_clip_node->target_id) {
     render_surface->SetClipRect(
-        gfx::ToEnclosingRect(parent_clip_node->data.clip_in_target_space));
+        gfx::ToEnclosingRect(parent_clip_node->clip_in_target_space));
     return;
   }
 
@@ -1144,7 +1203,7 @@
   gfx::Transform clip_parent_target_to_target;
   const bool success =
       transform_tree.ComputeTransformWithDestinationSublayerScale(
-          parent_clip_node->data.target_id,
+          parent_clip_node->target_id,
           transform_tree.TargetId(transform_node->id),
           &clip_parent_target_to_target);
 
@@ -1153,11 +1212,10 @@
     return;
   }
 
-  DCHECK_LT(parent_clip_node->data.target_id,
+  DCHECK_LT(parent_clip_node->target_id,
             transform_tree.TargetId(transform_node->id));
   render_surface->SetClipRect(gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
-      clip_parent_target_to_target,
-      parent_clip_node->data.clip_in_target_space)));
+      clip_parent_target_to_target, parent_clip_node->clip_in_target_space)));
 }
 
 template <typename LayerType>
@@ -1206,7 +1264,7 @@
   // (included) and its target surface (excluded).
   const EffectNode* node = tree.Node(render_surface->EffectTreeIndex());
   float draw_opacity = tree.EffectiveOpacity(node);
-  for (node = tree.parent(node); node && !node->data.has_render_surface;
+  for (node = tree.parent(node); node && !node->has_render_surface;
        node = tree.parent(node)) {
     draw_opacity *= tree.EffectiveOpacity(node);
   }
@@ -1232,8 +1290,8 @@
   const LayerImpl* replica_layer = render_surface->ReplicaLayer();
   const TransformNode* surface_transform_node =
       tree.Node(render_surface->TransformTreeIndex());
-  replica_to_surface.Scale(surface_transform_node->data.sublayer_scale.x(),
-                           surface_transform_node->data.sublayer_scale.y());
+  replica_to_surface.Scale(surface_transform_node->sublayer_scale.x(),
+                           surface_transform_node->sublayer_scale.y());
   replica_to_surface.Translate(replica_layer->offset_to_transform_parent().x(),
                                replica_layer->offset_to_transform_parent().y());
   gfx::Transform replica_transform_node_to_surface;
@@ -1241,11 +1299,10 @@
                         render_surface->TransformTreeIndex(),
                         &replica_transform_node_to_surface);
   replica_to_surface.PreconcatTransform(replica_transform_node_to_surface);
-  if (surface_transform_node->data.sublayer_scale.x() != 0 &&
-      surface_transform_node->data.sublayer_scale.y() != 0) {
-    replica_to_surface.Scale(
-        1.0 / surface_transform_node->data.sublayer_scale.x(),
-        1.0 / surface_transform_node->data.sublayer_scale.y());
+  if (surface_transform_node->sublayer_scale.x() != 0 &&
+      surface_transform_node->sublayer_scale.y() != 0) {
+    replica_to_surface.Scale(1.0 / surface_transform_node->sublayer_scale.x(),
+                             1.0 / surface_transform_node->sublayer_scale.y());
   }
   return replica_to_surface;
 }
@@ -1267,15 +1324,15 @@
         layer->draw_properties().screen_space_transform;
   }
   layer->draw_properties().screen_space_transform_is_animating =
-      transform_node->data.to_screen_is_potentially_animated;
+      transform_node->to_screen_is_potentially_animated;
 
   layer->draw_properties().opacity =
       LayerDrawOpacity(layer, property_trees->effect_tree);
   if (property_trees->non_root_surfaces_enabled) {
-    layer->draw_properties().is_clipped = clip_node->data.layers_are_clipped;
+    layer->draw_properties().is_clipped = clip_node->layers_are_clipped;
   } else {
     layer->draw_properties().is_clipped =
-        clip_node->data.layers_are_clipped_when_surfaces_disabled;
+        clip_node->layers_are_clipped_when_surfaces_disabled;
   }
 
   gfx::Rect bounds_in_target_space = MathUtil::MapEnclosingClippedRect(
@@ -1303,7 +1360,8 @@
 
   SetSurfaceIsClipped(clip_node, render_surface);
   SetSurfaceDrawOpacity(property_trees->effect_tree, render_surface);
-  SetSurfaceDrawTransform(property_trees->transform_tree, render_surface);
+  SetSurfaceDrawTransform(property_trees->transform_tree,
+                          property_trees->effect_tree, render_surface);
   render_surface->SetScreenSpaceTransform(
       property_trees->transform_tree.ToScreenSpaceTransformWithoutSublayerScale(
           render_surface->TransformTreeIndex()));
@@ -1358,15 +1416,14 @@
     // When the page scale layer is also the root layer, the node should also
     // store the combined scale factor and not just the page scale factor.
     float post_local_scale_factor = page_scale_factor * device_scale_factor;
-    node->data.post_local_scale_factor = post_local_scale_factor;
-    node->data.post_local = device_transform;
-    node->data.post_local.Scale(post_local_scale_factor,
-                                post_local_scale_factor);
+    node->post_local_scale_factor = post_local_scale_factor;
+    node->post_local = device_transform;
+    node->post_local.Scale(post_local_scale_factor, post_local_scale_factor);
   } else {
-    node->data.post_local_scale_factor = page_scale_factor;
-    node->data.update_post_local_transform(gfx::PointF(), gfx::Point3F());
+    node->post_local_scale_factor = page_scale_factor;
+    node->update_post_local_transform(gfx::PointF(), gfx::Point3F());
   }
-  node->data.needs_local_transform_update = true;
+  node->needs_local_transform_update = true;
   property_trees->transform_tree.set_needs_update(true);
 }
 
@@ -1402,11 +1459,11 @@
 
   TransformNode* node = property_trees->transform_tree.Node(
       overscroll_elasticity_layer->transform_tree_index());
-  if (node->data.scroll_offset == gfx::ScrollOffset(elastic_overscroll))
+  if (node->scroll_offset == gfx::ScrollOffset(elastic_overscroll))
     return;
 
-  node->data.scroll_offset = gfx::ScrollOffset(elastic_overscroll);
-  node->data.needs_local_transform_update = true;
+  node->scroll_offset = gfx::ScrollOffset(elastic_overscroll);
+  node->needs_local_transform_update = true;
   property_trees->transform_tree.set_needs_update(true);
 }
 
diff --git a/cc/trees/effect_node.cc b/cc/trees/effect_node.cc
new file mode 100644
index 0000000..c26ddd93
--- /dev/null
+++ b/cc/trees/effect_node.cc
@@ -0,0 +1,141 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_argument.h"
+#include "cc/proto/gfx_conversions.h"
+#include "cc/proto/property_tree.pb.h"
+#include "cc/trees/effect_node.h"
+
+namespace cc {
+
+EffectNode::EffectNode()
+    : id(-1),
+      parent_id(-1),
+      owner_id(-1),
+      opacity(1.f),
+      screen_space_opacity(1.f),
+      has_render_surface(false),
+      render_surface(nullptr),
+      has_copy_request(false),
+      hidden_by_backface_visibility(false),
+      double_sided(false),
+      is_drawn(true),
+      subtree_hidden(false),
+      has_potential_opacity_animation(false),
+      is_currently_animating_opacity(false),
+      effect_changed(false),
+      num_copy_requests_in_subtree(0),
+      has_unclipped_descendants(false),
+      transform_id(0),
+      clip_id(0),
+      target_id(0),
+      mask_layer_id(-1),
+      replica_layer_id(-1),
+      replica_mask_layer_id(-1) {}
+
+EffectNode::EffectNode(const EffectNode& other) = default;
+
+bool EffectNode::operator==(const EffectNode& other) const {
+  return id == other.id && parent_id == other.parent_id &&
+         owner_id == other.owner_id && opacity == other.opacity &&
+         screen_space_opacity == other.screen_space_opacity &&
+         has_render_surface == other.has_render_surface &&
+         has_copy_request == other.has_copy_request &&
+         background_filters == other.background_filters &&
+         sublayer_scale == other.sublayer_scale &&
+         hidden_by_backface_visibility == other.hidden_by_backface_visibility &&
+         double_sided == other.double_sided && is_drawn == other.is_drawn &&
+         subtree_hidden == other.subtree_hidden &&
+         has_potential_opacity_animation ==
+             other.has_potential_opacity_animation &&
+         is_currently_animating_opacity ==
+             other.is_currently_animating_opacity &&
+         effect_changed == other.effect_changed &&
+         num_copy_requests_in_subtree == other.num_copy_requests_in_subtree &&
+         transform_id == other.transform_id && clip_id == other.clip_id &&
+         target_id == other.target_id && mask_layer_id == other.mask_layer_id &&
+         replica_layer_id == other.replica_layer_id &&
+         replica_mask_layer_id == other.replica_mask_layer_id;
+}
+
+void EffectNode::ToProtobuf(proto::TreeNode* proto) const {
+  proto->set_id(id);
+  proto->set_parent_id(parent_id);
+  proto->set_owner_id(owner_id);
+
+  DCHECK(!proto->has_effect_node_data());
+  proto::EffectNodeData* data = proto->mutable_effect_node_data();
+  data->set_opacity(opacity);
+  data->set_screen_space_opacity(screen_space_opacity);
+  data->set_has_render_surface(has_render_surface);
+  data->set_has_copy_request(has_copy_request);
+  data->set_hidden_by_backface_visibility(hidden_by_backface_visibility);
+  data->set_double_sided(double_sided);
+  data->set_is_drawn(is_drawn);
+  data->set_subtree_hidden(subtree_hidden);
+  data->set_has_potential_opacity_animation(has_potential_opacity_animation);
+  data->set_is_currently_animating_opacity(is_currently_animating_opacity);
+  data->set_effect_changed(effect_changed);
+  data->set_num_copy_requests_in_subtree(num_copy_requests_in_subtree);
+  data->set_transform_id(transform_id);
+  data->set_clip_id(clip_id);
+  data->set_target_id(target_id);
+  data->set_mask_layer_id(mask_layer_id);
+  data->set_replica_layer_id(replica_layer_id);
+  data->set_replica_mask_layer_id(replica_mask_layer_id);
+  Vector2dFToProto(sublayer_scale, data->mutable_sublayer_scale());
+}
+
+void EffectNode::FromProtobuf(const proto::TreeNode& proto) {
+  id = proto.id();
+  parent_id = proto.parent_id();
+  owner_id = proto.owner_id();
+
+  DCHECK(proto.has_effect_node_data());
+  const proto::EffectNodeData& data = proto.effect_node_data();
+
+  opacity = data.opacity();
+  screen_space_opacity = data.screen_space_opacity();
+  has_render_surface = data.has_render_surface();
+  has_copy_request = data.has_copy_request();
+  hidden_by_backface_visibility = data.hidden_by_backface_visibility();
+  double_sided = data.double_sided();
+  is_drawn = data.is_drawn();
+  subtree_hidden = data.subtree_hidden();
+  has_potential_opacity_animation = data.has_potential_opacity_animation();
+  is_currently_animating_opacity = data.is_currently_animating_opacity();
+  effect_changed = data.effect_changed();
+  num_copy_requests_in_subtree = data.num_copy_requests_in_subtree();
+  transform_id = data.transform_id();
+  clip_id = data.clip_id();
+  target_id = data.target_id();
+  mask_layer_id = data.mask_layer_id();
+  replica_layer_id = data.replica_layer_id();
+  replica_mask_layer_id = data.replica_mask_layer_id();
+  sublayer_scale = ProtoToVector2dF(data.sublayer_scale());
+}
+
+void EffectNode::AsValueInto(base::trace_event::TracedValue* value) const {
+  value->SetInteger("id", id);
+  value->SetInteger("parent_id", parent_id);
+  value->SetInteger("owner_id", owner_id);
+  value->SetDouble("opacity", opacity);
+  value->SetBoolean("has_render_surface", has_render_surface);
+  value->SetBoolean("has_copy_request", has_copy_request);
+  value->SetBoolean("double_sided", double_sided);
+  value->SetBoolean("is_drawn", is_drawn);
+  value->SetBoolean("has_potential_opacity_animation",
+                    has_potential_opacity_animation);
+  value->SetBoolean("effect_changed", effect_changed);
+  value->SetInteger("num_copy_requests_in_subtree",
+                    num_copy_requests_in_subtree);
+  value->SetInteger("transform_id", transform_id);
+  value->SetInteger("clip_id", clip_id);
+  value->SetInteger("target_id", target_id);
+  value->SetInteger("mask_layer_id", mask_layer_id);
+  value->SetInteger("replica_layer_id", replica_layer_id);
+  value->SetInteger("replica_mask_layer_id", replica_mask_layer_id);
+}
+
+}  // namespace cc
diff --git a/cc/trees/effect_node.h b/cc/trees/effect_node.h
new file mode 100644
index 0000000..1e3c73c
--- /dev/null
+++ b/cc/trees/effect_node.h
@@ -0,0 +1,73 @@
+// 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 CC_TREES_EFFECT_NODE_H_
+#define CC_TREES_EFFECT_NODE_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/output/filter_operations.h"
+
+namespace base {
+namespace trace_event {
+class TracedValue;
+}  // namespace trace_event
+}  // namespace base
+
+namespace cc {
+
+class RenderSurfaceImpl;
+
+namespace proto {
+class TreeNode;
+}  // namespace proto
+
+struct CC_EXPORT EffectNode {
+  EffectNode();
+  EffectNode(const EffectNode& other);
+
+  int id;
+  int parent_id;
+  int owner_id;
+
+  float opacity;
+  float screen_space_opacity;
+
+  FilterOperations background_filters;
+
+  gfx::Vector2dF sublayer_scale;
+
+  bool has_render_surface;
+  RenderSurfaceImpl* render_surface;
+  bool has_copy_request;
+  bool hidden_by_backface_visibility;
+  bool double_sided;
+  bool is_drawn;
+  // TODO(jaydasika) : Delete this after implementation of
+  // SetHideLayerAndSubtree is cleaned up. (crbug.com/595843)
+  bool subtree_hidden;
+  bool has_potential_opacity_animation;
+  bool is_currently_animating_opacity;
+  // We need to track changes to effects on the compositor to compute damage
+  // rect.
+  bool effect_changed;
+  int num_copy_requests_in_subtree;
+  bool has_unclipped_descendants;
+  int transform_id;
+  int clip_id;
+  // Effect node id of which this effect contributes to.
+  int target_id;
+  int mask_layer_id;
+  int replica_layer_id;
+  int replica_mask_layer_id;
+
+  bool operator==(const EffectNode& other) const;
+
+  void ToProtobuf(proto::TreeNode* proto) const;
+  void FromProtobuf(const proto::TreeNode& proto);
+  void AsValueInto(base::trace_event::TracedValue* value) const;
+};
+
+}  // namespace cc
+
+#endif  // CC_TREES_EFFECT_NODE_H_
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 98aa7f3..0263d55 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -18,9 +18,11 @@
 #include "cc/proto/begin_main_frame_and_commit_state.pb.h"
 #include "cc/proto/gfx_conversions.h"
 #include "cc/trees/draw_property_utils.h"
+#include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/property_tree_builder.h"
+#include "cc/trees/scroll_node.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
 #include "ui/gfx/transform.h"
@@ -219,11 +221,10 @@
     ScrollTree* scroll_tree) {
   for (LayerImpl* layer : *layer_list) {
     if (layer->is_drawn_render_surface_layer_list_member()) {
-      DCHECK_GT(scroll_tree->Node(layer->scroll_tree_index())
-                    ->data.num_drawn_descendants,
-                0);
-      scroll_tree->Node(layer->scroll_tree_index())
-          ->data.num_drawn_descendants--;
+      DCHECK_GT(
+          scroll_tree->Node(layer->scroll_tree_index())->num_drawn_descendants,
+          0);
+      scroll_tree->Node(layer->scroll_tree_index())->num_drawn_descendants--;
     }
     layer->set_is_drawn_render_surface_layer_list_member(false);
   }
@@ -303,14 +304,14 @@
                                                 ScrollTree* scroll_tree) {
   for (int i = static_cast<int>(scroll_tree->size()) - 1; i > 0; --i) {
     ScrollNode* node = scroll_tree->Node(i);
-    scroll_tree->parent(node)->data.num_drawn_descendants +=
-        node->data.num_drawn_descendants;
+    scroll_tree->parent(node)->num_drawn_descendants +=
+        node->num_drawn_descendants;
   }
   for (LayerImpl* layer : *layer_tree_impl) {
     bool scrolls_drawn_descendant = false;
     if (layer->scrollable()) {
       ScrollNode* node = scroll_tree->Node(layer->scroll_tree_index());
-      if (node->data.num_drawn_descendants > 0)
+      if (node->num_drawn_descendants > 0)
         scrolls_drawn_descendant = true;
     }
     layer->set_scrolls_drawn_descendant(scrolls_drawn_descendant);
@@ -324,7 +325,7 @@
     bool can_render_to_separate_surface) {
   ScrollTree* scroll_tree = &property_trees->scroll_tree;
   for (int i = 0; i < static_cast<int>(scroll_tree->size()); ++i)
-    scroll_tree->Node(i)->data.num_drawn_descendants = 0;
+    scroll_tree->Node(i)->num_drawn_descendants = 0;
 
   // Add all non-skipped surfaces to the initial render surface layer list. Add
   // all non-skipped layers to the layer list of their target surface, and
@@ -338,8 +339,7 @@
     layer->set_is_drawn_render_surface_layer_list_member(false);
 
     bool layer_is_drawn =
-        property_trees->effect_tree.Node(layer->effect_tree_index())
-            ->data.is_drawn;
+        property_trees->effect_tree.Node(layer->effect_tree_index())->is_drawn;
     bool is_root = layer_tree_impl->IsRootLayer(layer);
     bool skip_layer =
         !is_root && draw_property_utils::LayerShouldBeSkipped(
@@ -399,7 +399,7 @@
       continue;
 
     layer->set_is_drawn_render_surface_layer_list_member(true);
-    scroll_tree->Node(layer->scroll_tree_index())->data.num_drawn_descendants++;
+    scroll_tree->Node(layer->scroll_tree_index())->num_drawn_descendants++;
     layer->render_target()->layer_list().push_back(layer);
 
     // The layer contributes its drawable content rect to its render target.
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index 4f47e2ea..52386ed 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -40,10 +40,14 @@
 #include "cc/test/geometry_test_utils.h"
 #include "cc/test/layer_tree_host_common_test.h"
 #include "cc/test/test_task_graph_runner.h"
+#include "cc/trees/clip_node.h"
 #include "cc/trees/draw_property_utils.h"
+#include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/scroll_node.h"
 #include "cc/trees/single_thread_proxy.h"
 #include "cc/trees/task_runner_provider.h"
+#include "cc/trees/transform_node.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/effects/SkOffsetImageFilter.h"
@@ -189,7 +193,7 @@
   const int transform_tree_size = parent->layer_tree_impl()
                                       ->property_trees()
                                       ->transform_tree.next_available_id();
-  EXPECT_LT(node->data.transform_id, transform_tree_size);
+  EXPECT_LT(node->transform_id, transform_tree_size);
 }
 
 TEST_F(LayerTreeHostCommonTest, TransformsForSingleLayer) {
@@ -1373,7 +1377,7 @@
   EffectTree& effect_tree =
       parent->layer_tree_impl()->property_trees()->effect_tree;
   EffectNode* node = effect_tree.Node(render_surface1->effect_tree_index());
-  EXPECT_TRUE(node->data.is_drawn);
+  EXPECT_TRUE(node->is_drawn);
 
   // When parent is transparent, the layer should not be drawn.
   parent->OnOpacityAnimated(0.f);
@@ -1388,7 +1392,7 @@
   }
 
   node = effect_tree.Node(render_surface1->effect_tree_index());
-  EXPECT_FALSE(node->data.is_drawn);
+  EXPECT_FALSE(node->is_drawn);
   EXPECT_EQ(gfx::Rect(), render_surface1->visible_layer_rect());
 }
 
@@ -1707,9 +1711,6 @@
   EXPECT_TRUE(child->test_properties()->should_flatten_transform);
   EXPECT_FALSE(grand_child->test_properties()->should_flatten_transform);
 
-  gfx::Transform expected_child_draw_transform = identity_matrix;
-  gfx::Transform expected_grand_child_draw_transform = identity_matrix;
-
   gfx::Transform flattened_rotation_about_y = rotation_about_y_axis;
   flattened_rotation_about_y.FlattenTo2d();
 
@@ -3675,7 +3676,7 @@
   EXPECT_FALSE(root->layer_tree_impl()
                    ->property_trees()
                    ->transform_tree.Node(grand_child->transform_tree_index())
-                   ->data.ancestors_are_invertible);
+                   ->ancestors_are_invertible);
 
   // CalcDrawProps skips a subtree when a layer's screen space transform is
   // uninvertible
@@ -3748,7 +3749,7 @@
       host_impl.active_tree()
           ->property_trees()
           ->transform_tree.Node(grand_child_ptr->transform_tree_index())
-          ->data.ancestors_are_invertible);
+          ->ancestors_are_invertible);
 
   // Since |grand_child| has an uninvertible screen space transform, it is
   // skipped so
@@ -4993,7 +4994,7 @@
 
   gfx::Transform expected_duplicate_child_draw_transform =
       child->DrawTransform();
-  EXPECT_TRANSFORMATION_MATRIX_EQ(child->DrawTransform(),
+  EXPECT_TRANSFORMATION_MATRIX_EQ(expected_duplicate_child_draw_transform,
                                   duplicate_child_non_owner->DrawTransform());
   EXPECT_TRANSFORMATION_MATRIX_EQ(
       child->ScreenSpaceTransform(),
@@ -5207,7 +5208,7 @@
   EffectTree& tree =
       root_layer->layer_tree_impl()->property_trees()->effect_tree;
   EffectNode* node = tree.Node(child_ptr->effect_tree_index());
-  EXPECT_FALSE(node->data.is_drawn);
+  EXPECT_FALSE(node->is_drawn);
 
   // A layer should be drawn and it should contribute to drawn surface when
   // it has animating opacity even if it has opacity 0.
@@ -5223,7 +5224,7 @@
   child_ptr = root_layer->layer_tree_impl()->LayerById(2);
   tree = root_layer->layer_tree_impl()->property_trees()->effect_tree;
   node = tree.Node(child_ptr->effect_tree_index());
-  EXPECT_TRUE(node->data.is_drawn);
+  EXPECT_TRUE(node->is_drawn);
   EXPECT_TRUE(tree.ContributesToDrawnSurface(child_ptr->effect_tree_index()));
 
   // But if the opacity of the layer remains 0 after activation, it should not
@@ -5239,7 +5240,7 @@
   ExecuteCalculateDrawProperties(active_root);
 
   node = active_effect_tree.Node(active_child->effect_tree_index());
-  EXPECT_FALSE(node->data.is_drawn);
+  EXPECT_FALSE(node->is_drawn);
   EXPECT_FALSE(active_effect_tree.ContributesToDrawnSurface(
       active_child->effect_tree_index()));
 }
@@ -5723,15 +5724,15 @@
   EffectTree& tree =
       root_layer->layer_tree_impl()->property_trees()->effect_tree;
   EffectNode* node = tree.Node(copy_grand_parent_layer->effect_tree_index());
-  EXPECT_FALSE(node->data.is_drawn);
+  EXPECT_FALSE(node->is_drawn);
   node = tree.Node(copy_parent_layer->effect_tree_index());
-  EXPECT_FALSE(node->data.is_drawn);
+  EXPECT_FALSE(node->is_drawn);
   node = tree.Node(copy_layer->effect_tree_index());
-  EXPECT_TRUE(node->data.is_drawn);
+  EXPECT_TRUE(node->is_drawn);
   node = tree.Node(copy_child_layer->effect_tree_index());
-  EXPECT_TRUE(node->data.is_drawn);
+  EXPECT_TRUE(node->is_drawn);
   node = tree.Node(copy_grand_child_layer->effect_tree_index());
-  EXPECT_FALSE(node->data.is_drawn);
+  EXPECT_FALSE(node->is_drawn);
 
   // Though copy_layer is drawn, it shouldn't contribute to drawn surface as its
   // actually hidden.
@@ -6650,24 +6651,24 @@
   const EffectTree& tree =
       root->layer_tree_impl()->property_trees()->effect_tree;
   EXPECT_TRUE(tree.Node(render_surface1->effect_tree_index())
-                  ->data.hidden_by_backface_visibility);
+                  ->hidden_by_backface_visibility);
   EXPECT_TRUE(tree.Node(render_surface2->effect_tree_index())
-                  ->data.hidden_by_backface_visibility);
+                  ->hidden_by_backface_visibility);
 
   back_facing->OnTransformAnimated(identity_transform);
   render_surface2->OnTransformAnimated(rotate_about_y);
   ExecuteCalculateDrawProperties(root);
   EXPECT_FALSE(tree.Node(render_surface1->effect_tree_index())
-                   ->data.hidden_by_backface_visibility);
+                   ->hidden_by_backface_visibility);
   EXPECT_TRUE(tree.Node(render_surface2->effect_tree_index())
-                  ->data.hidden_by_backface_visibility);
+                  ->hidden_by_backface_visibility);
 
   render_surface1->OnTransformAnimated(rotate_about_y);
   ExecuteCalculateDrawProperties(root);
   EXPECT_TRUE(tree.Node(render_surface1->effect_tree_index())
-                  ->data.hidden_by_backface_visibility);
+                  ->hidden_by_backface_visibility);
   EXPECT_TRUE(tree.Node(render_surface2->effect_tree_index())
-                  ->data.hidden_by_backface_visibility);
+                  ->hidden_by_backface_visibility);
 }
 
 TEST_F(LayerTreeHostCommonTest, ClippedByScrollParent) {
@@ -9332,7 +9333,7 @@
 
   ClipTree& clip_tree = root->layer_tree_impl()->property_trees()->clip_tree;
   ClipNode* clip_node = clip_tree.Node(render_surface->clip_tree_index());
-  EXPECT_FALSE(clip_node->data.applies_local_clip);
+  EXPECT_FALSE(clip_node->applies_local_clip);
   EXPECT_EQ(gfx::Rect(20, 20), test_layer->visible_layer_rect());
 }
 
@@ -9980,13 +9981,13 @@
   TransformTree& tree =
       root->layer_tree_impl()->property_trees()->transform_tree;
   TransformNode* node = tree.Node(render_surface1->transform_tree_index());
-  EXPECT_EQ(node->data.sublayer_scale, gfx::Vector2dF(2.f, 2.f));
+  EXPECT_EQ(node->sublayer_scale, gfx::Vector2dF(2.f, 2.f));
 
   node = tree.Node(between_targets->transform_tree_index());
-  EXPECT_EQ(node->data.sublayer_scale, gfx::Vector2dF(1.f, 1.f));
+  EXPECT_EQ(node->sublayer_scale, gfx::Vector2dF(1.f, 1.f));
 
   node = tree.Node(render_surface2->transform_tree_index());
-  EXPECT_EQ(node->data.sublayer_scale, gfx::Vector2dF(2.f, 2.f));
+  EXPECT_EQ(node->sublayer_scale, gfx::Vector2dF(2.f, 2.f));
 
   EXPECT_EQ(gfx::Rect(15, 15), test_layer->visible_layer_rect());
 }
@@ -10126,20 +10127,20 @@
 
   EffectTree& tree = root->layer_tree_host()->property_trees()->effect_tree;
   EffectNode* node = tree.Node(animated->effect_tree_index());
-  EXPECT_FALSE(node->data.is_currently_animating_opacity);
-  EXPECT_TRUE(node->data.has_potential_opacity_animation);
+  EXPECT_FALSE(node->is_currently_animating_opacity);
+  EXPECT_TRUE(node->has_potential_opacity_animation);
 
   animation_ptr->set_time_offset(base::TimeDelta::FromMilliseconds(0));
   root->layer_tree_host()->AnimateLayers(
       base::TimeTicks::FromInternalValue(std::numeric_limits<int64_t>::max()));
   node = tree.Node(animated->effect_tree_index());
-  EXPECT_TRUE(node->data.is_currently_animating_opacity);
-  EXPECT_TRUE(node->data.has_potential_opacity_animation);
+  EXPECT_TRUE(node->is_currently_animating_opacity);
+  EXPECT_TRUE(node->has_potential_opacity_animation);
 
   player->AbortAnimations(TargetProperty::OPACITY, false /*needs_completion*/);
   node = tree.Node(animated->effect_tree_index());
-  EXPECT_FALSE(node->data.is_currently_animating_opacity);
-  EXPECT_FALSE(node->data.has_potential_opacity_animation);
+  EXPECT_FALSE(node->is_currently_animating_opacity);
+  EXPECT_FALSE(node->has_potential_opacity_animation);
 }
 
 TEST_F(LayerTreeHostCommonTest, TransformAnimationsTrackingTest) {
@@ -10190,21 +10191,21 @@
   TransformTree& tree =
       root->layer_tree_host()->property_trees()->transform_tree;
   TransformNode* node = tree.Node(animated->transform_tree_index());
-  EXPECT_FALSE(node->data.is_currently_animating);
-  EXPECT_TRUE(node->data.has_potential_animation);
+  EXPECT_FALSE(node->is_currently_animating);
+  EXPECT_TRUE(node->has_potential_animation);
 
   animation_ptr->set_time_offset(base::TimeDelta::FromMilliseconds(0));
   root->layer_tree_host()->AnimateLayers(
       base::TimeTicks::FromInternalValue(std::numeric_limits<int64_t>::max()));
   node = tree.Node(animated->transform_tree_index());
-  EXPECT_TRUE(node->data.is_currently_animating);
-  EXPECT_TRUE(node->data.has_potential_animation);
+  EXPECT_TRUE(node->is_currently_animating);
+  EXPECT_TRUE(node->has_potential_animation);
 
   player->AbortAnimations(TargetProperty::TRANSFORM,
                           false /*needs_completion*/);
   node = tree.Node(animated->transform_tree_index());
-  EXPECT_FALSE(node->data.is_currently_animating);
-  EXPECT_FALSE(node->data.has_potential_animation);
+  EXPECT_FALSE(node->is_currently_animating);
+  EXPECT_FALSE(node->has_potential_animation);
 }
 
 TEST_F(LayerTreeHostCommonTest, SerializeScrollUpdateInfo) {
@@ -10341,82 +10342,81 @@
   property_tree_root->id = kRootPropertyTreeNodeId;
   property_tree_root->parent_id = kInvalidPropertyTreeNodeId;
   property_tree_root->owner_id = kInvalidPropertyTreeNodeId;
-  property_tree_root->data.scrollable = false;
-  property_tree_root->data.main_thread_scrolling_reasons =
+  property_tree_root->scrollable = false;
+  property_tree_root->main_thread_scrolling_reasons =
       MainThreadScrollingReason::kNotScrollingOnMain;
-  property_tree_root->data.contains_non_fast_scrollable_region = false;
-  property_tree_root->data.transform_id = kRootPropertyTreeNodeId;
+  property_tree_root->contains_non_fast_scrollable_region = false;
+  property_tree_root->transform_id = kRootPropertyTreeNodeId;
 
   // The node owned by root1
   ScrollNode scroll_root1;
   scroll_root1.id = 1;
   scroll_root1.owner_id = root1->id();
-  scroll_root1.data.user_scrollable_horizontal = true;
-  scroll_root1.data.user_scrollable_vertical = true;
-  scroll_root1.data.transform_id = root1->transform_tree_index();
+  scroll_root1.user_scrollable_horizontal = true;
+  scroll_root1.user_scrollable_vertical = true;
+  scroll_root1.transform_id = root1->transform_tree_index();
   expected_scroll_tree.Insert(scroll_root1, 0);
 
   // The node owned by parent2
   ScrollNode scroll_parent2;
   scroll_parent2.id = 2;
   scroll_parent2.owner_id = parent2->id();
-  scroll_parent2.data.scrollable = true;
-  scroll_parent2.data.main_thread_scrolling_reasons =
+  scroll_parent2.scrollable = true;
+  scroll_parent2.main_thread_scrolling_reasons =
       parent2->main_thread_scrolling_reasons();
-  scroll_parent2.data.scroll_clip_layer_bounds = root1->bounds();
-  scroll_parent2.data.bounds = parent2->bounds();
-  scroll_parent2.data.max_scroll_offset_affected_by_page_scale = true;
-  scroll_parent2.data.is_inner_viewport_scroll_layer = true;
-  scroll_parent2.data.user_scrollable_horizontal = true;
-  scroll_parent2.data.user_scrollable_vertical = true;
-  scroll_parent2.data.transform_id = parent2->transform_tree_index();
+  scroll_parent2.scroll_clip_layer_bounds = root1->bounds();
+  scroll_parent2.bounds = parent2->bounds();
+  scroll_parent2.max_scroll_offset_affected_by_page_scale = true;
+  scroll_parent2.is_inner_viewport_scroll_layer = true;
+  scroll_parent2.user_scrollable_horizontal = true;
+  scroll_parent2.user_scrollable_vertical = true;
+  scroll_parent2.transform_id = parent2->transform_tree_index();
   expected_scroll_tree.Insert(scroll_parent2, 1);
 
   // The node owned by child6
   ScrollNode scroll_child6;
   scroll_child6.id = 3;
   scroll_child6.owner_id = child6->id();
-  scroll_child6.data.main_thread_scrolling_reasons =
+  scroll_child6.main_thread_scrolling_reasons =
       child6->main_thread_scrolling_reasons();
-  scroll_child6.data.should_flatten = true;
-  scroll_child6.data.user_scrollable_horizontal = true;
-  scroll_child6.data.user_scrollable_vertical = true;
-  scroll_child6.data.transform_id = child6->transform_tree_index();
+  scroll_child6.should_flatten = true;
+  scroll_child6.user_scrollable_horizontal = true;
+  scroll_child6.user_scrollable_vertical = true;
+  scroll_child6.transform_id = child6->transform_tree_index();
   expected_scroll_tree.Insert(scroll_child6, 2);
 
   // The node owned by child7, child7 also owns a transform node
   ScrollNode scroll_child7;
   scroll_child7.id = 4;
   scroll_child7.owner_id = child7->id();
-  scroll_child7.data.scrollable = true;
-  scroll_child7.data.scroll_clip_layer_bounds = parent3->bounds();
-  scroll_child7.data.bounds = child7->bounds();
-  scroll_child7.data.user_scrollable_horizontal = true;
-  scroll_child7.data.user_scrollable_vertical = true;
-  scroll_child7.data.transform_id = child7->transform_tree_index();
+  scroll_child7.scrollable = true;
+  scroll_child7.scroll_clip_layer_bounds = parent3->bounds();
+  scroll_child7.bounds = child7->bounds();
+  scroll_child7.user_scrollable_horizontal = true;
+  scroll_child7.user_scrollable_vertical = true;
+  scroll_child7.transform_id = child7->transform_tree_index();
   expected_scroll_tree.Insert(scroll_child7, 1);
 
   // The node owned by grand_child11, grand_child11 also owns a transform node
   ScrollNode scroll_grand_child11;
   scroll_grand_child11.id = 5;
   scroll_grand_child11.owner_id = grand_child11->id();
-  scroll_grand_child11.data.scrollable = true;
-  scroll_grand_child11.data.user_scrollable_horizontal = true;
-  scroll_grand_child11.data.user_scrollable_vertical = true;
-  scroll_grand_child11.data.transform_id =
-      grand_child11->transform_tree_index();
+  scroll_grand_child11.scrollable = true;
+  scroll_grand_child11.user_scrollable_horizontal = true;
+  scroll_grand_child11.user_scrollable_vertical = true;
+  scroll_grand_child11.transform_id = grand_child11->transform_tree_index();
   expected_scroll_tree.Insert(scroll_grand_child11, 4);
 
   // The node owned by parent5
   ScrollNode scroll_parent5;
   scroll_parent5.id = 8;
   scroll_parent5.owner_id = parent5->id();
-  scroll_parent5.data.contains_non_fast_scrollable_region = true;
-  scroll_parent5.data.bounds = gfx::Size(10, 10);
-  scroll_parent5.data.should_flatten = true;
-  scroll_parent5.data.user_scrollable_horizontal = true;
-  scroll_parent5.data.user_scrollable_vertical = true;
-  scroll_parent5.data.transform_id = parent5->transform_tree_index();
+  scroll_parent5.contains_non_fast_scrollable_region = true;
+  scroll_parent5.bounds = gfx::Size(10, 10);
+  scroll_parent5.should_flatten = true;
+  scroll_parent5.user_scrollable_horizontal = true;
+  scroll_parent5.user_scrollable_vertical = true;
+  scroll_parent5.transform_id = parent5->transform_tree_index();
   expected_scroll_tree.Insert(scroll_parent5, 1);
 
   expected_scroll_tree.SetScrollOffset(parent2->id(), gfx::ScrollOffset(0, 0));
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 0c6928e..dd3c629 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -82,6 +82,7 @@
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_host_common.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/scroll_node.h"
 #include "cc/trees/single_thread_proxy.h"
 #include "cc/trees/tree_synchronizer.h"
 #include "gpu/GLES2/gl2extchromium.h"
@@ -277,6 +278,13 @@
   // It is released before shutdown.
   DCHECK(!output_surface_);
 
+  DCHECK(!renderer_);
+  DCHECK(!resource_provider_);
+  DCHECK(!resource_pool_);
+  DCHECK(!tile_task_manager_);
+  DCHECK(!single_thread_synchronous_task_graph_runner_);
+  DCHECK(!image_decode_controller_);
+
   if (input_handler_client_) {
     input_handler_client_->WillShutdown();
     input_handler_client_ = NULL;
@@ -298,10 +306,6 @@
 
   animation_host_->ClearTimelines();
   animation_host_->SetMutatorHostClient(nullptr);
-
-  CleanUpTileManagerAndUIResources();
-  renderer_ = nullptr;
-  resource_provider_ = nullptr;
 }
 
 void LayerTreeHostImpl::BeginMainFrameAborted(CommitEarlyOutReason reason) {
@@ -1595,6 +1599,11 @@
         !OuterViewportScrollLayer()->user_scrollable_vertical();
   }
 
+  if (GetDrawMode() == DRAW_MODE_RESOURCELESS_SOFTWARE) {
+    metadata.is_resourceless_software_draw_with_scroll_or_animation =
+        IsActivelyScrolling() || animation_host_->NeedsAnimateLayers();
+  }
+
   for (LayerImpl* surface_layer : active_tree_->SurfaceLayers()) {
     metadata.referenced_surfaces.push_back(
         static_cast<SurfaceLayerImpl*>(surface_layer)->surface_id());
@@ -1669,28 +1678,9 @@
                                                 resource_provider_.get());
   }
 
-  if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE) {
-    bool disable_picture_quad_image_filtering =
-        IsActivelyScrolling() || animation_host_->NeedsAnimateLayers();
-
-    // We must disable the image hijack canvas when using GPU rasterization but
-    // performing a resourceless software draw. Otherwise, we will attempt to
-    // use the GPU ImageDecodeController during software raster.
-    bool use_image_hijack_canvas = !use_gpu_rasterization_;
-
-    std::unique_ptr<SoftwareRenderer> temp_software_renderer =
-        SoftwareRenderer::Create(this, &settings_.renderer_settings,
-                                 output_surface_, nullptr,
-                                 use_image_hijack_canvas);
-    temp_software_renderer->DrawFrame(
-        &frame->render_passes, active_tree_->device_scale_factor(),
-        gfx::ColorSpace(), DeviceViewport(), DeviceClip(),
-        disable_picture_quad_image_filtering);
-  } else {
-    renderer_->DrawFrame(&frame->render_passes,
-                         active_tree_->device_scale_factor(), gfx::ColorSpace(),
-                         DeviceViewport(), DeviceClip(), false);
-  }
+  renderer_->DrawFrame(&frame->render_passes,
+                       active_tree_->device_scale_factor(), gfx::ColorSpace(),
+                       DeviceViewport(), DeviceClip());
   // The render passes should be consumed by the renderer.
   DCHECK(frame->render_passes.empty());
 
@@ -2147,9 +2137,9 @@
         resource_provider_.get(), texture_mailbox_deleter_.get(),
         settings_.renderer_settings.highp_threshold_min);
   } else if (output_surface_->software_device()) {
-    renderer_ = SoftwareRenderer::Create(
-        this, &settings_.renderer_settings, output_surface_,
-        resource_provider_.get(), true /* use_image_hijack_canvas */);
+    renderer_ =
+        SoftwareRenderer::Create(this, &settings_.renderer_settings,
+                                 output_surface_, resource_provider_.get());
   }
   DCHECK(renderer_);
 
@@ -2468,11 +2458,11 @@
   InputHandler::ScrollStatus scroll_status;
   scroll_status.main_thread_scrolling_reasons =
       MainThreadScrollingReason::kNotScrollingOnMain;
-  if (!!scroll_node->data.main_thread_scrolling_reasons) {
+  if (!!scroll_node->main_thread_scrolling_reasons) {
     TRACE_EVENT0("cc", "LayerImpl::TryScroll: Failed ShouldScrollOnMainThread");
     scroll_status.thread = InputHandler::SCROLL_ON_MAIN_THREAD;
     scroll_status.main_thread_scrolling_reasons =
-        scroll_node->data.main_thread_scrolling_reasons;
+        scroll_node->main_thread_scrolling_reasons;
     return scroll_status;
   }
 
@@ -2486,7 +2476,7 @@
     return scroll_status;
   }
 
-  if (scroll_node->data.contains_non_fast_scrollable_region) {
+  if (scroll_node->contains_non_fast_scrollable_region) {
     bool clipped = false;
     gfx::Transform inverse_screen_space_transform(
         gfx::Transform::kSkipInitialization);
@@ -2512,7 +2502,7 @@
     }
   }
 
-  if (!scroll_node->data.scrollable) {
+  if (!scroll_node->scrollable) {
     TRACE_EVENT0("cc", "LayerImpl::tryScroll: Ignored not scrollable");
     scroll_status.thread = InputHandler::SCROLL_IGNORED;
     scroll_status.main_thread_scrolling_reasons =
@@ -2539,7 +2529,7 @@
 static bool IsMainThreadScrolling(const InputHandler::ScrollStatus& status,
                                   const ScrollNode* scroll_node) {
   if (status.thread == InputHandler::SCROLL_ON_MAIN_THREAD) {
-    if (!!scroll_node->data.main_thread_scrolling_reasons) {
+    if (!!scroll_node->main_thread_scrolling_reasons) {
       DCHECK(MainThreadScrollingReason::MainThreadCanSetScrollReasons(
           status.main_thread_scrolling_reasons));
     } else {
@@ -2623,7 +2613,7 @@
   ScrollNode* scroll_node = scroll_tree.Node(child->scroll_tree_index());
   for (; scroll_tree.parent(scroll_node);
        scroll_node = scroll_tree.parent(scroll_node)) {
-    if (scroll_node->data.scrollable)
+    if (scroll_node->scrollable)
       return scroll_node->owner_id == scroll_ancestor->id();
   }
   return false;
@@ -2773,9 +2763,9 @@
 
   gfx::Vector2dF adjusted_scroll(delta);
   adjusted_scroll.Scale(1.f / scale_factor);
-  if (!scroll_node->data.user_scrollable_horizontal)
+  if (!scroll_node->user_scrollable_horizontal)
     adjusted_scroll.set_x(0);
-  if (!scroll_node->data.user_scrollable_vertical)
+  if (!scroll_node->user_scrollable_vertical)
     adjusted_scroll.set_y(0);
 
   gfx::ScrollOffset old_offset =
@@ -2807,9 +2797,9 @@
       current_offset + gfx::ScrollOffset(delta), scroll_node);
   DCHECK_EQ(
       ElementId(active_tree()->LayerById(scroll_node->owner_id)->element_id()),
-      scroll_node->data.element_id);
+      scroll_node->element_id);
 
-  animation_host_->ImplOnlyScrollAnimationCreate(scroll_node->data.element_id,
+  animation_host_->ImplOnlyScrollAnimationCreate(scroll_node->element_id,
                                                  target_offset, current_offset);
 
   SetNeedsOneBeginImplFrame();
@@ -2827,9 +2817,9 @@
   ScrollNode* scroll_node = scroll_tree.CurrentlyScrollingNode();
   if (scroll_node) {
     gfx::Vector2dF delta = scroll_delta;
-    if (!scroll_node->data.user_scrollable_horizontal)
+    if (!scroll_node->user_scrollable_horizontal)
       delta.set_x(0);
-    if (!scroll_node->data.user_scrollable_vertical)
+    if (!scroll_node->user_scrollable_vertical)
       delta.set_y(0);
 
     if (ScrollAnimationUpdateTarget(scroll_node, delta)) {
@@ -2859,11 +2849,11 @@
     if (scroll_node) {
       for (; scroll_tree.parent(scroll_node);
            scroll_node = scroll_tree.parent(scroll_node)) {
-        if (!scroll_node->data.scrollable ||
-            scroll_node->data.is_outer_viewport_scroll_layer)
+        if (!scroll_node->scrollable ||
+            scroll_node->is_outer_viewport_scroll_layer)
           continue;
 
-        if (scroll_node->data.is_inner_viewport_scroll_layer) {
+        if (scroll_node->is_inner_viewport_scroll_layer) {
           gfx::Vector2dF scrolled = viewport()->ScrollAnimated(pending_delta);
           // Viewport::ScrollAnimated returns pending_delta as long as it
           // starts an animation.
@@ -3013,7 +3003,7 @@
   // details.
   const float kEpsilon = 0.1f;
 
-  if (scroll_node->data.is_inner_viewport_scroll_layer) {
+  if (scroll_node->is_inner_viewport_scroll_layer) {
     bool affect_top_controls = !wheel_scrolling_;
     Viewport::ScrollResult result = viewport()->ScrollBy(
         delta, viewport_point, scroll_state->is_direct_manipulation(),
@@ -3034,7 +3024,7 @@
   bool scrolled = std::abs(applied_delta.x()) > kEpsilon;
   scrolled = scrolled || std::abs(applied_delta.y()) > kEpsilon;
 
-  if (scrolled && !scroll_node->data.is_inner_viewport_scroll_layer) {
+  if (scrolled && !scroll_node->is_inner_viewport_scroll_layer) {
     // If the applied delta is within 45 degrees of the input
     // delta, bail out to make it easier to scroll just one layer
     // in one direction without affecting any of its parents.
@@ -3072,8 +3062,8 @@
       // Skip the outer viewport scroll layer so that we try to scroll the
       // viewport only once. i.e. The inner viewport layer represents the
       // viewport.
-      if (!scroll_node->data.scrollable ||
-          scroll_node->data.is_outer_viewport_scroll_layer)
+      if (!scroll_node->scrollable ||
+          scroll_node->is_outer_viewport_scroll_layer)
         continue;
       current_scroll_chain.push_front(scroll_node);
     }
@@ -3173,8 +3163,8 @@
     for (; scroll_tree.parent(scroll_node);
          scroll_node = scroll_tree.parent(scroll_node)) {
       // The inner viewport layer represents the viewport.
-      if (!scroll_node->data.scrollable ||
-          scroll_node->data.is_outer_viewport_scroll_layer)
+      if (!scroll_node->scrollable ||
+          scroll_node->is_outer_viewport_scroll_layer)
         continue;
 
       float height =
@@ -3830,10 +3820,10 @@
     const gfx::Vector2dF& scroll_delta) {
   DCHECK_EQ(
       ElementId(active_tree()->LayerById(scroll_node->owner_id)->element_id()),
-      scroll_node->data.element_id);
+      scroll_node->element_id);
 
   return animation_host_->ImplOnlyScrollAnimationUpdateTarget(
-      scroll_node->data.element_id, scroll_delta,
+      scroll_node->element_id, scroll_delta,
       active_tree_->property_trees()->scroll_tree.MaxScrollOffset(
           scroll_node->id),
       CurrentBeginFrameArgs().frame_time);
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 43e5e4db..b3807cf 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -62,8 +62,10 @@
 #include "cc/test/test_shared_bitmap_manager.h"
 #include "cc/test/test_task_graph_runner.h"
 #include "cc/test/test_web_graphics_context_3d.h"
+#include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/single_thread_proxy.h"
+#include "cc/trees/transform_node.h"
 #include "media/base/media.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -2940,7 +2942,7 @@
         host_impl_->active_tree()->property_trees()->effect_tree.Node(
             active_scrollbar_layer->effect_tree_index());
     EXPECT_FLOAT_EQ(active_scrollbar_layer->Opacity(),
-                    active_tree_node->data.opacity);
+                    active_tree_node->opacity);
 
     host_impl_->ScrollbarAnimationControllerForId(scroll->id())
         ->DidMouseMoveNear(0);
@@ -2964,14 +2966,14 @@
     host_impl_->pending_tree()
         ->property_trees()
         ->always_use_active_tree_opacity_effect_ids.push_back(400);
-    EXPECT_FLOAT_EQ(1.f, active_tree_node->data.opacity);
+    EXPECT_FLOAT_EQ(1.f, active_tree_node->opacity);
     EXPECT_FLOAT_EQ(1.f, active_scrollbar_layer->Opacity());
-    EXPECT_FLOAT_EQ(0.f, pending_tree_node->data.opacity);
+    EXPECT_FLOAT_EQ(0.f, pending_tree_node->opacity);
     host_impl_->ActivateSyncTree();
     active_tree_node =
         host_impl_->active_tree()->property_trees()->effect_tree.Node(
             active_scrollbar_layer->effect_tree_index());
-    EXPECT_FLOAT_EQ(1.f, active_tree_node->data.opacity);
+    EXPECT_FLOAT_EQ(1.f, active_tree_node->opacity);
     EXPECT_FLOAT_EQ(1.f, active_scrollbar_layer->Opacity());
   }
 };
@@ -9647,7 +9649,7 @@
 class ResourcelessSoftwareLayerTreeHostImplTest : public LayerTreeHostImplTest {
  protected:
   std::unique_ptr<OutputSurface> CreateOutputSurface() override {
-    return FakeOutputSurface::Create3dWithResourcelessSoftwareSupport();
+    return FakeOutputSurface::CreateDelegating3d();
   }
 };
 
@@ -9854,7 +9856,7 @@
   TransformNode* node =
       host_impl_->active_tree()->property_trees()->transform_tree.Node(
           test_layer->transform_tree_index());
-  EXPECT_EQ(node->data.sublayer_scale, gfx::Vector2dF(1.f, 1.f));
+  EXPECT_EQ(node->sublayer_scale, gfx::Vector2dF(1.f, 1.f));
 
   gfx::Transform external_transform;
   external_transform.Translate(10, 10);
@@ -9870,7 +9872,7 @@
                      resourceless_software_draw);
   node = host_impl_->active_tree()->property_trees()->transform_tree.Node(
       test_layer->transform_tree_index());
-  EXPECT_EQ(node->data.sublayer_scale, gfx::Vector2dF(2.f, 2.f));
+  EXPECT_EQ(node->sublayer_scale, gfx::Vector2dF(2.f, 2.f));
 
   // Clear the external transform.
   external_transform = gfx::Transform();
@@ -9881,7 +9883,7 @@
                      resourceless_software_draw);
   node = host_impl_->active_tree()->property_trees()->transform_tree.Node(
       test_layer->transform_tree_index());
-  EXPECT_EQ(node->data.sublayer_scale, gfx::Vector2dF(1.f, 1.f));
+  EXPECT_EQ(node->sublayer_scale, gfx::Vector2dF(1.f, 1.f));
 }
 
 TEST_F(LayerTreeHostImplTest, ScrollAnimated) {
@@ -10897,27 +10899,27 @@
       host_impl_->active_tree()->property_trees()->transform_tree.Node(
           page_scale_layer->transform_tree_index());
   // SetPageScaleOnActiveTree also updates the factors in property trees.
-  EXPECT_EQ(active_tree_node->data.post_local_scale_factor, 2.f);
+  EXPECT_EQ(active_tree_node->post_local_scale_factor, 2.f);
   EXPECT_EQ(host_impl_->active_tree()->current_page_scale_factor(), 2.f);
 
   TransformNode* pending_tree_node =
       host_impl_->pending_tree()->property_trees()->transform_tree.Node(
           page_scale_layer->transform_tree_index());
-  EXPECT_EQ(pending_tree_node->data.post_local_scale_factor, 1.f);
+  EXPECT_EQ(pending_tree_node->post_local_scale_factor, 1.f);
   EXPECT_EQ(host_impl_->pending_tree()->current_page_scale_factor(), 2.f);
 
   host_impl_->pending_tree()->UpdateDrawProperties(false);
   pending_tree_node =
       host_impl_->pending_tree()->property_trees()->transform_tree.Node(
           page_scale_layer->transform_tree_index());
-  EXPECT_EQ(pending_tree_node->data.post_local_scale_factor, 2.f);
+  EXPECT_EQ(pending_tree_node->post_local_scale_factor, 2.f);
 
   host_impl_->ActivateSyncTree();
   host_impl_->active_tree()->UpdateDrawProperties(false);
   active_tree_node =
       host_impl_->active_tree()->property_trees()->transform_tree.Node(
           page_scale_layer->transform_tree_index());
-  EXPECT_EQ(active_tree_node->data.post_local_scale_factor, 2.f);
+  EXPECT_EQ(active_tree_node->post_local_scale_factor, 2.f);
 }
 
 TEST_F(LayerTreeHostImplTest, SubLayerScaleForNodeInSubtreeOfPageScaleLayer) {
@@ -10940,7 +10942,7 @@
   TransformNode* node =
       host_impl_->active_tree()->property_trees()->transform_tree.Node(
           in_subtree_of_page_scale_layer->transform_tree_index());
-  EXPECT_EQ(node->data.sublayer_scale, gfx::Vector2dF(1.f, 1.f));
+  EXPECT_EQ(node->sublayer_scale, gfx::Vector2dF(1.f, 1.f));
 
   host_impl_->active_tree()->SetPageScaleOnActiveTree(2.f);
 
@@ -10949,7 +10951,7 @@
   in_subtree_of_page_scale_layer = host_impl_->active_tree()->LayerById(100);
   node = host_impl_->active_tree()->property_trees()->transform_tree.Node(
       in_subtree_of_page_scale_layer->transform_tree_index());
-  EXPECT_EQ(node->data.sublayer_scale, gfx::Vector2dF(2.f, 2.f));
+  EXPECT_EQ(node->sublayer_scale, gfx::Vector2dF(2.f, 2.f));
 }
 
 TEST_F(LayerTreeHostImplTest, JitterTest) {
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 74e73a25..3e298044 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -45,12 +45,15 @@
 #include "cc/test/fake_scoped_ui_resource.h"
 #include "cc/test/fake_video_frame_provider.h"
 #include "cc/test/geometry_test_utils.h"
+#include "cc/test/layer_internals_for_test.h"
 #include "cc/test/layer_tree_test.h"
 #include "cc/test/test_shared_bitmap_manager.h"
 #include "cc/test/test_web_graphics_context_3d.h"
+#include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/single_thread_proxy.h"
+#include "cc/trees/transform_node.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/khronos/GLES2/gl2.h"
@@ -978,11 +981,11 @@
     EffectNode* node = effect_tree.Node(root_->effect_tree_index());
     switch (layer_tree_host()->source_frame_number()) {
       case 1:
-        node->data.opacity = 0.5f;
-        node->data.is_currently_animating_opacity = true;
+        node->opacity = 0.5f;
+        node->is_currently_animating_opacity = true;
         break;
       case 2:
-        node->data.is_currently_animating_opacity = false;
+        node->is_currently_animating_opacity = false;
         break;
     }
   }
@@ -997,12 +1000,12 @@
         PostSetNeedsCommitToMainThread();
         break;
       case 1:
-        EXPECT_EQ(node->data.opacity, 0.75f);
+        EXPECT_EQ(node->opacity, 0.75f);
         impl->sync_tree()->root_layer_for_testing()->OnOpacityAnimated(0.75f);
         PostSetNeedsCommitToMainThread();
         break;
       case 2:
-        EXPECT_EQ(node->data.opacity, 0.5f);
+        EXPECT_EQ(node->opacity, 0.5f);
         EndTest();
         break;
     }
@@ -1034,14 +1037,14 @@
     rotate10.Rotate(10.f);
     switch (layer_tree_host()->source_frame_number()) {
       case 1:
-        node->data.local = rotate10;
-        node->data.is_currently_animating = true;
+        node->local = rotate10;
+        node->is_currently_animating = true;
         break;
       case 2:
-        node->data.is_currently_animating = true;
+        node->is_currently_animating = true;
         break;
       case 3:
-        node->data.is_currently_animating = false;
+        node->is_currently_animating = false;
         break;
     }
   }
@@ -1062,19 +1065,19 @@
         PostSetNeedsCommitToMainThread();
         break;
       case 1:
-        EXPECT_EQ(node->data.local, rotate20);
+        EXPECT_EQ(node->local, rotate20);
         impl->sync_tree()->root_layer_for_testing()->OnTransformAnimated(
             rotate20);
         PostSetNeedsCommitToMainThread();
         break;
       case 2:
-        EXPECT_EQ(node->data.local, rotate20);
+        EXPECT_EQ(node->local, rotate20);
         impl->sync_tree()->root_layer_for_testing()->OnTransformAnimated(
             rotate20);
         PostSetNeedsCommitToMainThread();
         break;
       case 3:
-        EXPECT_EQ(node->data.local, rotate10);
+        EXPECT_EQ(node->local, rotate10);
         EndTest();
     }
   }
@@ -1116,7 +1119,7 @@
     if (layer_tree_host()->source_frame_number() == 1) {
       gfx::Transform scale;
       scale.Scale(2.0, 2.0);
-      child_->OnTransformAnimated(scale);
+      LayerInternalsForTest(child_.get()).OnTransformAnimated(scale);
     }
   }
 
diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc
index 9d7ba1f..4d660a5 100644
--- a/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/cc/trees/layer_tree_host_unittest_animation.cc
@@ -25,6 +25,7 @@
 #include "cc/test/fake_picture_layer.h"
 #include "cc/test/layer_tree_test.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/transform_node.h"
 
 namespace cc {
 namespace {
@@ -1686,7 +1687,7 @@
     translate.Translate(5, 5);
     switch (host_impl->sync_tree()->source_frame_number()) {
       case 2:
-        EXPECT_TRANSFORMATION_MATRIX_EQ(node->data.local, translate);
+        EXPECT_TRANSFORMATION_MATRIX_EQ(node->local, translate);
         EndTest();
         break;
       default:
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc
index fecc96ca..759586a 100644
--- a/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -23,6 +23,7 @@
 #include "cc/test/test_shared_bitmap_manager.h"
 #include "cc/test/test_task_graph_runner.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/scroll_node.h"
 #include "ui/gfx/geometry/point_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index d0e1b73..4d6ec707 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -33,12 +33,16 @@
 #include "cc/layers/render_surface_impl.h"
 #include "cc/layers/scrollbar_layer_impl_base.h"
 #include "cc/resources/ui_resource_request.h"
+#include "cc/trees/clip_node.h"
 #include "cc/trees/draw_property_utils.h"
+#include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_host_common.h"
 #include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/occlusion_tracker.h"
 #include "cc/trees/property_tree.h"
 #include "cc/trees/property_tree_builder.h"
+#include "cc/trees/scroll_node.h"
+#include "cc/trees/transform_node.h"
 #include "ui/gfx/geometry/box_f.h"
 #include "ui/gfx/geometry/point_conversions.h"
 #include "ui/gfx/geometry/rect_conversions.h"
@@ -158,13 +162,12 @@
 
   if (transform_id != -1) {
     TransformNode* node = transform_tree.Node(transform_id);
-    if (node->data.scroll_offset !=
-        scroll_tree.current_scroll_offset(layer_id)) {
-      node->data.scroll_offset = scroll_tree.current_scroll_offset(layer_id);
-      node->data.needs_local_transform_update = true;
+    if (node->scroll_offset != scroll_tree.current_scroll_offset(layer_id)) {
+      node->scroll_offset = scroll_tree.current_scroll_offset(layer_id);
+      node->needs_local_transform_update = true;
       transform_tree.set_needs_update(true);
     }
-    node->data.transform_changed = true;
+    node->transform_changed = true;
     property_trees()->changed = true;
     set_needs_update_draw_properties();
   }
@@ -357,8 +360,8 @@
     if (clip_node) {
       DCHECK_EQ(layer->id(), clip_node->owner_id);
       gfx::SizeF bounds = gfx::SizeF(layer->bounds());
-      if (clip_node->data.clip.size() != bounds) {
-        clip_node->data.clip.set_size(bounds);
+      if (clip_node->clip.size() != bounds) {
+        clip_node->clip.set_size(bounds);
         clip_tree->set_needs_update(true);
       }
     }
@@ -619,10 +622,10 @@
     if (property_trees_.IsInIdToIndexMap(PropertyTrees::TreeType::EFFECT, id)) {
       EffectNode* node = property_trees_.effect_tree.Node(
           property_trees_.effect_id_to_index_map[id]);
-      if (!node->data.is_currently_animating_opacity ||
-          node->data.opacity == layer_id_to_opacity.second)
+      if (!node->is_currently_animating_opacity ||
+          node->opacity == layer_id_to_opacity.second)
         continue;
-      node->data.opacity = layer_id_to_opacity.second;
+      node->opacity = layer_id_to_opacity.second;
       property_trees_.effect_tree.set_needs_update(true);
     }
   }
@@ -634,11 +637,11 @@
                                          id)) {
       TransformNode* node = property_trees_.transform_tree.Node(
           property_trees_.transform_id_to_index_map[id]);
-      if (!node->data.is_currently_animating ||
-          node->data.local == layer_id_to_transform.second)
+      if (!node->is_currently_animating ||
+          node->local == layer_id_to_transform.second)
         continue;
-      node->data.local = layer_id_to_transform.second;
-      node->data.needs_local_transform_update = true;
+      node->local = layer_id_to_transform.second;
+      node->needs_local_transform_update = true;
       property_trees_.transform_tree.set_needs_update(true);
     }
   }
@@ -1660,18 +1663,18 @@
   // We first check if the point is clipped by viewport.
   const ClipNode* clip_node = clip_tree.Node(1);
   gfx::Rect combined_clip_in_target_space =
-      gfx::ToEnclosingRect(clip_node->data.combined_clip_in_target_space);
+      gfx::ToEnclosingRect(clip_node->combined_clip_in_target_space);
   if (!PointHitsRect(screen_space_point, gfx::Transform(),
                      combined_clip_in_target_space, NULL))
     return true;
 
   for (const ClipNode* clip_node = clip_tree.Node(layer->clip_tree_index());
        clip_node->id > 1; clip_node = clip_tree.parent(clip_node)) {
-    if (clip_node->data.applies_local_clip) {
+    if (clip_node->applies_local_clip) {
       const TransformNode* transform_node =
-          transform_tree.Node(clip_node->data.target_id);
+          transform_tree.Node(clip_node->target_id);
       gfx::Rect combined_clip_in_target_space =
-          gfx::ToEnclosingRect(clip_node->data.combined_clip_in_target_space);
+          gfx::ToEnclosingRect(clip_node->combined_clip_in_target_space);
 
       const LayerImpl* target_layer =
           layer->layer_tree_impl()->LayerById(transform_node->owner_id);
diff --git a/cc/trees/layer_tree_impl_unittest.cc b/cc/trees/layer_tree_impl_unittest.cc
index a7997b8..7c190da 100644
--- a/cc/trees/layer_tree_impl_unittest.cc
+++ b/cc/trees/layer_tree_impl_unittest.cc
@@ -14,6 +14,7 @@
 #include "cc/test/layer_tree_host_common_test.h"
 #include "cc/test/test_shared_bitmap_manager.h"
 #include "cc/test/test_task_graph_runner.h"
+#include "cc/trees/clip_node.h"
 #include "cc/trees/draw_property_utils.h"
 #include "cc/trees/layer_tree_host_impl.h"
 #include "ui/gfx/geometry/size_conversions.h"
@@ -447,7 +448,7 @@
 
   ClipTree& clip_tree = host_impl().active_tree()->property_trees()->clip_tree;
   ClipNode* clip_node = clip_tree.Node(result_layer->clip_tree_index());
-  EXPECT_NE(clip_node->data.transform_id, clip_node->data.target_id);
+  EXPECT_NE(clip_node->transform_id, clip_node->target_id);
 }
 
 TEST_F(LayerTreeImplTest, HitTestingSiblings) {
diff --git a/cc/trees/occlusion_tracker.cc b/cc/trees/occlusion_tracker.cc
index fe5b0a3..09519af 100644
--- a/cc/trees/occlusion_tracker.cc
+++ b/cc/trees/occlusion_tracker.cc
@@ -211,9 +211,11 @@
       &outset_top, &outset_right, &outset_bottom, &outset_left);
 
   // The filter can move pixels from outside of the clip, so allow affected_area
-  // to expand outside the clip.
-  affected_area_in_target.Inset(
-      -outset_left, -outset_top, -outset_right, -outset_bottom);
+  // to expand outside the clip. Notably the content we're concerned with here
+  // is not the affected area, but rather stuff slightly outside it. Thus the
+  // directions of the outsets are reversed from normal.
+  affected_area_in_target.Inset(-outset_right, -outset_bottom, -outset_left,
+                                -outset_top);
   SimpleEnclosedRegion affected_occlusion = *occlusion_from_inside_target;
   affected_occlusion.Intersect(affected_area_in_target);
 
diff --git a/cc/trees/occlusion_tracker_unittest.cc b/cc/trees/occlusion_tracker_unittest.cc
index 7a7599d..ec11958c 100644
--- a/cc/trees/occlusion_tracker_unittest.cc
+++ b/cc/trees/occlusion_tracker_unittest.cc
@@ -1464,12 +1464,14 @@
           occlusion_rect = gfx::Rect(0, 0, 50, 200);
           break;
         case RIGHT:
+          // This is the right edge; filtered_surface is scaled by half.
           occlusion_rect = gfx::Rect(100, 0, 50, 200);
           break;
         case TOP:
           occlusion_rect = gfx::Rect(0, 0, 200, 50);
           break;
         case BOTTOM:
+          // This is the bottom edge; filtered_surface is scaled by half.
           occlusion_rect = gfx::Rect(0, 100, 200, 50);
           break;
       }
@@ -1501,9 +1503,9 @@
                 occlusion.occlusion_from_outside_target().ToString());
 
       // The surface has a background blur, so it needs pixels that are
-      // currently considered occluded in order to be drawn. So the pixels it
-      // needs should be removed some the occluded area so that when we get to
-      // the parent they are drawn.
+      // currently considered occluded in order to be drawn. The pixels it
+      // needs should be removed from the occluded area, so that they are drawn
+      // when we get to the parent.
       this->VisitContributingSurface(filtered_surface, &occlusion);
       this->EnterLayer(parent, &occlusion);
 
@@ -1536,6 +1538,127 @@
 ALL_OCCLUSIONTRACKER_TEST(
     OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter);
 
+class OcclusionTrackerTestDontOccludePixelsNeededForDropShadowBackgroundFilter
+    : public OcclusionTrackerTest {
+ protected:
+  explicit OcclusionTrackerTestDontOccludePixelsNeededForDropShadowBackgroundFilter(
+      bool opaque_layers)
+      : OcclusionTrackerTest(opaque_layers) {}
+  void RunMyTest() override {
+    gfx::Transform scale_by_half;
+    scale_by_half.Scale(0.5, 0.5);
+
+    FilterOperations filters;
+    filters.Append(FilterOperation::CreateDropShadowFilter(gfx::Point(10, 10),
+                                                           5, SK_ColorBLACK));
+
+    enum Direction {
+      LEFT,
+      RIGHT,
+      TOP,
+      BOTTOM,
+      LAST_DIRECTION = BOTTOM,
+    };
+
+    for (int i = 0; i <= LAST_DIRECTION; ++i) {
+      SCOPED_TRACE(i);
+
+      // Make a 50x50 filtered surface that is adjacent to occluding layers
+      // which are above it in the z-order in various configurations. The
+      // surface is scaled to test that the pixel moving is done in the target
+      // space, where the background filter is applied.
+      TestContentLayerImpl* parent = this->CreateRoot(
+          this->identity_matrix, gfx::PointF(), gfx::Size(200, 200));
+      LayerImpl* filtered_surface = this->CreateDrawingLayer(
+          parent, scale_by_half, gfx::PointF(50.f, 50.f), gfx::Size(100, 100),
+          false);
+      filtered_surface->test_properties()->background_filters = filters;
+      gfx::Rect occlusion_rect;
+      switch (i) {
+        case LEFT:
+          occlusion_rect = gfx::Rect(0, 0, 50, 200);
+          break;
+        case RIGHT:
+          // This is the right edge; filtered_surface is scaled by half.
+          occlusion_rect = gfx::Rect(100, 0, 50, 200);
+          break;
+        case TOP:
+          occlusion_rect = gfx::Rect(0, 0, 200, 50);
+          break;
+        case BOTTOM:
+          // This is the bottom edge; filtered_surface is scaled by half.
+          occlusion_rect = gfx::Rect(0, 100, 200, 50);
+          break;
+      }
+
+      LayerImpl* occluding_layer = this->CreateDrawingLayer(
+          parent, this->identity_matrix, gfx::PointF(occlusion_rect.origin()),
+          occlusion_rect.size(), true);
+      occluding_layer->test_properties()->force_render_surface = false;
+      this->CalcDrawEtc(parent);
+
+      TestOcclusionTrackerWithClip occlusion(gfx::Rect(0, 0, 200, 200));
+
+      // This layer occludes pixels directly beside the filtered_surface.
+      // Because filtered surface blends pixels in a radius, it will need to see
+      // some of the pixels (up to radius far) underneath the occluding layers.
+      this->VisitLayer(occluding_layer, &occlusion);
+
+      EXPECT_EQ(occlusion_rect.ToString(),
+                occlusion.occlusion_from_inside_target().ToString());
+      EXPECT_TRUE(occlusion.occlusion_from_outside_target().IsEmpty());
+
+      this->VisitLayer(filtered_surface, &occlusion);
+
+      // The occlusion is used fully inside the surface.
+      gfx::Rect occlusion_inside_surface =
+          occlusion_rect - gfx::Vector2d(50, 50);
+      EXPECT_TRUE(occlusion.occlusion_from_inside_target().IsEmpty());
+      EXPECT_EQ(occlusion_inside_surface.ToString(),
+                occlusion.occlusion_from_outside_target().ToString());
+
+      // The surface has a background filter, so it needs pixels that are
+      // currently considered occluded in order to be drawn. The pixels it
+      // needs should be removed from the occluded area, so that they are drawn
+      // when we get to the parent.
+      this->VisitContributingSurface(filtered_surface, &occlusion);
+      this->EnterLayer(parent, &occlusion);
+
+      gfx::Rect expected_occlusion;
+      switch (i) {
+        case LEFT:
+          // The right half of the occlusion is close enough to cast a shadow
+          // that would be visible in the background filter. The shadow reaches
+          // 3*5 + 10 = 25 pixels to the right.
+          expected_occlusion = gfx::Rect(0, 0, 25, 200);
+          break;
+        case RIGHT:
+          // The shadow spreads 3*5 - 10 = 5 pixels to the left, so the
+          // occlusion must recede by 5 to account for that.
+          expected_occlusion = gfx::Rect(105, 0, 45, 200);
+          break;
+        case TOP:
+          // Similar to LEFT.
+          expected_occlusion = gfx::Rect(0, 0, 200, 25);
+          break;
+        case BOTTOM:
+          // Similar to RIGHT.
+          expected_occlusion = gfx::Rect(0, 105, 200, 45);
+          break;
+      }
+
+      EXPECT_EQ(expected_occlusion.ToString(),
+                occlusion.occlusion_from_inside_target().ToString());
+      EXPECT_TRUE(occlusion.occlusion_from_outside_target().IsEmpty());
+
+      this->DestroyLayers();
+    }
+  }
+};
+
+ALL_OCCLUSIONTRACKER_TEST(
+    OcclusionTrackerTestDontOccludePixelsNeededForDropShadowBackgroundFilter);
+
 class OcclusionTrackerTestTwoBackgroundFiltersReduceOcclusionTwice
     : public OcclusionTrackerTest {
  protected:
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index 9f87656..62de5d7 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -10,60 +10,22 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/trace_event/trace_event_argument.h"
-#include "cc/base/math_util.h"
-#include "cc/input/main_thread_scrolling_reason.h"
-#include "cc/input/scroll_state.h"
 #include "cc/layers/layer_impl.h"
 #include "cc/output/copy_output_request.h"
-#include "cc/proto/gfx_conversions.h"
 #include "cc/proto/property_tree.pb.h"
-#include "cc/proto/scroll_offset.pb.h"
 #include "cc/proto/synced_property_conversions.h"
-#include "cc/proto/transform.pb.h"
-#include "cc/proto/vector2df.pb.h"
+#include "cc/trees/clip_node.h"
+#include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_host_common.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/property_tree.h"
+#include "cc/trees/scroll_node.h"
+#include "cc/trees/transform_node.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
 
 namespace cc {
 
 template <typename T>
-bool TreeNode<T>::operator==(const TreeNode<T>& other) const {
-  return id == other.id && parent_id == other.parent_id &&
-         owner_id == other.owner_id && data == other.data;
-}
-
-template <typename T>
-void TreeNode<T>::ToProtobuf(proto::TreeNode* proto) const {
-  proto->set_id(id);
-  proto->set_parent_id(parent_id);
-  proto->set_owner_id(owner_id);
-  data.ToProtobuf(proto);
-}
-
-template <typename T>
-void TreeNode<T>::FromProtobuf(const proto::TreeNode& proto) {
-  id = proto.id();
-  parent_id = proto.parent_id();
-  owner_id = proto.owner_id();
-  data.FromProtobuf(proto);
-}
-
-template <typename T>
-void TreeNode<T>::AsValueInto(base::trace_event::TracedValue* value) const {
-  value->SetInteger("id", id);
-  value->SetInteger("parent_id", parent_id);
-  value->SetInteger("owner_id", owner_id);
-  data.AsValueInto(value);
-}
-
-template struct TreeNode<TransformNodeData>;
-template struct TreeNode<ClipNodeData>;
-template struct TreeNode<EffectNodeData>;
-template struct TreeNode<ScrollNodeData>;
-
-template <typename T>
 PropertyTree<T>::PropertyTree()
     : needs_update_(false) {
   nodes_.push_back(T());
@@ -71,9 +33,15 @@
   back()->parent_id = -1;
 }
 
+// Equivalent to
+// PropertyTree<T>::~PropertyTree() = default;
+// but due to a gcc bug the generated destructor will have wrong symbol
+// visibility in component build.
 template <typename T>
-PropertyTree<T>::~PropertyTree() {
-}
+PropertyTree<T>::~PropertyTree() {}
+
+template <typename T>
+PropertyTree<T>& PropertyTree<T>::operator=(const PropertyTree<T>&) = default;
 
 TransformTree::TransformTree()
     : source_to_parent_updates_allowed_(true),
@@ -83,8 +51,8 @@
   cached_data_.push_back(TransformCachedNodeData());
 }
 
-TransformTree::~TransformTree() {
-}
+TransformTree::~TransformTree() = default;
+TransformTree& TransformTree::operator=(const TransformTree&) = default;
 
 template <typename T>
 int PropertyTree<T>::Insert(const T& tree_node, int parent_id) {
@@ -156,542 +124,6 @@
 template class PropertyTree<EffectNode>;
 template class PropertyTree<ScrollNode>;
 
-TransformNodeData::TransformNodeData()
-    : source_node_id(-1),
-      sorting_context_id(0),
-      needs_local_transform_update(true),
-      node_and_ancestors_are_animated_or_invertible(true),
-      is_invertible(true),
-      ancestors_are_invertible(true),
-      has_potential_animation(false),
-      is_currently_animating(false),
-      to_screen_is_potentially_animated(false),
-      has_only_translation_animations(true),
-      flattens_inherited_transform(false),
-      node_and_ancestors_are_flat(true),
-      node_and_ancestors_have_only_integer_translation(true),
-      scrolls(false),
-      needs_sublayer_scale(false),
-      affected_by_inner_viewport_bounds_delta_x(false),
-      affected_by_inner_viewport_bounds_delta_y(false),
-      affected_by_outer_viewport_bounds_delta_x(false),
-      affected_by_outer_viewport_bounds_delta_y(false),
-      in_subtree_of_page_scale_layer(false),
-      transform_changed(false),
-      post_local_scale_factor(1.0f) {}
-
-TransformNodeData::TransformNodeData(const TransformNodeData& other) = default;
-
-TransformNodeData::~TransformNodeData() {
-}
-
-bool TransformNodeData::operator==(const TransformNodeData& other) const {
-  return pre_local == other.pre_local && local == other.local &&
-         post_local == other.post_local && to_parent == other.to_parent &&
-         source_node_id == other.source_node_id &&
-         sorting_context_id == other.sorting_context_id &&
-         needs_local_transform_update == other.needs_local_transform_update &&
-         node_and_ancestors_are_animated_or_invertible ==
-             other.node_and_ancestors_are_animated_or_invertible &&
-         is_invertible == other.is_invertible &&
-         ancestors_are_invertible == other.ancestors_are_invertible &&
-         has_potential_animation == other.has_potential_animation &&
-         is_currently_animating == other.is_currently_animating &&
-         to_screen_is_potentially_animated ==
-             other.to_screen_is_potentially_animated &&
-         has_only_translation_animations ==
-             other.has_only_translation_animations &&
-         flattens_inherited_transform == other.flattens_inherited_transform &&
-         node_and_ancestors_are_flat == other.node_and_ancestors_are_flat &&
-         node_and_ancestors_have_only_integer_translation ==
-             other.node_and_ancestors_have_only_integer_translation &&
-         scrolls == other.scrolls &&
-         needs_sublayer_scale == other.needs_sublayer_scale &&
-         affected_by_inner_viewport_bounds_delta_x ==
-             other.affected_by_inner_viewport_bounds_delta_x &&
-         affected_by_inner_viewport_bounds_delta_y ==
-             other.affected_by_inner_viewport_bounds_delta_y &&
-         affected_by_outer_viewport_bounds_delta_x ==
-             other.affected_by_outer_viewport_bounds_delta_x &&
-         affected_by_outer_viewport_bounds_delta_y ==
-             other.affected_by_outer_viewport_bounds_delta_y &&
-         in_subtree_of_page_scale_layer ==
-             other.in_subtree_of_page_scale_layer &&
-         transform_changed == other.transform_changed &&
-         post_local_scale_factor == other.post_local_scale_factor &&
-         sublayer_scale == other.sublayer_scale &&
-         scroll_offset == other.scroll_offset &&
-         scroll_snap == other.scroll_snap &&
-         source_offset == other.source_offset &&
-         source_to_parent == other.source_to_parent;
-}
-
-void TransformNodeData::update_pre_local_transform(
-    const gfx::Point3F& transform_origin) {
-  pre_local.MakeIdentity();
-  pre_local.Translate3d(-transform_origin.x(), -transform_origin.y(),
-                        -transform_origin.z());
-}
-
-void TransformNodeData::update_post_local_transform(
-    const gfx::PointF& position,
-    const gfx::Point3F& transform_origin) {
-  post_local.MakeIdentity();
-  post_local.Scale(post_local_scale_factor, post_local_scale_factor);
-  post_local.Translate3d(
-      position.x() + source_offset.x() + transform_origin.x(),
-      position.y() + source_offset.y() + transform_origin.y(),
-      transform_origin.z());
-}
-
-void TransformNodeData::ToProtobuf(proto::TreeNode* proto) const {
-  DCHECK(!proto->has_transform_node_data());
-  proto::TranformNodeData* data = proto->mutable_transform_node_data();
-
-  TransformToProto(pre_local, data->mutable_pre_local());
-  TransformToProto(local, data->mutable_local());
-  TransformToProto(post_local, data->mutable_post_local());
-
-  TransformToProto(to_parent, data->mutable_to_parent());
-
-  data->set_source_node_id(source_node_id);
-  data->set_sorting_context_id(sorting_context_id);
-
-  data->set_needs_local_transform_update(needs_local_transform_update);
-
-  data->set_node_and_ancestors_are_animated_or_invertible(
-      node_and_ancestors_are_animated_or_invertible);
-
-  data->set_is_invertible(is_invertible);
-  data->set_ancestors_are_invertible(ancestors_are_invertible);
-
-  data->set_has_potential_animation(has_potential_animation);
-  data->set_is_currently_animating(is_currently_animating);
-  data->set_to_screen_is_potentially_animated(
-      to_screen_is_potentially_animated);
-  data->set_has_only_translation_animations(has_only_translation_animations);
-
-  data->set_flattens_inherited_transform(flattens_inherited_transform);
-  data->set_node_and_ancestors_are_flat(node_and_ancestors_are_flat);
-
-  data->set_node_and_ancestors_have_only_integer_translation(
-      node_and_ancestors_have_only_integer_translation);
-  data->set_scrolls(scrolls);
-  data->set_needs_sublayer_scale(needs_sublayer_scale);
-
-  data->set_affected_by_inner_viewport_bounds_delta_x(
-      affected_by_inner_viewport_bounds_delta_x);
-  data->set_affected_by_inner_viewport_bounds_delta_y(
-      affected_by_inner_viewport_bounds_delta_y);
-  data->set_affected_by_outer_viewport_bounds_delta_x(
-      affected_by_outer_viewport_bounds_delta_x);
-  data->set_affected_by_outer_viewport_bounds_delta_y(
-      affected_by_outer_viewport_bounds_delta_y);
-
-  data->set_in_subtree_of_page_scale_layer(in_subtree_of_page_scale_layer);
-  data->set_transform_changed(transform_changed);
-  data->set_post_local_scale_factor(post_local_scale_factor);
-
-  Vector2dFToProto(sublayer_scale, data->mutable_sublayer_scale());
-  ScrollOffsetToProto(scroll_offset, data->mutable_scroll_offset());
-  Vector2dFToProto(scroll_snap, data->mutable_scroll_snap());
-  Vector2dFToProto(source_offset, data->mutable_source_offset());
-  Vector2dFToProto(source_to_parent, data->mutable_source_to_parent());
-}
-
-void TransformNodeData::FromProtobuf(const proto::TreeNode& proto) {
-  DCHECK(proto.has_transform_node_data());
-  const proto::TranformNodeData& data = proto.transform_node_data();
-
-  pre_local = ProtoToTransform(data.pre_local());
-  local = ProtoToTransform(data.local());
-  post_local = ProtoToTransform(data.post_local());
-
-  to_parent = ProtoToTransform(data.to_parent());
-
-  source_node_id = data.source_node_id();
-  sorting_context_id = data.sorting_context_id();
-
-  needs_local_transform_update = data.needs_local_transform_update();
-
-  node_and_ancestors_are_animated_or_invertible =
-      data.node_and_ancestors_are_animated_or_invertible();
-
-  is_invertible = data.is_invertible();
-  ancestors_are_invertible = data.ancestors_are_invertible();
-
-  has_potential_animation = data.has_potential_animation();
-  is_currently_animating = data.is_currently_animating();
-  to_screen_is_potentially_animated = data.to_screen_is_potentially_animated();
-  has_only_translation_animations = data.has_only_translation_animations();
-
-  flattens_inherited_transform = data.flattens_inherited_transform();
-  node_and_ancestors_are_flat = data.node_and_ancestors_are_flat();
-
-  node_and_ancestors_have_only_integer_translation =
-      data.node_and_ancestors_have_only_integer_translation();
-  scrolls = data.scrolls();
-  needs_sublayer_scale = data.needs_sublayer_scale();
-
-  affected_by_inner_viewport_bounds_delta_x =
-      data.affected_by_inner_viewport_bounds_delta_x();
-  affected_by_inner_viewport_bounds_delta_y =
-      data.affected_by_inner_viewport_bounds_delta_y();
-  affected_by_outer_viewport_bounds_delta_x =
-      data.affected_by_outer_viewport_bounds_delta_x();
-  affected_by_outer_viewport_bounds_delta_y =
-      data.affected_by_outer_viewport_bounds_delta_y();
-
-  in_subtree_of_page_scale_layer = data.in_subtree_of_page_scale_layer();
-  transform_changed = data.transform_changed();
-  post_local_scale_factor = data.post_local_scale_factor();
-
-  sublayer_scale = ProtoToVector2dF(data.sublayer_scale());
-  scroll_offset = ProtoToScrollOffset(data.scroll_offset());
-  scroll_snap = ProtoToVector2dF(data.scroll_snap());
-  source_offset = ProtoToVector2dF(data.source_offset());
-  source_to_parent = ProtoToVector2dF(data.source_to_parent());
-}
-
-void TransformNodeData::AsValueInto(
-    base::trace_event::TracedValue* value) const {
-  MathUtil::AddToTracedValue("pre_local", pre_local, value);
-  MathUtil::AddToTracedValue("local", local, value);
-  MathUtil::AddToTracedValue("post_local", post_local, value);
-  // TODO(sunxd): make frameviewer work without target_id
-  value->SetInteger("target_id", 0);
-  value->SetInteger("content_target_id", 0);
-  value->SetInteger("source_node_id", source_node_id);
-  value->SetInteger("sorting_context_id", sorting_context_id);
-}
-
-TransformCachedNodeData::TransformCachedNodeData()
-    : target_id(-1), content_target_id(-1) {}
-
-TransformCachedNodeData::TransformCachedNodeData(
-    const TransformCachedNodeData& other) = default;
-
-TransformCachedNodeData::~TransformCachedNodeData() {}
-
-bool TransformCachedNodeData::operator==(
-    const TransformCachedNodeData& other) const {
-  return from_target == other.from_target && to_target == other.to_target &&
-         from_screen == other.from_screen && to_screen == other.to_screen &&
-         target_id == other.target_id &&
-         content_target_id == other.content_target_id;
-}
-
-void TransformCachedNodeData::ToProtobuf(
-    proto::TransformCachedNodeData* proto) const {
-  TransformToProto(from_target, proto->mutable_from_target());
-  TransformToProto(to_target, proto->mutable_to_target());
-  TransformToProto(from_screen, proto->mutable_from_screen());
-  TransformToProto(to_screen, proto->mutable_to_screen());
-  proto->set_target_id(target_id);
-  proto->set_content_target_id(content_target_id);
-}
-
-void TransformCachedNodeData::FromProtobuf(
-    const proto::TransformCachedNodeData& proto) {
-  from_target = ProtoToTransform(proto.from_target());
-  to_target = ProtoToTransform(proto.to_target());
-  from_screen = ProtoToTransform(proto.from_screen());
-  to_screen = ProtoToTransform(proto.to_screen());
-  target_id = proto.target_id();
-  content_target_id = proto.content_target_id();
-}
-
-ClipNodeData::ClipNodeData()
-    : transform_id(-1),
-      target_id(-1),
-      applies_local_clip(true),
-      layer_clipping_uses_only_local_clip(false),
-      target_is_clipped(false),
-      layers_are_clipped(false),
-      layers_are_clipped_when_surfaces_disabled(false),
-      resets_clip(false) {}
-
-ClipNodeData::ClipNodeData(const ClipNodeData& other) = default;
-
-bool ClipNodeData::operator==(const ClipNodeData& other) const {
-  return clip == other.clip &&
-         combined_clip_in_target_space == other.combined_clip_in_target_space &&
-         clip_in_target_space == other.clip_in_target_space &&
-         transform_id == other.transform_id && target_id == other.target_id &&
-         applies_local_clip == other.applies_local_clip &&
-         layer_clipping_uses_only_local_clip ==
-             other.layer_clipping_uses_only_local_clip &&
-         target_is_clipped == other.target_is_clipped &&
-         layers_are_clipped == other.layers_are_clipped &&
-         layers_are_clipped_when_surfaces_disabled ==
-             other.layers_are_clipped_when_surfaces_disabled &&
-         resets_clip == other.resets_clip;
-}
-
-void ClipNodeData::ToProtobuf(proto::TreeNode* proto) const {
-  DCHECK(!proto->has_clip_node_data());
-  proto::ClipNodeData* data = proto->mutable_clip_node_data();
-
-  RectFToProto(clip, data->mutable_clip());
-  RectFToProto(combined_clip_in_target_space,
-               data->mutable_combined_clip_in_target_space());
-  RectFToProto(clip_in_target_space, data->mutable_clip_in_target_space());
-
-  data->set_transform_id(transform_id);
-  data->set_target_id(target_id);
-  data->set_applies_local_clip(applies_local_clip);
-  data->set_layer_clipping_uses_only_local_clip(
-      layer_clipping_uses_only_local_clip);
-  data->set_target_is_clipped(target_is_clipped);
-  data->set_layers_are_clipped(layers_are_clipped);
-  data->set_layers_are_clipped_when_surfaces_disabled(
-      layers_are_clipped_when_surfaces_disabled);
-  data->set_resets_clip(resets_clip);
-}
-
-void ClipNodeData::FromProtobuf(const proto::TreeNode& proto) {
-  DCHECK(proto.has_clip_node_data());
-  const proto::ClipNodeData& data = proto.clip_node_data();
-
-  clip = ProtoToRectF(data.clip());
-  combined_clip_in_target_space =
-      ProtoToRectF(data.combined_clip_in_target_space());
-  clip_in_target_space = ProtoToRectF(data.clip_in_target_space());
-
-  transform_id = data.transform_id();
-  target_id = data.target_id();
-  applies_local_clip = data.applies_local_clip();
-  layer_clipping_uses_only_local_clip =
-      data.layer_clipping_uses_only_local_clip();
-  target_is_clipped = data.target_is_clipped();
-  layers_are_clipped = data.layers_are_clipped();
-  layers_are_clipped_when_surfaces_disabled =
-      data.layers_are_clipped_when_surfaces_disabled();
-  resets_clip = data.resets_clip();
-}
-
-void ClipNodeData::AsValueInto(base::trace_event::TracedValue* value) const {
-  MathUtil::AddToTracedValue("clip", clip, value);
-  value->SetInteger("transform_id", transform_id);
-  value->SetInteger("target_id", target_id);
-  value->SetBoolean("applies_local_clip", applies_local_clip);
-  value->SetBoolean("layer_clipping_uses_only_local_clip",
-                    layer_clipping_uses_only_local_clip);
-  value->SetBoolean("target_is_clipped", target_is_clipped);
-  value->SetBoolean("layers_are_clipped", layers_are_clipped);
-  value->SetBoolean("layers_are_clipped_when_surfaces_disabled",
-                    layers_are_clipped_when_surfaces_disabled);
-  value->SetBoolean("resets_clip", resets_clip);
-}
-
-EffectNodeData::EffectNodeData()
-    : opacity(1.f),
-      screen_space_opacity(1.f),
-      has_render_surface(false),
-      render_surface(nullptr),
-      has_copy_request(false),
-      hidden_by_backface_visibility(false),
-      double_sided(false),
-      is_drawn(true),
-      subtree_hidden(false),
-      has_potential_opacity_animation(false),
-      is_currently_animating_opacity(false),
-      effect_changed(false),
-      num_copy_requests_in_subtree(0),
-      has_unclipped_descendants(false),
-      transform_id(0),
-      clip_id(0),
-      target_id(0),
-      mask_layer_id(-1),
-      replica_layer_id(-1),
-      replica_mask_layer_id(-1) {}
-
-EffectNodeData::EffectNodeData(const EffectNodeData& other) = default;
-
-bool EffectNodeData::operator==(const EffectNodeData& other) const {
-  return opacity == other.opacity &&
-         screen_space_opacity == other.screen_space_opacity &&
-         has_render_surface == other.has_render_surface &&
-         has_copy_request == other.has_copy_request &&
-         background_filters == other.background_filters &&
-         hidden_by_backface_visibility == other.hidden_by_backface_visibility &&
-         double_sided == other.double_sided && is_drawn == other.is_drawn &&
-         subtree_hidden == other.subtree_hidden &&
-         has_potential_opacity_animation ==
-             other.has_potential_opacity_animation &&
-         is_currently_animating_opacity ==
-             other.is_currently_animating_opacity &&
-         effect_changed == other.effect_changed &&
-         num_copy_requests_in_subtree == other.num_copy_requests_in_subtree &&
-         transform_id == other.transform_id && clip_id == other.clip_id &&
-         target_id == other.target_id && mask_layer_id == other.mask_layer_id &&
-         replica_layer_id == other.replica_layer_id &&
-         replica_mask_layer_id == other.replica_mask_layer_id;
-}
-
-void EffectNodeData::ToProtobuf(proto::TreeNode* proto) const {
-  DCHECK(!proto->has_effect_node_data());
-  proto::EffectNodeData* data = proto->mutable_effect_node_data();
-  data->set_opacity(opacity);
-  data->set_screen_space_opacity(screen_space_opacity);
-  data->set_has_render_surface(has_render_surface);
-  data->set_has_copy_request(has_copy_request);
-  data->set_hidden_by_backface_visibility(hidden_by_backface_visibility);
-  data->set_double_sided(double_sided);
-  data->set_is_drawn(is_drawn);
-  data->set_subtree_hidden(subtree_hidden);
-  data->set_has_potential_opacity_animation(has_potential_opacity_animation);
-  data->set_is_currently_animating_opacity(is_currently_animating_opacity);
-  data->set_effect_changed(effect_changed);
-  data->set_num_copy_requests_in_subtree(num_copy_requests_in_subtree);
-  data->set_transform_id(transform_id);
-  data->set_clip_id(clip_id);
-  data->set_target_id(target_id);
-  data->set_mask_layer_id(mask_layer_id);
-  data->set_replica_layer_id(replica_layer_id);
-  data->set_replica_mask_layer_id(replica_mask_layer_id);
-}
-
-void EffectNodeData::FromProtobuf(const proto::TreeNode& proto) {
-  DCHECK(proto.has_effect_node_data());
-  const proto::EffectNodeData& data = proto.effect_node_data();
-
-  opacity = data.opacity();
-  screen_space_opacity = data.screen_space_opacity();
-  has_render_surface = data.has_render_surface();
-  has_copy_request = data.has_copy_request();
-  hidden_by_backface_visibility = data.hidden_by_backface_visibility();
-  double_sided = data.double_sided();
-  is_drawn = data.is_drawn();
-  subtree_hidden = data.subtree_hidden();
-  has_potential_opacity_animation = data.has_potential_opacity_animation();
-  is_currently_animating_opacity = data.is_currently_animating_opacity();
-  effect_changed = data.effect_changed();
-  num_copy_requests_in_subtree = data.num_copy_requests_in_subtree();
-  transform_id = data.transform_id();
-  clip_id = data.clip_id();
-  target_id = data.target_id();
-  mask_layer_id = data.mask_layer_id();
-  replica_layer_id = data.replica_layer_id();
-  replica_mask_layer_id = data.replica_mask_layer_id();
-}
-
-void EffectNodeData::AsValueInto(base::trace_event::TracedValue* value) const {
-  value->SetDouble("opacity", opacity);
-  value->SetBoolean("has_render_surface", has_render_surface);
-  value->SetBoolean("has_copy_request", has_copy_request);
-  value->SetBoolean("double_sided", double_sided);
-  value->SetBoolean("is_drawn", is_drawn);
-  value->SetBoolean("has_potential_opacity_animation",
-                    has_potential_opacity_animation);
-  value->SetBoolean("effect_changed", effect_changed);
-  value->SetInteger("num_copy_requests_in_subtree",
-                    num_copy_requests_in_subtree);
-  value->SetInteger("transform_id", transform_id);
-  value->SetInteger("clip_id", clip_id);
-  value->SetInteger("target_id", target_id);
-  value->SetInteger("mask_layer_id", mask_layer_id);
-  value->SetInteger("replica_layer_id", replica_layer_id);
-  value->SetInteger("replica_mask_layer_id", replica_mask_layer_id);
-}
-
-ScrollNodeData::ScrollNodeData()
-    : scrollable(false),
-      main_thread_scrolling_reasons(
-          MainThreadScrollingReason::kNotScrollingOnMain),
-      contains_non_fast_scrollable_region(false),
-      max_scroll_offset_affected_by_page_scale(false),
-      is_inner_viewport_scroll_layer(false),
-      is_outer_viewport_scroll_layer(false),
-      should_flatten(false),
-      user_scrollable_horizontal(false),
-      user_scrollable_vertical(false),
-      transform_id(0),
-      num_drawn_descendants(0) {}
-
-ScrollNodeData::ScrollNodeData(const ScrollNodeData& other) = default;
-
-bool ScrollNodeData::operator==(const ScrollNodeData& other) const {
-  return scrollable == other.scrollable &&
-         main_thread_scrolling_reasons == other.main_thread_scrolling_reasons &&
-         contains_non_fast_scrollable_region ==
-             other.contains_non_fast_scrollable_region &&
-         scroll_clip_layer_bounds == other.scroll_clip_layer_bounds &&
-         bounds == other.bounds &&
-         max_scroll_offset_affected_by_page_scale ==
-             other.max_scroll_offset_affected_by_page_scale &&
-         is_inner_viewport_scroll_layer ==
-             other.is_inner_viewport_scroll_layer &&
-         is_outer_viewport_scroll_layer ==
-             other.is_outer_viewport_scroll_layer &&
-         offset_to_transform_parent == other.offset_to_transform_parent &&
-         should_flatten == other.should_flatten &&
-         user_scrollable_horizontal == other.user_scrollable_horizontal &&
-         user_scrollable_vertical == other.user_scrollable_vertical &&
-         element_id == other.element_id && transform_id == other.transform_id;
-}
-
-void ScrollNodeData::ToProtobuf(proto::TreeNode* proto) const {
-  DCHECK(!proto->has_scroll_node_data());
-  proto::ScrollNodeData* data = proto->mutable_scroll_node_data();
-  data->set_scrollable(scrollable);
-  data->set_main_thread_scrolling_reasons(main_thread_scrolling_reasons);
-  data->set_contains_non_fast_scrollable_region(
-      contains_non_fast_scrollable_region);
-  SizeToProto(scroll_clip_layer_bounds,
-              data->mutable_scroll_clip_layer_bounds());
-  SizeToProto(bounds, data->mutable_bounds());
-  data->set_max_scroll_offset_affected_by_page_scale(
-      max_scroll_offset_affected_by_page_scale);
-  data->set_is_inner_viewport_scroll_layer(is_inner_viewport_scroll_layer);
-  data->set_is_outer_viewport_scroll_layer(is_outer_viewport_scroll_layer);
-  Vector2dFToProto(offset_to_transform_parent,
-                   data->mutable_offset_to_transform_parent());
-  data->set_should_flatten(should_flatten);
-  data->set_user_scrollable_horizontal(user_scrollable_horizontal);
-  data->set_user_scrollable_vertical(user_scrollable_vertical);
-  element_id.ToProtobuf(data->mutable_element_id());
-  data->set_transform_id(transform_id);
-}
-
-void ScrollNodeData::FromProtobuf(const proto::TreeNode& proto) {
-  DCHECK(proto.has_scroll_node_data());
-  const proto::ScrollNodeData& data = proto.scroll_node_data();
-
-  scrollable = data.scrollable();
-  main_thread_scrolling_reasons = data.main_thread_scrolling_reasons();
-  contains_non_fast_scrollable_region =
-      data.contains_non_fast_scrollable_region();
-  scroll_clip_layer_bounds = ProtoToSize(data.scroll_clip_layer_bounds());
-  bounds = ProtoToSize(data.bounds());
-  max_scroll_offset_affected_by_page_scale =
-      data.max_scroll_offset_affected_by_page_scale();
-  is_inner_viewport_scroll_layer = data.is_inner_viewport_scroll_layer();
-  is_outer_viewport_scroll_layer = data.is_outer_viewport_scroll_layer();
-  offset_to_transform_parent =
-      ProtoToVector2dF(data.offset_to_transform_parent());
-  should_flatten = data.should_flatten();
-  user_scrollable_horizontal = data.user_scrollable_horizontal();
-  user_scrollable_vertical = data.user_scrollable_vertical();
-  element_id.FromProtobuf(data.element_id());
-  transform_id = data.transform_id();
-}
-
-void ScrollNodeData::AsValueInto(base::trace_event::TracedValue* value) const {
-  value->SetBoolean("scrollable", scrollable);
-  MathUtil::AddToTracedValue("scroll_clip_layer_bounds",
-                             scroll_clip_layer_bounds, value);
-  MathUtil::AddToTracedValue("bounds", bounds, value);
-  MathUtil::AddToTracedValue("offset_to_transform_parent",
-                             offset_to_transform_parent, value);
-  value->SetBoolean("should_flatten", should_flatten);
-  value->SetBoolean("user_scrollable_horizontal", user_scrollable_horizontal);
-  value->SetBoolean("user_scrollable_vertical", user_scrollable_vertical);
-
-  element_id.AddToTracedValue(value);
-  value->SetInteger("transform_id", transform_id);
-}
-
 int TransformTree::Insert(const TransformNode& tree_node, int parent_id) {
   int node_id = PropertyTree<TransformNode>::Insert(tree_node, parent_id);
   DCHECK_EQ(node_id, static_cast<int>(cached_data_.size()));
@@ -731,11 +163,11 @@
   bool success = ComputeTransform(source_id, dest_id, transform);
 
   const TransformNode* dest_node = Node(dest_id);
-  if (!dest_node->data.needs_sublayer_scale)
+  if (!dest_node->needs_sublayer_scale)
     return success;
 
-  transform->matrix().postScale(dest_node->data.sublayer_scale.x(),
-                                dest_node->data.sublayer_scale.y(), 1.f);
+  transform->matrix().postScale(dest_node->sublayer_scale.x(),
+                                dest_node->sublayer_scale.y(), 1.f);
   return success;
 }
 
@@ -746,15 +178,15 @@
   bool success = ComputeTransform(source_id, dest_id, transform);
 
   const TransformNode* source_node = Node(source_id);
-  if (!source_node->data.needs_sublayer_scale)
+  if (!source_node->needs_sublayer_scale)
     return success;
 
-  if (source_node->data.sublayer_scale.x() == 0 ||
-      source_node->data.sublayer_scale.y() == 0)
+  if (source_node->sublayer_scale.x() == 0 ||
+      source_node->sublayer_scale.y() == 0)
     return false;
 
-  transform->Scale(1.f / source_node->data.sublayer_scale.x(),
-                   1.f / source_node->data.sublayer_scale.y());
+  transform->Scale(1.f / source_node->sublayer_scale.x(),
+                   1.f / source_node->sublayer_scale.y());
   return success;
 }
 
@@ -766,13 +198,13 @@
 
 bool TransformTree::NeedsSourceToParentUpdate(TransformNode* node) {
   return (source_to_parent_updates_allowed() &&
-          node->parent_id != node->data.source_node_id);
+          node->parent_id != node->source_node_id);
 }
 
 void TransformTree::ResetChangeTracking() {
   for (int id = 1; id < static_cast<int>(size()); ++id) {
     TransformNode* node = Node(id);
-    node->data.transform_changed = false;
+    node->transform_changed = false;
   }
 }
 
@@ -780,18 +212,17 @@
   TransformNode* node = Node(id);
   TransformNode* parent_node = parent(node);
   TransformNode* target_node = Node(TargetId(id));
-  TransformNode* source_node = Node(node->data.source_node_id);
+  TransformNode* source_node = Node(node->source_node_id);
   property_trees()->UpdateCachedNumber();
-  if (node->data.needs_local_transform_update ||
-      NeedsSourceToParentUpdate(node))
+  if (node->needs_local_transform_update || NeedsSourceToParentUpdate(node))
     UpdateLocalTransform(node);
   else
     UndoSnapping(node);
   UpdateScreenSpaceTransform(node, parent_node, target_node);
   UpdateSublayerScale(node);
-  UpdateTargetSpaceTransform(node, target_node);
   UpdateAnimationProperties(node, parent_node);
   UpdateSnapping(node);
+  UpdateTargetSpaceTransform(node, target_node);
   UpdateNodeAndAncestorsHaveIntegerTranslations(node, parent_node);
   UpdateTransformChanged(node, parent_node, source_node);
   UpdateNodeAndAncestorsAreAnimatedOrInvertible(node, parent_node);
@@ -822,8 +253,8 @@
   // R^{-1} * A^{-1}. If at least one of A and R isn't flat, the inverse of
   // flattened(A * R) won't be R^{-1} * A{-1}, so multiplying C's to_screen and
   // A's from_screen will not produce the correct result.
-  if (!dest || (dest->data.ancestors_are_invertible &&
-                dest->data.node_and_ancestors_are_flat)) {
+  if (!dest ||
+      (dest->ancestors_are_invertible && dest->node_and_ancestors_are_flat)) {
     transform->ConcatTransform(ToScreen(current->id));
     if (dest)
       transform->ConcatTransform(FromScreen(dest->id));
@@ -843,10 +274,9 @@
   source_to_destination.push_back(current->id);
   current = parent(current);
   bool destination_has_non_zero_sublayer_scale =
-      dest->data.sublayer_scale.x() != 0.f &&
-      dest->data.sublayer_scale.y() != 0.f;
+      dest->sublayer_scale.x() != 0.f && dest->sublayer_scale.y() != 0.f;
   DCHECK(destination_has_non_zero_sublayer_scale ||
-         !dest->data.ancestors_are_invertible);
+         !dest->ancestors_are_invertible);
   for (; current && current->id > dest_id; current = parent(current)) {
     if (destination_has_non_zero_sublayer_scale &&
         TargetId(current->id) == dest_id &&
@@ -860,9 +290,8 @@
     combined_transform = ToTarget(current->id);
     // The stored target space transform has sublayer scale baked in, but we
     // need the unscaled transform.
-    combined_transform.matrix().postScale(1.0f / dest->data.sublayer_scale.x(),
-                                          1.0f / dest->data.sublayer_scale.y(),
-                                          1.0f);
+    combined_transform.matrix().postScale(
+        1.0f / dest->sublayer_scale.x(), 1.0f / dest->sublayer_scale.y(), 1.0f);
   } else if (current->id < dest_id) {
     // We have reached the lowest common ancestor of the source and destination
     // nodes. This case can occur when we are transforming between a node
@@ -891,9 +320,9 @@
   for (size_t i = 0; i < source_to_destination_size; ++i) {
     size_t index = source_to_destination_size - 1 - i;
     const TransformNode* node = Node(source_to_destination[index]);
-    if (node->data.flattens_inherited_transform)
+    if (node->flattens_inherited_transform)
       combined_transform.FlattenTo2d();
-    combined_transform.PreconcatTransform(node->data.to_parent);
+    combined_transform.PreconcatTransform(node->to_parent);
   }
 
   transform->ConcatTransform(combined_transform);
@@ -909,8 +338,8 @@
   // Just as in CombineTransformsBetween, we can use screen space transforms in
   // this computation only when there isn't any non-trivial flattening
   // involved.
-  if (current->data.ancestors_are_invertible &&
-      current->data.node_and_ancestors_are_flat) {
+  if (current->ancestors_are_invertible &&
+      current->node_and_ancestors_are_flat) {
     transform->PreconcatTransform(FromScreen(current->id));
     if (dest)
       transform->PreconcatTransform(ToScreen(dest->id));
@@ -931,11 +360,11 @@
 }
 
 void TransformTree::UpdateLocalTransform(TransformNode* node) {
-  gfx::Transform transform = node->data.post_local;
+  gfx::Transform transform = node->post_local;
   if (NeedsSourceToParentUpdate(node)) {
     gfx::Transform to_parent;
-    ComputeTransform(node->data.source_node_id, node->parent_id, &to_parent);
-    node->data.source_to_parent = to_parent.To2dTranslation();
+    ComputeTransform(node->source_node_id, node->parent_id, &to_parent);
+    node->source_to_parent = to_parent.To2dTranslation();
   }
 
   gfx::Vector2dF fixed_position_adjustment;
@@ -943,76 +372,73 @@
       property_trees()->inner_viewport_container_bounds_delta();
   gfx::Vector2dF outer_viewport_bounds_delta =
       property_trees()->outer_viewport_container_bounds_delta();
-  if (node->data.affected_by_inner_viewport_bounds_delta_x)
+  if (node->affected_by_inner_viewport_bounds_delta_x)
     fixed_position_adjustment.set_x(inner_viewport_bounds_delta.x());
-  else if (node->data.affected_by_outer_viewport_bounds_delta_x)
+  else if (node->affected_by_outer_viewport_bounds_delta_x)
     fixed_position_adjustment.set_x(outer_viewport_bounds_delta.x());
 
-  if (node->data.affected_by_inner_viewport_bounds_delta_y)
+  if (node->affected_by_inner_viewport_bounds_delta_y)
     fixed_position_adjustment.set_y(inner_viewport_bounds_delta.y());
-  else if (node->data.affected_by_outer_viewport_bounds_delta_y)
+  else if (node->affected_by_outer_viewport_bounds_delta_y)
     fixed_position_adjustment.set_y(outer_viewport_bounds_delta.y());
 
-  transform.Translate(
-      node->data.source_to_parent.x() - node->data.scroll_offset.x() +
-          fixed_position_adjustment.x(),
-      node->data.source_to_parent.y() - node->data.scroll_offset.y() +
-          fixed_position_adjustment.y());
-  transform.PreconcatTransform(node->data.local);
-  transform.PreconcatTransform(node->data.pre_local);
-  node->data.set_to_parent(transform);
-  node->data.needs_local_transform_update = false;
+  transform.Translate(node->source_to_parent.x() - node->scroll_offset.x() +
+                          fixed_position_adjustment.x(),
+                      node->source_to_parent.y() - node->scroll_offset.y() +
+                          fixed_position_adjustment.y());
+  transform.PreconcatTransform(node->local);
+  transform.PreconcatTransform(node->pre_local);
+  node->set_to_parent(transform);
+  node->needs_local_transform_update = false;
 }
 
 void TransformTree::UpdateScreenSpaceTransform(TransformNode* node,
                                                TransformNode* parent_node,
                                                TransformNode* target_node) {
   if (!parent_node) {
-    SetToScreen(node->id, node->data.to_parent);
-    node->data.ancestors_are_invertible = true;
-    node->data.to_screen_is_potentially_animated = false;
-    node->data.node_and_ancestors_are_flat = node->data.to_parent.IsFlat();
+    SetToScreen(node->id, node->to_parent);
+    node->ancestors_are_invertible = true;
+    node->to_screen_is_potentially_animated = false;
+    node->node_and_ancestors_are_flat = node->to_parent.IsFlat();
   } else {
     gfx::Transform to_screen_space_transform = ToScreen(parent_node->id);
-    if (node->data.flattens_inherited_transform)
+    if (node->flattens_inherited_transform)
       to_screen_space_transform.FlattenTo2d();
-    to_screen_space_transform.PreconcatTransform(node->data.to_parent);
-    node->data.ancestors_are_invertible =
-        parent_node->data.ancestors_are_invertible;
-    node->data.node_and_ancestors_are_flat =
-        parent_node->data.node_and_ancestors_are_flat &&
-        node->data.to_parent.IsFlat();
+    to_screen_space_transform.PreconcatTransform(node->to_parent);
+    node->ancestors_are_invertible = parent_node->ancestors_are_invertible;
+    node->node_and_ancestors_are_flat =
+        parent_node->node_and_ancestors_are_flat && node->to_parent.IsFlat();
     SetToScreen(node->id, to_screen_space_transform);
   }
 
   gfx::Transform from_screen;
   if (!ToScreen(node->id).GetInverse(&from_screen))
-    node->data.ancestors_are_invertible = false;
+    node->ancestors_are_invertible = false;
   SetFromScreen(node->id, from_screen);
 }
 
 void TransformTree::UpdateSublayerScale(TransformNode* node) {
   // The sublayer scale depends on the screen space transform, so update it too.
-  if (!node->data.needs_sublayer_scale) {
-    node->data.sublayer_scale = gfx::Vector2dF(1.0f, 1.0f);
+  if (!node->needs_sublayer_scale) {
+    node->sublayer_scale = gfx::Vector2dF(1.0f, 1.0f);
     return;
   }
 
   float layer_scale_factor =
       device_scale_factor_ * device_transform_scale_factor_;
-  if (node->data.in_subtree_of_page_scale_layer)
+  if (node->in_subtree_of_page_scale_layer)
     layer_scale_factor *= page_scale_factor_;
-  node->data.sublayer_scale = MathUtil::ComputeTransform2dScaleComponents(
+  node->sublayer_scale = MathUtil::ComputeTransform2dScaleComponents(
       ToScreen(node->id), layer_scale_factor);
 }
 
 void TransformTree::UpdateTargetSpaceTransform(TransformNode* node,
                                                TransformNode* target_node) {
   gfx::Transform target_space_transform;
-  if (node->data.needs_sublayer_scale) {
+  if (node->needs_sublayer_scale) {
     target_space_transform.MakeIdentity();
-    target_space_transform.Scale(node->data.sublayer_scale.x(),
-                                 node->data.sublayer_scale.y());
+    target_space_transform.Scale(node->sublayer_scale.x(),
+                                 node->sublayer_scale.y());
   } else {
     // In order to include the root transform for the root surface, we walk up
     // to the root of the transform tree in ComputeTransform.
@@ -1023,7 +449,7 @@
 
   gfx::Transform from_target;
   if (!target_space_transform.GetInverse(&from_target))
-    node->data.ancestors_are_invertible = false;
+    node->ancestors_are_invertible = false;
   SetToTarget(node->id, target_space_transform);
   SetFromTarget(node->id, from_target);
 }
@@ -1032,23 +458,22 @@
                                               TransformNode* parent_node) {
   bool ancestor_is_animating = false;
   if (parent_node)
-    ancestor_is_animating = parent_node->data.to_screen_is_potentially_animated;
-  node->data.to_screen_is_potentially_animated =
-      node->data.has_potential_animation || ancestor_is_animating;
+    ancestor_is_animating = parent_node->to_screen_is_potentially_animated;
+  node->to_screen_is_potentially_animated =
+      node->has_potential_animation || ancestor_is_animating;
 }
 
 void TransformTree::UndoSnapping(TransformNode* node) {
   // to_parent transform has the scroll snap from previous frame baked in.
   // We need to undo it and use the un-snapped transform to compute current
   // target and screen space transforms.
-  node->data.to_parent.Translate(-node->data.scroll_snap.x(),
-                                 -node->data.scroll_snap.y());
+  node->to_parent.Translate(-node->scroll_snap.x(), -node->scroll_snap.y());
 }
 
 void TransformTree::UpdateSnapping(TransformNode* node) {
-  if (!node->data.scrolls || node->data.to_screen_is_potentially_animated ||
+  if (!node->scrolls || node->to_screen_is_potentially_animated ||
       !ToScreen(node->id).IsScaleOrTranslation() ||
-      !node->data.ancestors_are_invertible) {
+      !node->ancestors_are_invertible) {
     return;
   }
 
@@ -1071,67 +496,60 @@
   // Now that we have our scroll delta, we must apply it to each of our
   // combined, to/from matrices.
   SetToScreen(node->id, rounded);
-  node->data.to_parent.Translate(translation.x(), translation.y());
+  node->to_parent.Translate(translation.x(), translation.y());
   gfx::Transform from_screen = FromScreen(node->id);
   from_screen.matrix().postTranslate(-translation.x(), -translation.y(), 0);
   SetFromScreen(node->id, from_screen);
-  gfx::Transform to_target = ToTarget(node->id);
-  to_target.Translate(translation.x(), translation.y());
-  SetToTarget(node->id, to_target);
-  gfx::Transform from_target = FromTarget(node->id);
-  from_target.matrix().postTranslate(-translation.x(), -translation.y(), 0);
-  SetFromTarget(node->id, from_target);
-  node->data.scroll_snap = translation;
+  node->scroll_snap = translation;
 }
 
 void TransformTree::UpdateTransformChanged(TransformNode* node,
                                            TransformNode* parent_node,
                                            TransformNode* source_node) {
-  if (parent_node && parent_node->data.transform_changed) {
-    node->data.transform_changed = true;
+  if (parent_node && parent_node->transform_changed) {
+    node->transform_changed = true;
     return;
   }
 
   if (source_node && source_node->id != parent_node->id &&
-      source_to_parent_updates_allowed_ && source_node->data.transform_changed)
-    node->data.transform_changed = true;
+      source_to_parent_updates_allowed_ && source_node->transform_changed)
+    node->transform_changed = true;
 }
 
 void TransformTree::UpdateNodeAndAncestorsAreAnimatedOrInvertible(
     TransformNode* node,
     TransformNode* parent_node) {
   if (!parent_node) {
-    node->data.node_and_ancestors_are_animated_or_invertible =
-        node->data.has_potential_animation || node->data.is_invertible;
+    node->node_and_ancestors_are_animated_or_invertible =
+        node->has_potential_animation || node->is_invertible;
     return;
   }
-  if (!parent_node->data.node_and_ancestors_are_animated_or_invertible) {
-    node->data.node_and_ancestors_are_animated_or_invertible = false;
+  if (!parent_node->node_and_ancestors_are_animated_or_invertible) {
+    node->node_and_ancestors_are_animated_or_invertible = false;
     return;
   }
-  bool is_invertible = node->data.is_invertible;
+  bool is_invertible = node->is_invertible;
   // Even when the current node's transform and the parent's screen space
   // transform are invertible, the current node's screen space transform can
   // become uninvertible due to floating-point arithmetic.
-  if (!node->data.ancestors_are_invertible &&
-      parent_node->data.ancestors_are_invertible)
+  if (!node->ancestors_are_invertible && parent_node->ancestors_are_invertible)
     is_invertible = false;
-  node->data.node_and_ancestors_are_animated_or_invertible =
-      node->data.has_potential_animation || is_invertible;
+  node->node_and_ancestors_are_animated_or_invertible =
+      node->has_potential_animation || is_invertible;
 }
 
 void TransformTree::SetDeviceTransform(const gfx::Transform& transform,
                                        gfx::PointF root_position) {
   gfx::Transform root_post_local = transform;
   TransformNode* node = Node(1);
-  root_post_local.Scale(node->data.post_local_scale_factor,
-                        node->data.post_local_scale_factor);
+  root_post_local.Scale(node->post_local_scale_factor,
+                        node->post_local_scale_factor);
   root_post_local.Translate(root_position.x(), root_position.y());
-  if (node->data.post_local == root_post_local)
+  if (node->post_local == root_post_local)
     return;
 
-  node->data.post_local = root_post_local;
-  node->data.needs_local_transform_update = true;
+  node->post_local = root_post_local;
+  node->needs_local_transform_update = true;
   set_needs_update(true);
 }
 
@@ -1152,7 +570,7 @@
 
   set_needs_update(true);
   for (int i : nodes_affected_by_inner_viewport_bounds_delta_)
-    Node(i)->data.needs_local_transform_update = true;
+    Node(i)->needs_local_transform_update = true;
 }
 
 void TransformTree::UpdateOuterViewportContainerBoundsDelta() {
@@ -1161,7 +579,7 @@
 
   set_needs_update(true);
   for (int i : nodes_affected_by_outer_viewport_bounds_delta_)
-    Node(i)->data.needs_local_transform_update = true;
+    Node(i)->needs_local_transform_update = true;
 }
 
 void TransformTree::AddNodeAffectedByInnerViewportBoundsDelta(int node_id) {
@@ -1250,10 +668,9 @@
   }
   const TransformNode* node = Node(id);
   gfx::Transform screen_space_transform = ToScreen(id);
-  if (node->data.sublayer_scale.x() != 0.0 &&
-      node->data.sublayer_scale.y() != 0.0)
-    screen_space_transform.Scale(1.0 / node->data.sublayer_scale.x(),
-                                 1.0 / node->data.sublayer_scale.y());
+  if (node->sublayer_scale.x() != 0.0 && node->sublayer_scale.y() != 0.0)
+    screen_space_transform.Scale(1.0 / node->sublayer_scale.x(),
+                                 1.0 / node->sublayer_scale.y());
   return screen_space_transform;
 }
 
@@ -1340,14 +757,14 @@
 }
 
 float EffectTree::EffectiveOpacity(const EffectNode* node) const {
-  return node->data.subtree_hidden ? 0.f : node->data.opacity;
+  return node->subtree_hidden ? 0.f : node->opacity;
 }
 
 void EffectTree::UpdateOpacities(EffectNode* node, EffectNode* parent_node) {
-  node->data.screen_space_opacity = EffectiveOpacity(node);
+  node->screen_space_opacity = EffectiveOpacity(node);
 
   if (parent_node)
-    node->data.screen_space_opacity *= parent_node->data.screen_space_opacity;
+    node->screen_space_opacity *= parent_node->screen_space_opacity;
 }
 
 void EffectTree::UpdateIsDrawn(EffectNode* node, EffectNode* parent_node) {
@@ -1358,64 +775,80 @@
   // 2) Nodes that have a background filter.
   // 3) Nodes with animating screen space opacity on main thread or pending tree
   //    are drawn if their parent is drawn irrespective of their opacity.
-  if (node->data.has_copy_request)
-    node->data.is_drawn = true;
+  if (node->has_copy_request)
+    node->is_drawn = true;
   else if (EffectiveOpacity(node) == 0.f &&
-           (!node->data.has_potential_opacity_animation ||
+           (!node->has_potential_opacity_animation ||
             property_trees()->is_active) &&
-           node->data.background_filters.IsEmpty())
-    node->data.is_drawn = false;
+           node->background_filters.IsEmpty())
+    node->is_drawn = false;
   else if (parent_node)
-    node->data.is_drawn = parent_node->data.is_drawn;
+    node->is_drawn = parent_node->is_drawn;
   else
-    node->data.is_drawn = true;
+    node->is_drawn = true;
 }
 
 void EffectTree::UpdateEffectChanged(EffectNode* node,
                                      EffectNode* parent_node) {
-  if (parent_node && parent_node->data.effect_changed) {
-    node->data.effect_changed = true;
+  if (parent_node && parent_node->effect_changed) {
+    node->effect_changed = true;
   }
 }
 
 void EffectTree::UpdateBackfaceVisibility(EffectNode* node,
                                           EffectNode* parent_node) {
   if (!parent_node) {
-    node->data.hidden_by_backface_visibility = false;
+    node->hidden_by_backface_visibility = false;
     return;
   }
-  if (parent_node->data.hidden_by_backface_visibility) {
-    node->data.hidden_by_backface_visibility = true;
+  if (parent_node->hidden_by_backface_visibility) {
+    node->hidden_by_backface_visibility = true;
     return;
   }
 
   TransformTree& transform_tree = property_trees()->transform_tree;
-  if (node->data.has_render_surface && !node->data.double_sided) {
-    TransformNode* transform_node =
-        transform_tree.Node(node->data.transform_id);
-    if (transform_node->data.is_invertible &&
-        transform_node->data.ancestors_are_invertible) {
-      if (transform_node->data.sorting_context_id) {
+  if (node->has_render_surface && !node->double_sided) {
+    TransformNode* transform_node = transform_tree.Node(node->transform_id);
+    if (transform_node->is_invertible &&
+        transform_node->ancestors_are_invertible) {
+      if (transform_node->sorting_context_id) {
         const TransformNode* parent_transform_node =
             transform_tree.parent(transform_node);
         if (parent_transform_node &&
-            parent_transform_node->data.sorting_context_id ==
-                transform_node->data.sorting_context_id) {
+            parent_transform_node->sorting_context_id ==
+                transform_node->sorting_context_id) {
           gfx::Transform surface_draw_transform;
           transform_tree.ComputeTransform(
               transform_node->id, transform_tree.TargetId(transform_node->id),
               &surface_draw_transform);
-          node->data.hidden_by_backface_visibility =
+          node->hidden_by_backface_visibility =
               surface_draw_transform.IsBackFaceVisible();
         } else {
-          node->data.hidden_by_backface_visibility =
-              transform_node->data.local.IsBackFaceVisible();
+          node->hidden_by_backface_visibility =
+              transform_node->local.IsBackFaceVisible();
         }
         return;
       }
     }
   }
-  node->data.hidden_by_backface_visibility = false;
+  node->hidden_by_backface_visibility = false;
+}
+
+void EffectTree::UpdateSublayerScale(EffectNode* effect_node) {
+  if (!effect_node->has_render_surface || effect_node->transform_id == 0) {
+    effect_node->sublayer_scale = gfx::Vector2dF(1.0f, 1.0f);
+    return;
+  }
+
+  TransformTree& transform_tree = property_trees()->transform_tree;
+  float layer_scale_factor = transform_tree.device_scale_factor() *
+                             transform_tree.device_transform_scale_factor();
+  TransformNode* transform_node =
+      transform_tree.Node(effect_node->transform_id);
+  if (transform_node->in_subtree_of_page_scale_layer)
+    layer_scale_factor *= transform_tree.page_scale_factor();
+  effect_node->sublayer_scale = MathUtil::ComputeTransform2dScaleComponents(
+      transform_tree.ToScreen(transform_node->id), layer_scale_factor);
 }
 
 void EffectTree::UpdateEffects(int id) {
@@ -1426,6 +859,7 @@
   UpdateIsDrawn(node, parent_node);
   UpdateEffectChanged(node, parent_node);
   UpdateBackfaceVisibility(node, parent_node);
+  UpdateSublayerScale(node);
 }
 
 void EffectTree::AddCopyRequest(int node_id,
@@ -1463,8 +897,8 @@
     int node_id,
     std::vector<std::unique_ptr<CopyOutputRequest>>* requests) {
   EffectNode* effect_node = Node(node_id);
-  DCHECK(effect_node->data.has_render_surface);
-  DCHECK(effect_node->data.has_copy_request);
+  DCHECK(effect_node->has_render_surface);
+  DCHECK(effect_node->has_copy_request);
 
   auto range = copy_requests_.equal_range(node_id);
   for (auto it = range.first; it != range.second; ++it)
@@ -1477,7 +911,7 @@
 
     // The area needs to be transformed from the space of content that draws to
     // the surface to the space of the surface itself.
-    int destination_id = effect_node->data.transform_id;
+    int destination_id = effect_node->transform_id;
     int source_id;
     if (effect_node->parent_id != -1) {
       // For non-root surfaces, transform only by sub-layer scale.
@@ -1503,8 +937,8 @@
 
 void EffectTree::ClearCopyRequests() {
   for (auto& node : nodes()) {
-    node.data.num_copy_requests_in_subtree = 0;
-    node.data.has_copy_request = false;
+    node.num_copy_requests_in_subtree = 0;
+    node.has_copy_request = false;
   }
 
   // Any copy requests that are still left will be aborted (sending an empty
@@ -1517,13 +951,13 @@
   DCHECK_GE(id, 0);
   const EffectNode* node = Node(id);
   while (node->id > 1) {
-    if (node->data.has_copy_request)
+    if (node->has_copy_request)
       return node->id;
 
     node = parent(node);
   }
 
-  if (node->data.has_copy_request)
+  if (node->has_copy_request)
     return node->id;
   else
     return -1;
@@ -1539,41 +973,41 @@
   // copy requests.
   EffectNode* node = Node(id);
   EffectNode* parent_node = parent(node);
-  return node->data.is_drawn && (!parent_node || parent_node->data.is_drawn);
+  return node->is_drawn && (!parent_node || parent_node->is_drawn);
 }
 
 void EffectTree::ResetChangeTracking() {
   for (int id = 1; id < static_cast<int>(size()); ++id) {
     EffectNode* node = Node(id);
-    node->data.effect_changed = false;
+    node->effect_changed = false;
   }
 }
 
 void TransformTree::UpdateNodeAndAncestorsHaveIntegerTranslations(
     TransformNode* node,
     TransformNode* parent_node) {
-  node->data.node_and_ancestors_have_only_integer_translation =
-      node->data.to_parent.IsIdentityOrIntegerTranslation();
+  node->node_and_ancestors_have_only_integer_translation =
+      node->to_parent.IsIdentityOrIntegerTranslation();
   if (parent_node)
-    node->data.node_and_ancestors_have_only_integer_translation =
-        node->data.node_and_ancestors_have_only_integer_translation &&
-        parent_node->data.node_and_ancestors_have_only_integer_translation;
+    node->node_and_ancestors_have_only_integer_translation =
+        node->node_and_ancestors_have_only_integer_translation &&
+        parent_node->node_and_ancestors_have_only_integer_translation;
 }
 
 void ClipTree::SetViewportClip(gfx::RectF viewport_rect) {
   if (size() < 2)
     return;
   ClipNode* node = Node(1);
-  if (viewport_rect == node->data.clip)
+  if (viewport_rect == node->clip)
     return;
-  node->data.clip = viewport_rect;
+  node->clip = viewport_rect;
   set_needs_update(true);
 }
 
 gfx::RectF ClipTree::ViewportClip() {
   const unsigned long min_size = 1;
   DCHECK_GT(size(), min_size);
-  return Node(1)->data.clip;
+  return Node(1)->clip;
 }
 
 bool ClipTree::operator==(const ClipTree& other) const {
@@ -1730,21 +1164,21 @@
 
 gfx::ScrollOffset ScrollTree::MaxScrollOffset(int scroll_node_id) const {
   const ScrollNode* scroll_node = Node(scroll_node_id);
-  gfx::SizeF scroll_bounds = gfx::SizeF(scroll_node->data.bounds.width(),
-                                        scroll_node->data.bounds.height());
+  gfx::SizeF scroll_bounds =
+      gfx::SizeF(scroll_node->bounds.width(), scroll_node->bounds.height());
 
-  if (scroll_node->data.is_inner_viewport_scroll_layer) {
+  if (scroll_node->is_inner_viewport_scroll_layer) {
     scroll_bounds.Enlarge(
         property_trees()->inner_viewport_scroll_bounds_delta().x(),
         property_trees()->inner_viewport_scroll_bounds_delta().y());
   }
 
-  if (!scroll_node->data.scrollable || scroll_bounds.IsEmpty())
+  if (!scroll_node->scrollable || scroll_bounds.IsEmpty())
     return gfx::ScrollOffset();
 
   TransformTree& transform_tree = property_trees()->transform_tree;
   float scale_factor = 1.f;
-  if (scroll_node->data.max_scroll_offset_affected_by_page_scale)
+  if (scroll_node->max_scroll_offset_affected_by_page_scale)
     scale_factor = transform_tree.page_scale_factor();
 
   gfx::SizeF scaled_scroll_bounds = gfx::ScaleSize(scroll_bounds, scale_factor);
@@ -1764,14 +1198,13 @@
 
 gfx::Size ScrollTree::scroll_clip_layer_bounds(int scroll_node_id) const {
   const ScrollNode* scroll_node = Node(scroll_node_id);
-  gfx::Size scroll_clip_layer_bounds =
-      scroll_node->data.scroll_clip_layer_bounds;
+  gfx::Size scroll_clip_layer_bounds = scroll_node->scroll_clip_layer_bounds;
 
   gfx::Vector2dF scroll_clip_layer_bounds_delta;
-  if (scroll_node->data.is_inner_viewport_scroll_layer) {
+  if (scroll_node->is_inner_viewport_scroll_layer) {
     scroll_clip_layer_bounds_delta.Add(
         property_trees()->inner_viewport_container_bounds_delta());
-  } else if (scroll_node->data.is_outer_viewport_scroll_layer) {
+  } else if (scroll_node->is_outer_viewport_scroll_layer) {
     scroll_clip_layer_bounds_delta.Add(
         property_trees()->outer_viewport_container_bounds_delta());
   }
@@ -1802,13 +1235,13 @@
   const ScrollNode* scroll_node = Node(scroll_node_id);
   const TransformTree& transform_tree = property_trees()->transform_tree;
   const TransformNode* transform_node =
-      transform_tree.Node(scroll_node->data.transform_id);
+      transform_tree.Node(scroll_node->transform_id);
   gfx::Transform screen_space_transform(
-      1, 0, 0, 1, scroll_node->data.offset_to_transform_parent.x(),
-      scroll_node->data.offset_to_transform_parent.y());
+      1, 0, 0, 1, scroll_node->offset_to_transform_parent.x(),
+      scroll_node->offset_to_transform_parent.y());
   screen_space_transform.ConcatTransform(
       transform_tree.ToScreen(transform_node->id));
-  if (scroll_node->data.should_flatten)
+  if (scroll_node->should_flatten)
     screen_space_transform.FlattenTo2d();
   return screen_space_transform;
 }
@@ -2016,17 +1449,17 @@
                                     const gfx::Vector2dF& scroll,
                                     LayerTreeImpl* layer_tree_impl) {
   gfx::ScrollOffset adjusted_scroll(scroll);
-  if (!scroll_node->data.user_scrollable_horizontal)
+  if (!scroll_node->user_scrollable_horizontal)
     adjusted_scroll.set_x(0);
-  if (!scroll_node->data.user_scrollable_vertical)
+  if (!scroll_node->user_scrollable_vertical)
     adjusted_scroll.set_y(0);
-  DCHECK(scroll_node->data.scrollable);
+  DCHECK(scroll_node->scrollable);
   gfx::ScrollOffset old_offset = current_scroll_offset(scroll_node->owner_id);
   gfx::ScrollOffset new_offset =
       ClampScrollOffsetToLimits(old_offset + adjusted_scroll, scroll_node);
   if (SetScrollOffset(scroll_node->owner_id, new_offset))
     layer_tree_impl->DidUpdateScrollOffset(scroll_node->owner_id,
-                                           scroll_node->data.transform_id);
+                                           scroll_node->transform_id);
 
   gfx::ScrollOffset unscrolled =
       old_offset + gfx::ScrollOffset(scroll) - new_offset;
@@ -2191,11 +1624,11 @@
         effect_tree.Node(effect_id_to_index_map[id]);
     EffectNode* target_effect_node =
         target_tree->effect_tree.Node(target_tree->effect_id_to_index_map[id]);
-    float source_opacity = source_effect_node->data.opacity;
-    float target_opacity = target_effect_node->data.opacity;
+    float source_opacity = source_effect_node->opacity;
+    float target_opacity = target_effect_node->opacity;
     if (source_opacity == target_opacity)
       continue;
-    target_effect_node->data.opacity = source_opacity;
+    target_effect_node->opacity = source_opacity;
     target_tree->effect_tree.set_needs_update(true);
   }
 }
@@ -2235,7 +1668,7 @@
   for (int i = 1; i < static_cast<int>(transform_tree.size()); ++i) {
     TransformNode* node = transform_tree.Node(i);
     TransformNode* parent_node = transform_tree.parent(node);
-    TransformNode* source_node = transform_tree.Node(node->data.source_node_id);
+    TransformNode* source_node = transform_tree.Node(node->source_node_id);
     transform_tree.UpdateTransformChanged(node, parent_node, source_node);
   }
 }
@@ -2243,16 +1676,16 @@
 void PropertyTrees::PushChangeTrackingTo(PropertyTrees* tree) {
   for (int id = 1; id < static_cast<int>(effect_tree.size()); ++id) {
     EffectNode* node = effect_tree.Node(id);
-    if (node->data.effect_changed) {
+    if (node->effect_changed) {
       EffectNode* target_node = tree->effect_tree.Node(node->id);
-      target_node->data.effect_changed = true;
+      target_node->effect_changed = true;
     }
   }
   for (int id = 1; id < static_cast<int>(transform_tree.size()); ++id) {
     TransformNode* node = transform_tree.Node(id);
-    if (node->data.transform_changed) {
+    if (node->transform_changed) {
       TransformNode* target_node = tree->transform_tree.Node(node->id);
-      target_node->data.transform_changed = true;
+      target_node->transform_changed = true;
     }
   }
   // Ensure that change tracking is updated even if property trees don't have
@@ -2332,8 +1765,7 @@
 
     cached_data_.animation_scales[transform_node_id]
         .to_screen_has_scale_animation =
-        !node->data.has_only_translation_animations ||
-        ancestor_is_animating_scale;
+        !node->has_only_translation_animations || ancestor_is_animating_scale;
 
     // Once we've failed to compute a maximum animated scale at an ancestor, we
     // continue to fail.
@@ -2351,8 +1783,7 @@
     // as another node is decreasing scale from 10 to 1. Naively combining these
     // scales would produce a scale of 100.
     bool failed_for_multiple_scale_animations =
-        ancestor_is_animating_scale &&
-        !node->data.has_only_translation_animations;
+        ancestor_is_animating_scale && !node->has_only_translation_animations;
 
     if (failed_at_ancestor || failed_for_non_scale_or_translation ||
         failed_for_multiple_scale_animations) {
@@ -2371,10 +1802,10 @@
           .combined_maximum_animation_target_scale = 0.f;
       cached_data_.animation_scales[transform_node_id]
           .combined_starting_animation_scale = 0.f;
-    } else if (node->data.has_only_translation_animations) {
+    } else if (node->has_only_translation_animations) {
       // An ancestor is animating scale.
       gfx::Vector2dF local_scales =
-          MathUtil::ComputeTransform2dScaleComponents(node->data.local, 0.f);
+          MathUtil::ComputeTransform2dScaleComponents(node->local, 0.f);
       float max_local_scale = std::max(local_scales.x(), local_scales.y());
       cached_data_.animation_scales[transform_node_id]
           .combined_maximum_animation_target_scale =
@@ -2393,7 +1824,7 @@
           layer_impl, &cached_data_.animation_scales[transform_node_id]
                            .local_starting_animation_scale);
       gfx::Vector2dF local_scales =
-          MathUtil::ComputeTransform2dScaleComponents(node->data.local, 0.f);
+          MathUtil::ComputeTransform2dScaleComponents(node->local, 0.f);
       float max_local_scale = std::max(local_scales.x(), local_scales.y());
 
       if (cached_data_.animation_scales[transform_node_id]
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h
index b40c909..4dbf6c4 100644
--- a/cc/trees/property_tree.h
+++ b/cc/trees/property_tree.h
@@ -14,7 +14,6 @@
 #include "cc/animation/element_id.h"
 #include "cc/base/cc_export.h"
 #include "cc/base/synced_property.h"
-#include "cc/output/filter_operations.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/geometry/scroll_offset.h"
 #include "ui/gfx/transform.h"
@@ -28,22 +27,21 @@
 namespace cc {
 
 namespace proto {
-class ClipNodeData;
-class EffectNodeData;
 class PropertyTree;
 class PropertyTrees;
 class ScrollNodeData;
-class TransformNodeData;
-class TransformCachedNodeData;
-class TransformTreeData;
 class TreeNode;
 }  // namespace proto
 
 class CopyOutputRequest;
 class LayerTreeImpl;
-class RenderSurfaceImpl;
 class ScrollState;
+struct ClipNode;
+struct EffectNode;
 struct ScrollAndScaleSet;
+struct ScrollNode;
+struct TransformNode;
+struct TransformCachedNodeData;
 
 // ------------------------------*IMPORTANT*---------------------------------
 // Each class declared here has a corresponding proto defined in
@@ -54,288 +52,6 @@
 
 typedef SyncedProperty<AdditionGroup<gfx::ScrollOffset>> SyncedScrollOffset;
 
-template <typename T>
-struct CC_EXPORT TreeNode {
-  TreeNode() : id(-1), parent_id(-1), owner_id(-1), data() {}
-  int id;
-  int parent_id;
-  int owner_id;
-  T data;
-
-  bool operator==(const TreeNode<T>& other) const;
-
-  void ToProtobuf(proto::TreeNode* proto) const;
-  void FromProtobuf(const proto::TreeNode& proto);
-
-  void AsValueInto(base::trace_event::TracedValue* value) const;
-};
-
-struct CC_EXPORT TransformNodeData {
-  TransformNodeData();
-  TransformNodeData(const TransformNodeData& other);
-  ~TransformNodeData();
-
-  // The local transform information is combined to form to_parent (ignoring
-  // snapping) as follows:
-  //
-  //   to_parent = M_post_local * T_scroll * M_local * M_pre_local.
-  //
-  // The pre/post may seem odd when read LTR, but we multiply our points from
-  // the right, so the pre_local matrix affects the result "first". This lines
-  // up with the notions of pre/post used in skia and gfx::Transform.
-  //
-  // TODO(vollick): The values labeled with "will be moved..." take up a lot of
-  // space, but are only necessary for animated or scrolled nodes (otherwise
-  // we'll just use the baked to_parent). These values will be ultimately stored
-  // directly on the transform/scroll display list items when that's possible,
-  // or potentially in a scroll tree.
-  //
-  // TODO(vollick): will be moved when accelerated effects are implemented.
-  gfx::Transform pre_local;
-  gfx::Transform local;
-  gfx::Transform post_local;
-
-  gfx::Transform to_parent;
-
-  // This is the node with respect to which source_offset is defined. This will
-  // not be needed once layerization moves to cc, but is needed in order to
-  // efficiently update the transform tree for changes to position in the layer
-  // tree.
-  int source_node_id;
-
-  // This id determines which 3d rendering context the node is in. 0 is a
-  // special value and indicates that the node is not in any 3d rendering
-  // context.
-  int sorting_context_id;
-
-  // TODO(vollick): will be moved when accelerated effects are implemented.
-  bool needs_local_transform_update : 1;
-
-  bool node_and_ancestors_are_animated_or_invertible : 1;
-
-  bool is_invertible : 1;
-  bool ancestors_are_invertible : 1;
-
-  bool has_potential_animation : 1;
-  bool is_currently_animating : 1;
-  bool to_screen_is_potentially_animated : 1;
-  bool has_only_translation_animations : 1;
-
-  // Flattening, when needed, is only applied to a node's inherited transform,
-  // never to its local transform.
-  bool flattens_inherited_transform : 1;
-
-  // This is true if the to_parent transform at every node on the path to the
-  // root is flat.
-  bool node_and_ancestors_are_flat : 1;
-
-  // This is needed to know if a layer can use lcd text.
-  bool node_and_ancestors_have_only_integer_translation : 1;
-
-  bool scrolls : 1;
-
-  bool needs_sublayer_scale : 1;
-
-  // These are used to position nodes wrt the right or bottom of the inner or
-  // outer viewport.
-  bool affected_by_inner_viewport_bounds_delta_x : 1;
-  bool affected_by_inner_viewport_bounds_delta_y : 1;
-  bool affected_by_outer_viewport_bounds_delta_x : 1;
-  bool affected_by_outer_viewport_bounds_delta_y : 1;
-
-  // Layer scale factor is used as a fallback when we either cannot adjust
-  // raster scale or if the raster scale cannot be extracted from the screen
-  // space transform. For layers in the subtree of the page scale layer, the
-  // layer scale factor should include the page scale factor.
-  bool in_subtree_of_page_scale_layer : 1;
-
-  // We need to track changes to to_screen transform to compute the damage rect.
-  bool transform_changed : 1;
-
-  // TODO(vollick): will be moved when accelerated effects are implemented.
-  float post_local_scale_factor;
-
-  gfx::Vector2dF sublayer_scale;
-
-  // TODO(vollick): will be moved when accelerated effects are implemented.
-  gfx::ScrollOffset scroll_offset;
-
-  // We scroll snap where possible, but this means fixed-pos elements must be
-  // adjusted.  This value stores the snapped amount for this purpose.
-  gfx::Vector2dF scroll_snap;
-
-  // TODO(vollick): will be moved when accelerated effects are implemented.
-  gfx::Vector2dF source_offset;
-  gfx::Vector2dF source_to_parent;
-
-  bool operator==(const TransformNodeData& other) const;
-
-  void set_to_parent(const gfx::Transform& transform) {
-    to_parent = transform;
-    is_invertible = to_parent.IsInvertible();
-  }
-
-  void update_pre_local_transform(const gfx::Point3F& transform_origin);
-
-  void update_post_local_transform(const gfx::PointF& position,
-                                   const gfx::Point3F& transform_origin);
-
-  void ToProtobuf(proto::TreeNode* proto) const;
-  void FromProtobuf(const proto::TreeNode& proto);
-
-  void AsValueInto(base::trace_event::TracedValue* value) const;
-};
-
-// TODO(sunxd): move this into PropertyTrees::cached_data_.
-struct CC_EXPORT TransformCachedNodeData {
-  TransformCachedNodeData();
-  TransformCachedNodeData(const TransformCachedNodeData& other);
-  ~TransformCachedNodeData();
-
-  gfx::Transform from_target;
-  gfx::Transform to_target;
-  gfx::Transform from_screen;
-  gfx::Transform to_screen;
-  int target_id;
-  // This id is used for all content that draws into a render surface associated
-  // with this transform node.
-  int content_target_id;
-
-  bool operator==(const TransformCachedNodeData& other) const;
-
-  void ToProtobuf(proto::TransformCachedNodeData* proto) const;
-  void FromProtobuf(const proto::TransformCachedNodeData& proto);
-};
-
-typedef TreeNode<TransformNodeData> TransformNode;
-
-struct CC_EXPORT ClipNodeData {
-  ClipNodeData();
-  ClipNodeData(const ClipNodeData& other);
-
-  // The clip rect that this node contributes, expressed in the space of its
-  // transform node.
-  gfx::RectF clip;
-
-  // Clip nodes are uses for two reasons. First, they are used for determining
-  // which parts of each layer are visible. Second, they are used for
-  // determining whether a clip needs to be applied when drawing a layer, and if
-  // so, the rect that needs to be used. These can be different since not all
-  // clips need to be applied directly to each layer. For example, a layer is
-  // implicitly clipped by the bounds of its target render surface and by clips
-  // applied to this surface. |combined_clip_in_target_space| is used for
-  // computing visible rects, and |clip_in_target_space| is used for computing
-  // clips applied at draw time. Both rects are expressed in the space of the
-  // target transform node, and may include clips contributed by ancestors.
-  gfx::RectF combined_clip_in_target_space;
-  gfx::RectF clip_in_target_space;
-
-  // The id of the transform node that defines the clip node's local space.
-  int transform_id;
-
-  // The id of the transform node that defines the clip node's target space.
-  int target_id;
-
-  // Whether this node contributes a new clip (that is, whether |clip| needs to
-  // be applied), rather than only inheriting ancestor clips.
-  bool applies_local_clip : 1;
-
-  // When true, |clip_in_target_space| does not include clips from ancestor
-  // nodes.
-  bool layer_clipping_uses_only_local_clip : 1;
-
-  // True if target surface needs to be drawn with a clip applied.
-  bool target_is_clipped : 1;
-
-  // True if layers with this clip tree node need to be drawn with a clip
-  // applied.
-  bool layers_are_clipped : 1;
-  bool layers_are_clipped_when_surfaces_disabled : 1;
-
-  // Nodes that correspond to unclipped surfaces disregard ancestor clips.
-  bool resets_clip : 1;
-
-  bool operator==(const ClipNodeData& other) const;
-
-  void ToProtobuf(proto::TreeNode* proto) const;
-  void FromProtobuf(const proto::TreeNode& proto);
-  void AsValueInto(base::trace_event::TracedValue* value) const;
-};
-
-typedef TreeNode<ClipNodeData> ClipNode;
-
-struct CC_EXPORT EffectNodeData {
-  EffectNodeData();
-  EffectNodeData(const EffectNodeData& other);
-
-  float opacity;
-  float screen_space_opacity;
-
-  FilterOperations background_filters;
-
-  bool has_render_surface;
-  RenderSurfaceImpl* render_surface;
-  bool has_copy_request;
-  bool hidden_by_backface_visibility;
-  bool double_sided;
-  bool is_drawn;
-  // TODO(jaydasika) : Delete this after implementation of
-  // SetHideLayerAndSubtree is cleaned up. (crbug.com/595843)
-  bool subtree_hidden;
-  bool has_potential_opacity_animation;
-  bool is_currently_animating_opacity;
-  // We need to track changes to effects on the compositor to compute damage
-  // rect.
-  bool effect_changed;
-  int num_copy_requests_in_subtree;
-  bool has_unclipped_descendants;
-  int transform_id;
-  int clip_id;
-  // Effect node id of which this effect contributes to.
-  int target_id;
-  int mask_layer_id;
-  int replica_layer_id;
-  int replica_mask_layer_id;
-
-  bool operator==(const EffectNodeData& other) const;
-
-  void ToProtobuf(proto::TreeNode* proto) const;
-  void FromProtobuf(const proto::TreeNode& proto);
-  void AsValueInto(base::trace_event::TracedValue* value) const;
-};
-
-typedef TreeNode<EffectNodeData> EffectNode;
-
-struct CC_EXPORT ScrollNodeData {
-  ScrollNodeData();
-  ScrollNodeData(const ScrollNodeData& other);
-
-  bool scrollable;
-  uint32_t main_thread_scrolling_reasons;
-  bool contains_non_fast_scrollable_region;
-  gfx::Size scroll_clip_layer_bounds;
-  gfx::Size bounds;
-  bool max_scroll_offset_affected_by_page_scale;
-  bool is_inner_viewport_scroll_layer;
-  bool is_outer_viewport_scroll_layer;
-  gfx::Vector2dF offset_to_transform_parent;
-  bool should_flatten;
-  bool user_scrollable_horizontal;
-  bool user_scrollable_vertical;
-  ElementId element_id;
-  int transform_id;
-  // Number of drawn layers pointing to this node or any of its descendants.
-  int num_drawn_descendants;
-
-  bool operator==(const ScrollNodeData& other) const;
-
-  void ToProtobuf(proto::TreeNode* proto) const;
-  void FromProtobuf(const proto::TreeNode& proto);
-  void AsValueInto(base::trace_event::TracedValue* value) const;
-};
-
-typedef TreeNode<ScrollNodeData> ScrollNode;
-
 class PropertyTrees;
 
 template <typename T>
@@ -343,7 +59,13 @@
  public:
   PropertyTree();
   PropertyTree(const PropertyTree& other) = delete;
+
+  // These C++ special member functions cannot be implicit inline because
+  // they are exported by CC_EXPORT. They will be instantiated in every
+  // compilation units that included this header, and compilation can fail
+  // because T may be incomplete.
   ~PropertyTree();
+  PropertyTree<T>& operator=(const PropertyTree<T>&);
 
   bool operator==(const PropertyTree<T>& other) const;
 
@@ -400,7 +122,14 @@
 class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> {
  public:
   TransformTree();
+
+  // These C++ special member functions cannot be implicit inline because
+  // they are exported by CC_EXPORT. They will be instantiated in every
+  // compilation units that included this header, and compilation can fail
+  // because TransformCachedNodeData may be incomplete.
+  TransformTree(const TransformTree&) = delete;
   ~TransformTree();
+  TransformTree& operator=(const TransformTree&);
 
   bool operator==(const TransformTree& other) const;
 
@@ -604,6 +333,8 @@
 
   float EffectiveOpacity(const EffectNode* node) const;
 
+  void UpdateSublayerScale(EffectNode* node);
+
   void UpdateEffects(int id);
 
   void UpdateEffectChanged(EffectNode* node, EffectNode* parent_node);
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index 7f35dd9..f9ebb6f 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -13,9 +13,13 @@
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_impl.h"
 #include "cc/output/copy_output_request.h"
+#include "cc/trees/clip_node.h"
 #include "cc/trees/draw_property_utils.h"
+#include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/scroll_node.h"
+#include "cc/trees/transform_node.h"
 #include "ui/gfx/geometry/point_f.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
 
@@ -280,7 +284,7 @@
   bool is_root = !Parent(layer);
 
   // Whether we have an ancestor clip that we might need to apply.
-  bool ancestor_clips_subtree = is_root || parent->data.layers_are_clipped;
+  bool ancestor_clips_subtree = is_root || parent->layers_are_clipped;
 
   bool layers_are_clipped = false;
   bool has_unclipped_surface = false;
@@ -299,7 +303,7 @@
       // of its own, but clips from ancestor nodes don't need to be considered
       // when computing clip rects or visibility.
       has_unclipped_surface = true;
-      DCHECK(!parent->data.applies_local_clip);
+      DCHECK(!parent->applies_local_clip);
     }
     // A surface with unclipped descendants cannot be clipped by its ancestor
     // clip at draw time since the unclipped descendants aren't affected by the
@@ -320,8 +324,7 @@
   // Without surfaces, all non-viewport clips have to be applied using layer
   // clipping.
   bool layers_are_clipped_when_surfaces_disabled =
-      layer_clips_subtree ||
-      parent->data.layers_are_clipped_when_surfaces_disabled;
+      layer_clips_subtree || parent->layers_are_clipped_when_surfaces_disabled;
 
   // Render surface's clip is needed during hit testing. So, we need to create
   // a clip node for every render surface.
@@ -329,9 +332,9 @@
 
   if (!requires_node) {
     data_for_children->clip_tree_parent = parent_id;
-    DCHECK_EQ(layers_are_clipped, parent->data.layers_are_clipped);
+    DCHECK_EQ(layers_are_clipped, parent->layers_are_clipped);
     DCHECK_EQ(layers_are_clipped_when_surfaces_disabled,
-              parent->data.layers_are_clipped_when_surfaces_disabled);
+              parent->layers_are_clipped_when_surfaces_disabled);
   } else {
     LayerType* transform_parent = data_for_children->transform_tree_parent;
     if (PositionConstraint(layer).is_fixed_position() &&
@@ -339,32 +342,31 @@
       transform_parent = data_for_children->transform_fixed_parent;
     }
     ClipNode node;
-    node.data.clip =
-        gfx::RectF(gfx::PointF() + layer->offset_to_transform_parent(),
-                   gfx::SizeF(layer->bounds()));
-    node.data.transform_id = transform_parent->transform_tree_index();
-    node.data.target_id = data_for_children->property_trees->effect_tree
-                              .Node(data_for_children->render_target)
-                              ->data.transform_id;
+    node.clip = gfx::RectF(gfx::PointF() + layer->offset_to_transform_parent(),
+                           gfx::SizeF(layer->bounds()));
+    node.transform_id = transform_parent->transform_tree_index();
+    node.target_id = data_for_children->property_trees->effect_tree
+                         .Node(data_for_children->render_target)
+                         ->transform_id;
     node.owner_id = layer->id();
 
     if (ancestor_clips_subtree || layer_clips_subtree) {
       // Surfaces reset the rect used for layer clipping. At other nodes, layer
       // clipping state from ancestors must continue to get propagated.
-      node.data.layer_clipping_uses_only_local_clip =
+      node.layer_clipping_uses_only_local_clip =
           (created_render_surface && NumUnclippedDescendants(layer) == 0) ||
           !ancestor_clips_subtree;
     } else {
       // Otherwise, we're either unclipped, or exist only in order to apply our
       // parent's clips in our space.
-      node.data.layer_clipping_uses_only_local_clip = false;
+      node.layer_clipping_uses_only_local_clip = false;
     }
 
-    node.data.applies_local_clip = layer_clips_subtree;
-    node.data.resets_clip = has_unclipped_surface;
-    node.data.target_is_clipped = data_for_children->target_is_clipped;
-    node.data.layers_are_clipped = layers_are_clipped;
-    node.data.layers_are_clipped_when_surfaces_disabled =
+    node.applies_local_clip = layer_clips_subtree;
+    node.resets_clip = has_unclipped_surface;
+    node.target_is_clipped = data_for_children->target_is_clipped;
+    node.layers_are_clipped = layers_are_clipped;
+    node.layers_are_clipped_when_surfaces_disabled =
         layers_are_clipped_when_surfaces_disabled;
 
     data_for_children->clip_tree_parent =
@@ -528,14 +530,14 @@
   data_for_children->property_trees->transform_id_to_index_map[layer->id()] =
       node->id;
 
-  node->data.scrolls = is_scrollable;
-  node->data.flattens_inherited_transform = data_for_children->should_flatten;
+  node->scrolls = is_scrollable;
+  node->flattens_inherited_transform = data_for_children->should_flatten;
 
-  node->data.sorting_context_id = layer->sorting_context_id();
+  node->sorting_context_id = layer->sorting_context_id();
 
   if (layer == data_from_ancestor.page_scale_layer)
     data_for_children->in_subtree_of_page_scale_layer = true;
-  node->data.in_subtree_of_page_scale_layer =
+  node->in_subtree_of_page_scale_layer =
       data_for_children->in_subtree_of_page_scale_layer;
 
   // Surfaces inherently flatten transforms.
@@ -546,19 +548,19 @@
   data_for_children->property_trees->transform_tree.SetTargetId(
       node->id, data_for_children->property_trees->effect_tree
                     .Node(data_from_ancestor.render_target)
-                    ->data.transform_id);
+                    ->transform_id);
   data_for_children->property_trees->transform_tree.SetContentTargetId(
       node->id, data_for_children->property_trees->effect_tree
                     .Node(data_for_children->render_target)
-                    ->data.transform_id);
+                    ->transform_id);
   DCHECK_NE(
       data_for_children->property_trees->transform_tree.TargetId(node->id),
       kInvalidPropertyTreeNodeId);
 
-  node->data.has_potential_animation = has_potentially_animated_transform;
-  node->data.is_currently_animating = layer->TransformIsAnimating();
+  node->has_potential_animation = has_potentially_animated_transform;
+  node->is_currently_animating = layer->TransformIsAnimating();
   if (has_potentially_animated_transform) {
-    node->data.has_only_translation_animations =
+    node->has_only_translation_animations =
         layer->HasOnlyTranslationTransforms();
   }
 
@@ -574,57 +576,57 @@
   }
 
   if (has_surface && !is_root)
-    node->data.needs_sublayer_scale = true;
+    node->needs_sublayer_scale = true;
 
-  node->data.source_node_id = source_index;
-  node->data.post_local_scale_factor = post_local_scale_factor;
+  node->source_node_id = source_index;
+  node->post_local_scale_factor = post_local_scale_factor;
   if (is_root) {
     data_for_children->property_trees->transform_tree.SetDeviceTransform(
         *data_from_ancestor.device_transform, layer->position());
     data_for_children->property_trees->transform_tree
         .SetDeviceTransformScaleFactor(*data_from_ancestor.device_transform);
   } else {
-    node->data.source_offset = source_offset;
-    node->data.update_post_local_transform(layer->position(),
-                                           TransformOrigin(layer));
+    node->source_offset = source_offset;
+    node->update_post_local_transform(layer->position(),
+                                      TransformOrigin(layer));
   }
 
   if (is_overscroll_elasticity_layer) {
     DCHECK(!is_scrollable);
-    node->data.scroll_offset =
+    node->scroll_offset =
         gfx::ScrollOffset(data_from_ancestor.elastic_overscroll);
   } else if (!ScrollParent(layer)) {
-    node->data.scroll_offset = layer->CurrentScrollOffset();
+    node->scroll_offset = layer->CurrentScrollOffset();
   }
 
   if (is_fixed) {
     if (data_from_ancestor.affected_by_inner_viewport_bounds_delta) {
-      node->data.affected_by_inner_viewport_bounds_delta_x =
+      node->affected_by_inner_viewport_bounds_delta_x =
           PositionConstraint(layer).is_fixed_to_right_edge();
-      node->data.affected_by_inner_viewport_bounds_delta_y =
+      node->affected_by_inner_viewport_bounds_delta_y =
           PositionConstraint(layer).is_fixed_to_bottom_edge();
-      if (node->data.affected_by_inner_viewport_bounds_delta_x ||
-          node->data.affected_by_inner_viewport_bounds_delta_y) {
+      if (node->affected_by_inner_viewport_bounds_delta_x ||
+          node->affected_by_inner_viewport_bounds_delta_y) {
         data_for_children->property_trees->transform_tree
             .AddNodeAffectedByInnerViewportBoundsDelta(node->id);
       }
     } else if (data_from_ancestor.affected_by_outer_viewport_bounds_delta) {
-      node->data.affected_by_outer_viewport_bounds_delta_x =
+      node->affected_by_outer_viewport_bounds_delta_x =
           PositionConstraint(layer).is_fixed_to_right_edge();
-      node->data.affected_by_outer_viewport_bounds_delta_y =
+      node->affected_by_outer_viewport_bounds_delta_y =
           PositionConstraint(layer).is_fixed_to_bottom_edge();
-      if (node->data.affected_by_outer_viewport_bounds_delta_x ||
-          node->data.affected_by_outer_viewport_bounds_delta_y) {
+      if (node->affected_by_outer_viewport_bounds_delta_x ||
+          node->affected_by_outer_viewport_bounds_delta_y) {
         data_for_children->property_trees->transform_tree
             .AddNodeAffectedByOuterViewportBoundsDelta(node->id);
       }
     }
   }
 
-  node->data.local = layer->transform();
-  node->data.update_pre_local_transform(TransformOrigin(layer));
+  node->local = layer->transform();
+  node->update_pre_local_transform(TransformOrigin(layer));
 
-  node->data.needs_local_transform_update = true;
+  node->needs_local_transform_update = true;
   data_from_ancestor.property_trees->transform_tree.UpdateTransforms(node->id);
 
   layer->set_offset_to_transform_parent(gfx::Vector2dF());
@@ -632,7 +634,7 @@
   // Flattening (if needed) will be handled by |node|.
   layer->set_should_flatten_transform_from_property_tree(false);
 
-  data_for_children->scroll_snap += node->data.scroll_snap;
+  data_for_children->scroll_snap += node->scroll_snap;
 
   node->owner_id = layer->id();
 
@@ -893,26 +895,26 @@
         .push_back(node.owner_id);
   }
 
-  node.data.opacity = Opacity(layer);
-  node.data.has_render_surface = should_create_render_surface;
-  node.data.has_copy_request = HasCopyRequest(layer);
-  node.data.background_filters = BackgroundFilters(layer);
-  node.data.has_potential_opacity_animation = has_potential_opacity_animation;
-  node.data.double_sided = DoubleSided(layer);
-  node.data.subtree_hidden = HideLayerAndSubtree(layer);
-  node.data.is_currently_animating_opacity = layer->OpacityIsAnimating();
+  node.opacity = Opacity(layer);
+  node.has_render_surface = should_create_render_surface;
+  node.has_copy_request = HasCopyRequest(layer);
+  node.background_filters = BackgroundFilters(layer);
+  node.has_potential_opacity_animation = has_potential_opacity_animation;
+  node.double_sided = DoubleSided(layer);
+  node.subtree_hidden = HideLayerAndSubtree(layer);
+  node.is_currently_animating_opacity = layer->OpacityIsAnimating();
 
   EffectTree& effect_tree = data_for_children->property_trees->effect_tree;
   if (MaskLayer(layer)) {
-    node.data.mask_layer_id = MaskLayer(layer)->id();
-    effect_tree.AddMaskOrReplicaLayerId(node.data.mask_layer_id);
+    node.mask_layer_id = MaskLayer(layer)->id();
+    effect_tree.AddMaskOrReplicaLayerId(node.mask_layer_id);
   }
   if (ReplicaLayer(layer)) {
-    node.data.replica_layer_id = ReplicaLayer(layer)->id();
-    effect_tree.AddMaskOrReplicaLayerId(node.data.replica_layer_id);
+    node.replica_layer_id = ReplicaLayer(layer)->id();
+    effect_tree.AddMaskOrReplicaLayerId(node.replica_layer_id);
     if (MaskLayer(ReplicaLayer(layer))) {
-      node.data.replica_mask_layer_id = MaskLayer(ReplicaLayer(layer))->id();
-      effect_tree.AddMaskOrReplicaLayerId(node.data.replica_mask_layer_id);
+      node.replica_mask_layer_id = MaskLayer(ReplicaLayer(layer))->id();
+      effect_tree.AddMaskOrReplicaLayerId(node.replica_mask_layer_id);
     }
   }
 
@@ -924,19 +926,18 @@
       // In this case, we will create a transform node, so it's safe to use the
       // next available id from the transform tree as this effect node's
       // transform id.
-      node.data.transform_id =
+      node.transform_id =
           data_from_ancestor.property_trees->transform_tree.next_available_id();
-      node.data.has_unclipped_descendants =
-          (NumUnclippedDescendants(layer) != 0);
+      node.has_unclipped_descendants = (NumUnclippedDescendants(layer) != 0);
     }
-    node.data.clip_id = data_from_ancestor.clip_tree_parent;
+    node.clip_id = data_from_ancestor.clip_tree_parent;
   } else {
     // Root render surface acts the unbounded and untransformed to draw content
     // into. Transform node created from root layer (includes device scale
     // factor) and clip node created from root layer (include viewports) applies
     // to root render surface's content, but not root render surface itself.
-    node.data.transform_id = kRootPropertyTreeNodeId;
-    node.data.clip_id = kViewportClipTreeNodeId;
+    node.transform_id = kRootPropertyTreeNodeId;
+    node.clip_id = kViewportClipTreeNodeId;
   }
   data_for_children->effect_tree_parent = effect_tree.Insert(node, parent_id);
   int node_id = data_for_children->effect_tree_parent;
@@ -991,48 +992,47 @@
   } else {
     ScrollNode node;
     node.owner_id = layer->id();
-    node.data.scrollable = scrollable;
-    node.data.main_thread_scrolling_reasons = main_thread_scrolling_reasons;
-    node.data.contains_non_fast_scrollable_region =
+    node.scrollable = scrollable;
+    node.main_thread_scrolling_reasons = main_thread_scrolling_reasons;
+    node.contains_non_fast_scrollable_region =
         contains_non_fast_scrollable_region;
     gfx::Size clip_bounds;
     if (layer->scroll_clip_layer()) {
       clip_bounds = layer->scroll_clip_layer()->bounds();
       DCHECK(layer->scroll_clip_layer()->transform_tree_index() !=
              kInvalidPropertyTreeNodeId);
-      node.data.max_scroll_offset_affected_by_page_scale =
+      node.max_scroll_offset_affected_by_page_scale =
           !data_from_ancestor.property_trees->transform_tree
                .Node(layer->scroll_clip_layer()->transform_tree_index())
-               ->data.in_subtree_of_page_scale_layer &&
+               ->in_subtree_of_page_scale_layer &&
           data_from_ancestor.in_subtree_of_page_scale_layer;
     }
 
-    node.data.scroll_clip_layer_bounds = clip_bounds;
-    node.data.is_inner_viewport_scroll_layer =
+    node.scroll_clip_layer_bounds = clip_bounds;
+    node.is_inner_viewport_scroll_layer =
         layer == data_from_ancestor.inner_viewport_scroll_layer;
-    node.data.is_outer_viewport_scroll_layer =
+    node.is_outer_viewport_scroll_layer =
         layer == data_from_ancestor.outer_viewport_scroll_layer;
 
-    node.data.bounds = layer->bounds();
-    node.data.offset_to_transform_parent = layer->offset_to_transform_parent();
-    node.data.should_flatten =
-        layer->should_flatten_transform_from_property_tree();
-    node.data.user_scrollable_horizontal = layer->user_scrollable_horizontal();
-    node.data.user_scrollable_vertical = layer->user_scrollable_vertical();
-    node.data.element_id = layer->element_id();
-    node.data.transform_id =
+    node.bounds = layer->bounds();
+    node.offset_to_transform_parent = layer->offset_to_transform_parent();
+    node.should_flatten = layer->should_flatten_transform_from_property_tree();
+    node.user_scrollable_horizontal = layer->user_scrollable_horizontal();
+    node.user_scrollable_vertical = layer->user_scrollable_vertical();
+    node.element_id = layer->element_id();
+    node.transform_id =
         data_for_children->transform_tree_parent->transform_tree_index();
 
     data_for_children->scroll_tree_parent =
         data_for_children->property_trees->scroll_tree.Insert(node, parent_id);
     data_for_children->main_thread_scrolling_reasons =
-        node.data.main_thread_scrolling_reasons;
+        node.main_thread_scrolling_reasons;
     data_for_children->scroll_tree_parent_created_by_uninheritable_criteria =
         scroll_node_uninheritable_criteria;
     data_for_children->property_trees->scroll_id_to_index_map[layer->id()] =
         data_for_children->scroll_tree_parent;
 
-    if (node.data.scrollable) {
+    if (node.scrollable) {
       data_for_children->property_trees->scroll_tree.SetBaseScrollOffset(
           layer->id(), layer->CurrentScrollOffset());
     }
@@ -1182,9 +1182,9 @@
       data_for_children.effect_tree_parent);
 
   if (effect_node->owner_id == layer->id()) {
-    if (effect_node->data.has_copy_request)
+    if (effect_node->has_copy_request)
       data_to_parent->num_copy_requests_in_subtree++;
-    effect_node->data.num_copy_requests_in_subtree =
+    effect_node->num_copy_requests_in_subtree =
         data_to_parent->num_copy_requests_in_subtree;
   }
 }
@@ -1290,10 +1290,10 @@
       .clear();
 
   ClipNode root_clip;
-  root_clip.data.resets_clip = true;
-  root_clip.data.applies_local_clip = true;
-  root_clip.data.clip = gfx::RectF(viewport);
-  root_clip.data.transform_id = kRootPropertyTreeNodeId;
+  root_clip.resets_clip = true;
+  root_clip.applies_local_clip = true;
+  root_clip.clip = gfx::RectF(viewport);
+  root_clip.transform_id = kRootPropertyTreeNodeId;
   data_for_recursion.clip_tree_parent =
       data_for_recursion.property_trees->clip_tree.Insert(
           root_clip, kRootPropertyTreeNodeId);
diff --git a/cc/trees/property_tree_unittest.cc b/cc/trees/property_tree_unittest.cc
index f5f1e05..d007cb2 100644
--- a/cc/trees/property_tree_unittest.cc
+++ b/cc/trees/property_tree_unittest.cc
@@ -7,14 +7,21 @@
 #include "cc/input/main_thread_scrolling_reason.h"
 #include "cc/proto/property_tree.pb.h"
 #include "cc/test/geometry_test_utils.h"
+#include "cc/trees/clip_node.h"
 #include "cc/trees/draw_property_utils.h"
+#include "cc/trees/effect_node.h"
+#include "cc/trees/scroll_node.h"
+#include "cc/trees/transform_node.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cc {
 namespace {
 
-TEST(PropertyTreeSerializationTest, TransformNodeDataSerialization) {
-  TransformNodeData original;
+TEST(PropertyTreeSerializationTest, TransformNodeSerialization) {
+  TransformNode original;
+  original.id = 3;
+  original.parent_id = 2;
+  original.owner_id = 4;
   original.pre_local.Translate3d(1.f, 2.f, 3.f);
   original.local.Translate3d(3.f, 1.f, 5.f);
   original.post_local.Translate3d(1.f, 8.f, 3.f);
@@ -45,20 +52,6 @@
 
   proto::TreeNode proto;
   original.ToProtobuf(&proto);
-  TransformNodeData result;
-  result.FromProtobuf(proto);
-
-  EXPECT_EQ(original, result);
-}
-
-TEST(PropertyTreeSerializationTest, TransformNodeSerialization) {
-  TransformNode original;
-  original.id = 3;
-  original.parent_id = 2;
-  original.owner_id = 4;
-
-  proto::TreeNode proto;
-  original.ToProtobuf(&proto);
   TransformNode result;
   result.FromProtobuf(proto);
 
@@ -75,14 +68,14 @@
   original.SetContentTargetId(root.id, 4);
   TransformNode second;
   second.owner_id = 2;
-  second.data.local.Translate3d(2.f, 2.f, 0.f);
-  second.data.source_node_id = 0;
+  second.local.Translate3d(2.f, 2.f, 0.f);
+  second.source_node_id = 0;
   second.id = original.Insert(second, 0);
   original.SetTargetId(second.id, 0);
   TransformNode third;
   third.owner_id = 3;
-  third.data.scrolls = true;
-  third.data.source_node_id = 1;
+  third.scrolls = true;
+  third.source_node_id = 1;
   third.id = original.Insert(third, 1);
   original.SetTargetId(third.id, 0);
 
@@ -109,8 +102,11 @@
   EXPECT_EQ(original, result);
 }
 
-TEST(PropertyTreeSerializationTest, ClipNodeDataSerialization) {
-  ClipNodeData original;
+TEST(PropertyTreeSerializationTest, ClipNodeSerialization) {
+  ClipNode original;
+  original.id = 3;
+  original.parent_id = 2;
+  original.owner_id = 4;
   original.clip = gfx::RectF(0.5f, 0.5f);
   original.combined_clip_in_target_space = gfx::RectF(0.6f, 0.6f);
   original.clip_in_target_space = gfx::RectF(0.7f, 0.7f);
@@ -125,20 +121,6 @@
 
   proto::TreeNode proto;
   original.ToProtobuf(&proto);
-  ClipNodeData result;
-  result.FromProtobuf(proto);
-
-  EXPECT_EQ(original, result);
-}
-
-TEST(PropertyTreeSerializationTest, ClipNodeSerialization) {
-  ClipNode original;
-  original.id = 3;
-  original.parent_id = 2;
-  original.owner_id = 4;
-
-  proto::TreeNode proto;
-  original.ToProtobuf(&proto);
   ClipNode result;
   result.FromProtobuf(proto);
 
@@ -149,16 +131,16 @@
   ClipTree original;
   ClipNode& root = *original.Node(0);
   root.owner_id = 1;
-  root.data.transform_id = 2;
-  root.data.target_id = 1;
+  root.transform_id = 2;
+  root.target_id = 1;
   ClipNode second;
   second.owner_id = 2;
-  second.data.transform_id = 4;
-  second.data.applies_local_clip = true;
+  second.transform_id = 4;
+  second.applies_local_clip = true;
   ClipNode third;
   third.owner_id = 3;
-  third.data.target_id = 3;
-  third.data.target_is_clipped = false;
+  third.target_id = 3;
+  third.target_is_clipped = false;
 
   original.Insert(second, 0);
   original.Insert(third, 1);
@@ -176,8 +158,11 @@
   EXPECT_EQ(original, result);
 }
 
-TEST(PropertyTreeSerializationTest, EffectNodeDataSerialization) {
-  EffectNodeData original;
+TEST(PropertyTreeSerializationTest, EffectNodeSerialization) {
+  EffectNode original;
+  original.id = 3;
+  original.parent_id = 2;
+  original.owner_id = 4;
   original.opacity = 0.5f;
   original.screen_space_opacity = 0.6f;
   original.has_render_surface = false;
@@ -186,20 +171,7 @@
   original.mask_layer_id = 6;
   original.replica_layer_id = 10;
   original.replica_mask_layer_id = 9;
-
-  proto::TreeNode proto;
-  original.ToProtobuf(&proto);
-  EffectNodeData result;
-  result.FromProtobuf(proto);
-
-  EXPECT_EQ(original, result);
-}
-
-TEST(PropertyTreeSerializationTest, EffectNodeSerialization) {
-  EffectNode original;
-  original.id = 3;
-  original.parent_id = 2;
-  original.owner_id = 4;
+  original.sublayer_scale = gfx::Vector2dF(0.5f, 0.5f);
 
   proto::TreeNode proto;
   original.ToProtobuf(&proto);
@@ -213,19 +185,19 @@
   EffectTree original;
   EffectNode& root = *original.Node(0);
   root.owner_id = 5;
-  root.data.transform_id = 2;
-  root.data.clip_id = 1;
+  root.transform_id = 2;
+  root.clip_id = 1;
   EffectNode second;
   second.owner_id = 6;
-  second.data.transform_id = 4;
-  second.data.opacity = true;
-  second.data.mask_layer_id = 32;
+  second.transform_id = 4;
+  second.opacity = true;
+  second.mask_layer_id = 32;
   EffectNode third;
   third.owner_id = 7;
-  third.data.clip_id = 3;
-  third.data.replica_layer_id = 44;
-  third.data.replica_mask_layer_id = 45;
-  third.data.has_render_surface = false;
+  third.clip_id = 3;
+  third.replica_layer_id = 44;
+  third.replica_mask_layer_id = 45;
+  third.has_render_surface = false;
 
   original.Insert(second, 0);
   original.Insert(third, 1);
@@ -246,8 +218,11 @@
   EXPECT_EQ(original, result);
 }
 
-TEST(PropertyTreeSerializationTest, ScrollNodeDataSerialization) {
-  ScrollNodeData original;
+TEST(PropertyTreeSerializationTest, ScrollNodeSerialization) {
+  ScrollNode original;
+  original.id = 3;
+  original.parent_id = 2;
+  original.owner_id = 4;
   original.scrollable = true;
   original.main_thread_scrolling_reasons =
       MainThreadScrollingReason::kScrollbarScrolling;
@@ -260,20 +235,6 @@
 
   proto::TreeNode proto;
   original.ToProtobuf(&proto);
-  ScrollNodeData result;
-  result.FromProtobuf(proto);
-
-  EXPECT_EQ(original, result);
-}
-
-TEST(PropertyTreeSerializationTest, ScrollNodeSerialization) {
-  ScrollNode original;
-  original.id = 3;
-  original.parent_id = 2;
-  original.owner_id = 4;
-
-  proto::TreeNode proto;
-  original.ToProtobuf(&proto);
   ScrollNode result;
   result.FromProtobuf(proto);
 
@@ -286,11 +247,11 @@
   ScrollTree& original = property_trees.scroll_tree;
   ScrollNode second;
   second.owner_id = 10;
-  second.data.scrollable = true;
-  second.data.bounds = gfx::Size(15, 15);
+  second.scrollable = true;
+  second.bounds = gfx::Size(15, 15);
   ScrollNode third;
   third.owner_id = 20;
-  third.data.contains_non_fast_scrollable_region = true;
+  third.contains_non_fast_scrollable_region = true;
 
   original.Insert(second, 0);
   original.Insert(third, 1);
@@ -434,7 +395,7 @@
     TransformTree& tree = property_trees.transform_tree;
     TransformNode& root = *tree.Node(0);
     root.id = 0;
-    root.data.local.Translate(2, 2);
+    root.local.Translate(2, 2);
     tree.SetTargetId(root.id, 0);
     SetupTransformTreeForTest(&tree);
     tree.UpdateTransforms(0);
@@ -469,13 +430,13 @@
     PropertyTrees property_trees;
     TransformTree& tree = property_trees.transform_tree;
     TransformNode& root = *tree.Node(0);
-    root.data.local.Translate(2, 2);
+    root.local.Translate(2, 2);
     tree.SetTargetId(root.id, 0);
     tree.UpdateTransforms(0);
 
     TransformNode child;
-    child.data.local.Translate(3, 3);
-    child.data.source_node_id = 0;
+    child.local.Translate(3, 3);
+    child.source_node_id = 0;
     child.id = tree.Insert(child, 0);
     tree.SetTargetId(child.id, 0);
 
@@ -522,19 +483,19 @@
     PropertyTrees property_trees;
     TransformTree& tree = property_trees.transform_tree;
     TransformNode& root = *tree.Node(0);
-    root.data.local.Translate(2, 2);
+    root.local.Translate(2, 2);
     tree.SetTargetId(root.id, 0);
     tree.UpdateTransforms(0);
 
     TransformNode child;
-    child.data.local.Translate(3, 3);
-    child.data.source_node_id = 0;
+    child.local.Translate(3, 3);
+    child.source_node_id = 0;
     child.id = tree.Insert(child, 0);
     tree.SetTargetId(child.id, 0);
 
     TransformNode sibling;
-    sibling.data.local.Translate(7, 7);
-    sibling.data.source_node_id = 0;
+    sibling.local.Translate(7, 7);
+    sibling.source_node_id = 0;
     sibling.id = tree.Insert(sibling, 0);
     tree.SetTargetId(sibling.id, 0);
 
@@ -579,25 +540,25 @@
     PropertyTrees property_trees;
     TransformTree& tree = property_trees.transform_tree;
     TransformNode& root = *tree.Node(0);
-    root.data.local.Translate(2, 2);
+    root.local.Translate(2, 2);
     tree.SetTargetId(root.id, 0);
     tree.UpdateTransforms(0);
 
     TransformNode singular;
-    singular.data.local.matrix().set(2, 2, 0.0);
-    singular.data.source_node_id = 0;
+    singular.local.matrix().set(2, 2, 0.0);
+    singular.source_node_id = 0;
     singular.id = tree.Insert(singular, 0);
     tree.SetTargetId(singular.id, 0);
 
     TransformNode child;
-    child.data.local.Translate(3, 3);
-    child.data.source_node_id = 1;
+    child.local.Translate(3, 3);
+    child.source_node_id = 1;
     child.id = tree.Insert(child, 1);
     tree.SetTargetId(child.id, 0);
 
     TransformNode sibling;
-    sibling.data.local.Translate(7, 7);
-    sibling.data.source_node_id = 1;
+    sibling.local.Translate(7, 7);
+    sibling.source_node_id = 1;
     sibling.id = tree.Insert(sibling, 1);
     tree.SetTargetId(sibling.id, 0);
 
@@ -636,31 +597,31 @@
     int grand_parent = tree.Insert(TransformNode(), 0);
     tree.SetContentTargetId(grand_parent, grand_parent);
     tree.SetTargetId(grand_parent, grand_parent);
-    tree.Node(grand_parent)->data.source_node_id = 0;
+    tree.Node(grand_parent)->source_node_id = 0;
 
     gfx::Transform rotation_about_x;
     rotation_about_x.RotateAboutXAxis(15);
 
     int parent = tree.Insert(TransformNode(), grand_parent);
-    tree.Node(parent)->data.needs_sublayer_scale = true;
+    tree.Node(parent)->needs_sublayer_scale = true;
     tree.SetTargetId(parent, grand_parent);
     tree.SetContentTargetId(parent, parent);
-    tree.Node(parent)->data.source_node_id = grand_parent;
-    tree.Node(parent)->data.local = rotation_about_x;
+    tree.Node(parent)->source_node_id = grand_parent;
+    tree.Node(parent)->local = rotation_about_x;
 
     int child = tree.Insert(TransformNode(), parent);
     tree.SetTargetId(child, parent);
     tree.SetContentTargetId(child, parent);
-    tree.Node(child)->data.source_node_id = parent;
-    tree.Node(child)->data.flattens_inherited_transform = true;
-    tree.Node(child)->data.local = rotation_about_x;
+    tree.Node(child)->source_node_id = parent;
+    tree.Node(child)->flattens_inherited_transform = true;
+    tree.Node(child)->local = rotation_about_x;
 
     int grand_child = tree.Insert(TransformNode(), child);
     tree.SetTargetId(grand_child, parent);
     tree.SetContentTargetId(grand_child, parent);
-    tree.Node(grand_child)->data.source_node_id = child;
-    tree.Node(grand_child)->data.flattens_inherited_transform = true;
-    tree.Node(grand_child)->data.local = rotation_about_x;
+    tree.Node(grand_child)->source_node_id = child;
+    tree.Node(grand_child)->flattens_inherited_transform = true;
+    tree.Node(grand_child)->local = rotation_about_x;
 
     tree.set_needs_update(true);
     SetupTransformTreeForTest(&tree);
@@ -690,7 +651,7 @@
     EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_about_x, grand_child_to_child);
 
     // Remove flattening at grand_child, and recompute transforms.
-    tree.Node(grand_child)->data.flattens_inherited_transform = false;
+    tree.Node(grand_child)->flattens_inherited_transform = false;
     tree.set_needs_update(true);
     SetupTransformTreeForTest(&tree);
     draw_property_utils::ComputeTransforms(&tree);
@@ -717,13 +678,13 @@
     PropertyTrees property_trees;
     TransformTree& tree = property_trees.transform_tree;
     TransformNode& root = *tree.Node(0);
-    root.data.local.Translate(2, 2);
+    root.local.Translate(2, 2);
     tree.SetTargetId(root.id, 0);
     tree.UpdateTransforms(0);
 
     TransformNode child;
-    child.data.local.Scale(2, 2);
-    child.data.source_node_id = 0;
+    child.local.Scale(2, 2);
+    child.source_node_id = 0;
     child.id = tree.Insert(child, 0);
     tree.SetTargetId(child.id, 0);
 
@@ -763,8 +724,8 @@
     tree.UpdateTransforms(0);
 
     TransformNode child;
-    child.data.local.Scale(0, 0);
-    child.data.source_node_id = 0;
+    child.local.Scale(0, 0);
+    child.source_node_id = 0;
     child.id = tree.Insert(child, 0);
     tree.SetTargetId(child.id, 0);
 
@@ -803,40 +764,40 @@
     tree.UpdateTransforms(0);
 
     TransformNode grand_parent;
-    grand_parent.data.local.Scale(2.f, 2.f);
-    grand_parent.data.source_node_id = 0;
-    grand_parent.data.needs_sublayer_scale = true;
+    grand_parent.local.Scale(2.f, 2.f);
+    grand_parent.source_node_id = 0;
+    grand_parent.needs_sublayer_scale = true;
     int grand_parent_id = tree.Insert(grand_parent, 0);
     tree.SetTargetId(grand_parent_id, 0);
     tree.UpdateTransforms(grand_parent_id);
 
     TransformNode parent;
-    parent.data.local.Translate(15.f, 15.f);
-    parent.data.source_node_id = grand_parent_id;
+    parent.local.Translate(15.f, 15.f);
+    parent.source_node_id = grand_parent_id;
     int parent_id = tree.Insert(parent, grand_parent_id);
     tree.SetTargetId(parent_id, grand_parent_id);
     tree.UpdateTransforms(parent_id);
 
     TransformNode child;
-    child.data.local.Scale(3.f, 3.f);
-    child.data.source_node_id = parent_id;
+    child.local.Scale(3.f, 3.f);
+    child.source_node_id = parent_id;
     int child_id = tree.Insert(child, parent_id);
     tree.SetTargetId(child_id, grand_parent_id);
     tree.UpdateTransforms(child_id);
 
     TransformNode grand_child;
-    grand_child.data.local.Scale(5.f, 5.f);
-    grand_child.data.source_node_id = child_id;
-    grand_child.data.needs_sublayer_scale = true;
+    grand_child.local.Scale(5.f, 5.f);
+    grand_child.source_node_id = child_id;
+    grand_child.needs_sublayer_scale = true;
     int grand_child_id = tree.Insert(grand_child, child_id);
     tree.SetTargetId(grand_child_id, grand_parent_id);
     SetupTransformTreeForTest(&tree);
     tree.UpdateTransforms(grand_child_id);
 
     EXPECT_EQ(gfx::Vector2dF(2.f, 2.f),
-              tree.Node(grand_parent_id)->data.sublayer_scale);
+              tree.Node(grand_parent_id)->sublayer_scale);
     EXPECT_EQ(gfx::Vector2dF(30.f, 30.f),
-              tree.Node(grand_child_id)->data.sublayer_scale);
+              tree.Node(grand_child_id)->sublayer_scale);
 
     // Compute transform from grand_parent to grand_child.
     gfx::Transform expected_transform_without_sublayer_scale;
@@ -921,25 +882,25 @@
     tree.UpdateTransforms(0);
 
     TransformNode grand_parent;
-    grand_parent.data.local.Scale(2.f, 0.f);
-    grand_parent.data.source_node_id = 0;
-    grand_parent.data.needs_sublayer_scale = true;
+    grand_parent.local.Scale(2.f, 0.f);
+    grand_parent.source_node_id = 0;
+    grand_parent.needs_sublayer_scale = true;
     int grand_parent_id = tree.Insert(grand_parent, 0);
     tree.SetTargetId(grand_parent_id, 0);
     tree.SetContentTargetId(grand_parent_id, grand_parent_id);
     tree.UpdateTransforms(grand_parent_id);
 
     TransformNode parent;
-    parent.data.local.Translate(1.f, 1.f);
-    parent.data.source_node_id = grand_parent_id;
+    parent.local.Translate(1.f, 1.f);
+    parent.source_node_id = grand_parent_id;
     int parent_id = tree.Insert(parent, grand_parent_id);
     tree.SetTargetId(parent_id, grand_parent_id);
     tree.SetContentTargetId(parent_id, grand_parent_id);
     tree.UpdateTransforms(parent_id);
 
     TransformNode child;
-    child.data.local.Translate(3.f, 4.f);
-    child.data.source_node_id = parent_id;
+    child.local.Translate(3.f, 4.f);
+    child.source_node_id = parent_id;
     int child_id = tree.Insert(child, parent_id);
     tree.SetTargetId(child_id, grand_parent_id);
     tree.SetContentTargetId(child_id, grand_parent_id);
@@ -954,9 +915,9 @@
     EXPECT_TRUE(success);
     EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform, transform);
 
-    tree.Node(grand_parent_id)->data.local.MakeIdentity();
-    tree.Node(grand_parent_id)->data.local.Scale(0.f, 2.f);
-    tree.Node(grand_parent_id)->data.needs_local_transform_update = true;
+    tree.Node(grand_parent_id)->local.MakeIdentity();
+    tree.Node(grand_parent_id)->local.Scale(0.f, 2.f);
+    tree.Node(grand_parent_id)->needs_local_transform_update = true;
     tree.set_needs_update(true);
     SetupTransformTreeForTest(&tree);
 
@@ -966,9 +927,9 @@
     EXPECT_TRUE(success);
     EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform, transform);
 
-    tree.Node(grand_parent_id)->data.local.MakeIdentity();
-    tree.Node(grand_parent_id)->data.local.Scale(0.f, 0.f);
-    tree.Node(grand_parent_id)->data.needs_local_transform_update = true;
+    tree.Node(grand_parent_id)->local.MakeIdentity();
+    tree.Node(grand_parent_id)->local.Scale(0.f, 0.f);
+    tree.Node(grand_parent_id)->needs_local_transform_update = true;
     tree.set_needs_update(true);
     SetupTransformTreeForTest(&tree);
 
@@ -996,8 +957,8 @@
     int parent = tree.Insert(TransformNode(), 0);
     tree.SetContentTargetId(parent, parent);
     tree.SetTargetId(parent, parent);
-    tree.Node(parent)->data.source_node_id = 0;
-    tree.Node(parent)->data.local.Translate(2, 2);
+    tree.Node(parent)->source_node_id = 0;
+    tree.Node(parent)->local.Translate(2, 2);
 
     gfx::Transform rotation_about_x;
     rotation_about_x.RotateAboutXAxis(15);
@@ -1005,14 +966,14 @@
     int child = tree.Insert(TransformNode(), parent);
     tree.SetContentTargetId(child, child);
     tree.SetTargetId(child, child);
-    tree.Node(child)->data.source_node_id = parent;
-    tree.Node(child)->data.local = rotation_about_x;
+    tree.Node(child)->source_node_id = parent;
+    tree.Node(child)->local = rotation_about_x;
 
     int grand_child = tree.Insert(TransformNode(), child);
     tree.SetContentTargetId(grand_child, grand_child);
     tree.SetTargetId(grand_child, grand_child);
-    tree.Node(grand_child)->data.source_node_id = child;
-    tree.Node(grand_child)->data.flattens_inherited_transform = true;
+    tree.Node(grand_child)->source_node_id = child;
+    tree.Node(grand_child)->flattens_inherited_transform = true;
 
     tree.set_needs_update(true);
     SetupTransformTreeForTest(&tree);
@@ -1044,18 +1005,18 @@
     int child = tree.Insert(EffectNode(), parent);
     SetupEffectTreeForTest(&tree);
 
-    EXPECT_EQ(tree.Node(child)->data.screen_space_opacity, 1.f);
-    tree.Node(parent)->data.opacity = 0.5f;
+    EXPECT_EQ(tree.Node(child)->screen_space_opacity, 1.f);
+    tree.Node(parent)->opacity = 0.5f;
     tree.set_needs_update(true);
     SetupEffectTreeForTest(&tree);
     draw_property_utils::ComputeEffects(&tree);
-    EXPECT_EQ(tree.Node(child)->data.screen_space_opacity, 0.5f);
+    EXPECT_EQ(tree.Node(child)->screen_space_opacity, 0.5f);
 
-    tree.Node(child)->data.opacity = 0.5f;
+    tree.Node(child)->opacity = 0.5f;
     tree.set_needs_update(true);
     SetupEffectTreeForTest(&tree);
     draw_property_utils::ComputeEffects(&tree);
-    EXPECT_EQ(tree.Node(child)->data.screen_space_opacity, 0.25f);
+    EXPECT_EQ(tree.Node(child)->screen_space_opacity, 0.25f);
   }
 };
 
@@ -1072,38 +1033,38 @@
 
     int parent = tree.Insert(TransformNode(), 0);
     tree.SetTargetId(parent, parent);
-    tree.Node(parent)->data.local.Translate(1.5f, 1.5f);
+    tree.Node(parent)->local.Translate(1.5f, 1.5f);
 
     int child = tree.Insert(TransformNode(), parent);
     tree.SetTargetId(child, parent);
-    tree.Node(child)->data.local.Translate(1, 1);
+    tree.Node(child)->local.Translate(1, 1);
     tree.set_needs_update(true);
     SetupTransformTreeForTest(&tree);
     draw_property_utils::ComputeTransforms(&tree);
-    EXPECT_FALSE(tree.Node(parent)
-                     ->data.node_and_ancestors_have_only_integer_translation);
-    EXPECT_FALSE(tree.Node(child)
-                     ->data.node_and_ancestors_have_only_integer_translation);
+    EXPECT_FALSE(
+        tree.Node(parent)->node_and_ancestors_have_only_integer_translation);
+    EXPECT_FALSE(
+        tree.Node(child)->node_and_ancestors_have_only_integer_translation);
 
-    tree.Node(parent)->data.local.Translate(0.5f, 0.5f);
-    tree.Node(child)->data.local.Translate(0.5f, 0.5f);
+    tree.Node(parent)->local.Translate(0.5f, 0.5f);
+    tree.Node(child)->local.Translate(0.5f, 0.5f);
     tree.set_needs_update(true);
     SetupTransformTreeForTest(&tree);
     draw_property_utils::ComputeTransforms(&tree);
-    EXPECT_TRUE(tree.Node(parent)
-                    ->data.node_and_ancestors_have_only_integer_translation);
-    EXPECT_FALSE(tree.Node(child)
-                     ->data.node_and_ancestors_have_only_integer_translation);
+    EXPECT_TRUE(
+        tree.Node(parent)->node_and_ancestors_have_only_integer_translation);
+    EXPECT_FALSE(
+        tree.Node(child)->node_and_ancestors_have_only_integer_translation);
 
-    tree.Node(child)->data.local.Translate(0.5f, 0.5f);
+    tree.Node(child)->local.Translate(0.5f, 0.5f);
     tree.SetTargetId(child, child);
     tree.set_needs_update(true);
     SetupTransformTreeForTest(&tree);
     draw_property_utils::ComputeTransforms(&tree);
-    EXPECT_TRUE(tree.Node(parent)
-                    ->data.node_and_ancestors_have_only_integer_translation);
-    EXPECT_TRUE(tree.Node(child)
-                    ->data.node_and_ancestors_have_only_integer_translation);
+    EXPECT_TRUE(
+        tree.Node(parent)->node_and_ancestors_have_only_integer_translation);
+    EXPECT_TRUE(
+        tree.Node(child)->node_and_ancestors_have_only_integer_translation);
   }
 };
 
@@ -1120,14 +1081,14 @@
 
     int parent = tree.Insert(TransformNode(), 0);
     tree.SetTargetId(parent, parent);
-    tree.Node(parent)->data.scrolls = true;
+    tree.Node(parent)->scrolls = true;
 
     int child = tree.Insert(TransformNode(), parent);
     TransformNode* child_node = tree.Node(child);
     tree.SetTargetId(child, parent);
-    child_node->data.scrolls = true;
-    child_node->data.local.Scale3d(6.0f, 6.0f, 0.0f);
-    child_node->data.local.Translate(1.3f, 1.3f);
+    child_node->scrolls = true;
+    child_node->local.Scale3d(6.0f, 6.0f, 0.0f);
+    child_node->local.Translate(1.3f, 1.3f);
     tree.set_needs_update(true);
 
     SetupTransformTreeForTest(&tree);
@@ -1138,10 +1099,10 @@
     // The following checks are to ensure that snapping is skipped because of
     // singular transform (and not because of other reasons which also cause
     // snapping to be skipped).
-    EXPECT_TRUE(child_node->data.scrolls);
+    EXPECT_TRUE(child_node->scrolls);
     EXPECT_TRUE(tree.ToTarget(child).IsScaleOrTranslation());
-    EXPECT_FALSE(child_node->data.to_screen_is_potentially_animated);
-    EXPECT_FALSE(child_node->data.ancestors_are_invertible);
+    EXPECT_FALSE(child_node->to_screen_is_potentially_animated);
+    EXPECT_FALSE(child_node->ancestors_are_invertible);
 
     gfx::Transform rounded = tree.ToTarget(child);
     rounded.RoundTranslationComponents();
diff --git a/cc/trees/scroll_node.cc b/cc/trees/scroll_node.cc
new file mode 100644
index 0000000..a20fe2f
--- /dev/null
+++ b/cc/trees/scroll_node.cc
@@ -0,0 +1,127 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_argument.h"
+#include "cc/animation/element_id.h"
+#include "cc/base/math_util.h"
+#include "cc/input/main_thread_scrolling_reason.h"
+#include "cc/proto/gfx_conversions.h"
+#include "cc/proto/property_tree.pb.h"
+#include "cc/trees/scroll_node.h"
+
+namespace cc {
+
+ScrollNode::ScrollNode()
+    : id(-1),
+      parent_id(-1),
+      owner_id(-1),
+      scrollable(false),
+      main_thread_scrolling_reasons(
+          MainThreadScrollingReason::kNotScrollingOnMain),
+      contains_non_fast_scrollable_region(false),
+      max_scroll_offset_affected_by_page_scale(false),
+      is_inner_viewport_scroll_layer(false),
+      is_outer_viewport_scroll_layer(false),
+      should_flatten(false),
+      user_scrollable_horizontal(false),
+      user_scrollable_vertical(false),
+      transform_id(0),
+      num_drawn_descendants(0) {}
+
+ScrollNode::ScrollNode(const ScrollNode& other) = default;
+
+bool ScrollNode::operator==(const ScrollNode& other) const {
+  return id == other.id && parent_id == other.parent_id &&
+         owner_id == other.owner_id && scrollable == other.scrollable &&
+         main_thread_scrolling_reasons == other.main_thread_scrolling_reasons &&
+         contains_non_fast_scrollable_region ==
+             other.contains_non_fast_scrollable_region &&
+         scroll_clip_layer_bounds == other.scroll_clip_layer_bounds &&
+         bounds == other.bounds &&
+         max_scroll_offset_affected_by_page_scale ==
+             other.max_scroll_offset_affected_by_page_scale &&
+         is_inner_viewport_scroll_layer ==
+             other.is_inner_viewport_scroll_layer &&
+         is_outer_viewport_scroll_layer ==
+             other.is_outer_viewport_scroll_layer &&
+         offset_to_transform_parent == other.offset_to_transform_parent &&
+         should_flatten == other.should_flatten &&
+         user_scrollable_horizontal == other.user_scrollable_horizontal &&
+         user_scrollable_vertical == other.user_scrollable_vertical &&
+         element_id == other.element_id && transform_id == other.transform_id;
+}
+
+void ScrollNode::ToProtobuf(proto::TreeNode* proto) const {
+  proto->set_id(id);
+  proto->set_parent_id(parent_id);
+  proto->set_owner_id(owner_id);
+
+  DCHECK(!proto->has_scroll_node_data());
+  proto::ScrollNodeData* data = proto->mutable_scroll_node_data();
+  data->set_scrollable(scrollable);
+  data->set_main_thread_scrolling_reasons(main_thread_scrolling_reasons);
+  data->set_contains_non_fast_scrollable_region(
+      contains_non_fast_scrollable_region);
+  SizeToProto(scroll_clip_layer_bounds,
+              data->mutable_scroll_clip_layer_bounds());
+  SizeToProto(bounds, data->mutable_bounds());
+  data->set_max_scroll_offset_affected_by_page_scale(
+      max_scroll_offset_affected_by_page_scale);
+  data->set_is_inner_viewport_scroll_layer(is_inner_viewport_scroll_layer);
+  data->set_is_outer_viewport_scroll_layer(is_outer_viewport_scroll_layer);
+  Vector2dFToProto(offset_to_transform_parent,
+                   data->mutable_offset_to_transform_parent());
+  data->set_should_flatten(should_flatten);
+  data->set_user_scrollable_horizontal(user_scrollable_horizontal);
+  data->set_user_scrollable_vertical(user_scrollable_vertical);
+  element_id.ToProtobuf(data->mutable_element_id());
+  data->set_transform_id(transform_id);
+}
+
+void ScrollNode::FromProtobuf(const proto::TreeNode& proto) {
+  id = proto.id();
+  parent_id = proto.parent_id();
+  owner_id = proto.owner_id();
+
+  DCHECK(proto.has_scroll_node_data());
+  const proto::ScrollNodeData& data = proto.scroll_node_data();
+
+  scrollable = data.scrollable();
+  main_thread_scrolling_reasons = data.main_thread_scrolling_reasons();
+  contains_non_fast_scrollable_region =
+      data.contains_non_fast_scrollable_region();
+  scroll_clip_layer_bounds = ProtoToSize(data.scroll_clip_layer_bounds());
+  bounds = ProtoToSize(data.bounds());
+  max_scroll_offset_affected_by_page_scale =
+      data.max_scroll_offset_affected_by_page_scale();
+  is_inner_viewport_scroll_layer = data.is_inner_viewport_scroll_layer();
+  is_outer_viewport_scroll_layer = data.is_outer_viewport_scroll_layer();
+  offset_to_transform_parent =
+      ProtoToVector2dF(data.offset_to_transform_parent());
+  should_flatten = data.should_flatten();
+  user_scrollable_horizontal = data.user_scrollable_horizontal();
+  user_scrollable_vertical = data.user_scrollable_vertical();
+  element_id.FromProtobuf(data.element_id());
+  transform_id = data.transform_id();
+}
+
+void ScrollNode::AsValueInto(base::trace_event::TracedValue* value) const {
+  value->SetInteger("id", id);
+  value->SetInteger("parent_id", parent_id);
+  value->SetInteger("owner_id", owner_id);
+  value->SetBoolean("scrollable", scrollable);
+  MathUtil::AddToTracedValue("scroll_clip_layer_bounds",
+                             scroll_clip_layer_bounds, value);
+  MathUtil::AddToTracedValue("bounds", bounds, value);
+  MathUtil::AddToTracedValue("offset_to_transform_parent",
+                             offset_to_transform_parent, value);
+  value->SetBoolean("should_flatten", should_flatten);
+  value->SetBoolean("user_scrollable_horizontal", user_scrollable_horizontal);
+  value->SetBoolean("user_scrollable_vertical", user_scrollable_vertical);
+
+  element_id.AddToTracedValue(value);
+  value->SetInteger("transform_id", transform_id);
+}
+
+}  // namespace cc
diff --git a/cc/trees/scroll_node.h b/cc/trees/scroll_node.h
new file mode 100644
index 0000000..745ee69
--- /dev/null
+++ b/cc/trees/scroll_node.h
@@ -0,0 +1,58 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TREES_SCROLL_NODE_H_
+#define CC_TREES_SCROLL_NODE_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/output/filter_operations.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace base {
+namespace trace_event {
+class TracedValue;
+}  // namespace trace_event
+}  // namespace base
+
+namespace cc {
+
+namespace proto {
+class TreeNode;
+}  // namespace proto
+
+struct CC_EXPORT ScrollNode {
+  ScrollNode();
+  ScrollNode(const ScrollNode& other);
+
+  int id;
+  int parent_id;
+  int owner_id;
+
+  bool scrollable;
+  uint32_t main_thread_scrolling_reasons;
+  bool contains_non_fast_scrollable_region;
+  gfx::Size scroll_clip_layer_bounds;
+  gfx::Size bounds;
+  bool max_scroll_offset_affected_by_page_scale;
+  bool is_inner_viewport_scroll_layer;
+  bool is_outer_viewport_scroll_layer;
+  gfx::Vector2dF offset_to_transform_parent;
+  bool should_flatten;
+  bool user_scrollable_horizontal;
+  bool user_scrollable_vertical;
+  ElementId element_id;
+  int transform_id;
+  // Number of drawn layers pointing to this node or any of its descendants.
+  int num_drawn_descendants;
+
+  bool operator==(const ScrollNode& other) const;
+
+  void ToProtobuf(proto::TreeNode* proto) const;
+  void FromProtobuf(const proto::TreeNode& proto);
+  void AsValueInto(base::trace_event::TracedValue* value) const;
+};
+
+}  // namespace cc
+
+#endif  // CC_TREES_SCROLL_NODE_H_
diff --git a/cc/trees/transform_node.cc b/cc/trees/transform_node.cc
new file mode 100644
index 0000000..ab2693b3
--- /dev/null
+++ b/cc/trees/transform_node.cc
@@ -0,0 +1,271 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_argument.h"
+#include "cc/base/math_util.h"
+#include "cc/proto/gfx_conversions.h"
+#include "cc/proto/property_tree.pb.h"
+#include "cc/trees/transform_node.h"
+#include "ui/gfx/geometry/point3_f.h"
+
+namespace cc {
+
+TransformNode::TransformNode()
+    : id(-1),
+      parent_id(-1),
+      owner_id(-1),
+      source_node_id(-1),
+      sorting_context_id(0),
+      needs_local_transform_update(true),
+      node_and_ancestors_are_animated_or_invertible(true),
+      is_invertible(true),
+      ancestors_are_invertible(true),
+      has_potential_animation(false),
+      is_currently_animating(false),
+      to_screen_is_potentially_animated(false),
+      has_only_translation_animations(true),
+      flattens_inherited_transform(false),
+      node_and_ancestors_are_flat(true),
+      node_and_ancestors_have_only_integer_translation(true),
+      scrolls(false),
+      needs_sublayer_scale(false),
+      affected_by_inner_viewport_bounds_delta_x(false),
+      affected_by_inner_viewport_bounds_delta_y(false),
+      affected_by_outer_viewport_bounds_delta_x(false),
+      affected_by_outer_viewport_bounds_delta_y(false),
+      in_subtree_of_page_scale_layer(false),
+      transform_changed(false),
+      post_local_scale_factor(1.0f) {}
+
+TransformNode::TransformNode(const TransformNode&) = default;
+
+bool TransformNode::operator==(const TransformNode& other) const {
+  return id == other.id && parent_id == other.parent_id &&
+         owner_id == other.owner_id && pre_local == other.pre_local &&
+         local == other.local && post_local == other.post_local &&
+         to_parent == other.to_parent &&
+         source_node_id == other.source_node_id &&
+         sorting_context_id == other.sorting_context_id &&
+         needs_local_transform_update == other.needs_local_transform_update &&
+         node_and_ancestors_are_animated_or_invertible ==
+             other.node_and_ancestors_are_animated_or_invertible &&
+         is_invertible == other.is_invertible &&
+         ancestors_are_invertible == other.ancestors_are_invertible &&
+         has_potential_animation == other.has_potential_animation &&
+         is_currently_animating == other.is_currently_animating &&
+         to_screen_is_potentially_animated ==
+             other.to_screen_is_potentially_animated &&
+         has_only_translation_animations ==
+             other.has_only_translation_animations &&
+         flattens_inherited_transform == other.flattens_inherited_transform &&
+         node_and_ancestors_are_flat == other.node_and_ancestors_are_flat &&
+         node_and_ancestors_have_only_integer_translation ==
+             other.node_and_ancestors_have_only_integer_translation &&
+         scrolls == other.scrolls &&
+         needs_sublayer_scale == other.needs_sublayer_scale &&
+         affected_by_inner_viewport_bounds_delta_x ==
+             other.affected_by_inner_viewport_bounds_delta_x &&
+         affected_by_inner_viewport_bounds_delta_y ==
+             other.affected_by_inner_viewport_bounds_delta_y &&
+         affected_by_outer_viewport_bounds_delta_x ==
+             other.affected_by_outer_viewport_bounds_delta_x &&
+         affected_by_outer_viewport_bounds_delta_y ==
+             other.affected_by_outer_viewport_bounds_delta_y &&
+         in_subtree_of_page_scale_layer ==
+             other.in_subtree_of_page_scale_layer &&
+         transform_changed == other.transform_changed &&
+         post_local_scale_factor == other.post_local_scale_factor &&
+         sublayer_scale == other.sublayer_scale &&
+         scroll_offset == other.scroll_offset &&
+         scroll_snap == other.scroll_snap &&
+         source_offset == other.source_offset &&
+         source_to_parent == other.source_to_parent;
+}
+
+void TransformNode::update_pre_local_transform(
+    const gfx::Point3F& transform_origin) {
+  pre_local.MakeIdentity();
+  pre_local.Translate3d(-transform_origin.x(), -transform_origin.y(),
+                        -transform_origin.z());
+}
+
+void TransformNode::update_post_local_transform(
+    const gfx::PointF& position,
+    const gfx::Point3F& transform_origin) {
+  post_local.MakeIdentity();
+  post_local.Scale(post_local_scale_factor, post_local_scale_factor);
+  post_local.Translate3d(
+      position.x() + source_offset.x() + transform_origin.x(),
+      position.y() + source_offset.y() + transform_origin.y(),
+      transform_origin.z());
+}
+
+void TransformNode::ToProtobuf(proto::TreeNode* proto) const {
+  proto->set_id(id);
+  proto->set_parent_id(parent_id);
+  proto->set_owner_id(owner_id);
+
+  DCHECK(!proto->has_transform_node_data());
+  proto::TranformNodeData* data = proto->mutable_transform_node_data();
+
+  TransformToProto(pre_local, data->mutable_pre_local());
+  TransformToProto(local, data->mutable_local());
+  TransformToProto(post_local, data->mutable_post_local());
+
+  TransformToProto(to_parent, data->mutable_to_parent());
+
+  data->set_source_node_id(source_node_id);
+  data->set_sorting_context_id(sorting_context_id);
+
+  data->set_needs_local_transform_update(needs_local_transform_update);
+
+  data->set_node_and_ancestors_are_animated_or_invertible(
+      node_and_ancestors_are_animated_or_invertible);
+
+  data->set_is_invertible(is_invertible);
+  data->set_ancestors_are_invertible(ancestors_are_invertible);
+
+  data->set_has_potential_animation(has_potential_animation);
+  data->set_is_currently_animating(is_currently_animating);
+  data->set_to_screen_is_potentially_animated(
+      to_screen_is_potentially_animated);
+  data->set_has_only_translation_animations(has_only_translation_animations);
+
+  data->set_flattens_inherited_transform(flattens_inherited_transform);
+  data->set_node_and_ancestors_are_flat(node_and_ancestors_are_flat);
+
+  data->set_node_and_ancestors_have_only_integer_translation(
+      node_and_ancestors_have_only_integer_translation);
+  data->set_scrolls(scrolls);
+  data->set_needs_sublayer_scale(needs_sublayer_scale);
+
+  data->set_affected_by_inner_viewport_bounds_delta_x(
+      affected_by_inner_viewport_bounds_delta_x);
+  data->set_affected_by_inner_viewport_bounds_delta_y(
+      affected_by_inner_viewport_bounds_delta_y);
+  data->set_affected_by_outer_viewport_bounds_delta_x(
+      affected_by_outer_viewport_bounds_delta_x);
+  data->set_affected_by_outer_viewport_bounds_delta_y(
+      affected_by_outer_viewport_bounds_delta_y);
+
+  data->set_in_subtree_of_page_scale_layer(in_subtree_of_page_scale_layer);
+  data->set_transform_changed(transform_changed);
+  data->set_post_local_scale_factor(post_local_scale_factor);
+
+  Vector2dFToProto(sublayer_scale, data->mutable_sublayer_scale());
+  ScrollOffsetToProto(scroll_offset, data->mutable_scroll_offset());
+  Vector2dFToProto(scroll_snap, data->mutable_scroll_snap());
+  Vector2dFToProto(source_offset, data->mutable_source_offset());
+  Vector2dFToProto(source_to_parent, data->mutable_source_to_parent());
+}
+
+void TransformNode::FromProtobuf(const proto::TreeNode& proto) {
+  id = proto.id();
+  parent_id = proto.parent_id();
+  owner_id = proto.owner_id();
+
+  DCHECK(proto.has_transform_node_data());
+  const proto::TranformNodeData& data = proto.transform_node_data();
+
+  pre_local = ProtoToTransform(data.pre_local());
+  local = ProtoToTransform(data.local());
+  post_local = ProtoToTransform(data.post_local());
+
+  to_parent = ProtoToTransform(data.to_parent());
+
+  source_node_id = data.source_node_id();
+  sorting_context_id = data.sorting_context_id();
+
+  needs_local_transform_update = data.needs_local_transform_update();
+
+  node_and_ancestors_are_animated_or_invertible =
+      data.node_and_ancestors_are_animated_or_invertible();
+
+  is_invertible = data.is_invertible();
+  ancestors_are_invertible = data.ancestors_are_invertible();
+
+  has_potential_animation = data.has_potential_animation();
+  is_currently_animating = data.is_currently_animating();
+  to_screen_is_potentially_animated = data.to_screen_is_potentially_animated();
+  has_only_translation_animations = data.has_only_translation_animations();
+
+  flattens_inherited_transform = data.flattens_inherited_transform();
+  node_and_ancestors_are_flat = data.node_and_ancestors_are_flat();
+
+  node_and_ancestors_have_only_integer_translation =
+      data.node_and_ancestors_have_only_integer_translation();
+  scrolls = data.scrolls();
+  needs_sublayer_scale = data.needs_sublayer_scale();
+
+  affected_by_inner_viewport_bounds_delta_x =
+      data.affected_by_inner_viewport_bounds_delta_x();
+  affected_by_inner_viewport_bounds_delta_y =
+      data.affected_by_inner_viewport_bounds_delta_y();
+  affected_by_outer_viewport_bounds_delta_x =
+      data.affected_by_outer_viewport_bounds_delta_x();
+  affected_by_outer_viewport_bounds_delta_y =
+      data.affected_by_outer_viewport_bounds_delta_y();
+
+  in_subtree_of_page_scale_layer = data.in_subtree_of_page_scale_layer();
+  transform_changed = data.transform_changed();
+  post_local_scale_factor = data.post_local_scale_factor();
+
+  sublayer_scale = ProtoToVector2dF(data.sublayer_scale());
+  scroll_offset = ProtoToScrollOffset(data.scroll_offset());
+  scroll_snap = ProtoToVector2dF(data.scroll_snap());
+  source_offset = ProtoToVector2dF(data.source_offset());
+  source_to_parent = ProtoToVector2dF(data.source_to_parent());
+}
+
+void TransformNode::AsValueInto(base::trace_event::TracedValue* value) const {
+  value->SetInteger("id", id);
+  value->SetInteger("parent_id", parent_id);
+  value->SetInteger("owner_id", owner_id);
+  MathUtil::AddToTracedValue("pre_local", pre_local, value);
+  MathUtil::AddToTracedValue("local", local, value);
+  MathUtil::AddToTracedValue("post_local", post_local, value);
+  // TODO(sunxd): make frameviewer work without target_id
+  value->SetInteger("target_id", 0);
+  value->SetInteger("content_target_id", 0);
+  value->SetInteger("source_node_id", source_node_id);
+  value->SetInteger("sorting_context_id", sorting_context_id);
+}
+
+TransformCachedNodeData::TransformCachedNodeData()
+    : target_id(-1), content_target_id(-1) {}
+
+TransformCachedNodeData::TransformCachedNodeData(
+    const TransformCachedNodeData& other) = default;
+
+TransformCachedNodeData::~TransformCachedNodeData() {}
+
+bool TransformCachedNodeData::operator==(
+    const TransformCachedNodeData& other) const {
+  return from_target == other.from_target && to_target == other.to_target &&
+         from_screen == other.from_screen && to_screen == other.to_screen &&
+         target_id == other.target_id &&
+         content_target_id == other.content_target_id;
+}
+
+void TransformCachedNodeData::ToProtobuf(
+    proto::TransformCachedNodeData* proto) const {
+  TransformToProto(from_target, proto->mutable_from_target());
+  TransformToProto(to_target, proto->mutable_to_target());
+  TransformToProto(from_screen, proto->mutable_from_screen());
+  TransformToProto(to_screen, proto->mutable_to_screen());
+  proto->set_target_id(target_id);
+  proto->set_content_target_id(content_target_id);
+}
+
+void TransformCachedNodeData::FromProtobuf(
+    const proto::TransformCachedNodeData& proto) {
+  from_target = ProtoToTransform(proto.from_target());
+  to_target = ProtoToTransform(proto.to_target());
+  from_screen = ProtoToTransform(proto.from_screen());
+  to_screen = ProtoToTransform(proto.to_screen());
+  target_id = proto.target_id();
+  content_target_id = proto.content_target_id();
+}
+
+}  // namespace cc
diff --git a/cc/trees/transform_node.h b/cc/trees/transform_node.h
new file mode 100644
index 0000000..b128d4dd
--- /dev/null
+++ b/cc/trees/transform_node.h
@@ -0,0 +1,168 @@
+// 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 CC_TREES_TRANSFORM_NODE_H_
+#define CC_TREES_TRANSFORM_NODE_H_
+
+#include "cc/base/cc_export.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/scroll_offset.h"
+#include "ui/gfx/transform.h"
+
+namespace base {
+namespace trace_event {
+class TracedValue;
+}  // namespace trace_event
+}  // namespace base
+
+namespace cc {
+
+namespace proto {
+class TransformCachedNodeData;
+class TreeNode;
+}  // namespace proto
+
+struct CC_EXPORT TransformNode {
+  TransformNode();
+  TransformNode(const TransformNode&);
+
+  int id;
+  int parent_id;
+  int owner_id;
+
+  // The local transform information is combined to form to_parent (ignoring
+  // snapping) as follows:
+  //
+  //   to_parent = M_post_local * T_scroll * M_local * M_pre_local.
+  //
+  // The pre/post may seem odd when read LTR, but we multiply our points from
+  // the right, so the pre_local matrix affects the result "first". This lines
+  // up with the notions of pre/post used in skia and gfx::Transform.
+  //
+  // TODO(vollick): The values labeled with "will be moved..." take up a lot of
+  // space, but are only necessary for animated or scrolled nodes (otherwise
+  // we'll just use the baked to_parent). These values will be ultimately stored
+  // directly on the transform/scroll display list items when that's possible,
+  // or potentially in a scroll tree.
+  //
+  // TODO(vollick): will be moved when accelerated effects are implemented.
+  gfx::Transform pre_local;
+  gfx::Transform local;
+  gfx::Transform post_local;
+
+  gfx::Transform to_parent;
+
+  // This is the node with respect to which source_offset is defined. This will
+  // not be needed once layerization moves to cc, but is needed in order to
+  // efficiently update the transform tree for changes to position in the layer
+  // tree.
+  int source_node_id;
+
+  // This id determines which 3d rendering context the node is in. 0 is a
+  // special value and indicates that the node is not in any 3d rendering
+  // context.
+  int sorting_context_id;
+
+  // TODO(vollick): will be moved when accelerated effects are implemented.
+  bool needs_local_transform_update : 1;
+
+  bool node_and_ancestors_are_animated_or_invertible : 1;
+
+  bool is_invertible : 1;
+  bool ancestors_are_invertible : 1;
+
+  bool has_potential_animation : 1;
+  bool is_currently_animating : 1;
+  bool to_screen_is_potentially_animated : 1;
+  bool has_only_translation_animations : 1;
+
+  // Flattening, when needed, is only applied to a node's inherited transform,
+  // never to its local transform.
+  bool flattens_inherited_transform : 1;
+
+  // This is true if the to_parent transform at every node on the path to the
+  // root is flat.
+  bool node_and_ancestors_are_flat : 1;
+
+  // This is needed to know if a layer can use lcd text.
+  bool node_and_ancestors_have_only_integer_translation : 1;
+
+  bool scrolls : 1;
+
+  bool needs_sublayer_scale : 1;
+
+  // These are used to position nodes wrt the right or bottom of the inner or
+  // outer viewport.
+  bool affected_by_inner_viewport_bounds_delta_x : 1;
+  bool affected_by_inner_viewport_bounds_delta_y : 1;
+  bool affected_by_outer_viewport_bounds_delta_x : 1;
+  bool affected_by_outer_viewport_bounds_delta_y : 1;
+
+  // Layer scale factor is used as a fallback when we either cannot adjust
+  // raster scale or if the raster scale cannot be extracted from the screen
+  // space transform. For layers in the subtree of the page scale layer, the
+  // layer scale factor should include the page scale factor.
+  bool in_subtree_of_page_scale_layer : 1;
+
+  // We need to track changes to to_screen transform to compute the damage rect.
+  bool transform_changed : 1;
+
+  // TODO(vollick): will be moved when accelerated effects are implemented.
+  float post_local_scale_factor;
+
+  gfx::Vector2dF sublayer_scale;
+
+  // TODO(vollick): will be moved when accelerated effects are implemented.
+  gfx::ScrollOffset scroll_offset;
+
+  // We scroll snap where possible, but this means fixed-pos elements must be
+  // adjusted.  This value stores the snapped amount for this purpose.
+  gfx::Vector2dF scroll_snap;
+
+  // TODO(vollick): will be moved when accelerated effects are implemented.
+  gfx::Vector2dF source_offset;
+  gfx::Vector2dF source_to_parent;
+
+  bool operator==(const TransformNode& other) const;
+
+  void set_to_parent(const gfx::Transform& transform) {
+    to_parent = transform;
+    is_invertible = to_parent.IsInvertible();
+  }
+
+  void update_pre_local_transform(const gfx::Point3F& transform_origin);
+
+  void update_post_local_transform(const gfx::PointF& position,
+                                   const gfx::Point3F& transform_origin);
+
+  void ToProtobuf(proto::TreeNode* proto) const;
+  void FromProtobuf(const proto::TreeNode& proto);
+
+  void AsValueInto(base::trace_event::TracedValue* value) const;
+};
+
+// TODO(sunxd): move this into PropertyTrees::cached_data_.
+struct CC_EXPORT TransformCachedNodeData {
+  TransformCachedNodeData();
+  TransformCachedNodeData(const TransformCachedNodeData& other);
+  ~TransformCachedNodeData();
+
+  gfx::Transform from_target;
+  gfx::Transform to_target;
+  gfx::Transform from_screen;
+  gfx::Transform to_screen;
+  int target_id;
+  // This id is used for all content that draws into a render surface associated
+  // with this transform node.
+  int content_target_id;
+
+  bool operator==(const TransformCachedNodeData& other) const;
+
+  void ToProtobuf(proto::TransformCachedNodeData* proto) const;
+  void FromProtobuf(const proto::TransformCachedNodeData& proto);
+};
+
+}  // namespace cc
+
+#endif  // CC_TREES_TRANSFORM_NODE_H_
diff --git a/cc/trees/tree_synchronizer_unittest.cc b/cc/trees/tree_synchronizer_unittest.cc
index 5ac778c..c50ff3ef 100644
--- a/cc/trees/tree_synchronizer_unittest.cc
+++ b/cc/trees/tree_synchronizer_unittest.cc
@@ -21,6 +21,7 @@
 #include "cc/test/fake_rendering_stats_instrumentation.h"
 #include "cc/test/test_shared_bitmap_manager.h"
 #include "cc/test/test_task_graph_runner.h"
+#include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_host_common.h"
 #include "cc/trees/single_thread_proxy.h"
 #include "cc/trees/task_runner_provider.h"
@@ -60,7 +61,7 @@
 
   std::unique_ptr<LayerImpl> CreateLayerImpl(
       LayerTreeImpl* tree_impl) override {
-    return MockLayerImpl::Create(tree_impl, layer_id_);
+    return MockLayerImpl::Create(tree_impl, id());
   }
 
   void PushPropertiesTo(LayerImpl* layer_impl) override {
@@ -101,25 +102,25 @@
       SCOPED_TRACE("mask_layer");
       int mask_layer_id = layer->mask_layer()->id();
       EXPECT_TRUE(tree_impl->LayerById(mask_layer_id));
-      EXPECT_EQ(mask_layer_id,
-                effect_tree.Node(layer_impl->effect_tree_index())
-                    ->data.mask_layer_id);
+      EXPECT_EQ(
+          mask_layer_id,
+          effect_tree.Node(layer_impl->effect_tree_index())->mask_layer_id);
     }
 
     if (layer->replica_layer()) {
       SCOPED_TRACE("replica_layer");
       int replica_layer_id = layer->replica_layer()->id();
       EXPECT_TRUE(tree_impl->LayerById(layer->replica_layer()->id()));
-      EXPECT_EQ(replica_layer_id,
-                effect_tree.Node(layer_impl->effect_tree_index())
-                    ->data.replica_layer_id);
+      EXPECT_EQ(
+          replica_layer_id,
+          effect_tree.Node(layer_impl->effect_tree_index())->replica_layer_id);
       if (layer->replica_layer()->mask_layer()) {
         SCOPED_TRACE("replica_mask_layer");
         int replica_mask_layer_id = layer->replica_layer()->mask_layer()->id();
         EXPECT_TRUE(tree_impl->LayerById(replica_mask_layer_id));
         EXPECT_EQ(replica_mask_layer_id,
                   effect_tree.Node(layer_impl->effect_tree_index())
-                      ->data.replica_mask_layer_id);
+                      ->replica_mask_layer_id);
       }
     }
 
diff --git a/chrome/VERSION b/chrome/VERSION
index 0c92b88..8456c5b 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=54
 MINOR=0
-BUILD=2790
+BUILD=2792
 PATCH=0
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 7483a0c..fa082e9 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -650,7 +650,7 @@
             android:exported="false"/>
         <receiver android:name="com.google.ipc.invalidation.ticl.android2.AndroidInternalScheduler$AlarmReceiver"
             android:exported="false"/>
-        <receiver android:name="com.google.ipc.invalidation.external.client2.contrib.AndroidListener$AlarmReceiver"
+        <receiver android:name="com.google.ipc.invalidation.external.client.contrib.AndroidListener$AlarmReceiver"
             android:exported="false"/>
 
         <!-- Android Notification service listener -->
diff --git a/chrome/android/java/res/color/dark_mode_tint.xml b/chrome/android/java/res/color/dark_mode_tint.xml
index 9026e931..0d032dd 100644
--- a/chrome/android/java/res/color/dark_mode_tint.xml
+++ b/chrome/android/java/res/color/dark_mode_tint.xml
@@ -4,10 +4,10 @@
      found in the LICENSE file.
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_selected="true" android:color="@color/light_active_color" />
-    <item android:state_focused="true" android:color="@color/light_active_color" />
-    <item android:state_pressed="true" android:color="@color/light_active_color" />
-    <item android:state_activated="true" android:color="@color/light_active_color" />
-    <item android:state_enabled="false" android:color="#335a5a5a" />
-    <item android:color="@color/light_normal_color"/>
+    <item android:state_selected="true" android:color="@color/toolbar_light_tint" />
+    <item android:state_focused="true" android:color="@color/toolbar_light_tint" />
+    <item android:state_pressed="true" android:color="@color/toolbar_light_tint" />
+    <item android:state_activated="true" android:color="@color/toolbar_light_tint" />
+    <item android:state_enabled="false" android:color="#3D000000" />
+    <item android:color="@color/toolbar_light_tint"/>
 </selector>
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index 2c00620..decd525 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -23,6 +23,7 @@
     <color name="google_grey_300">#e0e0e0</color>
     <color name="google_grey_600">#757575</color>
     <color name="toolbar_shadow_color">#1d000000</color>
+    <color name="toolbar_light_tint">#A3000000</color>
 
     <!-- Infobar colors -->
     <color name="infobar_accent_blue">#4285f4</color>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java
index 83fa3b7..7992cf9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java
@@ -66,6 +66,9 @@
     // A pointer back to the native part of the implementation for this dialog.
     long mNativeBluetoothChooserDialogPtr;
 
+    // Used to keep track of when the Mode Changed Receiver is registered.
+    boolean mIsLocationModeChangedReceiverRegistered = false;
+
     @VisibleForTesting
     final BroadcastReceiver mLocationModeBroadcastReceiver = new BroadcastReceiver() {
         @Override
@@ -152,11 +155,16 @@
 
         mActivity.registerReceiver(mLocationModeBroadcastReceiver,
                 new IntentFilter(LocationManager.MODE_CHANGED_ACTION));
+        mIsLocationModeChangedReceiverRegistered = true;
     }
 
     // Called to report the dialog's results back to native code.
     private void finishDialog(int resultCode, String id) {
-        mActivity.unregisterReceiver(mLocationModeBroadcastReceiver);
+        if (mIsLocationModeChangedReceiverRegistered) {
+            mActivity.unregisterReceiver(mLocationModeBroadcastReceiver);
+            mIsLocationModeChangedReceiverRegistered = false;
+        }
+
         if (mNativeBluetoothChooserDialogPtr != 0) {
             nativeOnDialogFinished(mNativeBluetoothChooserDialogPtr, resultCode, id);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java
index 1e73dc2e..50d60c9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java
@@ -178,7 +178,7 @@
         application.initializeSharedClasses();
 
         // Start or stop Physical Web
-        PhysicalWeb.onChromeStart(application);
+        PhysicalWeb.onChromeStart();
 
         mDeferredStartupComplete = true;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
index eccfd16e..4d5ea8f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
@@ -140,10 +140,10 @@
      */
     @SuppressWarnings("unused")
     @CalledByNative
-    private static void addShortcut(String id, String url, final String userTitle, String name,
-            String shortName, String iconUrl, Bitmap icon, int displayMode, int orientation,
-            int source, long themeColor, long backgroundColor, String manifestUrl,
-            final long callbackPointer) {
+    private static void addShortcut(String id, String url, String scopeUrl,
+            final String userTitle, String name, String shortName, String iconUrl, Bitmap icon,
+            int displayMode, int orientation, int source, long themeColor, long backgroundColor,
+            String manifestUrl, final long callbackPointer) {
         assert !ThreadUtils.runningOnUiThread();
 
         Context context = ContextUtils.getApplicationContext();
@@ -154,15 +154,20 @@
             if (CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_WEBAPK)) {
                 WebApkBuilder apkBuilder = ((ChromeApplication) context).createWebApkBuilder();
                 if (apkBuilder != null) {
-                    apkBuilder.buildWebApkAsync(url, GURLUtils.getOrigin(url), name, shortName,
-                            iconUrl, icon, displayMode, orientation, themeColor, backgroundColor,
-                            manifestUrl);
+                    if (TextUtils.isEmpty(scopeUrl)) {
+                        scopeUrl = GURLUtils.getOrigin(url);
+                    }
+                    apkBuilder.buildWebApkAsync(url, scopeUrl, name, shortName, iconUrl, icon,
+                            displayMode, orientation, themeColor, backgroundColor, manifestUrl);
                     return;
                 }
             }
+            if (TextUtils.isEmpty(scopeUrl)) {
+                scopeUrl = getScopeFromUrl(url);
+            }
             shortcutIntent = createWebappShortcutIntent(id, sDelegate.getFullscreenAction(), url,
-                    getScopeFromUrl(url), name, shortName, icon, WEBAPP_SHORTCUT_VERSION,
-                    displayMode, orientation, themeColor, backgroundColor, iconUrl.isEmpty());
+                    scopeUrl, name, shortName, icon, WEBAPP_SHORTCUT_VERSION, displayMode,
+                    orientation, themeColor, backgroundColor, iconUrl.isEmpty());
             shortcutIntent.putExtra(EXTRA_MAC, getEncodedMac(context, url));
         } else {
             // Add the shortcut as a launcher icon to open in the browser Activity.
@@ -511,9 +516,9 @@
     }
 
     /**
-     * Returns the URL with all but the last component of its path removed. This serves as a proxy
-     * for scope until the scope manifest member is available. This method assumes that the URL
-     * passed in is a valid URL with a path that contains at least one "/".
+     * Returns the URL with all but the last component of its path removed. This is used if the
+     * Web Manifest does not specify a scope. This method assumes that the URL passed in is a
+     * valid URL with a path that contains at least one "/".
      * @param url The url to convert to a scope.
      * @return The scope.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
index 93419efc..49d94a65 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -19,6 +19,7 @@
 import android.support.v4.widget.ExploreByTouchHelper;
 import android.util.AttributeSet;
 import android.util.Pair;
+import android.view.DragEvent;
 import android.view.MotionEvent;
 import android.view.SurfaceView;
 import android.view.View;
@@ -384,6 +385,23 @@
         return super.dispatchHoverEvent(e);
     }
 
+    @Override
+    public boolean dispatchDragEvent(DragEvent e) {
+        ContentViewCore contentViewCore = mTabVisible.getContentViewCore();
+        if (contentViewCore == null) return false;
+
+        if (mLayoutManager != null) mLayoutManager.getViewportPixel(mCacheViewport);
+        contentViewCore.setCurrentTouchEventOffsets(-mCacheViewport.left, -mCacheViewport.top);
+        boolean ret = super.dispatchDragEvent(e);
+
+        int action = e.getAction();
+        if (action == DragEvent.ACTION_DRAG_EXITED || action == DragEvent.ACTION_DRAG_ENDED
+                || action == DragEvent.ACTION_DROP) {
+            contentViewCore.setCurrentTouchEventOffsets(0.f, 0.f);
+        }
+        return ret;
+    }
+
     /**
      * @return The {@link LayoutManager} associated with this view.
      */
@@ -483,11 +501,11 @@
         if (actionMasked == MotionEvent.ACTION_DOWN
                 || actionMasked == MotionEvent.ACTION_HOVER_ENTER) {
             if (mLayoutManager != null) mLayoutManager.getViewportPixel(mCacheViewport);
-            contentViewCore.setCurrentMotionEventOffsets(-mCacheViewport.left, -mCacheViewport.top);
+            contentViewCore.setCurrentTouchEventOffsets(-mCacheViewport.left, -mCacheViewport.top);
         } else if (canClear && (actionMasked == MotionEvent.ACTION_UP
                                        || actionMasked == MotionEvent.ACTION_CANCEL
                                        || actionMasked == MotionEvent.ACTION_HOVER_EXIT)) {
-            contentViewCore.setCurrentMotionEventOffsets(0.f, 0.f);
+            contentViewCore.setCurrentTouchEventOffsets(0.f, 0.f);
         }
     }
 
@@ -902,7 +920,7 @@
      * @param contentViewCore The {@link ContentViewCore} to initialize.
      */
     private void initializeContentViewCore(ContentViewCore contentViewCore) {
-        contentViewCore.setCurrentMotionEventOffsets(0.f, 0.f);
+        contentViewCore.setCurrentTouchEventOffsets(0.f, 0.f);
         contentViewCore.setTopControlsHeight(
                 getTopControlsHeightPixels(), contentViewCore.doTopControlsShrinkBlinkSize());
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ClearNotificationAlarmReceiver.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ClearNotificationAlarmReceiver.java
index 3264166..52a7637 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ClearNotificationAlarmReceiver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ClearNotificationAlarmReceiver.java
@@ -21,6 +21,6 @@
     @Override
     public void onReceive(Context context, Intent intent) {
         Log.d(TAG, "Running NotificationCleanupAlarmReceiver");
-        UrlManager.getInstance(context).clearNotification();
+        UrlManager.getInstance().clearNotification();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java
index 9900cd90..22f951a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java
@@ -32,7 +32,6 @@
 import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeApplication;
 import org.chromium.chrome.browser.widget.FadingShadow;
 import org.chromium.chrome.browser.widget.FadingShadowView;
 
@@ -122,8 +121,7 @@
         mIsInitialDisplayRecorded = false;
         mIsRefreshing = false;
         mIsRefreshUserInitiated = false;
-        mPhysicalWebBleClient =
-            PhysicalWebBleClient.getInstance((ChromeApplication) getApplicationContext());
+        mPhysicalWebBleClient = PhysicalWebBleClient.getInstance();
     }
 
     @Override
@@ -169,7 +167,7 @@
     @Override
     protected void onStart() {
         super.onStart();
-        UrlManager.getInstance(this).addObserver(this);
+        UrlManager.getInstance().addObserver(this);
     }
 
     @Override
@@ -198,7 +196,7 @@
 
     @Override
     protected void onStop() {
-        UrlManager.getInstance(this).removeObserver(this);
+        UrlManager.getInstance().removeObserver(this);
         super.onStop();
     }
 
@@ -267,13 +265,13 @@
         // Clear the list adapter to trigger the empty list display.
         mAdapter.clear();
 
-        Collection<UrlInfo> urls = UrlManager.getInstance(this).getUrls(true);
+        Collection<UrlInfo> urls = UrlManager.getInstance().getUrls(true);
 
         // Check the Physical Web preference to ensure we do not resolve URLs when Physical Web is
         // off or onboarding. Normally the user will not reach this activity unless the preference
         // is explicitly enabled, but there is a button on the diagnostics page that launches into
         // the activity without checking the preference state.
-        if (urls.isEmpty() || !PhysicalWeb.isPhysicalWebPreferenceEnabled(this)) {
+        if (urls.isEmpty() || !PhysicalWeb.isPhysicalWebPreferenceEnabled()) {
             finishRefresh();
         } else {
             // Show the swipe-to-refresh busy indicator for refreshes initiated by a swipe.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java
index 8f806bab..ed8716c8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java
@@ -4,12 +4,10 @@
 
 package org.chromium.chrome.browser.physicalweb;
 
-import android.content.Context;
 import android.content.SharedPreferences;
 import android.os.Build;
 
 import org.chromium.base.ContextUtils;
-import org.chromium.chrome.browser.ChromeApplication;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager;
 
@@ -37,10 +35,9 @@
     /**
      * Checks whether the Physical Web preference is switched to On.
      *
-     * @param context An instance of android.content.Context
      * @return boolean {@code true} if the preference is On.
      */
-    public static boolean isPhysicalWebPreferenceEnabled(Context context) {
+    public static boolean isPhysicalWebPreferenceEnabled() {
         return PrivacyPreferencesManager.getInstance().isPhysicalWebEnabled();
     }
 
@@ -48,42 +45,37 @@
      * Checks whether the Physical Web onboard flow is active and the user has
      * not yet elected to either enable or decline the feature.
      *
-     * @param context An instance of android.content.Context
      * @return boolean {@code true} if onboarding is complete.
      */
-    public static boolean isOnboarding(Context context) {
+    public static boolean isOnboarding() {
         return PrivacyPreferencesManager.getInstance().isPhysicalWebOnboarding();
     }
 
     /**
      * Start the Physical Web feature.
      * At the moment, this only enables URL discovery over BLE.
-     * @param application An instance of {@link ChromeApplication}, used to get the
-     * appropriate PhysicalWebBleClient implementation.
      */
-    public static void startPhysicalWeb(final ChromeApplication application) {
-        PhysicalWebBleClient.getInstance(application).backgroundSubscribe(new Runnable() {
+    public static void startPhysicalWeb() {
+        PhysicalWebBleClient.getInstance().backgroundSubscribe(new Runnable() {
             @Override
             public void run() {
                 // We need to clear the list of nearby URLs so that they can be repopulated by the
                 // new subscription, but we don't know whether we are already subscribed, so we need
                 // to pass a callback so that we can clear as soon as we are resubscribed.
-                UrlManager.getInstance(application).clearNearbyUrls();
+                UrlManager.getInstance().clearNearbyUrls();
             }
         });
     }
 
     /**
      * Stop the Physical Web feature.
-     * @param application An instance of {@link ChromeApplication}, used to get the
-     * appropriate PhysicalWebBleClient implementation.
      */
-    public static void stopPhysicalWeb(final ChromeApplication application) {
-        PhysicalWebBleClient.getInstance(application).backgroundUnsubscribe(new Runnable() {
+    public static void stopPhysicalWeb() {
+        PhysicalWebBleClient.getInstance().backgroundUnsubscribe(new Runnable() {
             @Override
             public void run() {
                 // This isn't absolutely necessary, but it's nice to clean up all our shared prefs.
-                UrlManager.getInstance(application).clearAllUrls();
+                UrlManager.getInstance().clearAllUrls();
             }
         });
     }
@@ -100,12 +92,9 @@
     /**
      * Increments a value tracking how many times we've shown the Physical Web
      * opt-in notification.
-     *
-     * @param context An instance of android.content.Context
      */
-    public static void recordOptInNotification(Context context) {
-        SharedPreferences sharedPreferences =
-                ContextUtils.getAppSharedPreferences();
+    public static void recordOptInNotification() {
+        SharedPreferences sharedPreferences = ContextUtils.getAppSharedPreferences();
         int value = sharedPreferences.getInt(PREF_PHYSICAL_WEB_NOTIFY_COUNT, 0);
         sharedPreferences.edit().putInt(PREF_PHYSICAL_WEB_NOTIFY_COUNT, value + 1).apply();
     }
@@ -113,34 +102,29 @@
     /**
      * Gets the current count of how many times a high-priority opt-in notification
      * has been shown.
-     *
-     * @param context An instance of android.content.Context
      * @return an integer representing the high-priority notifification display count.
      */
-    public static int getOptInNotifyCount(Context context) {
-        SharedPreferences sharedPreferences =
-                ContextUtils.getAppSharedPreferences();
+    public static int getOptInNotifyCount() {
+        SharedPreferences sharedPreferences = ContextUtils.getAppSharedPreferences();
         return sharedPreferences.getInt(PREF_PHYSICAL_WEB_NOTIFY_COUNT, 0);
     }
 
     /**
      * Perform various Physical Web operations that should happen on startup.
-     * @param application An instance of {@link ChromeApplication}.
      */
-    public static void onChromeStart(ChromeApplication application) {
+    public static void onChromeStart() {
         // The PhysicalWebUma calls in this method should be called only when the native library is
         // loaded.  This is always the case on chrome startup.
-        if (featureIsEnabled()
-                && (isPhysicalWebPreferenceEnabled(application) || isOnboarding(application))) {
+        if (featureIsEnabled() && (isPhysicalWebPreferenceEnabled() || isOnboarding())) {
             boolean ignoreOtherClients =
                     ChromeFeatureList.isEnabled(IGNORE_OTHER_CLIENTS_FEATURE_NAME);
             ContextUtils.getAppSharedPreferences().edit()
                     .putBoolean(PREF_IGNORE_OTHER_CLIENTS, ignoreOtherClients)
                     .apply();
-            startPhysicalWeb(application);
-            PhysicalWebUma.uploadDeferredMetrics(application);
+            startPhysicalWeb();
+            PhysicalWebUma.uploadDeferredMetrics();
         } else {
-            stopPhysicalWeb(application);
+            stopPhysicalWeb();
         }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebBleClient.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebBleClient.java
index 01918a3..233bbb7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebBleClient.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebBleClient.java
@@ -6,6 +6,7 @@
 
 import android.app.Activity;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.chrome.browser.ChromeApplication;
 
@@ -21,14 +22,13 @@
 
     /**
      * Get a singleton instance of this class.
-     * @param chromeApplication An instance of {@link ChromeApplication}, used to get the
-     * appropriate PhysicalWebBleClient implementation.
      * @return an instance of this class (or subclass) as decided by the
      * application parameter
      */
-    public static PhysicalWebBleClient getInstance(ChromeApplication chromeApplication) {
+    public static PhysicalWebBleClient getInstance() {
         if (sInstance == null) {
-            sInstance = chromeApplication.createPhysicalWebBleClient();
+            sInstance = ((ChromeApplication) ContextUtils.getApplicationContext())
+                    .createPhysicalWebBleClient();
         }
         return sInstance;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java
index 69eff55..836e46b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java
@@ -104,8 +104,8 @@
         LocationUtils locationUtils = LocationUtils.getInstance();
         boolean isLocationServicesEnabled = locationUtils.isSystemLocationSettingEnabled(mContext);
         boolean isLocationPermissionGranted = locationUtils.hasAndroidLocationPermission(mContext);
-        boolean isPreferenceEnabled = PhysicalWeb.isPhysicalWebPreferenceEnabled(mContext);
-        boolean isOnboarding = PhysicalWeb.isOnboarding(mContext);
+        boolean isPreferenceEnabled = PhysicalWeb.isPhysicalWebPreferenceEnabled();
+        boolean isOnboarding = PhysicalWeb.isOnboarding();
 
         int prerequisitesResult = Utils.RESULT_SUCCESS;
         if (!isSdkVersionCorrect
@@ -156,7 +156,7 @@
     }
 
     private void appendUrlManagerReport(StringBuilder sb) {
-        UrlManager urlManager = UrlManager.getInstance(mContext);
+        UrlManager urlManager = UrlManager.getInstance();
 
         Set<String> nearbyUrls = new HashSet<>(urlManager.getNearbyUrls());
         Set<String> resolvedUrls = new HashSet<>(urlManager.getResolvedUrls());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebUma.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebUma.java
index eb672dd..1267b7a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebUma.java
@@ -198,12 +198,12 @@
         switch (referer) {
             case ListUrlsActivity.NOTIFICATION_REFERER:
                 handleTime(context, STANDARD_NOTIFICATION_PRESS_DELAYS,
-                        UrlManager.getInstance(context).getTimeSinceNotificationUpdate(),
+                        UrlManager.getInstance().getTimeSinceNotificationUpdate(),
                         TimeUnit.MILLISECONDS);
                 break;
             case ListUrlsActivity.OPTIN_REFERER:
                 handleTime(context, OPT_IN_NOTIFICATION_PRESS_DELAYS,
-                        UrlManager.getInstance(context).getTimeSinceNotificationUpdate(),
+                        UrlManager.getInstance().getTimeSinceNotificationUpdate(),
                         TimeUnit.MILLISECONDS);
                 break;
             case ListUrlsActivity.PREFERENCE_REFERER:
@@ -237,8 +237,8 @@
         handleEnum(context, createStateString(DATA_CONNECTION, actionName),
                 Utils.isDataConnectionActive(context) ? 1 : 0, BOOLEAN_BOUNDARY);
         int preferenceState = 2;
-        if (!PhysicalWeb.isOnboarding(context)) {
-            preferenceState = PhysicalWeb.isPhysicalWebPreferenceEnabled(context) ? 1 : 0;
+        if (!PhysicalWeb.isOnboarding()) {
+            preferenceState = PhysicalWeb.isPhysicalWebPreferenceEnabled() ? 1 : 0;
         }
         handleEnum(context, createStateString(PREFERENCE, actionName),
                 preferenceState, TRISTATE_BOUNDARY);
@@ -249,7 +249,7 @@
      * Additionally, this method will cause future stat records not to be deferred and instead
      * uploaded immediately.
      */
-    public static void uploadDeferredMetrics(Context context) {
+    public static void uploadDeferredMetrics() {
         // If uploads have been explicitely requested, they are now allowed.
         sUploadAllowed = true;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java
index 71f7e0e..e47895e1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java
@@ -103,6 +103,7 @@
      * Construct the UrlManager.
      * @param context An instance of android.content.Context
      */
+    @VisibleForTesting
     public UrlManager(Context context) {
         mContext = context;
         mNotificationManager = new NotificationManagerProxyImpl(
@@ -118,14 +119,22 @@
 
     /**
      * Get a singleton instance of this class.
-     * @param context An instance of android.content.Context.
+     * @return A singleton instance of this class.
+     */
+    public static UrlManager getInstance() {
+        if (sInstance == null) {
+            sInstance = new UrlManager(ContextUtils.getApplicationContext());
+        }
+        return sInstance;
+    }
+
+    /**
+     * Get a singleton instance of this class.
+     * @param context unused
      * @return A singleton instance of this class.
      */
     public static UrlManager getInstance(Context context) {
-        if (sInstance == null) {
-            sInstance = new UrlManager(context);
-        }
-        return sInstance;
+        return getInstance();
     }
 
     /**
@@ -166,7 +175,7 @@
         mNearbyUrls.add(urlInfo.getUrl());
         putCachedNearbyUrls();
 
-        if (!PhysicalWeb.isOnboarding(mContext) && !mResolvedUrls.contains(urlInfo.getUrl())) {
+        if (!PhysicalWeb.isOnboarding() && !mResolvedUrls.contains(urlInfo.getUrl())) {
             // We need to resolve the URL.
             resolveUrl(urlInfo);
             return;
@@ -196,7 +205,7 @@
         putCachedNearbyUrls();
 
         // If there are no URLs nearby to display, clear the notification.
-        if (getUrls(PhysicalWeb.isOnboarding(mContext)).isEmpty()) {
+        if (getUrls(PhysicalWeb.isOnboarding()).isEmpty()) {
             clearNotification();
         }
     }
@@ -320,7 +329,7 @@
         putCachedResolvedUrls();
 
         // If there are no URLs nearby to display, clear the notification.
-        if (getUrls(PhysicalWeb.isOnboarding(mContext)).isEmpty()) {
+        if (getUrls(PhysicalWeb.isOnboarding()).isEmpty()) {
             clearNotification();
         }
     }
@@ -481,18 +490,18 @@
             return;
         }
 
-        if (PhysicalWeb.isOnboarding(mContext)) {
-            if (PhysicalWeb.getOptInNotifyCount(mContext) < PhysicalWeb.OPTIN_NOTIFY_MAX_TRIES) {
+        if (PhysicalWeb.isOnboarding()) {
+            if (PhysicalWeb.getOptInNotifyCount() < PhysicalWeb.OPTIN_NOTIFY_MAX_TRIES) {
                 // high priority notification
                 createOptInNotification(true);
-                PhysicalWeb.recordOptInNotification(mContext);
+                PhysicalWeb.recordOptInNotification();
                 PhysicalWebUma.onOptInHighPriorityNotificationShown(mContext);
             } else {
                 // min priority notification
                 createOptInNotification(false);
                 PhysicalWebUma.onOptInMinPriorityNotificationShown(mContext);
             }
-        } else if (PhysicalWeb.isPhysicalWebPreferenceEnabled(mContext)) {
+        } else if (PhysicalWeb.isPhysicalWebPreferenceEnabled()) {
             createNotification();
         }
     }
@@ -578,7 +587,7 @@
         // Only trigger the notification if we know we didn't have a notification up already
         // (i.e., we have exactly 1 displayble URL) or this URL doesn't exist in the cache
         // (and hence the user hasn't swiped away a notification for this URL recently).
-        if (getUrls(PhysicalWeb.isOnboarding(mContext)).size() != 1
+        if (getUrls(PhysicalWeb.isOnboarding()).size() != 1
                 && urlInfo.hasBeenDisplayed()) {
             return;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PhysicalWebPreferenceFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PhysicalWebPreferenceFragment.java
index 689524c..083aab5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PhysicalWebPreferenceFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PhysicalWebPreferenceFragment.java
@@ -17,7 +17,6 @@
 
 import org.chromium.base.Log;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeApplication;
 import org.chromium.chrome.browser.physicalweb.ListUrlsActivity;
 import org.chromium.chrome.browser.physicalweb.PhysicalWeb;
 import org.chromium.chrome.browser.physicalweb.PhysicalWebUma;
@@ -65,8 +64,7 @@
                         && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                     PhysicalWebUma.onPrefsLocationGranted(getActivity());
                     Log.d(TAG, "Location permission granted");
-                    PhysicalWeb.startPhysicalWeb(
-                            (ChromeApplication) getActivity().getApplicationContext());
+                    PhysicalWeb.startPhysicalWeb();
                 } else {
                     PhysicalWebUma.onPrefsLocationDenied(getActivity());
                     Log.d(TAG, "Location permission denied");
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferencesManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferencesManager.java
index 983dcae..c4c2d433 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferencesManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferencesManager.java
@@ -13,7 +13,6 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeApplication;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.device.DeviceClassManager;
 import org.chromium.chrome.browser.physicalweb.PhysicalWeb;
@@ -441,10 +440,10 @@
         mSharedPreferences.edit().putInt(PREF_PHYSICAL_WEB, state).apply();
         if (enabled) {
             if (!isOnboarding) {
-                PhysicalWeb.startPhysicalWeb((ChromeApplication) mContext);
+                PhysicalWeb.startPhysicalWeb();
             }
         } else {
-            PhysicalWeb.stopPhysicalWeb((ChromeApplication) mContext);
+            PhysicalWeb.stopPhysicalWeb();
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index 003b5cc..6b1cd17d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -1714,6 +1714,16 @@
     public void onUrlFocusChange(final boolean hasFocus) {
         super.onUrlFocusChange(hasFocus);
 
+        // https://crbug.com/623885: The mToolbarButtonsContainer has its translationY modified
+        // during scroll so when the user scrolls on the NTP, it appears to scroll too. However
+        // during the URL focus and defocus animations it should not be touched. Unfortunately
+        // updateNtpTransitionAnimation() is called a few times after the URL focus animation has
+        // been completed while mUrlFocusChangeInProgress is set to false, causing translationY to
+        // non-zero at the end.
+        // We reset the translationY here so the mToolbarButtonsContainer is on screen for the
+        // defocusing animation.
+        mToolbarButtonsContainer.setTranslationY(0f);
+
         triggerUrlFocusAnimation(hasFocus);
 
         TransitionDrawable shadowDrawable = (TransitionDrawable) mToolbarShadow.getDrawable();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ProgressAnimationSmooth.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ProgressAnimationSmooth.java
index 3cae062b..5752248 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ProgressAnimationSmooth.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ProgressAnimationSmooth.java
@@ -33,8 +33,6 @@
 
     @Override
     public float updateProgress(float targetProgress, float frameTimeSec, int resolution) {
-        assert mProgress <= targetProgress;
-
         final float acceleratingDuration = computeAcceleratingDuration(
                 targetProgress, frameTimeSec);
         final float deceleratingDuration = frameTimeSec - acceleratingDuration;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java
index 0290f13..026484d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java
@@ -95,6 +95,7 @@
         public void run() {
             animateAlphaTo(0.0f);
             mIsRunningSmoothIndeterminate = false;
+            if (mAnimatingView != null) mAnimatingView.cancelAnimation();
         }
     };
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBarAnimatingView.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBarAnimatingView.java
index 8f1d9a3..a6e27c3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBarAnimatingView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBarAnimatingView.java
@@ -249,6 +249,7 @@
      */
     public void cancelAnimation() {
         mIsCanceled = true;
+        mAnimatorSet.cancel();
         // Reset position and alpha.
         setScaleX(0.0f);
         setTranslationX(0.0f);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothChooserDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothChooserDialogTest.java
index 45d5e499..67b8d8a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothChooserDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/BluetoothChooserDialogTest.java
@@ -57,6 +57,8 @@
             assertEquals(mFinishedEventType, -1);
             mFinishedEventType = eventType;
             mFinishedDeviceId = deviceId;
+            // The native code calls closeDialog() when OnDialogFinished is called.
+            closeDialog();
         }
 
         @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivityTest.java
index c1fdced..b008afc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivityTest.java
@@ -65,7 +65,7 @@
         mContext = getInstrumentation().getTargetContext();
         // Restore the onboarding state
         ContextUtils.getAppSharedPreferences().edit().putInt("physical_web", 2).apply();
-        UrlManager urlManager = UrlManager.getInstance(mContext);
+        UrlManager urlManager = UrlManager.getInstance();
         mMockPwsClient = new MockPwsClient();
         urlManager.overridePwsClientForTesting(mMockPwsClient);
         urlManager.overrideNotificationManagerForTesting(new MockNotificationManagerProxy());
@@ -156,7 +156,7 @@
         results.add(new PwsResult(url, url, null, title, desc));
         mMockPwsClient.addPwsResults(results);
         mMockPwsClient.addPwsResults(results);
-        UrlManager.getInstance(mContext).addUrl(url);
+        UrlManager.getInstance().addUrl(url);
         getInstrumentation().waitForIdleSync();
     }
 
diff --git a/chrome/android/webapk/shell_apk/javatests/src/org/chromium/webapk/shell_apk/DexLoaderTest.java b/chrome/android/webapk/shell_apk/javatests/src/org/chromium/webapk/shell_apk/DexLoaderTest.java
index 1e77656b..a002a79 100644
--- a/chrome/android/webapk/shell_apk/javatests/src/org/chromium/webapk/shell_apk/DexLoaderTest.java
+++ b/chrome/android/webapk/shell_apk/javatests/src/org/chromium/webapk/shell_apk/DexLoaderTest.java
@@ -42,15 +42,18 @@
             "org.chromium.webapk.shell_apk.test.dex_optimizer.DexOptimizerServiceImpl";
 
     /**
-     * Name of the dex file in DexOptimizer.apk.
+     * Name of dex files in DexOptimizer.apk.
      */
     private static final String DEX_ASSET_NAME = "canary.dex";
+    private static final String DEX_ASSET_NAME2 = "canary2.dex";
 
     /**
-     * Class to load to check whether dex is valid.
+     * Classes to load to check whether dex is valid.
      */
     private static final String CANARY_CLASS_NAME =
             "org.chromium.webapk.shell_apk.test.canary.Canary";
+    private static final String CANARY_CLASS_NAME2 =
+            "org.chromium.webapk.shell_apk.test.canary.Canary2";
 
     private Context mContext;
     private Context mRemoteContext;
@@ -217,47 +220,33 @@
     }
 
     /**
-     * Test that {@link DexLoader#load()} re-extracts the dex file from the APK after a call to
-     * {@link DexLoader#deleteCachedDexes()}.
+     * Test loading a dex file from a directory which was previously used for loading a different
+     * dex file.
      */
     @MediumTest
-    public void testLoadAfterDeleteCachedDexes() {
+    public void testLoadDifferentDexInLocalDataDir() {
         assertTrue(mLocalDexDir.mkdir());
 
-        {
-            // Load dex the first time. This should extract the dex file from the APK's assets and
-            // generate the optimized dex file.
-            FileMonitor localDexDirMonitor = new FileMonitor(mLocalDexDir);
-            localDexDirMonitor.startWatching();
-            ClassLoader loader = DexLoader.load(
-                    mRemoteContext, DEX_ASSET_NAME, CANARY_CLASS_NAME, null, mLocalDexDir);
-            localDexDirMonitor.stopWatching();
+        // Load canary.dex
+        ClassLoader loader1 = DexLoader.load(
+                mRemoteContext, DEX_ASSET_NAME, CANARY_CLASS_NAME, null, mLocalDexDir);
+        assertNotNull(loader1);
+        assertTrue(canLoadCanaryClass(loader1));
 
-            assertNotNull(loader);
-            assertTrue(canLoadCanaryClass(loader));
-
-            assertTrue(localDexDirMonitor.mReadPaths.contains(DEX_ASSET_NAME));
-            assertTrue(localDexDirMonitor.mModifiedPaths.contains(DEX_ASSET_NAME));
-        }
+        File canaryDexFile1 = new File(mLocalDexDir, DEX_ASSET_NAME);
+        assertTrue(canaryDexFile1.exists());
 
         DexLoader.deleteCachedDexes(mLocalDexDir);
 
-        {
-            // Load dex a second time.
-            FileMonitor localDexDirMonitor = new FileMonitor(mLocalDexDir);
-            localDexDirMonitor.startWatching();
-            ClassLoader loader = DexLoader.load(
-                    mRemoteContext, DEX_ASSET_NAME, CANARY_CLASS_NAME, null, mLocalDexDir);
-            localDexDirMonitor.stopWatching();
+        ClassLoader loader2 = DexLoader.load(
+                mRemoteContext, DEX_ASSET_NAME2, CANARY_CLASS_NAME2, null, mLocalDexDir);
+        assertNotNull(loader2);
+        assertTrue(canLoadClass(loader2, CANARY_CLASS_NAME2));
 
-            // The returned ClassLoader should be valid.
-            assertNotNull(loader);
-            assertTrue(canLoadCanaryClass(loader));
-
-            // We should have re-extracted the dex from the APK's assets.
-            assertTrue(localDexDirMonitor.mReadPaths.contains(DEX_ASSET_NAME));
-            assertTrue(localDexDirMonitor.mModifiedPaths.contains(DEX_ASSET_NAME));
-        }
+        // canary2.dex should have been extracted and the previously extracted canary.dex file
+        // should have been deleted.
+        assertTrue(new File(mLocalDexDir, DEX_ASSET_NAME2).exists());
+        assertFalse(canaryDexFile1.exists());
     }
 
     /**
@@ -325,8 +314,13 @@
 
     /** Returns whether the ClassLoader can load {@link CANARY_CLASS_NAME} */
     private boolean canLoadCanaryClass(ClassLoader loader) {
+        return canLoadClass(loader, CANARY_CLASS_NAME);
+    }
+
+    /** Returns whether the ClassLoader can load a class */
+    private boolean canLoadClass(ClassLoader loader, String className) {
         try {
-            loader.loadClass(CANARY_CLASS_NAME);
+            loader.loadClass(className);
             return true;
         } catch (Exception e) {
             return false;
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 6d229ff0..33a2bf0 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5659,8 +5659,8 @@
       <message name="IDS_FLAGS_GESTURE_REQUIREMENT_FOR_MEDIA_PLAYBACK_DESCRIPTION" desc="Description for the flag for gesture requiment for media playback">
         User gesture requirement for playing media elements. Disabling this will allow autoplay to work.
       </message>
-      <message name="IDS_FLAGS_PASSIVE_DOCUMENT_EVENT_LISTENERS_DESCRIPTION" desc="Description for the flag to adjust the default behaviour for document level passive listeners.">
-        Forces touchstart, touchmove, mousewheel and wheel event listeners on document level targets (which haven't requested otherwise) to be treated as passive.
+      <message name="IDS_FLAGS_PASSIVE_DOCUMENT_EVENT_LISTENERS_DESCRIPTION" desc="Description for the flag to adjust the default behaviour for document level passive touch listeners.">
+        Forces touchstart, and touchmove event listeners on document level targets (which haven't requested otherwise) to be treated as passive.
       </message>
       <message name="IDS_FLAGS_PASSIVE_DOCUMENT_EVENT_LISTENERS_NAME" desc="Name for the flag to adjust the default behaviour for document level passive listeners.">
         Document Level Event Listeners Passive Default
diff --git a/chrome/app/mash/mash_runner.cc b/chrome/app/mash/mash_runner.cc
index 927d57e..bd0e252f 100644
--- a/chrome/app/mash/mash_runner.cc
+++ b/chrome/app/mash/mash_runner.cc
@@ -26,7 +26,7 @@
 #include "services/shell/public/cpp/connector.h"
 #include "services/shell/public/cpp/identity.h"
 #include "services/shell/public/cpp/service.h"
-#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service_context.h"
 #include "services/shell/public/interfaces/service_factory.mojom.h"
 #include "services/shell/runner/common/switches.h"
 #include "services/shell/runner/host/child_process_base.h"
@@ -73,7 +73,7 @@
     service_ = CreateService(mojo_name);
     if (service_) {
       shell_connection_.reset(
-          new shell::ShellConnection(service_.get(), std::move(request)));
+          new shell::ServiceContext(service_.get(), std::move(request)));
       return;
     }
     LOG(ERROR) << "unknown name " << mojo_name;
@@ -108,7 +108,7 @@
 
   mojo::BindingSet<ServiceFactory> service_factory_bindings_;
   std::unique_ptr<shell::Service> service_;
-  std::unique_ptr<shell::ShellConnection> shell_connection_;
+  std::unique_ptr<shell::ServiceContext> shell_connection_;
 
   DISALLOW_COPY_AND_ASSIGN(DefaultService);
 };
@@ -187,7 +187,7 @@
   init_params->native_runner_delegate = &native_runner_delegate;
   background_shell.Init(std::move(init_params));
   service_.reset(new DefaultService);
-  shell_connection_.reset(new shell::ShellConnection(
+  shell_connection_.reset(new shell::ServiceContext(
       service_.get(),
       background_shell.CreateServiceRequest("exe:chrome_mash")));
   shell_connection_->connector()->Connect("mojo:mash_session");
@@ -205,7 +205,7 @@
   // TODO(sky): use MessagePumpMojo.
   base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
   service_.reset(new DefaultService);
-  shell_connection_.reset(new shell::ShellConnection(
+  shell_connection_.reset(new shell::ServiceContext(
       service_.get(), std::move(service_request)));
   message_loop.Run();
 }
diff --git a/chrome/app/mash/mash_runner.h b/chrome/app/mash/mash_runner.h
index 2a79f3f..108f9ed 100644
--- a/chrome/app/mash/mash_runner.h
+++ b/chrome/app/mash/mash_runner.h
@@ -12,7 +12,7 @@
 
 namespace shell {
 class Service;
-class ShellConnection;
+class ServiceContext;
 }
 
 // Responsible for running mash, both child and main processes.
@@ -30,7 +30,7 @@
   void StartChildApp(shell::mojom::ServiceRequest service_request);
 
   std::unique_ptr<shell::Service> service_;
-  std::unique_ptr<shell::ShellConnection> shell_connection_;
+  std::unique_ptr<shell::ServiceContext> shell_connection_;
 
   DISALLOW_COPY_AND_ASSIGN(MashRunner);
 };
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 86f4f72e..f45e0b7 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -835,9 +835,16 @@
   <message name="IDS_SETTINGS_LINKDOCTOR_PREF" desc="The documentation string of the 'Use Link Doctor' preference to help with navigation errors.">
     Use a web service to help resolve navigation errors
   </message>
-  <message name="IDS_SETTINGS_SUGGEST_PREF" desc="The documentation string of the 'Use Suggest' preference">
-    Use a prediction service to help complete searches and URLs typed in the address bar or the app launcher search box
-  </message>
+  <if expr="chromeos">
+    <message name="IDS_SETTINGS_SUGGEST_PREF" desc="The documentation string of the 'Use Suggest' preference">
+      Use a prediction service to help complete searches and URLs typed in the address bar or the app launcher search box
+    </message>
+  </if>
+  <if expr="not chromeos">
+    <message name="IDS_SETTINGS_SUGGEST_PREF" desc="The documentation string of the 'Use Suggest' preference">
+      Use a prediction service to help complete searches and URLs typed in the address bar
+    </message>
+  </if>
   <message name="IDS_SETTINGS_NETWORK_PREDICTION_ENABLED_DESCRIPTION" desc="In the advanced options tab, the text next to the checkbox that enables prediction of network actions.  Actions include browser-initiated DNS prefetching, TCP and SSL preconnection, and prerendering of webpages.">
     Use a prediction service to load pages more quickly
   </message>
diff --git a/chrome/app/theme/chrome_unscaled_resources.grd b/chrome/app/theme/chrome_unscaled_resources.grd
index dc26321b5..46433415 100644
--- a/chrome/app/theme/chrome_unscaled_resources.grd
+++ b/chrome/app/theme/chrome_unscaled_resources.grd
@@ -73,26 +73,6 @@
         <include name="IDR_PROFILE_AVATAR_2X_25" file="default_200_percent/common/profile_avatar_sun_cloud.png" type="BINDATA" />
         <include name="IDR_PROFILE_AVATAR_2X_26" file="default_200_percent/common/profile_avatar_placeholder.png" type="BINDATA" />
       </if>
-      <if expr="is_macosx and enable_app_list">
-        <!-- App Launcher icons for .app shim, dock icon. Unscaled, because the
-             icon file built does not depend on UI scale factor. -->
-        <if expr="_google_chrome">
-          <include name="IDR_APP_LIST_16" file="google_chrome/mac/app_list_16.png" type="BINDATA" />
-          <include name="IDR_APP_LIST_32" file="google_chrome/mac/app_list_32.png" type="BINDATA" />
-          <include name="IDR_APP_LIST_128" file="google_chrome/mac/app_list_128.png" type="BINDATA" />
-          <include name="IDR_APP_LIST_256" file="google_chrome/mac/app_list_256.png" type="BINDATA" />
-          <include name="IDR_APP_LIST_CANARY_16" file="google_chrome/mac/app_list_canary_16.png" type="BINDATA" />
-          <include name="IDR_APP_LIST_CANARY_32" file="google_chrome/mac/app_list_canary_32.png" type="BINDATA" />
-          <include name="IDR_APP_LIST_CANARY_128" file="google_chrome/mac/app_list_canary_128.png" type="BINDATA" />
-          <include name="IDR_APP_LIST_CANARY_256" file="google_chrome/mac/app_list_canary_256.png" type="BINDATA" />
-        </if>
-        <if expr="not _google_chrome">
-          <include name="IDR_APP_LIST_16" file="chromium/mac/app_list_16.png" type="BINDATA" />
-          <include name="IDR_APP_LIST_32" file="chromium/mac/app_list_32.png" type="BINDATA" />
-          <include name="IDR_APP_LIST_128" file="chromium/mac/app_list_128.png" type="BINDATA" />
-          <include name="IDR_APP_LIST_256" file="chromium/mac/app_list_256.png" type="BINDATA" />
-        </if>
-      </if>
       <if expr="is_linux and enable_app_list">
         <!-- App Launcher icons for desktop icon. -->
         <if expr="_google_chrome">
diff --git a/chrome/app/theme/chromium/mac/app_list_128.png b/chrome/app/theme/chromium/mac/app_list_128.png
deleted file mode 100644
index e52551432..0000000
--- a/chrome/app/theme/chromium/mac/app_list_128.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/chromium/mac/app_list_16.png b/chrome/app/theme/chromium/mac/app_list_16.png
deleted file mode 100644
index 8e5839e..0000000
--- a/chrome/app/theme/chromium/mac/app_list_16.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/chromium/mac/app_list_256.png b/chrome/app/theme/chromium/mac/app_list_256.png
deleted file mode 100644
index 5acdd92..0000000
--- a/chrome/app/theme/chromium/mac/app_list_256.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/chromium/mac/app_list_32.png b/chrome/app/theme/chromium/mac/app_list_32.png
deleted file mode 100644
index fa8b860b..0000000
--- a/chrome/app/theme/chromium/mac/app_list_32.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/android/preferences/important_sites_util.cc b/chrome/browser/android/preferences/important_sites_util.cc
index 3b0ec0d..6faed99 100644
--- a/chrome/browser/android/preferences/important_sites_util.cc
+++ b/chrome/browser/android/preferences/important_sites_util.cc
@@ -8,6 +8,7 @@
 #include <map>
 #include <set>
 
+#include "base/metrics/histogram_macros.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/engagement/site_engagement_score.h"
 #include "chrome/browser/engagement/site_engagement_service.h"
@@ -18,6 +19,25 @@
 
 namespace {
 
+// Do not change the values here, as they are used for UMA histograms.
+enum ReasonStatTypes {
+  DURABLE = 0,
+  NOTIFICATIONS,
+  ENGAGEMENT,
+  NOTIFICATIONS_AND_ENGAGEMENT,
+  DURABLE_AND_ENGAGEMENT,
+  NOTIFICATIONS_AND_DURABLE,
+  NOTIFICATIONS_AND_DURABLE_AND_ENGAGEMENT,
+  REASON_UNKNOWN,
+  REASON_BOUNDARY
+};
+
+struct ImportantReason {
+  bool engagement = false;
+  bool notifications = false;
+  bool durable = false;
+};
+
 std::vector<std::pair<GURL, double>> GetSortedTopEngagementOrigins(
     const SiteEngagementService* site_engagement_service,
     const std::map<GURL, double>& engagement_map,
@@ -142,6 +162,106 @@
   return final_list;
 }
 
+void ImportantSitesUtil::RecordMetricsForBlacklistedSites(
+    Profile* profile,
+    std::vector<std::string> blacklisted_sites) {
+  SiteEngagementService* site_engagement_service =
+      SiteEngagementService::Get(profile);
+
+  std::map<std::string, ImportantReason> reason_map;
+
+  std::map<GURL, double> engagement_map =
+      site_engagement_service->GetScoreMap();
+
+  // Site engagement.
+  for (const auto& url_score_pair : engagement_map) {
+    if (url_score_pair.second <
+        SiteEngagementScore::GetMediumEngagementBoundary()) {
+      continue;
+    }
+    const std::string& host = url_score_pair.first.host();
+    for (const std::string& blacklisted_site : blacklisted_sites) {
+      if (host.find(blacklisted_site) != std::string::npos) {
+        reason_map[blacklisted_site].engagement |= true;
+        break;
+      }
+    }
+  }
+
+  // Durable.
+  ContentSettingsForOneType content_settings_list;
+  HostContentSettingsMapFactory::GetForProfile(profile)->GetSettingsForOneType(
+      CONTENT_SETTINGS_TYPE_DURABLE_STORAGE,
+      content_settings::ResourceIdentifier(), &content_settings_list);
+  for (const ContentSettingPatternSource& site : content_settings_list) {
+    if (site.setting != CONTENT_SETTING_ALLOW)
+      continue;
+    GURL origin(site.primary_pattern.ToString());
+    if (!origin.is_valid())
+      continue;
+    const std::string& host = origin.host();
+    for (const std::string& blacklisted_site : blacklisted_sites) {
+      if (host.find(blacklisted_site) != std::string::npos) {
+        reason_map[blacklisted_site].durable |= true;
+        break;
+      }
+    }
+  }
+
+  // Notifications.
+  content_settings_list.clear();
+  HostContentSettingsMapFactory::GetForProfile(profile)->GetSettingsForOneType(
+      CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+      content_settings::ResourceIdentifier(), &content_settings_list);
+  for (const ContentSettingPatternSource& site : content_settings_list) {
+    if (site.setting != CONTENT_SETTING_ALLOW)
+      continue;
+    GURL origin(site.primary_pattern.ToString());
+    if (!origin.is_valid())
+      continue;
+    const std::string& host = origin.host();
+    for (const std::string& blacklisted_site : blacklisted_sites) {
+      if (host.find(blacklisted_site) != std::string::npos) {
+        reason_map[blacklisted_site].notifications |= true;
+        break;
+      }
+    }
+  }
+
+  // Note: we don't plan on adding new metrics here, this is just for the finch
+  // experiment to give us initial data on what signals actually mattered.
+  for (const auto& reason_pair : reason_map) {
+    const ImportantReason& reason = reason_pair.second;
+    if (reason.notifications && reason.durable && reason.engagement) {
+      UMA_HISTOGRAM_ENUMERATION("Storage.BlacklistedImportantSites.Reason",
+                                NOTIFICATIONS_AND_DURABLE_AND_ENGAGEMENT,
+                                REASON_BOUNDARY);
+    } else if (reason.notifications && reason.durable) {
+      UMA_HISTOGRAM_ENUMERATION("Storage.BlacklistedImportantSites.Reason",
+                                NOTIFICATIONS_AND_DURABLE, REASON_BOUNDARY);
+    } else if (reason.notifications && reason.engagement) {
+      UMA_HISTOGRAM_ENUMERATION("Storage.BlacklistedImportantSites.Reason",
+                                NOTIFICATIONS_AND_ENGAGEMENT, REASON_BOUNDARY);
+    } else if (reason.durable && reason.engagement) {
+      UMA_HISTOGRAM_ENUMERATION("Storage.BlacklistedImportantSites.Reason",
+                                DURABLE_AND_ENGAGEMENT, REASON_BOUNDARY);
+    } else if (reason.notifications) {
+      UMA_HISTOGRAM_ENUMERATION("Storage.BlacklistedImportantSites.Reason",
+                                NOTIFICATIONS, REASON_BOUNDARY);
+    } else if (reason.durable) {
+      UMA_HISTOGRAM_ENUMERATION("Storage.BlacklistedImportantSites.Reason",
+                                DURABLE, REASON_BOUNDARY);
+    } else if (reason.engagement) {
+      UMA_HISTOGRAM_ENUMERATION("Storage.BlacklistedImportantSites.Reason",
+                                ENGAGEMENT, REASON_BOUNDARY);
+    } else {
+      UMA_HISTOGRAM_ENUMERATION("Storage.BlacklistedImportantSites.Reason",
+                                REASON_UNKNOWN, REASON_BOUNDARY);
+
+    }
+  }
+}
+
 void ImportantSitesUtil::MarkOriginAsImportantForTesting(Profile* profile,
                                                          const GURL& origin) {
   // First get data from site engagement.
diff --git a/chrome/browser/android/preferences/important_sites_util.h b/chrome/browser/android/preferences/important_sites_util.h
index d174d3b..5aae87d 100644
--- a/chrome/browser/android/preferences/important_sites_util.h
+++ b/chrome/browser/android/preferences/important_sites_util.h
@@ -28,6 +28,10 @@
       size_t max_results,
       std::vector<GURL>* optional_example_origins);
 
+  static void RecordMetricsForBlacklistedSites(
+      Profile* profile,
+      std::vector<std::string> blacklisted_sites);
+
   // This marks the given origin as important so we can test features that rely
   // on important sites.
   static void MarkOriginAsImportantForTesting(Profile* profile,
diff --git a/chrome/browser/android/preferences/pref_service_bridge.cc b/chrome/browser/android/preferences/pref_service_bridge.cc
index b5bb0ef..b878f6fe 100644
--- a/chrome/browser/android/preferences/pref_service_bridge.cc
+++ b/chrome/browser/android/preferences/pref_service_bridge.cc
@@ -653,6 +653,11 @@
     filter_builder.AddRegisterableDomain(domain);
   }
 
+  if (!excluding_domains.empty()) {
+    ImportantSitesUtil::RecordMetricsForBlacklistedSites(GetOriginalProfile(),
+                                                         excluding_domains);
+  }
+
   browsing_data_remover->RemoveWithFilter(
       BrowsingDataRemover::Period(
           static_cast<browsing_data::TimePeriod>(time_period)),
diff --git a/chrome/browser/android/preferences/website_preference_bridge.cc b/chrome/browser/android/preferences/website_preference_bridge.cc
index dbf8e8f2..c6b5d7d 100644
--- a/chrome/browser/android/preferences/website_preference_bridge.cc
+++ b/chrome/browser/android/preferences/website_preference_bridge.cc
@@ -623,8 +623,8 @@
       }
       // Remove the trailing backslash so the origin is matched correctly in
       // SingleWebsitePreferences.mergePermissionInfoForTopLevelOrigin.
-      DCHECK(origin_str[origin_str.size() - 1] == '/');
-      origin_str = origin_str.substr(0, origin_str.size() - 1);
+      DCHECK_EQ('/', origin_str.back());
+      origin_str.pop_back();
       ScopedJavaLocalRef<jstring> origin =
           ConvertUTF8ToJavaString(env_, origin_str);
       Java_WebsitePreferenceBridge_insertLocalStorageInfoIntoMap(
diff --git a/chrome/browser/android/shortcut_helper.cc b/chrome/browser/android/shortcut_helper.cc
index e4769d9..3e1c122b 100644
--- a/chrome/browser/android/shortcut_helper.cc
+++ b/chrome/browser/android/shortcut_helper.cc
@@ -72,6 +72,8 @@
       base::android::ConvertUTF8ToJavaString(env, webapp_id);
   ScopedJavaLocalRef<jstring> java_url =
       base::android::ConvertUTF8ToJavaString(env, info.url.spec());
+  ScopedJavaLocalRef<jstring> java_scope_url =
+      base::android::ConvertUTF8ToJavaString(env, info.scope.spec());
   ScopedJavaLocalRef<jstring> java_user_title =
       base::android::ConvertUTF16ToJavaString(env, info.user_title);
   ScopedJavaLocalRef<jstring> java_name =
@@ -102,6 +104,7 @@
       env,
       java_webapp_id.obj(),
       java_url.obj(),
+      java_scope_url.obj(),
       java_user_title.obj(),
       java_name.obj(),
       java_short_name.obj(),
diff --git a/chrome/browser/android/shortcut_info.cc b/chrome/browser/android/shortcut_info.cc
index 035ace6..9371a8a 100644
--- a/chrome/browser/android/shortcut_info.cc
+++ b/chrome/browser/android/shortcut_info.cc
@@ -35,6 +35,9 @@
   if (manifest.start_url.is_valid())
     url = manifest.start_url;
 
+  if (manifest.scope.is_valid())
+    scope = manifest.scope;
+
   // Set the display based on the manifest value, if any.
   if (manifest.display != blink::WebDisplayModeUndefined)
     display = manifest.display;
diff --git a/chrome/browser/android/shortcut_info.h b/chrome/browser/android/shortcut_info.h
index 0766c54..85716d6a 100644
--- a/chrome/browser/android/shortcut_info.h
+++ b/chrome/browser/android/shortcut_info.h
@@ -42,6 +42,7 @@
 
   GURL manifest_url;
   GURL url;
+  GURL scope;
   base::string16 user_title;
   base::string16 name;
   base::string16 short_name;
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 5cd24d4..a414b17 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -2355,7 +2355,8 @@
 std::unique_ptr<net::test_server::HttpResponse> HandleDownloadRequestWithCookie(
     std::queue<net::HttpStatusCode>* status_codes,
     const net::test_server::HttpRequest& request) {
-  if (request.relative_url.find(kDownloadPathPrefix) != 0) {
+  if (!base::StartsWith(request.relative_url, kDownloadPathPrefix,
+                        base::CompareCase::SENSITIVE)) {
     return std::unique_ptr<net::test_server::HttpResponse>();
   }
 
@@ -3340,6 +3341,95 @@
                         WebViewGuestScrollTouchTest,
                         testing::Combine(testing::Bool(), testing::Bool()));
 
+#if defined(USE_AURA)
+class WebViewGuestTouchFocusTest : public WebViewTestBase {
+ public:
+  WebViewGuestTouchFocusTest() {}
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    WebViewTestBase::SetUpCommandLine(command_line);
+
+    command_line->AppendSwitchASCII(switches::kTouchEvents,
+                                    switches::kTouchEventsEnabled);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WebViewGuestTouchFocusTest);
+};
+
+class FocusChangeWaiter {
+ public:
+  explicit FocusChangeWaiter(content::WebContents* web_contents,
+                             bool expected_focus)
+      : web_contents_(web_contents), expected_focus_(expected_focus) {}
+  ~FocusChangeWaiter() {}
+
+  void WaitForFocusChange() {
+    while (expected_focus_ !=
+           IsWebContentsBrowserPluginFocused(web_contents_)) {
+      base::RunLoop().RunUntilIdle();
+    }
+  }
+
+ private:
+  content::WebContents* web_contents_;
+  bool expected_focus_;
+};
+
+IN_PROC_BROWSER_TEST_F(WebViewGuestTouchFocusTest,
+                       TouchFocusesBrowserPluginInEmbedder) {
+  // This test is only relevant for non-OOPIF WebView.
+  if (content::BrowserPluginGuestMode::UseCrossProcessFramesForGuests())
+    return;
+
+  LoadAppWithGuest("web_view/guest_focus_test");
+
+  // Lookup relevant information about guest and embedder.
+  content::WebContents* embedder_contents = GetEmbedderWebContents();
+
+  std::vector<content::WebContents*> guest_web_contents_list;
+  GetGuestViewManager()->WaitForNumGuestsCreated(1u);
+  GetGuestViewManager()->GetGuestWebContentsList(&guest_web_contents_list);
+  ASSERT_EQ(1u, guest_web_contents_list.size());
+
+  content::WebContents* guest_contents = guest_web_contents_list[0];
+
+  gfx::Rect embedder_rect = embedder_contents->GetContainerBounds();
+  gfx::Rect guest_rect = guest_contents->GetContainerBounds();
+
+  guest_rect.set_x(guest_rect.x() - embedder_rect.x());
+  guest_rect.set_y(guest_rect.y() - embedder_rect.y());
+  embedder_rect.set_x(0);
+  embedder_rect.set_y(0);
+
+  // Don't send events that need to be routed until we know the child's surface
+  // is ready for hit testing.
+  WaitForGuestSurfaceReady(guest_contents);
+
+  // 1) BrowserPlugin should not be focused at start.
+  EXPECT_FALSE(IsWebContentsBrowserPluginFocused(guest_contents));
+
+  // 2) Send touch event to guest, now BrowserPlugin should get focus.
+  {
+    gfx::Point point = guest_rect.CenterPoint();
+    FocusChangeWaiter focus_waiter(guest_contents, true);
+    SendRoutedTouchTapSequence(embedder_contents, point);
+    SendRoutedGestureTapSequence(embedder_contents, point);
+    focus_waiter.WaitForFocusChange();
+    EXPECT_TRUE(IsWebContentsBrowserPluginFocused(guest_contents));
+  }
+
+  // 3) Send touch start to embedder, now BrowserPlugin should lose focus.
+  {
+    gfx::Point point(10, 10);
+    FocusChangeWaiter focus_waiter(guest_contents, false);
+    SendRoutedTouchTapSequence(embedder_contents, point);
+    SendRoutedGestureTapSequence(embedder_contents,point);
+    focus_waiter.WaitForFocusChange();
+    EXPECT_FALSE(IsWebContentsBrowserPluginFocused(guest_contents));
+  }
+}
+#endif
+
 IN_PROC_BROWSER_TEST_P(WebViewGuestScrollTouchTest,
                        TestGuestGestureScrollsBubble) {
   // Just in case we're running ChromeOS tests, we need to make sure the
diff --git a/chrome/browser/banners/app_banner_data_fetcher.cc b/chrome/browser/banners/app_banner_data_fetcher.cc
index 2b647326..fe4e8742 100644
--- a/chrome/browser/banners/app_banner_data_fetcher.cc
+++ b/chrome/browser/banners/app_banner_data_fetcher.cc
@@ -115,6 +115,11 @@
   if (is_active_) {
     FOR_EACH_OBSERVER(Observer, observer_list_,
                       OnDecidedWhetherToShow(this, false));
+    if (was_canceled_by_page_ && !page_requested_prompt_) {
+      TrackBeforeInstallEvent(
+          BEFORE_INSTALL_EVENT_PROMPT_NOT_CALLED_AFTER_PREVENT_DEFAULT);
+    }
+
     is_active_ = false;
     was_canceled_by_page_ = false;
     page_requested_prompt_ = false;
@@ -188,6 +193,7 @@
   // Stash the referrer for the case where the banner is redisplayed.
   if (reply == blink::WebAppBannerPromptReply::Cancel &&
       !page_requested_prompt_) {
+    TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_PREVENT_DEFAULT_CALLED);
     was_canceled_by_page_ = true;
     referrer_ = referrer;
     OutputDeveloperNotShownMessage(web_contents, kRendererRequestCancel,
@@ -195,6 +201,17 @@
     return;
   }
 
+  // If we haven't yet returned, but either of |was_canceled_by_page_| or
+  // |page_requested_prompt_| is true, the page has requested a delayed showing
+  // of the prompt. Otherwise, the prompt was never canceled by the page.
+  if (was_canceled_by_page_ || page_requested_prompt_) {
+    TrackBeforeInstallEvent(
+        BEFORE_INSTALL_EVENT_PROMPT_CALLED_AFTER_PREVENT_DEFAULT);
+    was_canceled_by_page_ = false;
+  } else {
+    TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_NO_ACTION);
+  }
+
   AppBannerSettingsHelper::RecordMinutesFromFirstVisitToShow(
       web_contents, validated_url_, GetAppIdentifier(), GetCurrentTime());
 
@@ -202,6 +219,7 @@
   FOR_EACH_OBSERVER(Observer, observer_list_,
                     OnDecidedWhetherToShow(this, true));
 
+  TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_COMPLETE);
   ShowBanner(app_icon_url_, app_icon_.get(), app_title_, referrer);
   is_active_ = false;
 }
@@ -211,7 +229,7 @@
     int request_id) {
   if (was_canceled_by_page_) {
     // Simulate an "OK" from the website to restart the banner display pipeline.
-    was_canceled_by_page_ = false;
+    // Don't reset |was_canceled_by_page_| yet for metrics purposes.
     OnBannerPromptReply(render_frame_host, request_id,
                         blink::WebAppBannerPromptReply::None, referrer_);
   } else {
@@ -401,6 +419,8 @@
 
   app_icon_.reset(new SkBitmap(bitmap));
   event_request_id_ = ++gCurrentRequestID;
+
+  TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_CREATED);
   web_contents->GetMainFrame()->Send(
       new ChromeViewMsg_AppBannerPromptRequest(
         web_contents->GetMainFrame()->GetRoutingID(),
diff --git a/chrome/browser/banners/app_banner_metrics.cc b/chrome/browser/banners/app_banner_metrics.cc
index f9bbd34..58e373d 100644
--- a/chrome/browser/banners/app_banner_metrics.cc
+++ b/chrome/browser/banners/app_banner_metrics.cc
@@ -15,6 +15,7 @@
 const char kMinutesHistogram[] =
     "AppBanners.MinutesFromFirstVisitToBannerShown";
 const char kUserResponseHistogram[] = "AppBanners.UserResponse";
+const char kBeforeInstallEventHistogram[] = "AppBanners.BeforeInstallEvent";
 
 void TrackDismissEvent(int event) {
   DCHECK_LT(DISMISS_EVENT_MIN, event);
@@ -48,4 +49,10 @@
   UMA_HISTOGRAM_SPARSE_SLOWLY(kUserResponseHistogram, event);
 }
 
+void TrackBeforeInstallEvent(int event) {
+  DCHECK_LT(BEFORE_INSTALL_EVENT_MIN, event);
+  DCHECK_LT(event, BEFORE_INSTALL_EVENT_MAX);
+  UMA_HISTOGRAM_SPARSE_SLOWLY(kBeforeInstallEventHistogram, event);
+}
+
 }  // namespace banners
diff --git a/chrome/browser/banners/app_banner_metrics.h b/chrome/browser/banners/app_banner_metrics.h
index 8b96d8c8..357911aa 100644
--- a/chrome/browser/banners/app_banner_metrics.h
+++ b/chrome/browser/banners/app_banner_metrics.h
@@ -7,7 +7,7 @@
 
 namespace banners {
 
-// Keep in sync with the values defined in histograms.xml.
+// This enum backs a UMA histogram, so it should be treated as append-only.
 enum DisplayEvent {
   DISPLAY_EVENT_MIN = 0,
   DISPLAY_EVENT_BANNER_REQUESTED = 1,
@@ -25,6 +25,7 @@
   DISPLAY_EVENT_MAX = 13,
 };
 
+// This enum backs a UMA histogram, so it should be treated as append-only.
 enum InstallEvent {
   INSTALL_EVENT_MIN = 20,
   INSTALL_EVENT_NATIVE_APP_INSTALL_TRIGGERED = 21,
@@ -34,6 +35,7 @@
   INSTALL_EVENT_MAX = 25,
 };
 
+// This enum backs a UMA histogram, so it should be treated as append-only.
 enum DismissEvent {
   DISMISS_EVENT_MIN = 40,
   DISMISS_EVENT_ERROR = 41,
@@ -46,6 +48,7 @@
   DISMISS_EVENT_MAX = 48,
 };
 
+// This enum backs a UMA histogram, so it should be treated as append-only.
 enum UserResponse {
   USER_RESPONSE_MIN = 0,
   USER_RESPONSE_NATIVE_APP_ACCEPTED = 1,
@@ -57,17 +60,31 @@
   USER_RESPONSE_MAX = 7,
 };
 
+// This enum backs a UMA histogram, so it should be treated as append-only.
+enum BeforeInstallEvent {
+  BEFORE_INSTALL_EVENT_MIN = 0,
+  BEFORE_INSTALL_EVENT_CREATED = 1,
+  BEFORE_INSTALL_EVENT_COMPLETE = 2,
+  BEFORE_INSTALL_EVENT_NO_ACTION = 3,
+  BEFORE_INSTALL_EVENT_PREVENT_DEFAULT_CALLED = 4,
+  BEFORE_INSTALL_EVENT_PROMPT_CALLED_AFTER_PREVENT_DEFAULT = 5,
+  BEFORE_INSTALL_EVENT_PROMPT_NOT_CALLED_AFTER_PREVENT_DEFAULT = 6,
+  BEFORE_INSTALL_EVENT_MAX = 7,
+};
+
 extern const char kDismissEventHistogram[];
 extern const char kDisplayEventHistogram[];
 extern const char kInstallEventHistogram[];
 extern const char kMinutesHistogram[];
 extern const char kUserResponseHistogram[];
+extern const char kBeforeInstallEventHistogram[];
 
 void TrackDismissEvent(int event);
 void TrackDisplayEvent(int event);
 void TrackInstallEvent(int event);
 void TrackMinutesFromFirstVisitToBannerShown(int minutes);
 void TrackUserResponse(int event);
+void TrackBeforeInstallEvent(int event);
 
 };  // namespace banners
 
diff --git a/chrome/browser/banners/app_banner_settings_helper_unittest.cc b/chrome/browser/banners/app_banner_settings_helper_unittest.cc
index 0fb52d0..8f9acd5 100644
--- a/chrome/browser/banners/app_banner_settings_helper_unittest.cc
+++ b/chrome/browser/banners/app_banner_settings_helper_unittest.cc
@@ -30,7 +30,10 @@
   exploded_reference_time.second = 0;
   exploded_reference_time.millisecond = 0;
 
-  return base::Time::FromLocalExploded(exploded_reference_time);
+  base::Time out_time;
+  EXPECT_TRUE(
+      base::Time::FromLocalExploded(exploded_reference_time, &out_time));
+  return out_time;
 }
 
 bool IsWithinDay(base::Time time1, base::Time time2) {
diff --git a/chrome/browser/browsing_data/registrable_domain_filter_builder.cc b/chrome/browser/browsing_data/registrable_domain_filter_builder.cc
index 78fe5b4..a060483 100644
--- a/chrome/browser/browsing_data/registrable_domain_filter_builder.cc
+++ b/chrome/browser/browsing_data/registrable_domain_filter_builder.cc
@@ -16,6 +16,27 @@
 using net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES;
 using Relation = ContentSettingsPattern::Relation;
 
+namespace {
+
+// Whether this is a registrable domain.
+bool IsRegistrableDomain(const std::string& domain) {
+  return GetDomainAndRegistry(domain, INCLUDE_PRIVATE_REGISTRIES) == domain;
+}
+
+// Whether this is a subdomain of a registrable domain.
+bool IsSubdomainOfARegistrableDomain(const std::string& domain) {
+  std::string registrable_domain =
+      GetDomainAndRegistry(domain, INCLUDE_PRIVATE_REGISTRIES);
+  return registrable_domain != domain && registrable_domain != "";
+}
+
+// Note that for every domain, exactly one of the following holds:
+// 1. IsRegistrableDomain(domain)                  - e.g. google.com
+// 2. IsSubdomainOfARegistrableDomain(domain)      - e.g. www.google.com
+// 3. GetDomainAndRegistry(domain, _) == ""        - e.g. localhost, 127.0.0.1
+
+}  // namespace
+
 RegistrableDomainFilterBuilder::RegistrableDomainFilterBuilder(Mode mode)
     : BrowsingDataFilterBuilder(mode) {
 }
@@ -24,11 +45,9 @@
 
 void RegistrableDomainFilterBuilder::AddRegisterableDomain(
     const std::string& domain) {
-  // We check that the domain we're given is actually a eTLD+1, or an IP
-  // address.
-  DCHECK(GetDomainAndRegistry("www." + domain, INCLUDE_PRIVATE_REGISTRIES) ==
-             domain ||
-         GURL("http://" + domain).HostIsIPAddress());
+  // We check that the domain we're given is actually a eTLD+1, an IP address,
+  // or an internal hostname.
+  DCHECK(!IsSubdomainOfARegistrableDomain(domain));
   domain_list_.insert(domain);
 }
 
@@ -46,16 +65,16 @@
       new std::vector<ContentSettingsPattern>();
   patterns_from_domains->reserve(domain_list_.size());
 
-  std::unique_ptr<ContentSettingsPattern::BuilderInterface> builder(
-      ContentSettingsPattern::CreateBuilder(/* use_legacy_validate */ false));
   for (const std::string& domain : domain_list_) {
+    std::unique_ptr<ContentSettingsPattern::BuilderInterface> builder(
+        ContentSettingsPattern::CreateBuilder(/* use_legacy_validate */ false));
     builder->WithSchemeWildcard()
         ->WithPortWildcard()
         ->WithPathWildcard()
         ->WithHost(domain);
-    if (!GURL("http://" + domain).HostIsIPAddress()) {
+    if (IsRegistrableDomain(domain))
       builder->WithDomainWildcard();
-    }
+
     patterns_from_domains->push_back(builder->Build());
   }
 
@@ -99,10 +118,10 @@
     const GURL& url) {
   std::string url_registerable_domain =
       GetDomainAndRegistry(url, INCLUDE_PRIVATE_REGISTRIES);
-  return (registerable_domains->find(url_registerable_domain) !=
-              registerable_domains->end() ||
-          (url.HostIsIPAddress() && (registerable_domains->find(url.host()) !=
-                                     registerable_domains->end()))) ==
+  return (registerable_domains->find(
+              url_registerable_domain != "" ? url_registerable_domain
+                                            : url.host()) !=
+          registerable_domains->end()) ==
          (mode == WHITELIST);
 }
 
@@ -132,7 +151,7 @@
     cookie_domain = cookie_domain.substr(1);
   std::string parsed_cookie_domain =
       GetDomainAndRegistry(cookie_domain, INCLUDE_PRIVATE_REGISTRIES);
-  // This means we're an IP address.
+  // This means we're an IP address or an internal hostname.
   if (parsed_cookie_domain.empty())
     parsed_cookie_domain = cookie_domain;
   return (mode == WHITELIST) == (domains_and_ips->find(parsed_cookie_domain) !=
diff --git a/chrome/browser/browsing_data/registrable_domain_filter_builder.h b/chrome/browser/browsing_data/registrable_domain_filter_builder.h
index c7501af..c18c681 100644
--- a/chrome/browser/browsing_data/registrable_domain_filter_builder.h
+++ b/chrome/browser/browsing_data/registrable_domain_filter_builder.h
@@ -29,6 +29,19 @@
 //
 // See net/base/registry_controlled_domains/registry_controlled_domain.h for
 // more details on registrable domains and the current list of effective eTLDs.
+//
+// This filter also recognizes IP addresses and internal hostnames. Neither of
+// those have subdomains (or support domain cookies), and so the filter requires
+// the cookie (or other data type) source domain to be identical to the
+// domain (IP address or internal hostname) for it to be considered a match.
+//
+// Note that e.g. "subdomain.localhost" is NOT considered to be a subdomain
+// of the internal hostname "localhost". It is understood as a registrable
+// domain in the scope of the TLD "localhost" (from unknown registry),
+// and treated as any other registrable domain. For example,
+// "www.subdomain.localhost" will be matched by a filter containing
+// "subdomain.localhost". However, it is unrelated to "localhost", whose cookies
+// will never be visible on "*.localhost" or vice versa.
 class RegistrableDomainFilterBuilder : public BrowsingDataFilterBuilder {
  public:
   // Constructs a filter with the given |mode| - whitelist or blacklist.
@@ -38,7 +51,8 @@
 
   // Adds a registerable domain to the (white- or black-) list. This is expected
   // to not include subdomains, so basically tld+1. This can also be an IP
-  // address.
+  // address or an internal hostname.
+  //
   // Refer to net/base/registry_controlled_domains/registry_controlled_domain.h
   // for more details on registrable domains and the current list of effective.
   // TLDs. We expect a string that would be returned by
diff --git a/chrome/browser/browsing_data/registrable_domain_filter_builder_unittest.cc b/chrome/browser/browsing_data/registrable_domain_filter_builder_unittest.cc
index 9880ad6..b56dbcca 100644
--- a/chrome/browser/browsing_data/registrable_domain_filter_builder_unittest.cc
+++ b/chrome/browser/browsing_data/registrable_domain_filter_builder_unittest.cc
@@ -21,7 +21,15 @@
 // sp.nom.br is an eTLD, so this is a regular valid registrable domain, just
 // like google.com.
 const char kLongETLDDomain[] = "website.sp.nom.br";
-// An IP address can be a registerable domain.
+// This domain will also not be found in registries, and since it has only
+// one component, it will not be recognized as a valid registrable domain.
+const char kInternalHostname[] = "fileserver";
+// This domain will not be found in registries. It will be assumed that
+// it belongs to an unknown registry, and since it has two components,
+// they will be treated as the second level domain and TLD. Most importantly,
+// it will NOT be treated as a subdomain of "fileserver".
+const char kUnknownRegistryDomain[] = "second-level-domain.fileserver";
+// IP addresses are supported.
 const char kIPAddress[] = "192.168.1.1";
 
 struct TestCase {
@@ -116,10 +124,12 @@
   builder.AddRegisterableDomain(std::string(kGoogleDomain));
   builder.AddRegisterableDomain(std::string(kLongETLDDomain));
   builder.AddRegisterableDomain(std::string(kIPAddress));
+  builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
+  builder.AddRegisterableDomain(std::string(kInternalHostname));
   base::Callback<bool(const GURL&)> filter = builder.BuildGeneralFilter();
 
   TestCase test_cases[] = {
-      // We matche any URL on the specified domains.
+      // We match any URL on the specified domains.
       {"http://www.google.com/foo/bar", true},
       {"https://www.sub.google.com/foo/bar", true},
       {"https://sub.google.com", true},
@@ -129,6 +139,16 @@
       {"http://192.168.1.1", true},
       {"http://192.168.1.1:80", true},
 
+      // Internal hostnames do not have subdomains.
+      {"http://fileserver", true },
+      {"http://fileserver/foo/bar", true },
+      {"http://website.fileserver/foo/bar", false },
+
+      // This is a valid registrable domain with the TLD "fileserver", which
+      // is unrelated to the internal hostname "fileserver".
+      {"http://second-level-domain.fileserver/foo", true},
+      {"http://www.second-level-domain.fileserver/index.html", true},
+
       // Different domains.
       {"https://www.youtube.com", false},
       {"https://www.google.net", false},
@@ -148,10 +168,12 @@
   builder.AddRegisterableDomain(std::string(kGoogleDomain));
   builder.AddRegisterableDomain(std::string(kLongETLDDomain));
   builder.AddRegisterableDomain(std::string(kIPAddress));
+  builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
+  builder.AddRegisterableDomain(std::string(kInternalHostname));
   base::Callback<bool(const GURL&)> filter = builder.BuildGeneralFilter();
 
   TestCase test_cases[] = {
-      // We matches any URL that are not on the specified domains.
+      // We match any URL that are not on the specified domains.
       {"http://www.google.com/foo/bar", false},
       {"https://www.sub.google.com/foo/bar", false},
       {"https://sub.google.com", false},
@@ -161,6 +183,16 @@
       {"http://192.168.1.1", false},
       {"http://192.168.1.1:80", false},
 
+      // Internal hostnames do not have subdomains.
+      {"http://fileserver", false },
+      {"http://fileserver/foo/bar", false },
+      {"http://website.fileserver/foo/bar", true },
+
+      // This is a valid registrable domain with the TLD "fileserver", which
+      // is unrelated to the internal hostname "fileserver".
+      {"http://second-level-domain.fileserver/foo", false},
+      {"http://www.second-level-domain.fileserver/index.html", false},
+
       // Different domains.
       {"https://www.youtube.com", true},
       {"https://www.google.net", true},
@@ -180,6 +212,8 @@
   builder.AddRegisterableDomain(std::string(kGoogleDomain));
   builder.AddRegisterableDomain(std::string(kLongETLDDomain));
   builder.AddRegisterableDomain(std::string(kIPAddress));
+  builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
+  builder.AddRegisterableDomain(std::string(kInternalHostname));
   base::Callback<bool(const ContentSettingsPattern&)> filter =
       builder.BuildWebsiteSettingsPatternMatchesFilter();
 
@@ -212,6 +246,18 @@
       {"https://sp.nom.br", false},
       {"http://192.168.1.2", false},
 
+      // Internal hostnames do not have subdomains.
+      {"http://fileserver", true },
+      {"http://[*.]fileserver", false },
+      {"http://website.fileserver", false },
+
+      // This is a valid registrable domain with the TLD "fileserver", which
+      // is unrelated to the internal hostname "fileserver".
+      {"http://second-level-domain.fileserver", true},
+      {"http://[*.]second-level-domain.fileserver", true},
+      {"http://www.second-level-domain.fileserver", true},
+      {"http://[*.]www.second-level-domain.fileserver", true},
+
       // These patterns are more general than our registerable domain filter,
       // as they apply to more sites. So we don't match them. The content
       // settings categories that we'll be seeing from browsing_data_remover
@@ -230,6 +276,8 @@
   builder.AddRegisterableDomain(std::string(kGoogleDomain));
   builder.AddRegisterableDomain(std::string(kLongETLDDomain));
   builder.AddRegisterableDomain(std::string(kIPAddress));
+  builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
+  builder.AddRegisterableDomain(std::string(kInternalHostname));
   base::Callback<bool(const ContentSettingsPattern&)> filter =
       builder.BuildWebsiteSettingsPatternMatchesFilter();
 
@@ -262,6 +310,18 @@
       {"https://sp.nom.br", true},
       {"http://192.168.1.2", true},
 
+      // Internal hostnames do not have subdomains.
+      {"fileserver", false },
+      {"http://[*.]fileserver", true },
+      {"website.fileserver", true },
+
+      // This is a valid registrable domain with the TLD "fileserver", which
+      // is unrelated to the internal hostname "fileserver".
+      {"http://second-level-domain.fileserver", false},
+      {"http://[*.]second-level-domain.fileserver", false},
+      {"http://www.second-level-domain.fileserver", false},
+      {"http://[*.]www.second-level-domain.fileserver", false},
+
       // These patterns are more general than our registerable domain filter,
       // as they apply to more sites. So we don't match them. The content
       // settings categories that we'll be seeing from browsing_data_remover
@@ -280,6 +340,8 @@
   builder.AddRegisterableDomain(std::string(kGoogleDomain));
   builder.AddRegisterableDomain(std::string(kLongETLDDomain));
   builder.AddRegisterableDomain(std::string(kIPAddress));
+  builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
+  builder.AddRegisterableDomain(std::string(kInternalHostname));
   base::Callback<bool(const net::CanonicalCookie&)> filter =
       builder.BuildCookieFilter();
 
@@ -306,7 +368,18 @@
 
       // Different hosts in general.
       {"https://www.chrome.com", false},
-      {"http://192.168.2.1", false}};
+      {"http://192.168.2.1", false},
+
+      // Internal hostnames do not have subdomains.
+      {"https://fileserver", true },
+      {"http://fileserver/foo/bar", true },
+      {"http://website.fileserver", false },
+
+      // This is a valid registrable domain with the TLD "fileserver", which
+      // is unrelated to the internal hostname "fileserver".
+      {"http://second-level-domain.fileserver", true},
+      {"https://subdomain.second-level-domain.fileserver", true},
+  };
 
   for (TestCase test_case : test_cases)
     RunTestCase(test_case, filter);
@@ -318,6 +391,8 @@
   builder.AddRegisterableDomain(std::string(kGoogleDomain));
   builder.AddRegisterableDomain(std::string(kLongETLDDomain));
   builder.AddRegisterableDomain(std::string(kIPAddress));
+  builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
+  builder.AddRegisterableDomain(std::string(kInternalHostname));
   base::Callback<bool(const net::CanonicalCookie&)> filter =
       builder.BuildCookieFilter();
 
@@ -344,7 +419,18 @@
 
       // Different hosts in general.
       {"https://www.chrome.com", true},
-      {"http://192.168.2.1", true}};
+      {"http://192.168.2.1", true},
+
+      // Internal hostnames do not have subdomains.
+      {"https://fileserver", false },
+      {"http://fileserver/foo/bar", false },
+      {"http://website.fileserver", true },
+
+      // This is a valid registrable domain with the TLD "fileserver", which
+      // is unrelated to the internal hostname "fileserver".
+      {"http://second-level-domain.fileserver", false},
+      {"https://subdomain.second-level-domain.fileserver", false},
+  };
 
   for (TestCase test_case : test_cases)
     RunTestCase(test_case, filter);
@@ -356,20 +442,25 @@
   builder.AddRegisterableDomain(std::string(kGoogleDomain));
   builder.AddRegisterableDomain(std::string(kLongETLDDomain));
   builder.AddRegisterableDomain(std::string(kIPAddress));
+  builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
+  builder.AddRegisterableDomain(std::string(kInternalHostname));
   base::Callback<bool(const std::string&)> filter =
       builder.BuildChannelIDFilter();
 
   TestCase test_cases[] = {
-      // Channel ID server identifiers can be top-level domains...
+      // Channel ID server identifiers can be second level domains, ...
       {"google.com", true},
       {"website.sp.nom.br", true},
+      {"second-level-domain.fileserver", true},
 
-      // or IP addresses.
+      // ... IP addresses, or internal hostnames.
       {"192.168.1.1", true},
+      {"fileserver", true},
 
       // Channel IDs not in the whitelist are not matched.
       {"example.com", false},
       {"192.168.1.2", false},
+      {"website.fileserver", false},
   };
 
   for (TestCase test_case : test_cases)
@@ -382,20 +473,25 @@
   builder.AddRegisterableDomain(std::string(kGoogleDomain));
   builder.AddRegisterableDomain(std::string(kLongETLDDomain));
   builder.AddRegisterableDomain(std::string(kIPAddress));
+  builder.AddRegisterableDomain(std::string(kUnknownRegistryDomain));
+  builder.AddRegisterableDomain(std::string(kInternalHostname));
   base::Callback<bool(const std::string&)> filter =
       builder.BuildChannelIDFilter();
 
   TestCase test_cases[] = {
-      // Channel ID server identifiers can be top-level domains...
+      // Channel ID server identifiers can be second level domains, ...
       {"google.com", false},
       {"website.sp.nom.br", false},
+      {"second-level-domain.fileserver", false},
 
-      // or IP addresses.
+      // ...IP addresses, or internal hostnames.
       {"192.168.1.1", false},
+      {"fileserver", false},
 
       // Channel IDs that are not blacklisted are matched.
       {"example.com", true},
       {"192.168.1.2", true},
+      {"website.fileserver", true},
   };
 
   for (TestCase test_case : test_cases)
diff --git a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
index fba326f..e4db346 100644
--- a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
@@ -37,6 +37,7 @@
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/login/user_names.h"
 #include "components/signin/core/account_id/account_id.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
@@ -57,7 +58,7 @@
 //
 
 class LoggedInSpokenFeedbackTest : public InProcessBrowserTest {
- protected:
+ public:
   LoggedInSpokenFeedbackTest()
       : animation_mode_(ui::ScopedAnimationDurationScaleMode::ZERO_DURATION) {}
   ~LoggedInSpokenFeedbackTest() override {}
@@ -578,7 +579,15 @@
 
   // Press the sticky-key sequence: Search Search.
   SendKeyPress(ui::VKEY_LWIN);
-  SendKeyPress(ui::VKEY_LWIN);
+
+  // Sticky key has a minimum 100 ms check to prevent key repeat from toggling
+  // it.
+  content::BrowserThread::PostDelayedTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::Bind(&LoggedInSpokenFeedbackTest::SendKeyPress,
+                 base::Unretained(this), ui::VKEY_LWIN),
+      base::TimeDelta::FromMilliseconds(200));
+
   EXPECT_EQ("Sticky mode enabled", speech_monitor_.GetNextUtterance());
 
   // Even once we hear "sticky mode enabled" from the ChromeVox background
@@ -607,7 +616,15 @@
 
   // Press the sticky-key sequence: Search Search.
   SendKeyPress(ui::VKEY_LWIN);
-  SendKeyPress(ui::VKEY_LWIN);
+
+  // Sticky key has a minimum 100 ms check to prevent key repeat from toggling
+  // it.
+  content::BrowserThread::PostDelayedTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::Bind(&LoggedInSpokenFeedbackTest::SendKeyPress,
+                 base::Unretained(this), ui::VKEY_LWIN),
+      base::TimeDelta::FromMilliseconds(200));
+
   EXPECT_EQ("Sticky mode enabled", speech_monitor_.GetNextUtterance());
 
   SendKeyPress(ui::VKEY_H);
@@ -615,7 +632,15 @@
   }
 
   SendKeyPress(ui::VKEY_LWIN);
-  SendKeyPress(ui::VKEY_LWIN);
+
+  // Sticky key has a minimum 100 ms check to prevent key repeat from toggling
+  // it.
+  content::BrowserThread::PostDelayedTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::Bind(&LoggedInSpokenFeedbackTest::SendKeyPress,
+                 base::Unretained(this), ui::VKEY_LWIN),
+      base::TimeDelta::FromMilliseconds(200));
+
   while ("Sticky mode disabled" != speech_monitor_.GetNextUtterance()) {
   }
 }
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
index 2f0ed35..bf9389d8 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
@@ -642,7 +642,7 @@
 
   // |parent| may have a trailing slash if it is a root directory.
   std::string destination_url_string = params->parent_url;
-  if (destination_url_string[destination_url_string.size() - 1] != '/')
+  if (destination_url_string.back() != '/')
     destination_url_string += '/';
   destination_url_string += net::EscapePath(params->new_name);
 
diff --git a/chrome/browser/chromeos/file_manager/arc_file_tasks.cc b/chrome/browser/chromeos/file_manager/arc_file_tasks.cc
index eb3e33e..e16e6e5a 100644
--- a/chrome/browser/chromeos/file_manager/arc_file_tasks.cc
+++ b/chrome/browser/chromeos/file_manager/arc_file_tasks.cc
@@ -27,6 +27,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "extensions/browser/entry_info.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "net/base/escape.h"
 #include "net/base/filename_util.h"
 #include "storage/browser/fileapi/file_system_url.h"
 #include "url/gurl.h"
@@ -41,6 +42,10 @@
 
 constexpr base::FilePath::CharType kArcDownloadPath[] =
     FILE_PATH_LITERAL("/sdcard/Download");
+constexpr base::FilePath::CharType kRemovableMediaPath[] =
+    FILE_PATH_LITERAL("/media/removable");
+constexpr char kArcRemovableMediaProviderUrl[] =
+    "content://org.chromium.arc.removablemediaprovider/";
 constexpr char kAppIdSeparator = '/';
 constexpr char kPngDataUrlPrefix[] = "data:image/png;base64,";
 
@@ -149,6 +154,15 @@
     return true;
   }
 
+  // Convert paths under /media/removable.
+  base::FilePath relative_path;
+  if (base::FilePath(kRemovableMediaPath)
+          .AppendRelativePath(path, &relative_path)) {
+    *arc_url = GURL(kArcRemovableMediaProviderUrl)
+                   .Resolve(net::EscapePath(relative_path.AsUTF8Unsafe()));
+    return true;
+  }
+
   // TODO(kinaba): Add conversion logic once other file systems are supported.
   return false;
 }
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index be618d5..d2f554d 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -91,6 +91,7 @@
     ::switches::kDisableGpuCompositing,
     ::switches::kDisableGpuRasterization,
     ::switches::kDisableLowResTiling,
+    ::switches::kDisablePepper3DImageChromium,
     ::switches::kDisablePreferCompositingToLCDText,
     ::switches::kDisablePanelFitting,
     ::switches::kDisableRGBA4444Textures,
diff --git a/chrome/browser/chromeos/policy/device_status_collector.cc b/chrome/browser/chromeos/policy/device_status_collector.cc
index fdf71837..d731df4 100644
--- a/chrome/browser/chromeos/policy/device_status_collector.cc
+++ b/chrome/browser/chromeos/policy/device_status_collector.cc
@@ -103,7 +103,10 @@
 int64_t TimestampToDayKey(Time timestamp) {
   Time::Exploded exploded;
   timestamp.LocalMidnight().LocalExplode(&exploded);
-  return (Time::FromUTCExploded(exploded) - Time::UnixEpoch()).InMilliseconds();
+  Time out_time;
+  bool conversion_success = Time::FromUTCExploded(exploded, &out_time);
+  DCHECK(conversion_success);
+  return (out_time - Time::UnixEpoch()).InMilliseconds();
 }
 
 // Helper function (invoked via blocking pool) to fetch information about
diff --git a/chrome/browser/chromeos/profiles/profile_helper.cc b/chrome/browser/chromeos/profiles/profile_helper.cc
index 08c4058..91ff48c 100644
--- a/chrome/browser/chromeos/profiles/profile_helper.cc
+++ b/chrome/browser/chromeos/profiles/profile_helper.cc
@@ -7,6 +7,7 @@
 #include "base/barrier_closure.h"
 #include "base/callback.h"
 #include "base/command_line.h"
+#include "base/strings/string_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
 #include "chrome/browser/browsing_data/browsing_data_remover.h"
@@ -138,13 +139,12 @@
 
   // Check that profile directory starts with the correct prefix.
   std::string prefix(chrome::kProfileDirPrefix);
-  if (profile_dir.find(prefix) != 0) {
+  if (!base::StartsWith(profile_dir, prefix, base::CompareCase::SENSITIVE)) {
     // This happens when creating a TestingProfile in browser tests.
     return std::string();
   }
 
-  return profile_dir.substr(prefix.length(),
-                            profile_dir.length() - prefix.length());
+  return profile_dir.substr(prefix.length());
 }
 
 // static
diff --git a/chrome/browser/content_settings/host_content_settings_map_unittest.cc b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
index b5e4ac0..ee7029cd 100644
--- a/chrome/browser/content_settings/host_content_settings_map_unittest.cc
+++ b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
@@ -1351,6 +1351,119 @@
                 host, host, CONTENT_SETTINGS_TYPE_KEYGEN, std::string()));
 }
 
+TEST_F(HostContentSettingsMapTest, MigrateDomainScopedSettings) {
+  TestingProfile profile;
+  HostContentSettingsMap* host_content_settings_map =
+      HostContentSettingsMapFactory::GetForProfile(&profile);
+
+  // Set old formatted http settings.
+  GURL http_host("http://example.com/");
+  GURL http_host_narrower("http://a.example.com/");
+
+  // Change default setting to BLOCK.
+  host_content_settings_map->SetDefaultContentSetting(
+      CONTENT_SETTINGS_TYPE_COOKIES, CONTENT_SETTING_BLOCK);
+  EXPECT_EQ(
+      CONTENT_SETTING_BLOCK,
+      host_content_settings_map->GetContentSetting(
+          http_host, http_host, CONTENT_SETTINGS_TYPE_COOKIES, std::string()));
+  // Patterns generated for cookies used to be domain scoped.
+  host_content_settings_map->SetContentSettingCustomScope(
+      ContentSettingsPattern::FromURL(http_host),
+      ContentSettingsPattern::Wildcard(), CONTENT_SETTINGS_TYPE_COOKIES,
+      std::string(), CONTENT_SETTING_ALLOW);
+  EXPECT_EQ(
+      CONTENT_SETTING_ALLOW,
+      host_content_settings_map->GetContentSetting(
+          http_host, http_host, CONTENT_SETTINGS_TYPE_COOKIES, std::string()));
+  // Settings also apply to subdomains.
+  EXPECT_EQ(CONTENT_SETTING_ALLOW,
+            host_content_settings_map->GetContentSetting(
+                http_host_narrower, http_host_narrower,
+                CONTENT_SETTINGS_TYPE_COOKIES, std::string()));
+
+  ContentSettingsForOneType settings;
+  host_content_settings_map->GetSettingsForOneType(
+      CONTENT_SETTINGS_TYPE_COOKIES, std::string(), &settings);
+  // |host_content_settings_map| contains default setting and a domain scoped
+  // setting.
+  EXPECT_EQ(2U, settings.size());
+  EXPECT_TRUE(settings[0].primary_pattern.ToString() == "[*.]example.com");
+  EXPECT_TRUE(settings[1].primary_pattern.ToString() == "*");
+
+  // Set old formatted https settings.
+  GURL https_host("https://example.com/");
+  GURL https_host_narrower("https://a.example.com/");
+
+  // Change default setting to BLOCK.
+  host_content_settings_map->SetDefaultContentSetting(
+      CONTENT_SETTINGS_TYPE_POPUPS, CONTENT_SETTING_BLOCK);
+  EXPECT_EQ(
+      CONTENT_SETTING_BLOCK,
+      host_content_settings_map->GetContentSetting(
+          https_host, https_host, CONTENT_SETTINGS_TYPE_POPUPS, std::string()));
+  // Patterns generated for popups used to be domain scoped.
+  host_content_settings_map->SetContentSettingCustomScope(
+      ContentSettingsPattern::FromURL(https_host),
+      ContentSettingsPattern::Wildcard(), CONTENT_SETTINGS_TYPE_POPUPS,
+      std::string(), CONTENT_SETTING_ALLOW);
+  EXPECT_EQ(
+      CONTENT_SETTING_ALLOW,
+      host_content_settings_map->GetContentSetting(
+          https_host, https_host, CONTENT_SETTINGS_TYPE_POPUPS, std::string()));
+  // Settings also apply to subdomains.
+  EXPECT_EQ(CONTENT_SETTING_ALLOW,
+            host_content_settings_map->GetContentSetting(
+                https_host_narrower, https_host_narrower,
+                CONTENT_SETTINGS_TYPE_POPUPS, std::string()));
+
+  host_content_settings_map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_POPUPS,
+                                                   std::string(), &settings);
+  // |host_content_settings_map| contains default setting and a domain scoped
+  // setting.
+  EXPECT_EQ(2U, settings.size());
+  EXPECT_TRUE(settings[0].primary_pattern.ToString() ==
+              "https://[*.]example.com:443");
+  EXPECT_TRUE(settings[1].primary_pattern.ToString() == "*");
+
+  host_content_settings_map->MigrateDomainScopedSettings();
+
+  // After migration, settings only affect origins.
+  EXPECT_EQ(
+      CONTENT_SETTING_ALLOW,
+      host_content_settings_map->GetContentSetting(
+          http_host, http_host, CONTENT_SETTINGS_TYPE_COOKIES, std::string()));
+  EXPECT_EQ(CONTENT_SETTING_BLOCK,
+            host_content_settings_map->GetContentSetting(
+                http_host_narrower, http_host_narrower,
+                CONTENT_SETTINGS_TYPE_COOKIES, std::string()));
+  host_content_settings_map->GetSettingsForOneType(
+      CONTENT_SETTINGS_TYPE_COOKIES, std::string(), &settings);
+  // |host_content_settings_map| contains default setting and a origin scoped
+  // setting.
+  EXPECT_EQ(2U, settings.size());
+  EXPECT_TRUE(settings[0].primary_pattern.ToString() ==
+              "http://example.com:80");
+  EXPECT_TRUE(settings[1].primary_pattern.ToString() == "*");
+
+  EXPECT_EQ(
+      CONTENT_SETTING_ALLOW,
+      host_content_settings_map->GetContentSetting(
+          https_host, https_host, CONTENT_SETTINGS_TYPE_POPUPS, std::string()));
+  EXPECT_EQ(CONTENT_SETTING_BLOCK,
+            host_content_settings_map->GetContentSetting(
+                https_host_narrower, https_host_narrower,
+                CONTENT_SETTINGS_TYPE_POPUPS, std::string()));
+  host_content_settings_map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_POPUPS,
+                                                   std::string(), &settings);
+  // |host_content_settings_map| contains default setting and a origin scoped
+  // setting.
+  EXPECT_EQ(2U, settings.size());
+  EXPECT_TRUE(settings[0].primary_pattern.ToString() ==
+              "https://example.com:443");
+  EXPECT_TRUE(settings[1].primary_pattern.ToString() == "*");
+}
+
 TEST_F(HostContentSettingsMapTest, InvalidPattern) {
   // This is a regression test for crbug.com/618529, which fixed a memory leak
   // when a website setting was set under a URL that mapped to an invalid
diff --git a/chrome/browser/devtools/BUILD.gn b/chrome/browser/devtools/BUILD.gn
index 1d58c22f..76669503 100644
--- a/chrome/browser/devtools/BUILD.gn
+++ b/chrome/browser/devtools/BUILD.gn
@@ -13,10 +13,8 @@
     "//third_party/WebKit/Source/core/inspector:protocol_version",
   ]
   blink_protocol = "$root_gen_dir/blink/core/inspector/protocol.json"
-  browser_protocol = "//content/browser/devtools/browser_protocol.json"
   inputs = [
     blink_protocol,
-    browser_protocol,
   ]
   outputs = [
     "$target_gen_dir/devtools_protocol_constants.cc",
@@ -26,7 +24,6 @@
   args = [ "chrome" ]
   args += rebase_path(outputs, root_build_dir)
   args += [ rebase_path(blink_protocol, root_build_dir) ]
-  args += [ rebase_path(browser_protocol, root_build_dir) ]
 }
 
 # GYP version: chrome/chrome_debugger.gypi:debugger
diff --git a/chrome/browser/devtools/chrome_devtools_manager_delegate.cc b/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
index 3e683c86..9d61e11 100644
--- a/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
+++ b/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
@@ -6,6 +6,7 @@
 
 #include "build/build_config.h"
 #include "chrome/browser/devtools/devtools_network_protocol_handler.h"
+#include "components/devtools_discovery/devtools_discovery_manager.h"
 
 #if !defined(OS_ANDROID)
 #include "chrome/browser/devtools/devtools_window.h"
@@ -13,6 +14,8 @@
 #include "content/public/browser/devtools_agent_host.h"
 #endif  // !defined(OS_ANDROID)
 
+using devtools_discovery::DevToolsDiscoveryManager;
+
 ChromeDevToolsManagerDelegate::ChromeDevToolsManagerDelegate()
     : network_protocol_handler_(new DevToolsNetworkProtocolHandler()) {
 }
@@ -44,6 +47,11 @@
 base::DictionaryValue* ChromeDevToolsManagerDelegate::HandleCommand(
     content::DevToolsAgentHost* agent_host,
     base::DictionaryValue* command_dict) {
+  std::unique_ptr<base::DictionaryValue> result =
+      DevToolsDiscoveryManager::GetInstance()->HandleNewTargetCommand(
+          command_dict);
+  if (result)
+    return result.release();  // Caller takes ownership.
   return network_protocol_handler_->HandleCommand(agent_host, command_dict);
 }
 
diff --git a/chrome/browser/devtools/devtools_protocol_constants.gyp b/chrome/browser/devtools/devtools_protocol_constants.gyp
index 6e23876a..44ba629b 100644
--- a/chrome/browser/devtools/devtools_protocol_constants.gyp
+++ b/chrome/browser/devtools/devtools_protocol_constants.gyp
@@ -15,13 +15,11 @@
           'action_name': 'devtools_protocol_constants',
           'variables': {
             'blink_protocol': '<(SHARED_INTERMEDIATE_DIR)/blink/core/inspector/protocol.json',
-            'browser_protocol': '../../../content/browser/devtools/browser_protocol.json',
             'generator': 'devtools_protocol_constants_generator.py',
             'package': 'chrome'
           },
           'inputs': [
             '<(blink_protocol)',
-            '<(browser_protocol)',
             '<(generator)',
           ],
           'outputs': [
@@ -35,9 +33,8 @@
             '<(SHARED_INTERMEDIATE_DIR)/<(package)/browser/devtools/devtools_protocol_constants.cc',
             '<(SHARED_INTERMEDIATE_DIR)/<(package)/browser/devtools/devtools_protocol_constants.h',
             '<(blink_protocol)',
-            '<(browser_protocol)',
           ],
-          'message': 'Generating DevTools protocol constants from <(blink_protocol) and <(browser_protocol)'
+          'message': 'Generating DevTools protocol constants from <(blink_protocol)'
         }
       ],
     },
diff --git a/chrome/browser/devtools/devtools_protocol_constants_generator.py b/chrome/browser/devtools/devtools_protocol_constants_generator.py
index 1c84bbd..05c2853 100755
--- a/chrome/browser/devtools/devtools_protocol_constants_generator.py
+++ b/chrome/browser/devtools/devtools_protocol_constants_generator.py
@@ -11,7 +11,6 @@
 output_cc_path = sys.argv[2]
 output_h_path = sys.argv[3]
 blink_protocol_path = sys.argv[4]
-browser_protocol_path = sys.argv[5] if len(sys.argv) > 5 else None
 
 template_h = string.Template("""\
 // Copyright 2013 The Chromium Authors. All rights reserved.
@@ -24,8 +23,7 @@
 // THIS FILE IS AUTOGENERATED. DO NOT EDIT.
 // Generated by
 //  chrome/browser/devtools/devtools_protocol_constants_generator.py from
-//  gen/blink/core/inspector/protocol.json and
-//  content/browser/devtools/browser_protocol.json
+//  gen/blink/core/inspector/protocol.json
 
 #include <string>
 
@@ -53,8 +51,7 @@
 // THIS FILE IS AUTOGENERATED. DO NOT EDIT.
 // Generated by
 //  chrome/browser/devtools/devtools_protocol_constants_generator.py from
-//  gen/blink/core/inspector/protocol.json and
-//  content/browser/devtools/browser_protocol.json
+//  gen/blink/core/inspector/protocol.json
 
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
@@ -158,11 +155,6 @@
 
 domains = blink_protocol["domains"]
 
-if browser_protocol_path:
-  browser_protocol_data = open(browser_protocol_path).read()
-  browser_protocol = json.loads(browser_protocol_data)
-  domains = domains + browser_protocol["domains"]
-
 namespace_tree = {}
 
 for domain in domains:
diff --git a/chrome/browser/devtools/devtools_window_testing.cc b/chrome/browser/devtools/devtools_window_testing.cc
index 0cc7f9c..39f585e 100644
--- a/chrome/browser/devtools/devtools_window_testing.cc
+++ b/chrome/browser/devtools/devtools_window_testing.cc
@@ -197,9 +197,7 @@
 }
 
 DevToolsWindow* DevToolsWindowCreationObserver::devtools_window() {
-  if (devtools_windows_.empty())
-    return nullptr;
-  return devtools_windows_[devtools_windows_.size() - 1];
+  return !devtools_windows_.empty() ? devtools_windows_.back() : nullptr;
 }
 
 void DevToolsWindowCreationObserver::CloseAllSync() {
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index ca625e1..fc6b5fb 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -2558,8 +2558,10 @@
 EchoReferrerRequestHandler(const net::test_server::HttpRequest& request) {
   const std::string kReferrerHeader = "Referer";  // SIC
 
-  if (request.relative_url.find("/echoreferrer") != 0)
+  if (!base::StartsWith(request.relative_url, "/echoreferrer",
+                        base::CompareCase::SENSITIVE)) {
     return std::unique_ptr<net::test_server::HttpResponse>();
+  }
 
   std::unique_ptr<net::test_server::BasicHttpResponse> response(
       new net::test_server::BasicHttpResponse());
diff --git a/chrome/browser/download/download_request_limiter_unittest.cc b/chrome/browser/download/download_request_limiter_unittest.cc
index 17d79d1b..3583e49 100644
--- a/chrome/browser/download/download_request_limiter_unittest.cc
+++ b/chrome/browser/download/download_request_limiter_unittest.cc
@@ -100,7 +100,7 @@
   void SetUp(WebContents* web_contents) {
     PermissionBubbleManager::CreateForWebContents(web_contents);
     mock_permission_bubble_factory_.reset(new MockPermissionBubbleFactory(
-        false, PermissionBubbleManager::FromWebContents(web_contents)));
+        PermissionBubbleManager::FromWebContents(web_contents)));
     PermissionBubbleManager::FromWebContents(web_contents)
         ->DisplayPendingRequests();
   }
diff --git a/chrome/browser/engagement/site_engagement_score_unittest.cc b/chrome/browser/engagement/site_engagement_score_unittest.cc
index 1b1f6e7..1081851 100644
--- a/chrome/browser/engagement/site_engagement_score_unittest.cc
+++ b/chrome/browser/engagement/site_engagement_score_unittest.cc
@@ -33,7 +33,10 @@
   exploded_reference_time.second = 0;
   exploded_reference_time.millisecond = 0;
 
-  return base::Time::FromLocalExploded(exploded_reference_time);
+  base::Time out_time;
+  EXPECT_TRUE(
+      base::Time::FromLocalExploded(exploded_reference_time, &out_time));
+  return out_time;
 }
 
 }  // namespace
diff --git a/chrome/browser/engagement/site_engagement_service_unittest.cc b/chrome/browser/engagement/site_engagement_service_unittest.cc
index a2a864b9..3c409008 100644
--- a/chrome/browser/engagement/site_engagement_service_unittest.cc
+++ b/chrome/browser/engagement/site_engagement_service_unittest.cc
@@ -85,7 +85,10 @@
   exploded_reference_time.second = 0;
   exploded_reference_time.millisecond = 0;
 
-  return base::Time::FromLocalExploded(exploded_reference_time);
+  base::Time out_time;
+  EXPECT_TRUE(
+      base::Time::FromLocalExploded(exploded_reference_time, &out_time));
+  return out_time;
 }
 
 std::unique_ptr<KeyedService> BuildTestHistoryService(
diff --git a/chrome/browser/extensions/api/cookies/cookies_helpers.cc b/chrome/browser/extensions/api/cookies/cookies_helpers.cc
index 0ca4569..b507394 100644
--- a/chrome/browser/extensions/api/cookies/cookies_helpers.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_helpers.cc
@@ -134,7 +134,9 @@
   const std::string scheme =
       cookie.IsSecure() ? url::kHttpsScheme : url::kHttpScheme;
   const std::string host =
-      domain_key.find('.') != 0 ? domain_key : domain_key.substr(1);
+      base::StartsWith(domain_key, ".", base::CompareCase::SENSITIVE)
+          ? domain_key.substr(1)
+          : domain_key;
   return GURL(scheme + url::kStandardSchemeSeparator + host + "/");
 }
 
diff --git a/chrome/browser/extensions/api/debugger/debugger_api.cc b/chrome/browser/extensions/api/debugger/debugger_api.cc
index c20ff0fc..c3aa966 100644
--- a/chrome/browser/extensions/api/debugger/debugger_api.cc
+++ b/chrome/browser/extensions/api/debugger/debugger_api.cc
@@ -109,7 +109,8 @@
   int GetButtons() const override;
   bool Cancel() override;
 
-  std::string client_name_;
+ private:
+  const base::string16 client_name_;
   base::Closure dismissed_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(ExtensionDevToolsInfoBarDelegate);
@@ -119,7 +120,7 @@
     const base::Closure& dismissed_callback,
     const std::string& client_name)
     : ConfirmInfoBarDelegate(),
-      client_name_(client_name),
+      client_name_(base::UTF8ToUTF16(client_name)),
       dismissed_callback_(dismissed_callback) {}
 
 ExtensionDevToolsInfoBarDelegate::~ExtensionDevToolsInfoBarDelegate() {
@@ -147,8 +148,7 @@
 }
 
 base::string16 ExtensionDevToolsInfoBarDelegate::GetMessageText() const {
-  return l10n_util::GetStringFUTF16(IDS_DEV_TOOLS_INFOBAR_LABEL,
-                                    base::UTF8ToUTF16(client_name_));
+  return l10n_util::GetStringFUTF16(IDS_DEV_TOOLS_INFOBAR_LABEL, client_name_);
 }
 
 int ExtensionDevToolsInfoBarDelegate::GetButtons() const {
@@ -236,7 +236,7 @@
 
 void ExtensionDevToolsInfoBar::InfoBarDismissed() {
   std::map<ExtensionDevToolsClientHost*, base::Closure> copy = callbacks_;
-  for (const auto& pair: copy)
+  for (const auto& pair : copy)
     pair.second.Run();
 }
 
diff --git a/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate.cc b/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate.cc
index 98c9956..483482e 100644
--- a/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate.cc
+++ b/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate.cc
@@ -182,7 +182,7 @@
 
   const ScopedVector<SpellcheckHunspellDictionary>& dictionaries(
       service->GetHunspellDictionaries());
-  for (const auto& dictionary: dictionaries) {
+  for (const auto& dictionary : dictionaries) {
     hunspell_dictionaries_.push_back(dictionary->AsWeakPtr());
     if (should_listen)
       dictionary->AddObserver(this);
diff --git a/chrome/browser/extensions/convert_web_app_unittest.cc b/chrome/browser/extensions/convert_web_app_unittest.cc
index f61dfc7..21131f2 100644
--- a/chrome/browser/extensions/convert_web_app_unittest.cc
+++ b/chrome/browser/extensions/convert_web_app_unittest.cc
@@ -80,7 +80,9 @@
   exploded.minute = minute;
   exploded.second = second;
   exploded.millisecond = millisecond;
-  return base::Time::FromUTCExploded(exploded);
+  base::Time out_time;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
+  return out_time;
 }
 
 }  // namespace
diff --git a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
index a04d053..5544f4cb 100644
--- a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
+++ b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
@@ -168,7 +168,7 @@
 
   void RemoveAppHandler(const std::string& app_id) override {
     ExtensionGCMAppHandler::RemoveAppHandler(app_id);
-    if (!GetGCMDriver()->app_handlers().size())
+    if (GetGCMDriver()->app_handlers().empty())
       app_handler_count_drop_to_zero_ = true;
   }
 
diff --git a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
index 810b3a53..ad3a68d67 100644
--- a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
@@ -317,7 +317,7 @@
 
   // Create a MockPermissionBubbleFactory for the PermissionBubbleManager.
   mock_permission_bubble_factories_.push_back(base::WrapUnique(
-      new MockPermissionBubbleFactory(false, permission_bubble_manager)));
+      new MockPermissionBubbleFactory(permission_bubble_manager)));
 
   // Prepare the PermissionBubbleManager to display a mock bubble.
   permission_bubble_manager->DisplayPendingRequests();
diff --git a/chrome/browser/install_verification/win/module_list_unittest.cc b/chrome/browser/install_verification/win/module_list_unittest.cc
index cca65a6a..a9109073 100644
--- a/chrome/browser/install_verification/win/module_list_unittest.cc
+++ b/chrome/browser/install_verification/win/module_list_unittest.cc
@@ -44,7 +44,7 @@
   ASSERT_GT(module_list->size(), original_list_size);
 
   // Unload the module.
-  release_new_dll.Reset();
+  release_new_dll.RunAndReset();
 
   // Reset module_list here. That should typically be the last ref on
   // msvidc32.dll, so it will be unloaded now.
diff --git a/chrome/browser/media/router/BUILD.gn b/chrome/browser/media/router/BUILD.gn
index 8e149625..8389c16 100644
--- a/chrome/browser/media/router/BUILD.gn
+++ b/chrome/browser/media/router/BUILD.gn
@@ -6,11 +6,6 @@
 import("//mojo/public/tools/bindings/mojom.gni")
 import("//testing/test.gni")
 
-gypi_values = exec_script("//build/gypi_to_gn.py",
-                          [ rebase_path("media_router.gypi") ],
-                          "scope",
-                          [ "media_router.gypi" ])
-
 static_library("router") {
   deps = [
     "//base",
@@ -20,18 +15,65 @@
     "//content/public/browser",
     "//url",
   ]
-  sources = rebase_path(gypi_values.media_router_sources,
-                        ".",
-                        "//chrome/browser/media/router")
+  sources = [
+    "create_presentation_connection_request.cc",
+    "create_presentation_connection_request.h",
+    "issue.cc",
+    "issue.h",
+    "issue_manager.cc",
+    "issue_manager.h",
+    "issues_observer.cc",
+    "issues_observer.h",
+    "media_route.cc",
+    "media_route.h",
+    "media_router.h",
+    "media_router_base.cc",
+    "media_router_base.h",
+    "media_router_dialog_controller.cc",
+    "media_router_dialog_controller.h",
+    "media_router_factory.cc",
+    "media_router_factory.h",
+    "media_router_metrics.cc",
+    "media_router_metrics.h",
+    "media_routes_observer.cc",
+    "media_routes_observer.h",
+    "media_sink.cc",
+    "media_sink.h",
+    "media_sinks_observer.cc",
+    "media_sinks_observer.h",
+    "media_source.cc",
+    "media_source.h",
+    "media_source_helper.cc",
+    "media_source_helper.h",
+    "presentation_media_sinks_observer.cc",
+    "presentation_media_sinks_observer.h",
+    "presentation_request.cc",
+    "presentation_request.h",
+    "presentation_service_delegate_impl.cc",
+    "presentation_service_delegate_impl.h",
+    "presentation_session_messages_observer.cc",
+    "presentation_session_messages_observer.h",
+    "render_frame_host_id.h",
+    "route_request_result.cc",
+    "route_request_result.h",
+  ]
+
   if (!is_android) {
     deps += [
       ":mojo_bindings",
       "//extensions/browser",
       "//mojo/public/cpp/bindings",
     ]
-    sources += rebase_path(gypi_values.media_router_non_android_sources,
-                           ".",
-                           "//chrome/browser/media/router")
+    sources += [
+      "mojo/media_route_provider_util_win.cc",
+      "mojo/media_route_provider_util_win.h",
+      "mojo/media_router_mojo_impl.cc",
+      "mojo/media_router_mojo_impl.h",
+      "mojo/media_router_mojo_metrics.cc",
+      "mojo/media_router_mojo_metrics.h",
+      "mojo/media_router_type_converters.cc",
+      "mojo/media_router_type_converters.h",
+    ]
   }
 }
 
@@ -48,17 +90,23 @@
     "//chrome/test:test_support",
     "//testing/gmock",
   ]
-  sources = rebase_path(gypi_values.media_router_test_support_sources,
-                        ".",
-                        "//chrome/browser/media/router")
+  sources = [
+    "mock_media_router.cc",
+    "mock_media_router.h",
+    "mock_screen_availability_listener.cc",
+    "mock_screen_availability_listener.h",
+    "test_helper.cc",
+    "test_helper.h",
+  ]
+
   if (!is_android) {
     deps += [
       ":mojo_bindings",
       "//extensions/common",
     ]
-    sources +=
-        rebase_path(gypi_values.media_router_non_android_test_support_sources,
-                    ".",
-                    "//chrome/browser/media/router")
+    sources += [
+      "mojo/media_router_mojo_test.cc",
+      "mojo/media_router_mojo_test.h",
+    ]
   }
 }
diff --git a/chrome/browser/media/router/issue_manager.cc b/chrome/browser/media/router/issue_manager.cc
index 37d589f5..d3cb9d4 100644
--- a/chrome/browser/media/router/issue_manager.cc
+++ b/chrome/browser/media/router/issue_manager.cc
@@ -6,16 +6,20 @@
 
 #include <algorithm>
 
+#include "content/public/browser/browser_thread.h"
+
 namespace media_router {
 
 IssueManager::IssueManager() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 }
 
 IssueManager::~IssueManager() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 }
 
 void IssueManager::AddIssue(const Issue& issue) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   for (const Issue& next_issue : issues_) {
     if (next_issue.Equals(issue)) {
       return;
@@ -26,7 +30,7 @@
 }
 
 void IssueManager::ClearIssue(const Issue::Id& issue_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   issues_.erase(std::remove_if(issues_.begin(), issues_.end(),
                                [&issue_id](const Issue& issue) {
                                  return issue_id == issue.id();
@@ -36,18 +40,18 @@
 }
 
 size_t IssueManager::GetIssueCount() const {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   return issues_.size();
 }
 
 void IssueManager::ClearAllIssues() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   issues_.clear();
   MaybeUpdateTopIssue();
 }
 
 void IssueManager::ClearGlobalIssues() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   issues_.erase(
       std::remove_if(issues_.begin(), issues_.end(), [](const Issue& issue) {
         return issue.is_global();
@@ -56,7 +60,7 @@
 }
 
 void IssueManager::ClearIssuesWithRouteId(const MediaRoute::Id& route_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   issues_.erase(std::remove_if(issues_.begin(), issues_.end(),
                                [&route_id](const Issue& issue) {
                                  return route_id == issue.route_id();
@@ -66,28 +70,29 @@
 }
 
 void IssueManager::RegisterObserver(IssuesObserver* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(observer);
   DCHECK(!issues_observers_.HasObserver(observer));
 
   issues_observers_.AddObserver(observer);
-  if (!top_issue_id_.empty()) {
-    // Find the current top issue and report it to the observer.
-    for (const auto& next_issue : issues_) {
-      if (next_issue.id() == top_issue_id_) {
-        observer->OnIssueUpdated(&next_issue);
-      }
+  if (top_issue_id_.empty())
+    return;
+
+  // Find the current top issue and report it to the observer.
+  for (const auto& next_issue : issues_) {
+    if (next_issue.id() == top_issue_id_) {
+      observer->OnIssueUpdated(&next_issue);
     }
   }
 }
 
 void IssueManager::UnregisterObserver(IssuesObserver* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   issues_observers_.RemoveObserver(observer);
 }
 
 void IssueManager::MaybeUpdateTopIssue() {
-  Issue* new_top_issue = nullptr;
+  const Issue* new_top_issue = nullptr;
 
   if (issues_.empty()) {
     FOR_EACH_OBSERVER(IssuesObserver, issues_observers_,
@@ -98,10 +103,10 @@
   // Select the first blocking issue in the list of issues.
   // If there are none, simply select the first issue in the list.
   new_top_issue = &(issues_.front());
-  for (auto it = issues_.begin(); it != issues_.end(); ++it) {
+  for (const auto& issue : issues_) {
     // The first blocking issue is of higher priority than the first issue.
-    if (it->is_blocking()) {
-      new_top_issue = &(*it);
+    if (issue.is_blocking()) {
+      new_top_issue = &issue;
       break;
     }
   }
diff --git a/chrome/browser/media/router/issue_manager.h b/chrome/browser/media/router/issue_manager.h
index 51af2de..0c9ae27c 100644
--- a/chrome/browser/media/router/issue_manager.h
+++ b/chrome/browser/media/router/issue_manager.h
@@ -12,14 +12,13 @@
 #include "base/containers/hash_tables.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
-#include "base/threading/thread_checker.h"
 #include "chrome/browser/media/router/issue.h"
 #include "chrome/browser/media/router/issues_observer.h"
 
 namespace media_router {
 
 // IssueManager keeps track of current issues related to casting
-// connectivity and quality.
+// connectivity and quality. It lives on the UI thread.
 // TODO(apacible): Determine what other issues will be handled here.
 class IssueManager {
  public:
@@ -72,8 +71,6 @@
   // The ID of the current top issue.
   Issue::Id top_issue_id_;
 
-  base::ThreadChecker thread_checker_;
-
   DISALLOW_COPY_AND_ASSIGN(IssueManager);
 };
 
diff --git a/chrome/browser/media/router/issue_manager_unittest.cc b/chrome/browser/media/router/issue_manager_unittest.cc
index 351cce68..2c67b3c 100644
--- a/chrome/browser/media/router/issue_manager_unittest.cc
+++ b/chrome/browser/media/router/issue_manager_unittest.cc
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/media/router/issue_manager.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace media_router {
@@ -25,6 +26,7 @@
   IssueManagerUnitTest() {}
   ~IssueManagerUnitTest() override {}
 
+  content::TestBrowserThreadBundle thread_bundle_;
   IssueManager manager_;
 
  private:
diff --git a/chrome/browser/media/router/media_router_base.cc b/chrome/browser/media/router/media_router_base.cc
index fd8a50d0..b7b43c37 100644
--- a/chrome/browser/media/router/media_router_base.cc
+++ b/chrome/browser/media/router/media_router_base.cc
@@ -10,6 +10,7 @@
 #include "base/stl_util.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/browser_thread.h"
 
 namespace media_router {
 
@@ -51,7 +52,7 @@
 MediaRouterBase::AddPresentationConnectionStateChangedCallback(
     const MediaRoute::Id& route_id,
     const content::PresentationConnectionStateChangedCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   auto* callbacks = presentation_connection_state_callbacks_.get(route_id);
   if (!callbacks) {
diff --git a/chrome/browser/media/router/media_router_base.h b/chrome/browser/media/router/media_router_base.h
index edcfca3..92f29ca 100644
--- a/chrome/browser/media/router/media_router_base.h
+++ b/chrome/browser/media/router/media_router_base.h
@@ -12,7 +12,6 @@
 #include "base/containers/scoped_ptr_hash_map.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "base/threading/thread_checker.h"
 #include "chrome/browser/media/router/media_route.h"
 #include "chrome/browser/media/router/media_router.h"
 #include "chrome/browser/media/router/media_routes_observer.h"
@@ -64,8 +63,6 @@
       std::unique_ptr<PresentationConnectionStateChangedCallbacks>>
       presentation_connection_state_callbacks_;
 
-  base::ThreadChecker thread_checker_;
-
  private:
   friend class MediaRouterFactory;
   friend class MediaRouterMojoTest;
diff --git a/chrome/browser/media/router/media_router_dialog_controller.cc b/chrome/browser/media/router/media_router_dialog_controller.cc
index 1c89200c..ec8308ce 100644
--- a/chrome/browser/media/router/media_router_dialog_controller.cc
+++ b/chrome/browser/media/router/media_router_dialog_controller.cc
@@ -71,12 +71,12 @@
 }
 
 MediaRouterDialogController::~MediaRouterDialogController() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 }
 
 bool MediaRouterDialogController::ShowMediaRouterDialogForPresentation(
     std::unique_ptr<CreatePresentationConnectionRequest> request) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // Check if the media router dialog exists for |initiator| and return if so.
   if (IsShowingMediaRouterDialog())
@@ -89,14 +89,14 @@
   // Show the initiator holding the existing media router dialog.
   ActivateInitiatorWebContents();
 
-  media_router::MediaRouterMetrics::RecordMediaRouterDialogOrigin(
+  MediaRouterMetrics::RecordMediaRouterDialogOrigin(
       MediaRouterDialogOpenOrigin::PAGE);
 
   return true;
 }
 
 bool MediaRouterDialogController::ShowMediaRouterDialog() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // Don't create dialog if it already exists.
   bool dialog_needs_creation = !IsShowingMediaRouterDialog();
@@ -111,7 +111,7 @@
 }
 
 void MediaRouterDialogController::HideMediaRouterDialog() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   CloseMediaRouterDialog();
   Reset();
 }
diff --git a/chrome/browser/media/router/media_router_dialog_controller.h b/chrome/browser/media/router/media_router_dialog_controller.h
index faa3409..bf89f27 100644
--- a/chrome/browser/media/router/media_router_dialog_controller.h
+++ b/chrome/browser/media/router/media_router_dialog_controller.h
@@ -9,7 +9,6 @@
 #include <string>
 
 #include "base/macros.h"
-#include "base/threading/thread_checker.h"
 #include "chrome/browser/media/router/create_presentation_connection_request.h"
 #include "content/public/browser/web_contents_observer.h"
 
@@ -83,8 +82,6 @@
   // Closes the media router dialog if it exists.
   virtual void CloseMediaRouterDialog() = 0;
 
-  base::ThreadChecker thread_checker_;
-
  private:
   class InitiatorWebContentsObserver;
 
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
index 9ba4318..33189f86 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/media/router/mojo/media_router_type_converters.h"
 #include "chrome/browser/media/router/presentation_session_messages_observer.h"
 #include "chrome/browser/sessions/session_tab_helper.h"
+#include "content/public/browser/browser_thread.h"
 #include "extensions/browser/process_manager.h"
 
 #define DVLOG_WITH_INSTANCE(level) \
@@ -89,6 +90,7 @@
       availability_(interfaces::MediaRouter::SinkAvailability::UNAVAILABLE),
       current_wake_reason_(MediaRouteProviderWakeReason::TOTAL_COUNT),
       weak_factory_(this) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(event_page_tracker_);
 #if defined(OS_WIN)
   CanFirewallUseLocalPorts(
@@ -98,7 +100,7 @@
 }
 
 MediaRouterMojoImpl::~MediaRouterMojoImpl() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 }
 
 // static
@@ -116,7 +118,7 @@
 void MediaRouterMojoImpl::BindToMojoRequest(
     mojo::InterfaceRequest<interfaces::MediaRouter> request,
     const extensions::Extension& extension) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   binding_.reset(
       new mojo::Binding<interfaces::MediaRouter>(this, std::move(request)));
@@ -131,7 +133,7 @@
 }
 
 void MediaRouterMojoImpl::OnConnectionError() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   media_route_provider_.reset();
   binding_.reset();
@@ -152,7 +154,7 @@
     interfaces::MediaRouteProviderPtr media_route_provider_ptr,
     const interfaces::MediaRouter::RegisterMediaRouteProviderCallback&
         callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 #if defined(OS_WIN)
   // The MRPM may have been upgraded or otherwise reload such that we could be
   // seeing an MRPM that doesn't know mDNS is enabled, even if we've told a
@@ -191,7 +193,7 @@
 }
 
 void MediaRouterMojoImpl::OnIssue(const interfaces::IssuePtr issue) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DVLOG_WITH_INSTANCE(1) << "OnIssue " << issue->title;
   const Issue& issue_converted = issue.To<Issue>();
   issue_manager_.AddIssue(issue_converted);
@@ -201,7 +203,7 @@
     const mojo::String& media_source,
     mojo::Array<interfaces::MediaSinkPtr> sinks,
     mojo::Array<mojo::String> origins) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DVLOG_WITH_INSTANCE(1) << "OnSinksReceived";
   auto it = sinks_queries_.find(media_source);
   if (it == sinks_queries_.end()) {
@@ -245,7 +247,7 @@
     mojo::Array<interfaces::MediaRoutePtr> routes,
     const mojo::String& media_source,
     mojo::Array<mojo::String> joinable_route_ids) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   DVLOG_WITH_INSTANCE(1) << "OnRoutesUpdated";
   auto it = routes_queries_.find(media_source);
@@ -309,7 +311,7 @@
     const std::vector<MediaRouteResponseCallback>& callbacks,
     base::TimeDelta timeout,
     bool off_the_record) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   if (!origin.is_valid()) {
     DVLOG_WITH_INSTANCE(1) << "Invalid origin: " << origin;
@@ -337,7 +339,7 @@
     const std::vector<MediaRouteResponseCallback>& callbacks,
     base::TimeDelta timeout,
     bool off_the_record) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   std::unique_ptr<RouteRequestResult> error_result;
   if (!origin.is_valid()) {
@@ -372,7 +374,7 @@
     const std::vector<MediaRouteResponseCallback>& callbacks,
     base::TimeDelta timeout,
     bool off_the_record) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   if (!origin.is_valid()) {
     DVLOG_WITH_INSTANCE(1) << "Invalid origin: " << origin;
@@ -392,7 +394,7 @@
 }
 
 void MediaRouterMojoImpl::TerminateRoute(const MediaRoute::Id& route_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DVLOG(2) << "TerminateRoute " << route_id;
   SetWakeReason(MediaRouteProviderWakeReason::TERMINATE_ROUTE);
   RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoTerminateRoute,
@@ -400,7 +402,7 @@
 }
 
 void MediaRouterMojoImpl::DetachRoute(const MediaRoute::Id& route_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   SetWakeReason(MediaRouteProviderWakeReason::DETACH_ROUTE);
   RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoDetachRoute,
@@ -411,7 +413,7 @@
     const MediaRoute::Id& route_id,
     const std::string& message,
     const SendRouteMessageCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   SetWakeReason(MediaRouteProviderWakeReason::SEND_SESSION_MESSAGE);
   RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoSendSessionMessage,
@@ -422,7 +424,7 @@
     const MediaRoute::Id& route_id,
     std::unique_ptr<std::vector<uint8_t>> data,
     const SendRouteMessageCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   SetWakeReason(MediaRouteProviderWakeReason::SEND_SESSION_BINARY_MESSAGE);
   RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoSendSessionBinaryMessage,
@@ -431,12 +433,12 @@
 }
 
 void MediaRouterMojoImpl::AddIssue(const Issue& issue) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   issue_manager_.AddIssue(issue);
 }
 
 void MediaRouterMojoImpl::ClearIssue(const Issue::Id& issue_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   issue_manager_.ClearIssue(issue_id);
 }
 
@@ -456,7 +458,7 @@
     const std::string& search_input,
     const std::string& domain,
     const MediaSinkSearchResponseCallback& sink_callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   SetWakeReason(MediaRouteProviderWakeReason::SEARCH_SINKS);
   RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoSearchSinks,
@@ -466,7 +468,7 @@
 
 bool MediaRouterMojoImpl::RegisterMediaSinksObserver(
     MediaSinksObserver* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // Create an observer list for the media source and add |observer|
   // to it. Fail if |observer| is already registered.
@@ -502,7 +504,7 @@
 
 void MediaRouterMojoImpl::UnregisterMediaSinksObserver(
     MediaSinksObserver* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   const MediaSource::Id& source_id = observer->source().id();
   auto* sinks_query = sinks_queries_.get(source_id);
@@ -534,7 +536,7 @@
 
 void MediaRouterMojoImpl::RegisterMediaRoutesObserver(
     MediaRoutesObserver* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   const MediaSource::Id source_id = observer->source_id();
   auto* routes_query = routes_queries_.get(source_id);
   if (!routes_query) {
@@ -571,18 +573,18 @@
 }
 
 void MediaRouterMojoImpl::RegisterIssuesObserver(IssuesObserver* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   issue_manager_.RegisterObserver(observer);
 }
 
 void MediaRouterMojoImpl::UnregisterIssuesObserver(IssuesObserver* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   issue_manager_.UnregisterObserver(observer);
 }
 
 void MediaRouterMojoImpl::RegisterPresentationSessionMessagesObserver(
     PresentationSessionMessagesObserver* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(observer);
   const MediaRoute::Id& route_id = observer->route_id();
   auto* observer_list = messages_observers_.get(route_id);
@@ -603,7 +605,7 @@
 
 void MediaRouterMojoImpl::UnregisterPresentationSessionMessagesObserver(
     PresentationSessionMessagesObserver* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(observer);
 
   const MediaRoute::Id& route_id = observer->route_id();
@@ -956,7 +958,7 @@
 }
 
 void MediaRouterMojoImpl::ExecutePendingRequests() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(media_route_provider_);
   DCHECK(event_page_tracker_);
   DCHECK(!media_route_provider_extension_id_.empty());
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.h b/chrome/browser/media/router/mojo/media_router_mojo_impl.h
index 3d014bce..075fa1f 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl.h
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.h
@@ -45,6 +45,7 @@
 
 // MediaRouter implementation that delegates calls to the component extension.
 // Also handles the suspension and wakeup of the component extension.
+// Lives on the UI thread.
 class MediaRouterMojoImpl : public MediaRouterBase,
                             public interfaces::MediaRouter {
  public:
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl_unittest.cc b/chrome/browser/media/router/mojo/media_router_mojo_impl_unittest.cc
index 50d5bc8..c56fba5a 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl_unittest.cc
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl_unittest.cc
@@ -31,6 +31,7 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/version_info/version_info.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/process_manager.h"
 #include "extensions/browser/process_manager_factory.h"
@@ -134,7 +135,7 @@
 };
 
 class SinkResponseCallbackHandler {
-public:
+ public:
   MOCK_METHOD1(Invoke, void(const std::string& sink_id));
 };
 
@@ -1288,9 +1289,6 @@
   void TearDown() override {
     media_router_.reset();
     profile_.reset();
-    // Explicitly delete the TestingBrowserProcess before |message_loop_|.
-    // This allows it to do cleanup before |message_loop_| goes away.
-    TestingBrowserProcess::DeleteInstance();
   }
 
   // Constructs bindings so that |media_router_| delegates calls to
@@ -1340,6 +1338,7 @@
                                         expected_count);
   }
 
+  content::TestBrowserThreadBundle thread_bundle_;
   std::unique_ptr<MediaRouterMojoImpl> media_router_;
   RegisterMediaRouteProviderHandler provide_handler_;
   TestProcessManager* process_manager_;
@@ -1349,7 +1348,6 @@
 
  private:
   std::unique_ptr<TestingProfile> profile_;
-  base::MessageLoop message_loop_;
   interfaces::MediaRouteProviderPtr media_route_provider_proxy_;
   std::unique_ptr<mojo::Binding<interfaces::MediaRouteProvider>> binding_;
   base::HistogramTester histogram_tester_;
diff --git a/chrome/browser/media/webrtc_event_log_handler.cc b/chrome/browser/media/webrtc_event_log_handler.cc
index 0d9bacc..e5f6d49 100644
--- a/chrome/browser/media/webrtc_event_log_handler.cc
+++ b/chrome/browser/media/webrtc_event_log_handler.cc
@@ -31,14 +31,13 @@
                                            uint64_t rtc_event_log_id) {
   static const char kWebRtcEventLogFilePrefix[] = "WebRtcEventLog.";
   return directory.AppendASCII(kWebRtcEventLogFilePrefix +
-                               base::Int64ToString(rtc_event_log_id));
+                               base::Uint64ToString(rtc_event_log_id));
 }
 
 }  // namespace
 
 WebRtcEventLogHandler::WebRtcEventLogHandler(Profile* profile)
     : profile_(profile),
-      is_rtc_event_logging_in_progress_(false),
       current_rtc_event_log_id_(0) {
   DCHECK(profile_);
   thread_checker_.DetachFromThread();
@@ -94,16 +93,13 @@
     const base::FilePath& log_directory) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  if (is_rtc_event_logging_in_progress_) {
+  base::FilePath prefix_path =
+      GetWebRtcEventLogPrefixPath(log_directory, ++current_rtc_event_log_id_);
+  if (!host->StartWebRTCEventLog(prefix_path)) {
     error_callback.Run("RTC event logging already in progress");
     return;
   }
 
-  is_rtc_event_logging_in_progress_ = true;
-  base::FilePath prefix_path =
-      GetWebRtcEventLogPrefixPath(log_directory, ++current_rtc_event_log_id_);
-  host->EnableEventLogRecordings(prefix_path);
-
   if (delay.is_zero()) {
     const bool is_stopped = false, is_manual_stop = false;
     callback.Run(prefix_path.AsUTF8Unsafe(), is_stopped, is_manual_stop);
@@ -142,13 +138,11 @@
     return;
   }
 
-  if (!is_rtc_event_logging_in_progress_) {
+  if (!host->StopWebRTCEventLog()) {
     error_callback.Run("No RTC event logging in progress");
     return;
   }
 
-  host->DisableEventLogRecordings();
-  is_rtc_event_logging_in_progress_ = false;
   const bool is_stopped = true;
   callback.Run(prefix_path.AsUTF8Unsafe(), is_stopped, is_manual_stop);
 }
diff --git a/chrome/browser/media/webrtc_event_log_handler.h b/chrome/browser/media/webrtc_event_log_handler.h
index 33eaa5c..985b7ee 100644
--- a/chrome/browser/media/webrtc_event_log_handler.h
+++ b/chrome/browser/media/webrtc_event_log_handler.h
@@ -36,8 +36,9 @@
 
   explicit WebRtcEventLogHandler(Profile* profile);
 
-  // Starts an RTC event log. The call writes the most recent events to a
-  // file and then starts logging events for the given |delay|.
+  // Starts an RTC event log for each peerconnection on the specified |host|.
+  // The call writes the most recent events to a file and then starts logging
+  // events for the given |delay|.
   // If |delay| is zero, the logging will continue until
   // StopWebRtcEventLogging()
   // is explicitly invoked.
@@ -81,9 +82,6 @@
   // The profile associated with our renderer process.
   Profile* const profile_;
 
-  // Must be accessed on the UI thread.
-  bool is_rtc_event_logging_in_progress_;
-
   // This counter allows saving each log in a separate file.
   uint64_t current_rtc_event_log_id_;
 
diff --git a/chrome/browser/media/webrtc_log_uploader_unittest.cc b/chrome/browser/media/webrtc_log_uploader_unittest.cc
index 1271bb3..ff257c51 100644
--- a/chrome/browser/media/webrtc_log_uploader_unittest.cc
+++ b/chrome/browser/media/webrtc_log_uploader_unittest.cc
@@ -131,8 +131,8 @@
     EXPECT_GT(lines.size(), 1u);
     if (lines.size() < 2)
       return std::vector<std::string>();
-    EXPECT_TRUE(lines[lines.size() - 1].empty());
-    if (!lines[lines.size() - 1].empty())
+    EXPECT_TRUE(lines.back().empty());
+    if (!lines.back().empty())
       return std::vector<std::string>();
     lines.pop_back();
     return lines;
diff --git a/chrome/browser/media_galleries/fileapi/itunes_data_provider_browsertest.cc b/chrome/browser/media_galleries/fileapi/itunes_data_provider_browsertest.cc
index 00f9d62..389dbaf 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_data_provider_browsertest.cc
+++ b/chrome/browser/media_galleries/fileapi/itunes_data_provider_browsertest.cc
@@ -169,7 +169,7 @@
                        base::Unretained(this))));
     data_provider()->RefreshData(base::Bind(&ITunesDataProviderTest::StartTest,
                                             base::Unretained(this)));
-  };
+  }
 
   void OnLibraryChanged() {
     DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
@@ -402,10 +402,10 @@
   DISALLOW_COPY_AND_ASSIGN(ITunesDataProviderUniqueNameTest);
 };
 
+// Albums and tracks that aren't the same, but become the same after
+// replacing bad characters are not handled properly, but that case should
+// never happen in practice.
 class ITunesDataProviderEscapeTest : public ITunesDataProviderTest {
- // Albums and tracks that aren't the same, but become the same after
- // replacing bad characters are not handled properly, but that case should
- // never happen in practice.
  public:
   ITunesDataProviderEscapeTest() {}
 
diff --git a/chrome/browser/media_galleries/fileapi/picasa_file_util_unittest.cc b/chrome/browser/media_galleries/fileapi/picasa_file_util_unittest.cc
index e106960..33c4f54 100644
--- a/chrome/browser/media_galleries/fileapi/picasa_file_util_unittest.cc
+++ b/chrome/browser/media_galleries/fileapi/picasa_file_util_unittest.cc
@@ -100,8 +100,9 @@
 
   double GetVariantTimestamp() const {
     DCHECK(!folder_dir_.path().empty());
-    base::Time variant_epoch = base::Time::FromLocalExploded(
-        picasa::kPmpVariantTimeEpoch);
+    base::Time variant_epoch;
+    EXPECT_TRUE(base::Time::FromLocalExploded(picasa::kPmpVariantTimeEpoch,
+                                              &variant_epoch));
 
     int64_t microseconds_since_epoch =
         (folder_info_.timestamp - variant_epoch).InMicroseconds();
@@ -387,10 +388,12 @@
 
 TEST_F(PicasaFileUtilTest, DateFormat) {
   base::Time::Exploded exploded_shortmonth = { 2013, 4, 0, 16, 0, 0, 0, 0 };
-  base::Time shortmonth = base::Time::FromLocalExploded(exploded_shortmonth);
+  base::Time shortmonth;
+  EXPECT_TRUE(base::Time::FromLocalExploded(exploded_shortmonth, &shortmonth));
 
   base::Time::Exploded exploded_shortday = { 2013, 11, 0, 3, 0, 0, 0, 0 };
-  base::Time shortday = base::Time::FromLocalExploded(exploded_shortday);
+  base::Time shortday;
+  EXPECT_TRUE(base::Time::FromLocalExploded(exploded_shortday, &shortday));
 
   EXPECT_EQ("2013-04-16", DateToPathString(shortmonth));
   EXPECT_EQ("2013-11-03", DateToPathString(shortday));
@@ -400,7 +403,8 @@
   ScopedVector<TestFolder> test_folders;
   std::vector<std::string> expected_names;
 
-  base::Time test_date = base::Time::FromLocalExploded(test_date_exploded);
+  base::Time test_date;
+  EXPECT_TRUE(base::Time::FromLocalExploded(test_date_exploded, &test_date));
   base::Time test_date_2 = test_date - base::TimeDelta::FromDays(1);
 
   std::string test_date_string = DateToPathString(test_date);
@@ -472,7 +476,8 @@
 
 TEST_F(PicasaFileUtilTest, FolderContentsTrivial) {
   ScopedVector<TestFolder> test_folders;
-  base::Time test_date = base::Time::FromLocalExploded(test_date_exploded);
+  base::Time test_date;
+  EXPECT_TRUE(base::Time::FromLocalExploded(test_date_exploded, &test_date));
 
   test_folders.push_back(
       new TestFolder("folder-1-empty", test_date, "uid-empty", 0, 0));
@@ -489,7 +494,8 @@
 
 TEST_F(PicasaFileUtilTest, FolderWithManyFiles) {
   ScopedVector<TestFolder> test_folders;
-  base::Time test_date = base::Time::FromLocalExploded(test_date_exploded);
+  base::Time test_date;
+  EXPECT_TRUE(base::Time::FromLocalExploded(test_date_exploded, &test_date));
 
   test_folders.push_back(
       new TestFolder("folder-many-files", test_date, "uid-both", 50, 50));
@@ -500,7 +506,8 @@
 
 TEST_F(PicasaFileUtilTest, ManyFolders) {
   ScopedVector<TestFolder> test_folders;
-  base::Time test_date = base::Time::FromLocalExploded(test_date_exploded);
+  base::Time test_date;
+  EXPECT_TRUE(base::Time::FromLocalExploded(test_date_exploded, &test_date));
 
   for (unsigned int i = 0; i < 50; ++i) {
     base::Time date = test_date - base::TimeDelta::FromDays(i);
@@ -517,7 +524,8 @@
 
 TEST_F(PicasaFileUtilTest, AlbumExistence) {
   ScopedVector<TestFolder> test_folders;
-  base::Time test_date = base::Time::FromLocalExploded(test_date_exploded);
+  base::Time test_date;
+  EXPECT_TRUE(base::Time::FromLocalExploded(test_date_exploded, &test_date));
 
   std::vector<AlbumInfo> albums;
   AlbumInfo info;
@@ -539,7 +547,8 @@
 
 TEST_F(PicasaFileUtilTest, AlbumContents) {
   ScopedVector<TestFolder> test_folders;
-  base::Time test_date = base::Time::FromLocalExploded(test_date_exploded);
+  base::Time test_date;
+  EXPECT_TRUE(base::Time::FromLocalExploded(test_date_exploded, &test_date));
 
   std::vector<AlbumInfo> albums;
   AlbumInfo info;
diff --git a/chrome/browser/net/firefox_proxy_settings.cc b/chrome/browser/net/firefox_proxy_settings.cc
index 15fb3a7..59f217d2 100644
--- a/chrome/browser/net/firefox_proxy_settings.cc
+++ b/chrome/browser/net/firefox_proxy_settings.cc
@@ -113,8 +113,7 @@
     }
 
     // Value could be a string.
-    if (value.size() >= 2U &&
-        value[0] == '"' && value[value.size() - 1] == '"') {
+    if (value.size() >= 2U && value[0] == '"' && value.back() == '"') {
       value = value.substr(1, value.size() - 2);
       // ValueString only accept valid UTF-8.  Simply ignore that entry if it is
       // not UTF-8.
diff --git a/chrome/browser/ntp_snippets/OWNERS b/chrome/browser/ntp_snippets/OWNERS
index 16d46010..c7f9cc3f 100644
--- a/chrome/browser/ntp_snippets/OWNERS
+++ b/chrome/browser/ntp_snippets/OWNERS
@@ -1,2 +1 @@
-noyau@chromium.org
-bauerb@chromium.org
+file://components/ntp_snippets/OWNERS
diff --git a/chrome/browser/ntp_snippets/ntp_snippets_service_factory.cc b/chrome/browser/ntp_snippets/ntp_snippets_service_factory.cc
index b9216e7..ab7bfc0 100644
--- a/chrome/browser/ntp_snippets/ntp_snippets_service_factory.cc
+++ b/chrome/browser/ntp_snippets/ntp_snippets_service_factory.cc
@@ -80,9 +80,9 @@
 
   // TODO(mvanouwerkerk): Move the enable logic into the service once we start
   // observing pref changes.
-  bool enabled = profile->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled);
+  bool enabled = false;
 #if defined(OS_ANDROID)
-  enabled = enabled &&
+  enabled = profile->GetPrefs()->GetBoolean(prefs::kSearchSuggestEnabled) &&
             base::FeatureList::IsEnabled(chrome::android::kNTPSnippetsFeature);
 #endif  // OS_ANDROID
 
diff --git a/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc b/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc
index 4211e7f..d892a71a 100644
--- a/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc
+++ b/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc
@@ -143,6 +143,22 @@
   EXPECT_TRUE(result);
 }
 
+void WriteHTMLAttributes(const PasswordForm& form, base::Pickle* pickle) {
+  pickle->WriteInt(form.scheme);
+  pickle->WriteString(form.origin.spec());
+  pickle->WriteString(form.action.spec());
+  pickle->WriteString16(form.username_element);
+  pickle->WriteString16(form.username_value);
+  pickle->WriteString16(form.password_element);
+  pickle->WriteString16(form.password_value);
+  pickle->WriteString16(form.submit_element);
+}
+
+void WritePreferenceMetadata(const PasswordForm& form, base::Pickle* pickle) {
+  pickle->WriteBool(form.preferred);
+  pickle->WriteBool(form.blacklisted_by_user);
+}
+
 }  // anonymous namespace
 
 // Obscure magic: we need to declare storage for this constant because we use it
@@ -1139,9 +1155,12 @@
                                 base::Pickle* pickle,
                                 int stored_version,
                                 int effective_version);
+  // If |size_32| is true, stores the number of forms in the pickle as a 32bit
+  // uint, otherwise as 64 bit size_t.
   void CreateVersion0Pickle(bool size_32,
                             const PasswordForm& form,
                             base::Pickle* pickle);
+  void CheckVersion8Pickle();
   void CheckVersion7Pickle();
   // As explained in http://crbug.com/494229#c11, version 6 added a new optional
   // field to version 5. This field became required in version 7. Depending on
@@ -1153,16 +1172,6 @@
   void CheckVersion2Pickle();
   void CheckVersion1Pickle();
   void CheckVersion0Pickle(bool size_32, PasswordForm::Scheme scheme);
-
- private:
-  // Creates a Pickle from |form|. If |size_32| is true, stores the number of
-  // forms in the pickle as a 32bit uint, otherwise as 64 bit size_t. The latter
-  // should be the case for versions > 0. If |date_created_internal| is true,
-  // stores |date_created| as base::Time's internal value, otherwise as time_t.
-  void CreatePickle(bool size_32,
-                    bool date_created_internal,
-                    const PasswordForm& form,
-                    base::Pickle* pickle);
 };
 
 void NativeBackendKWalletPickleTest::CreateVersion1PlusPickle(
@@ -1171,7 +1180,11 @@
     int stored_version,
     int effective_version) {
   pickle->WriteInt(stored_version);
-  CreatePickle(false, true, form, pickle);
+  pickle->WriteUInt64(1);  // Number of forms in the pickle.
+  WriteHTMLAttributes(form, pickle);
+  pickle->WriteBool(form.ssl_valid);
+  WritePreferenceMetadata(form, pickle);
+  pickle->WriteInt64(form.date_created.ToInternalValue());
   if (effective_version < 2)
     return;
   pickle->WriteInt(form.type);
@@ -1196,32 +1209,31 @@
     const PasswordForm& form,
     base::Pickle* pickle) {
   pickle->WriteInt(0);
-  CreatePickle(size_32, false, form, pickle);
+  // Write the number of forms in the pickle in the appopriate bit size.
+  if (size_32)
+    pickle->WriteUInt32(1);
+  else
+    pickle->WriteUInt64(1);
+  WriteHTMLAttributes(form, pickle);
+  pickle->WriteBool(form.ssl_valid);
+  WritePreferenceMetadata(form, pickle);
+  // Old way to store the date.
+  pickle->WriteInt64(form.date_created.ToTimeT());
 }
 
-void NativeBackendKWalletPickleTest::CreatePickle(bool size_32,
-                                                  bool date_created_internal,
-                                                  const PasswordForm& form,
-                                                  base::Pickle* pickle) {
-  if (size_32)
-    pickle->WriteUInt32(1);  // Size of form list. 32 bits.
-  else
-    pickle->WriteUInt64(1);  // Size of form list. 64 bits.
-  pickle->WriteInt(form.scheme);
-  pickle->WriteString(form.origin.spec());
-  pickle->WriteString(form.action.spec());
-  pickle->WriteString16(form.username_element);
-  pickle->WriteString16(form.username_value);
-  pickle->WriteString16(form.password_element);
-  pickle->WriteString16(form.password_value);
-  pickle->WriteString16(form.submit_element);
-  pickle->WriteBool(form.ssl_valid);
-  pickle->WriteBool(form.preferred);
-  pickle->WriteBool(form.blacklisted_by_user);
-  if (date_created_internal)
-    pickle->WriteInt64(form.date_created.ToInternalValue());
-  else
-    pickle->WriteInt64(form.date_created.ToTimeT());
+void NativeBackendKWalletPickleTest::CheckVersion8Pickle() {
+  base::Pickle pickle;
+  PasswordForm default_values;
+  PasswordForm form = form_google_;
+
+  // Version 8 pickles deserialize with their own 'skip_zero_click' value.
+  form.skip_zero_click = false;
+  CreateVersion1PlusPickle(form, &pickle, 8, 8);
+  ScopedVector<PasswordForm> form_list =
+      NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle);
+  EXPECT_EQ(1u, form_list.size());
+  if (form_list.size() > 0)
+    CheckPasswordForm(form, *form_list[0], true);
 }
 
 void NativeBackendKWalletPickleTest::CheckVersion7Pickle() {
@@ -1238,15 +1250,6 @@
   form.skip_zero_click = true;
   if (form_list.size() > 0)
     CheckPasswordForm(form, *form_list[0], true);
-
-  // Version 8 pickles deserialize with their own 'skip_zero_click' value.
-  form.skip_zero_click = false;
-  CreateVersion1PlusPickle(form, &pickle, 8, 8);
-  form_list =
-      NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle);
-  EXPECT_EQ(1u, form_list.size());
-  if (form_list.size() > 0)
-    CheckPasswordForm(form, *form_list[0], true);
 }
 
 void NativeBackendKWalletPickleTest::CheckVersion6Pickle(
@@ -1392,3 +1395,11 @@
   CheckVersion6Pickle(false);
   CheckVersion6Pickle(true);
 }
+
+TEST_F(NativeBackendKWalletPickleTest, CheckVersion7Pickle) {
+  CheckVersion7Pickle();
+}
+
+TEST_F(NativeBackendKWalletPickleTest, CheckVersion8Pickle) {
+  CheckVersion8Pickle();
+}
diff --git a/chrome/browser/password_manager/password_store_mac.cc b/chrome/browser/password_manager/password_store_mac.cc
index 63dca04..fb82842 100644
--- a/chrome/browser/password_manager/password_store_mac.cc
+++ b/chrome/browser/password_manager/password_store_mac.cc
@@ -279,8 +279,7 @@
 }
 
 // Converts a Keychain time string to a Time object, returning true if
-// time_string_bytes was parsable. If the return value is false, the value of
-// |time| is unchanged.
+// time_string_bytes was parsable.
 bool TimeFromKeychainTimeString(const char* time_string_bytes,
                                 unsigned int byte_length,
                                 base::Time* time) {
@@ -298,11 +297,7 @@
                            &exploded_time.minute, &exploded_time.second);
   free(time_string);
 
-  if (assignments == 6) {
-    *time = base::Time::FromUTCExploded(exploded_time);
-    return true;
-  }
-  return false;
+  return assignments == 6 && base::Time::FromUTCExploded(exploded_time, time);
 }
 
 // Returns the PasswordForm Scheme corresponding to |auth_type|.
diff --git a/chrome/browser/password_manager/password_store_mac_unittest.cc b/chrome/browser/password_manager/password_store_mac_unittest.cc
index cc23104..b0cc46f 100644
--- a/chrome/browser/password_manager/password_store_mac_unittest.cc
+++ b/chrome/browser/password_manager/password_store_mac_unittest.cc
@@ -68,8 +68,7 @@
   *target_form_ptr = *arg0[0];
 }
 
-void Noop() {
-}
+void Noop() {}
 
 class MockPasswordStoreConsumer : public PasswordStoreConsumer {
  public:
@@ -108,7 +107,7 @@
 
 // Macro to simplify calling CheckFormsAgainstExpectations with a useful label.
 #define CHECK_FORMS(forms, expectations, i) \
-    CheckFormsAgainstExpectations(forms, expectations, #forms, i)
+  CheckFormsAgainstExpectations(forms, expectations, #forms, i)
 
 // Ensures that the data in |forms| match |expectations|, causing test failures
 // for any discrepencies.
@@ -118,7 +117,8 @@
     const std::vector<PasswordForm*>& forms,
     const std::vector<PasswordFormData*>& expectations,
 
-    const char* forms_label, unsigned int test_number) {
+    const char* forms_label,
+    unsigned int test_number) {
   EXPECT_EQ(expectations.size(), forms.size()) << forms_label << " in test "
                                                << test_number;
   if (expectations.size() != forms.size())
@@ -255,115 +255,43 @@
   void SetUp() override {
     MockAppleKeychain::KeychainTestData test_data[] = {
         // Basic HTML form.
-        {kSecAuthenticationTypeHTMLForm,
-         "some.domain.com",
-         kSecProtocolTypeHTTP,
-         NULL,
-         0,
-         NULL,
-         "20020601171500Z",
-         "joe_user",
-         "sekrit",
-         false},
+        {kSecAuthenticationTypeHTMLForm, "some.domain.com",
+         kSecProtocolTypeHTTP, NULL, 0, NULL, "20020601171500Z", "joe_user",
+         "sekrit", false},
         // HTML form with path.
-        {kSecAuthenticationTypeHTMLForm,
-         "some.domain.com",
-         kSecProtocolTypeHTTP,
-         "/insecure.html",
-         0,
-         NULL,
-         "19991231235959Z",
-         "joe_user",
-         "sekrit",
-         false},
+        {kSecAuthenticationTypeHTMLForm, "some.domain.com",
+         kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "19991231235959Z",
+         "joe_user", "sekrit", false},
         // Secure HTML form with path.
-        {kSecAuthenticationTypeHTMLForm,
-         "some.domain.com",
-         kSecProtocolTypeHTTPS,
-         "/secure.html",
-         0,
-         NULL,
-         "20100908070605Z",
-         "secure_user",
-         "password",
-         false},
+        {kSecAuthenticationTypeHTMLForm, "some.domain.com",
+         kSecProtocolTypeHTTPS, "/secure.html", 0, NULL, "20100908070605Z",
+         "secure_user", "password", false},
         // True negative item.
-        {kSecAuthenticationTypeHTMLForm,
-         "dont.remember.com",
-         kSecProtocolTypeHTTP,
-         NULL,
-         0,
-         NULL,
-         "20000101000000Z",
-         "",
-         "",
-         true},
+        {kSecAuthenticationTypeHTMLForm, "dont.remember.com",
+         kSecProtocolTypeHTTP, NULL, 0, NULL, "20000101000000Z", "", "", true},
         // De-facto negative item, type one.
-        {kSecAuthenticationTypeHTMLForm,
-         "dont.remember.com",
-         kSecProtocolTypeHTTP,
-         NULL,
-         0,
-         NULL,
-         "20000101000000Z",
-         "Password Not Stored",
-         "",
-         false},
+        {kSecAuthenticationTypeHTMLForm, "dont.remember.com",
+         kSecProtocolTypeHTTP, NULL, 0, NULL, "20000101000000Z",
+         "Password Not Stored", "", false},
         // De-facto negative item, type two.
-        {kSecAuthenticationTypeHTMLForm,
-         "dont.remember.com",
-         kSecProtocolTypeHTTPS,
-         NULL,
-         0,
-         NULL,
-         "20000101000000Z",
-         "Password Not Stored",
-         " ",
-         false},
+        {kSecAuthenticationTypeHTMLForm, "dont.remember.com",
+         kSecProtocolTypeHTTPS, NULL, 0, NULL, "20000101000000Z",
+         "Password Not Stored", " ", false},
         // HTTP auth basic, with port and path.
-        {kSecAuthenticationTypeHTTPBasic,
-         "some.domain.com",
-         kSecProtocolTypeHTTP,
-         "/insecure.html",
-         4567,
-         "low_security",
-         "19980330100000Z",
-         "basic_auth_user",
-         "basic",
-         false},
+        {kSecAuthenticationTypeHTTPBasic, "some.domain.com",
+         kSecProtocolTypeHTTP, "/insecure.html", 4567, "low_security",
+         "19980330100000Z", "basic_auth_user", "basic", false},
         // HTTP auth digest, secure.
-        {kSecAuthenticationTypeHTTPDigest,
-         "some.domain.com",
-         kSecProtocolTypeHTTPS,
-         NULL,
-         0,
-         "high_security",
-         "19980330100000Z",
-         "digest_auth_user",
-         "digest",
-         false},
+        {kSecAuthenticationTypeHTTPDigest, "some.domain.com",
+         kSecProtocolTypeHTTPS, NULL, 0, "high_security", "19980330100000Z",
+         "digest_auth_user", "digest", false},
         // An FTP password with an invalid date, for edge-case testing.
-        {kSecAuthenticationTypeDefault,
-         "a.server.com",
-         kSecProtocolTypeFTP,
-         NULL,
-         0,
-         NULL,
-         "20010203040",
-         "abc",
-         "123",
-         false},
+        {kSecAuthenticationTypeDefault, "a.server.com", kSecProtocolTypeFTP,
+         NULL, 0, NULL, "20010203040", "abc", "123", false},
         // Password for an Android application.
-        {kSecAuthenticationTypeHTMLForm,
-         "android://hash@com.domain.some/",
-         kSecProtocolTypeHTTPS,
-         "",
-         0,
-         NULL,
-         "20150515141312Z",
-         "joe_user",
-         "secret",
-         false},
+        {kSecAuthenticationTypeHTMLForm, "android://hash@com.domain.some/",
+         kSecProtocolTypeHTTPS, "", 0, NULL, "20150515141312Z", "joe_user",
+         "secret", false},
     };
 
     keychain_ = new MockAppleKeychain();
@@ -417,41 +345,37 @@
   } TestExpectations;
 
   TestExpectations expected[] = {
-    { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-      "http://some.domain.com/", L"joe_user", L"sekrit", false,
-      2002,  6,  1, 17, 15,  0 },
-    { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-      "http://some.domain.com/insecure.html", L"joe_user", L"sekrit", false,
-      1999, 12, 31, 23, 59, 59 },
-    { PasswordForm::SCHEME_HTML, "https://some.domain.com/",
-      "https://some.domain.com/secure.html", L"secure_user", L"password", true,
-      2010,  9,  8,  7,  6,  5 },
-    { PasswordForm::SCHEME_HTML, "http://dont.remember.com/",
-      "http://dont.remember.com/", NULL, NULL, false,
-      2000,  1,  1,  0,  0,  0 },
-    { PasswordForm::SCHEME_HTML, "http://dont.remember.com/",
-      "http://dont.remember.com/", NULL, NULL, false,
-      2000,  1,  1,  0,  0,  0 },
-    { PasswordForm::SCHEME_HTML, "https://dont.remember.com/",
-      "https://dont.remember.com/", NULL, NULL, true,
-      2000,  1,  1,  0,  0,  0 },
-    { PasswordForm::SCHEME_BASIC, "http://some.domain.com:4567/low_security",
-      "http://some.domain.com:4567/insecure.html", L"basic_auth_user", L"basic",
-      false, 1998, 03, 30, 10, 00, 00 },
-    { PasswordForm::SCHEME_DIGEST, "https://some.domain.com/high_security",
-      "https://some.domain.com/", L"digest_auth_user", L"digest", true,
-      1998,  3, 30, 10,  0,  0 },
-    // This one gives us an invalid date, which we will treat as a "NULL" date
-    // which is 1601.
-    { PasswordForm::SCHEME_OTHER, "http://a.server.com/",
-      "http://a.server.com/", L"abc", L"123", false,
-      1601,  1,  1,  0,  0,  0 },
-    { PasswordForm::SCHEME_HTML, "android://hash@com.domain.some/",
-      "", L"joe_user", L"secret", true,
-      2015,  5,  15, 14, 13, 12 },
+      {PasswordForm::SCHEME_HTML, "http://some.domain.com/",
+       "http://some.domain.com/", L"joe_user", L"sekrit", false, 2002, 6, 1, 17,
+       15, 0},
+      {PasswordForm::SCHEME_HTML, "http://some.domain.com/",
+       "http://some.domain.com/insecure.html", L"joe_user", L"sekrit", false,
+       1999, 12, 31, 23, 59, 59},
+      {PasswordForm::SCHEME_HTML, "https://some.domain.com/",
+       "https://some.domain.com/secure.html", L"secure_user", L"password", true,
+       2010, 9, 8, 7, 6, 5},
+      {PasswordForm::SCHEME_HTML, "http://dont.remember.com/",
+       "http://dont.remember.com/", NULL, NULL, false, 2000, 1, 1, 0, 0, 0},
+      {PasswordForm::SCHEME_HTML, "http://dont.remember.com/",
+       "http://dont.remember.com/", NULL, NULL, false, 2000, 1, 1, 0, 0, 0},
+      {PasswordForm::SCHEME_HTML, "https://dont.remember.com/",
+       "https://dont.remember.com/", NULL, NULL, true, 2000, 1, 1, 0, 0, 0},
+      {PasswordForm::SCHEME_BASIC, "http://some.domain.com:4567/low_security",
+       "http://some.domain.com:4567/insecure.html", L"basic_auth_user",
+       L"basic", false, 1998, 03, 30, 10, 00, 00},
+      {PasswordForm::SCHEME_DIGEST, "https://some.domain.com/high_security",
+       "https://some.domain.com/", L"digest_auth_user", L"digest", true, 1998,
+       3, 30, 10, 0, 0},
+      // This one gives us an invalid date, which we will treat as a "NULL" date
+      // which is 1601.
+      {PasswordForm::SCHEME_OTHER, "http://a.server.com/",
+       "http://a.server.com/", L"abc", L"123", false, 1601, 1, 1, 0, 0, 0},
+      {PasswordForm::SCHEME_HTML, "android://hash@com.domain.some/", "",
+       L"joe_user", L"secret", true, 2015, 5, 15, 14, 13, 12},
   };
 
   for (unsigned int i = 0; i < arraysize(expected); ++i) {
+    SCOPED_TRACE(testing::Message("In iteration ") << i);
     // Create our fake KeychainItemRef; see MockAppleKeychain docs.
     SecKeychainItemRef keychain_item =
         reinterpret_cast<SecKeychainItemRef>(i + 1);
@@ -459,36 +383,27 @@
     bool parsed = internal_keychain_helpers::FillPasswordFormFromKeychainItem(
         *keychain_, keychain_item, &form, true);
 
-    EXPECT_TRUE(parsed) << "In iteration " << i;
+    EXPECT_TRUE(parsed);
 
-    EXPECT_EQ(expected[i].scheme, form.scheme) << "In iteration " << i;
-    EXPECT_EQ(GURL(expected[i].origin), form.origin) << "In iteration " << i;
-    EXPECT_EQ(expected[i].ssl_valid, form.ssl_valid) << "In iteration " << i;
-    EXPECT_EQ(std::string(expected[i].signon_realm), form.signon_realm)
-        << "In iteration " << i;
+    EXPECT_EQ(expected[i].scheme, form.scheme);
+    EXPECT_EQ(GURL(expected[i].origin), form.origin);
+    EXPECT_EQ(expected[i].ssl_valid, form.ssl_valid);
+    EXPECT_EQ(std::string(expected[i].signon_realm), form.signon_realm);
     if (expected[i].username) {
-      EXPECT_EQ(WideToUTF16(expected[i].username), form.username_value)
-          << "In iteration " << i;
-      EXPECT_EQ(WideToUTF16(expected[i].password), form.password_value)
-          << "In iteration " << i;
-      EXPECT_FALSE(form.blacklisted_by_user) << "In iteration " << i;
+      EXPECT_EQ(WideToUTF16(expected[i].username), form.username_value);
+      EXPECT_EQ(WideToUTF16(expected[i].password), form.password_value);
+      EXPECT_FALSE(form.blacklisted_by_user);
     } else {
-      EXPECT_TRUE(form.blacklisted_by_user) << "In iteration " << i;
+      EXPECT_TRUE(form.blacklisted_by_user);
     }
     base::Time::Exploded exploded_time;
     form.date_created.UTCExplode(&exploded_time);
-    EXPECT_EQ(expected[i].creation_year, exploded_time.year)
-         << "In iteration " << i;
-    EXPECT_EQ(expected[i].creation_month, exploded_time.month)
-        << "In iteration " << i;
-    EXPECT_EQ(expected[i].creation_day, exploded_time.day_of_month)
-        << "In iteration " << i;
-    EXPECT_EQ(expected[i].creation_hour, exploded_time.hour)
-        << "In iteration " << i;
-    EXPECT_EQ(expected[i].creation_minute, exploded_time.minute)
-        << "In iteration " << i;
-    EXPECT_EQ(expected[i].creation_second, exploded_time.second)
-        << "In iteration " << i;
+    EXPECT_EQ(expected[i].creation_year, exploded_time.year);
+    EXPECT_EQ(expected[i].creation_month, exploded_time.month);
+    EXPECT_EQ(expected[i].creation_day, exploded_time.day_of_month);
+    EXPECT_EQ(expected[i].creation_hour, exploded_time.hour);
+    EXPECT_EQ(expected[i].creation_minute, exploded_time.minute);
+    EXPECT_EQ(expected[i].creation_second, exploded_time.second);
   }
 
   {
@@ -508,64 +423,76 @@
     const size_t expected_merge_matches;
   };
   // Most fields are left blank because we don't care about them for searching.
-  /* clang-format off */
   TestDataAndExpectation test_data[] = {
-    // An HTML form we've seen.
-    { { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-        NULL, NULL, NULL, NULL, NULL, L"joe_user", NULL, false, false, 0 },
-      2, 2 },
-    { { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-        NULL, NULL, NULL, NULL, NULL, L"wrong_user", NULL, false, false, 0 },
-      2, 0 },
-    // An HTML form we haven't seen
-    { { PasswordForm::SCHEME_HTML, "http://www.unseendomain.com/",
-        NULL, NULL, NULL, NULL, NULL, L"joe_user", NULL, false, false, 0 },
-      0, 0 },
-    // Basic auth that should match.
-    { { PasswordForm::SCHEME_BASIC, "http://some.domain.com:4567/low_security",
+      // An HTML form we've seen.
+      {{PasswordForm::SCHEME_HTML, "http://some.domain.com/", NULL, NULL, NULL,
+        NULL, NULL, L"joe_user", NULL, false, false, 0},
+       2,
+       2},
+      {{PasswordForm::SCHEME_HTML, "http://some.domain.com/", NULL, NULL, NULL,
+        NULL, NULL, L"wrong_user", NULL, false, false, 0},
+       2,
+       0},
+      // An HTML form we haven't seen
+      {{PasswordForm::SCHEME_HTML, "http://www.unseendomain.com/", NULL, NULL,
+        NULL, NULL, NULL, L"joe_user", NULL, false, false, 0},
+       0,
+       0},
+      // Basic auth that should match.
+      {{PasswordForm::SCHEME_BASIC, "http://some.domain.com:4567/low_security",
         NULL, NULL, NULL, NULL, NULL, L"basic_auth_user", NULL, false, false,
-        0 },
-      1, 1 },
-    // Basic auth with the wrong port.
-    { { PasswordForm::SCHEME_BASIC, "http://some.domain.com:1111/low_security",
+        0},
+       1,
+       1},
+      // Basic auth with the wrong port.
+      {{PasswordForm::SCHEME_BASIC, "http://some.domain.com:1111/low_security",
         NULL, NULL, NULL, NULL, NULL, L"basic_auth_user", NULL, false, false,
-        0 },
-      0, 0 },
-    // Digest auth we've saved under https, visited with http.
-    { { PasswordForm::SCHEME_DIGEST, "http://some.domain.com/high_security",
+        0},
+       0,
+       0},
+      // Digest auth we've saved under https, visited with http.
+      {{PasswordForm::SCHEME_DIGEST, "http://some.domain.com/high_security",
         NULL, NULL, NULL, NULL, NULL, L"digest_auth_user", NULL, false, false,
-        0 },
-      0, 0 },
-    // Digest auth that should match.
-    { { PasswordForm::SCHEME_DIGEST, "https://some.domain.com/high_security",
-        NULL, NULL, NULL, NULL, NULL, L"wrong_user", NULL, false, true, 0 },
-      1, 0 },
-    // Digest auth with the wrong domain.
-    { { PasswordForm::SCHEME_DIGEST, "https://some.domain.com/other_domain",
+        0},
+       0,
+       0},
+      // Digest auth that should match.
+      {{PasswordForm::SCHEME_DIGEST, "https://some.domain.com/high_security",
+        NULL, NULL, NULL, NULL, NULL, L"wrong_user", NULL, false, true, 0},
+       1,
+       0},
+      // Digest auth with the wrong domain.
+      {{PasswordForm::SCHEME_DIGEST, "https://some.domain.com/other_domain",
         NULL, NULL, NULL, NULL, NULL, L"digest_auth_user", NULL, false, true,
-        0 },
-      0, 0 },
-    // Android credentials (both legacy ones with origin, and without).
-    { { PasswordForm::SCHEME_HTML, "android://hash@com.domain.some/",
+        0},
+       0,
+       0},
+      // Android credentials (both legacy ones with origin, and without).
+      {{PasswordForm::SCHEME_HTML, "android://hash@com.domain.some/",
         "android://hash@com.domain.some/", NULL, NULL, NULL, NULL, L"joe_user",
-        NULL, false, true, 0 },
-      1, 1 },
-    { { PasswordForm::SCHEME_HTML, "android://hash@com.domain.some/",
-        NULL, NULL, NULL, NULL, NULL, L"joe_user", NULL, false, true, 0 },
-      1, 1 },
-    // Federated logins do not have a corresponding Keychain entry, and should
-    // not match the username/password stored for the same application. Note
-    // that it will match for filling, however, because that part does not know
-    // that it is a federated login.
-    { { PasswordForm::SCHEME_HTML, "android://hash@com.domain.some/",
-        NULL, NULL, NULL, NULL, NULL, L"joe_user",
-        password_manager::kTestingFederatedLoginMarker, false, true, 0 },
-      1, 0 },
-    /// Garbage forms should have no matches.
-    { { PasswordForm::SCHEME_HTML, "foo/bar/baz",
-        NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, false, 0 }, 0, 0 },
+        NULL, false, true, 0},
+       1,
+       1},
+      {{PasswordForm::SCHEME_HTML, "android://hash@com.domain.some/", NULL,
+        NULL, NULL, NULL, NULL, L"joe_user", NULL, false, true, 0},
+       1,
+       1},
+      // Federated logins do not have a corresponding Keychain entry, and should
+      // not match the username/password stored for the same application. Note
+      // that it will match for filling, however, because that part does not
+      // know
+      // that it is a federated login.
+      {{PasswordForm::SCHEME_HTML, "android://hash@com.domain.some/", NULL,
+        NULL, NULL, NULL, NULL, L"joe_user",
+        password_manager::kTestingFederatedLoginMarker, false, true, 0},
+       1,
+       0},
+      /// Garbage forms should have no matches.
+      {{PasswordForm::SCHEME_HTML, "foo/bar/baz", NULL, NULL, NULL, NULL, NULL,
+        NULL, NULL, false, false, 0},
+       0,
+       0},
   };
-  /* clang-format on */
 
   MacKeychainPasswordFormAdapter keychain_adapter(keychain_);
   MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_);
@@ -637,15 +564,15 @@
   MacKeychainPasswordFormAdapter keychain_adapter(keychain_);
 
   PasswordFormData base_form_data[] = {
-    { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-      "http://some.domain.com/insecure.html",
-      NULL, NULL, NULL, NULL, L"joe_user", NULL, true, false, 0 },
-    { PasswordForm::SCHEME_BASIC, "http://some.domain.com:4567/low_security",
-      "http://some.domain.com:4567/insecure.html",
-      NULL, NULL, NULL, NULL, L"basic_auth_user", NULL, true, false, 0 },
-    { PasswordForm::SCHEME_DIGEST, "https://some.domain.com/high_security",
-      "https://some.domain.com",
-      NULL, NULL, NULL, NULL, L"digest_auth_user", NULL, true, true, 0 },
+      {PasswordForm::SCHEME_HTML, "http://some.domain.com/",
+       "http://some.domain.com/insecure.html", NULL, NULL, NULL, NULL,
+       L"joe_user", NULL, true, false, 0},
+      {PasswordForm::SCHEME_BASIC, "http://some.domain.com:4567/low_security",
+       "http://some.domain.com:4567/insecure.html", NULL, NULL, NULL, NULL,
+       L"basic_auth_user", NULL, true, false, 0},
+      {PasswordForm::SCHEME_DIGEST, "https://some.domain.com/high_security",
+       "https://some.domain.com", NULL, NULL, NULL, NULL, L"digest_auth_user",
+       NULL, true, true, 0},
   };
 
   for (unsigned int i = 0; i < arraysize(base_form_data); ++i) {
@@ -681,10 +608,10 @@
     }
 
     for (unsigned int j = 0; j < modified_forms.size(); ++j) {
-      bool match = keychain_adapter.HasPasswordExactlyMatchingForm(
-          *modified_forms[j]);
-      EXPECT_FALSE(match) << "In modified version " << j
-          << " of base form " << i;
+      bool match =
+          keychain_adapter.HasPasswordExactlyMatchingForm(*modified_forms[j]);
+      EXPECT_FALSE(match) << "In modified version " << j << " of base form "
+                          << i;
     }
   }
 }
@@ -694,41 +621,46 @@
     PasswordFormData data;
     bool should_succeed;
   };
-  /* clang-format off */
   TestDataAndExpectation test_data[] = {
-    // Test a variety of scheme/port/protocol/path variations.
-    { { PasswordForm::SCHEME_HTML, "http://web.site.com/",
+      // Test a variety of scheme/port/protocol/path variations.
+      {{PasswordForm::SCHEME_HTML, "http://web.site.com/",
         "http://web.site.com/path/to/page.html", NULL, NULL, NULL, NULL,
-        L"anonymous", L"knock-knock", false, false, 0 }, true },
-    { { PasswordForm::SCHEME_HTML, "https://web.site.com/",
-        "https://web.site.com/", NULL, NULL, NULL, NULL,
-        L"admin", L"p4ssw0rd", false, false, 0 }, true },
-    { { PasswordForm::SCHEME_BASIC, "http://a.site.com:2222/therealm",
-        "http://a.site.com:2222/", NULL, NULL, NULL, NULL,
-        L"username", L"password", false, false, 0 }, true },
-    { { PasswordForm::SCHEME_DIGEST, "https://digest.site.com/differentrealm",
+        L"anonymous", L"knock-knock", false, false, 0},
+       true},
+      {{PasswordForm::SCHEME_HTML, "https://web.site.com/",
+        "https://web.site.com/", NULL, NULL, NULL, NULL, L"admin", L"p4ssw0rd",
+        false, false, 0},
+       true},
+      {{PasswordForm::SCHEME_BASIC, "http://a.site.com:2222/therealm",
+        "http://a.site.com:2222/", NULL, NULL, NULL, NULL, L"username",
+        L"password", false, false, 0},
+       true},
+      {{PasswordForm::SCHEME_DIGEST, "https://digest.site.com/differentrealm",
         "https://digest.site.com/secure.html", NULL, NULL, NULL, NULL,
-        L"testname", L"testpass", false, false, 0 }, true },
-    // Test that Android credentials can be stored. Also check the legacy form
-    // when |origin| was still filled with the Android URI (and not left empty).
-    { { PasswordForm::SCHEME_HTML, "android://hash@com.example.alpha/",
-        "", NULL, NULL, NULL, NULL,
-        L"joe_user", L"password", false, true, 0 }, true },
-    { { PasswordForm::SCHEME_HTML, "android://hash@com.example.beta/",
+        L"testname", L"testpass", false, false, 0},
+       true},
+      // Test that Android credentials can be stored. Also check the legacy form
+      // when |origin| was still filled with the Android URI (and not left
+      // empty).
+      {{PasswordForm::SCHEME_HTML, "android://hash@com.example.alpha/", "",
+        NULL, NULL, NULL, NULL, L"joe_user", L"password", false, true, 0},
+       true},
+      {{PasswordForm::SCHEME_HTML, "android://hash@com.example.beta/",
         "android://hash@com.example.beta/", NULL, NULL, NULL, NULL,
-        L"jane_user", L"password2", false, true, 0 }, true },
-    // Make sure that garbage forms are rejected.
-    { { PasswordForm::SCHEME_HTML, "gobbledygook",
-        "gobbledygook", NULL, NULL, NULL, NULL,
-        L"anonymous", L"knock-knock", false, false, 0 }, false },
-    // Test that failing to update a duplicate (forced using the magic failure
-    // password; see MockAppleKeychain::ItemModifyAttributesAndData) is
-    // reported.
-    { { PasswordForm::SCHEME_HTML, "http://some.domain.com",
+        L"jane_user", L"password2", false, true, 0},
+       true},
+      // Make sure that garbage forms are rejected.
+      {{PasswordForm::SCHEME_HTML, "gobbledygook", "gobbledygook", NULL, NULL,
+        NULL, NULL, L"anonymous", L"knock-knock", false, false, 0},
+       false},
+      // Test that failing to update a duplicate (forced using the magic failure
+      // password; see MockAppleKeychain::ItemModifyAttributesAndData) is
+      // reported.
+      {{PasswordForm::SCHEME_HTML, "http://some.domain.com",
         "http://some.domain.com/insecure.html", NULL, NULL, NULL, NULL,
-        L"joe_user", L"fail_me", false, false, 0 }, false },
+        L"joe_user", L"fail_me", false, false, 0},
+       false},
   };
-  /* clang-format on */
 
   MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_);
   owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
@@ -739,10 +671,10 @@
     bool add_succeeded = owned_keychain_adapter.AddPassword(*in_form);
     EXPECT_EQ(test_data[i].should_succeed, add_succeeded);
     if (add_succeeded) {
-      EXPECT_TRUE(owned_keychain_adapter.HasPasswordsMergeableWithForm(
-          *in_form));
-      EXPECT_TRUE(owned_keychain_adapter.HasPasswordExactlyMatchingForm(
-          *in_form));
+      EXPECT_TRUE(
+          owned_keychain_adapter.HasPasswordsMergeableWithForm(*in_form));
+      EXPECT_TRUE(
+          owned_keychain_adapter.HasPasswordExactlyMatchingForm(*in_form));
     }
   }
 
@@ -750,21 +682,26 @@
   // TODO(engedy): Add a test to verify that updating Android credentials work.
   // See: https://crbug.com/476851.
   {
-    PasswordFormData data = {
-      PasswordForm::SCHEME_HTML, "http://some.domain.com",
-      "http://some.domain.com/insecure.html", NULL,
-      NULL, NULL, NULL, L"joe_user", L"updated_password", false, false, 0
-    };
+    PasswordFormData data = {PasswordForm::SCHEME_HTML,
+                             "http://some.domain.com",
+                             "http://some.domain.com/insecure.html",
+                             NULL,
+                             NULL,
+                             NULL,
+                             NULL,
+                             L"joe_user",
+                             L"updated_password",
+                             false,
+                             false,
+                             0};
     std::unique_ptr<PasswordForm> update_form =
         CreatePasswordFormFromDataForTesting(data);
     MacKeychainPasswordFormAdapter keychain_adapter(keychain_);
     EXPECT_TRUE(keychain_adapter.AddPassword(*update_form));
     SecKeychainItemRef keychain_item = reinterpret_cast<SecKeychainItemRef>(2);
     PasswordForm stored_form;
-    internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_,
-                                                                keychain_item,
-                                                                &stored_form,
-                                                                true);
+    internal_keychain_helpers::FillPasswordFormFromKeychainItem(
+        *keychain_, keychain_item, &stored_form, true);
     EXPECT_EQ(update_form->password_value, stored_form.password_value);
   }
 }
@@ -774,26 +711,29 @@
     PasswordFormData data;
     bool should_succeed;
   };
-  /* clang-format off */
   TestDataAndExpectation test_data[] = {
-    // Test deletion of an item that we add.
-    { { PasswordForm::SCHEME_HTML, "http://web.site.com/",
+      // Test deletion of an item that we add.
+      {{PasswordForm::SCHEME_HTML, "http://web.site.com/",
         "http://web.site.com/path/to/page.html", NULL, NULL, NULL, NULL,
-        L"anonymous", L"knock-knock", false, false, 0 }, true },
-    // Test that Android credentials can be removed. Also check the legacy case
-    // when |origin| was still filled with the Android URI (and not left empty).
-    { { PasswordForm::SCHEME_HTML, "android://hash@com.example.alpha/",
-        "", NULL, NULL, NULL, NULL,
-        L"joe_user", L"secret", false, true, 0 }, true },
-    { { PasswordForm::SCHEME_HTML, "android://hash@com.example.beta/",
+        L"anonymous", L"knock-knock", false, false, 0},
+       true},
+      // Test that Android credentials can be removed. Also check the legacy
+      // case
+      // when |origin| was still filled with the Android URI (and not left
+      // empty).
+      {{PasswordForm::SCHEME_HTML, "android://hash@com.example.alpha/", "",
+        NULL, NULL, NULL, NULL, L"joe_user", L"secret", false, true, 0},
+       true},
+      {{PasswordForm::SCHEME_HTML, "android://hash@com.example.beta/",
         "android://hash@com.example.beta/", NULL, NULL, NULL, NULL,
-        L"jane_user", L"secret", false, true, 0 }, true },
-    // Make sure we don't delete items we don't own.
-    { { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
+        L"jane_user", L"secret", false, true, 0},
+       true},
+      // Make sure we don't delete items we don't own.
+      {{PasswordForm::SCHEME_HTML, "http://some.domain.com/",
         "http://some.domain.com/insecure.html", NULL, NULL, NULL, NULL,
-        L"joe_user", NULL, true, false, 0 }, false },
+        L"joe_user", NULL, true, false, 0},
+       false},
   };
-  /* clang-format on */
 
   MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_);
   owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
@@ -891,83 +831,195 @@
 
 TEST_F(PasswordStoreMacInternalsTest, TestFormMerge) {
   // Set up a bunch of test data to use in varying combinations.
-  /* clang-format off */
-  PasswordFormData keychain_user_1 =
-      { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-        "http://some.domain.com/", "", L"", L"", L"", L"joe_user", L"sekrit",
-        false, false, 1010101010 };
-  PasswordFormData keychain_user_1_with_path =
-      { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-        "http://some.domain.com/page.html",
-        "", L"", L"", L"", L"joe_user", L"otherpassword",
-        false, false, 1010101010 };
-  PasswordFormData keychain_user_2 =
-      { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-        "http://some.domain.com/", "", L"", L"", L"", L"john.doe", L"sesame",
-        false, false, 958739876 };
-  PasswordFormData keychain_blacklist =
-      { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-        "http://some.domain.com/", "", L"", L"", L"", NULL, NULL,
-        false, false, 1010101010 };
-  PasswordFormData keychain_android =
-      { PasswordForm::SCHEME_HTML, "android://hash@com.domain.some/",
-        "", "", L"", L"", L"", L"joe_user", L"secret",
-        false, true, 1234567890 };
+  PasswordFormData keychain_user_1 = {PasswordForm::SCHEME_HTML,
+                                      "http://some.domain.com/",
+                                      "http://some.domain.com/",
+                                      "",
+                                      L"",
+                                      L"",
+                                      L"",
+                                      L"joe_user",
+                                      L"sekrit",
+                                      false,
+                                      false,
+                                      1010101010};
+  PasswordFormData keychain_user_1_with_path = {
+      PasswordForm::SCHEME_HTML,
+      "http://some.domain.com/",
+      "http://some.domain.com/page.html",
+      "",
+      L"",
+      L"",
+      L"",
+      L"joe_user",
+      L"otherpassword",
+      false,
+      false,
+      1010101010};
+  PasswordFormData keychain_user_2 = {PasswordForm::SCHEME_HTML,
+                                      "http://some.domain.com/",
+                                      "http://some.domain.com/",
+                                      "",
+                                      L"",
+                                      L"",
+                                      L"",
+                                      L"john.doe",
+                                      L"sesame",
+                                      false,
+                                      false,
+                                      958739876};
+  PasswordFormData keychain_blacklist = {PasswordForm::SCHEME_HTML,
+                                         "http://some.domain.com/",
+                                         "http://some.domain.com/",
+                                         "",
+                                         L"",
+                                         L"",
+                                         L"",
+                                         NULL,
+                                         NULL,
+                                         false,
+                                         false,
+                                         1010101010};
+  PasswordFormData keychain_android = {PasswordForm::SCHEME_HTML,
+                                       "android://hash@com.domain.some/",
+                                       "",
+                                       "",
+                                       L"",
+                                       L"",
+                                       L"",
+                                       L"joe_user",
+                                       L"secret",
+                                       false,
+                                       true,
+                                       1234567890};
 
-  PasswordFormData db_user_1 =
-      { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-        "http://some.domain.com/", "http://some.domain.com/action.cgi",
-        L"submit", L"username", L"password", L"joe_user", L"",
-        true, false, 1212121212 };
-  PasswordFormData db_user_1_with_path =
-      { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-        "http://some.domain.com/page.html",
-        "http://some.domain.com/handlepage.cgi",
-        L"submit", L"username", L"password", L"joe_user", L"",
-        true, false, 1234567890 };
-  PasswordFormData db_user_3_with_path =
-      { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-        "http://some.domain.com/page.html",
-        "http://some.domain.com/handlepage.cgi",
-        L"submit", L"username", L"password", L"second-account", L"",
-        true, false, 1240000000 };
-  PasswordFormData database_blacklist_with_path =
-      { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-        "http://some.domain.com/path.html", "http://some.domain.com/action.cgi",
-        L"submit", L"username", L"password", NULL, NULL,
-        true, false, 1212121212 };
-  PasswordFormData db_android =
-      { PasswordForm::SCHEME_HTML, "android://hash@com.domain.some/",
-        "android://hash@com.domain.some/", "", L"", L"", L"", L"joe_user", L"",
-        false, true, 1234567890 };
-  PasswordFormData db_federated =
-      { PasswordForm::SCHEME_HTML, "android://hash@com.domain.some/",
-        "android://hash@com.domain.some/", "", L"", L"", L"", L"joe_user",
-        password_manager::kTestingFederatedLoginMarker,
-        false, true, 3434343434 };
+  PasswordFormData db_user_1 = {PasswordForm::SCHEME_HTML,
+                                "http://some.domain.com/",
+                                "http://some.domain.com/",
+                                "http://some.domain.com/action.cgi",
+                                L"submit",
+                                L"username",
+                                L"password",
+                                L"joe_user",
+                                L"",
+                                true,
+                                false,
+                                1212121212};
+  PasswordFormData db_user_1_with_path = {
+      PasswordForm::SCHEME_HTML,
+      "http://some.domain.com/",
+      "http://some.domain.com/page.html",
+      "http://some.domain.com/handlepage.cgi",
+      L"submit",
+      L"username",
+      L"password",
+      L"joe_user",
+      L"",
+      true,
+      false,
+      1234567890};
+  PasswordFormData db_user_3_with_path = {
+      PasswordForm::SCHEME_HTML,
+      "http://some.domain.com/",
+      "http://some.domain.com/page.html",
+      "http://some.domain.com/handlepage.cgi",
+      L"submit",
+      L"username",
+      L"password",
+      L"second-account",
+      L"",
+      true,
+      false,
+      1240000000};
+  PasswordFormData database_blacklist_with_path = {
+      PasswordForm::SCHEME_HTML,
+      "http://some.domain.com/",
+      "http://some.domain.com/path.html",
+      "http://some.domain.com/action.cgi",
+      L"submit",
+      L"username",
+      L"password",
+      NULL,
+      NULL,
+      true,
+      false,
+      1212121212};
+  PasswordFormData db_android = {PasswordForm::SCHEME_HTML,
+                                 "android://hash@com.domain.some/",
+                                 "android://hash@com.domain.some/",
+                                 "",
+                                 L"",
+                                 L"",
+                                 L"",
+                                 L"joe_user",
+                                 L"",
+                                 false,
+                                 true,
+                                 1234567890};
+  PasswordFormData db_federated = {
+      PasswordForm::SCHEME_HTML,
+      "android://hash@com.domain.some/",
+      "android://hash@com.domain.some/",
+      "",
+      L"",
+      L"",
+      L"",
+      L"joe_user",
+      password_manager::kTestingFederatedLoginMarker,
+      false,
+      true,
+      3434343434};
 
-  PasswordFormData merged_user_1 =
-      { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-        "http://some.domain.com/", "http://some.domain.com/action.cgi",
-        L"submit", L"username", L"password", L"joe_user", L"sekrit",
-        true, false, 1212121212 };
-  PasswordFormData merged_user_1_with_db_path =
-      { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-        "http://some.domain.com/page.html",
-        "http://some.domain.com/handlepage.cgi",
-        L"submit", L"username", L"password", L"joe_user", L"sekrit",
-        true, false, 1234567890 };
-  PasswordFormData merged_user_1_with_both_paths =
-      { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-        "http://some.domain.com/page.html",
-        "http://some.domain.com/handlepage.cgi",
-        L"submit", L"username", L"password", L"joe_user", L"otherpassword",
-        true, false, 1234567890 };
-  PasswordFormData merged_android =
-      { PasswordForm::SCHEME_HTML, "android://hash@com.domain.some/",
-        "android://hash@com.domain.some/", "", L"", L"", L"", L"joe_user",
-        L"secret", false, true, 1234567890 };
-  /* clang-format on */
+  PasswordFormData merged_user_1 = {PasswordForm::SCHEME_HTML,
+                                    "http://some.domain.com/",
+                                    "http://some.domain.com/",
+                                    "http://some.domain.com/action.cgi",
+                                    L"submit",
+                                    L"username",
+                                    L"password",
+                                    L"joe_user",
+                                    L"sekrit",
+                                    true,
+                                    false,
+                                    1212121212};
+  PasswordFormData merged_user_1_with_db_path = {
+      PasswordForm::SCHEME_HTML,
+      "http://some.domain.com/",
+      "http://some.domain.com/page.html",
+      "http://some.domain.com/handlepage.cgi",
+      L"submit",
+      L"username",
+      L"password",
+      L"joe_user",
+      L"sekrit",
+      true,
+      false,
+      1234567890};
+  PasswordFormData merged_user_1_with_both_paths = {
+      PasswordForm::SCHEME_HTML,
+      "http://some.domain.com/",
+      "http://some.domain.com/page.html",
+      "http://some.domain.com/handlepage.cgi",
+      L"submit",
+      L"username",
+      L"password",
+      L"joe_user",
+      L"otherpassword",
+      true,
+      false,
+      1234567890};
+  PasswordFormData merged_android = {PasswordForm::SCHEME_HTML,
+                                     "android://hash@com.domain.some/",
+                                     "android://hash@com.domain.some/",
+                                     "",
+                                     L"",
+                                     L"",
+                                     L"",
+                                     L"joe_user",
+                                     L"secret",
+                                     false,
+                                     true,
+                                     1234567890};
 
   // Build up the big multi-dimensional array of data sets that will actually
   // drive the test. Use vectors rather than arrays so that initialization is
@@ -981,9 +1033,9 @@
     MERGE_IO_ARRAY_COUNT  // termination marker
   };
   const unsigned int kTestCount = 5;
-  std::vector< std::vector< std::vector<PasswordFormData*> > > test_data(
-      MERGE_IO_ARRAY_COUNT, std::vector< std::vector<PasswordFormData*> >(
-          kTestCount, std::vector<PasswordFormData*>()));
+  std::vector<std::vector<std::vector<PasswordFormData*>>> test_data(
+      MERGE_IO_ARRAY_COUNT, std::vector<std::vector<PasswordFormData*>>(
+                                kTestCount, std::vector<PasswordFormData*>()));
   unsigned int current_test = 0;
 
   // Test a merge with a few accounts in both systems, with partial overlap.
@@ -1059,9 +1111,8 @@
     }
 
     ScopedVector<autofill::PasswordForm> merged_forms;
-    internal_keychain_helpers::MergePasswordForms(&keychain_forms,
-                                                  &database_forms,
-                                                  &merged_forms);
+    internal_keychain_helpers::MergePasswordForms(
+        &keychain_forms, &database_forms, &merged_forms);
 
     CHECK_FORMS(keychain_forms.get(), test_data[KEYCHAIN_OUTPUT][test_case],
                 test_case);
@@ -1074,29 +1125,26 @@
 
 TEST_F(PasswordStoreMacInternalsTest, TestPasswordBulkLookup) {
   PasswordFormData db_data[] = {
-    { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-      "http://some.domain.com/", "http://some.domain.com/action.cgi",
-      L"submit", L"username", L"password", L"joe_user", L"",
-      true, false, 1212121212 },
-    { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-      "http://some.domain.com/page.html",
-      "http://some.domain.com/handlepage.cgi",
-      L"submit", L"username", L"password", L"joe_user", L"",
-      true, false, 1234567890 },
-    { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-      "http://some.domain.com/page.html",
-      "http://some.domain.com/handlepage.cgi",
-      L"submit", L"username", L"password", L"second-account", L"",
-      true, false, 1240000000 },
-    { PasswordForm::SCHEME_HTML, "http://dont.remember.com/",
-      "http://dont.remember.com/",
-      "http://dont.remember.com/handlepage.cgi",
-      L"submit", L"username", L"password", L"joe_user", L"",
-      true, false, 1240000000 },
-    { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-      "http://some.domain.com/path.html", "http://some.domain.com/action.cgi",
-      L"submit", L"username", L"password", NULL, NULL,
-      true, false, 1212121212 },
+      {PasswordForm::SCHEME_HTML, "http://some.domain.com/",
+       "http://some.domain.com/", "http://some.domain.com/action.cgi",
+       L"submit", L"username", L"password", L"joe_user", L"", true, false,
+       1212121212},
+      {PasswordForm::SCHEME_HTML, "http://some.domain.com/",
+       "http://some.domain.com/page.html",
+       "http://some.domain.com/handlepage.cgi", L"submit", L"username",
+       L"password", L"joe_user", L"", true, false, 1234567890},
+      {PasswordForm::SCHEME_HTML, "http://some.domain.com/",
+       "http://some.domain.com/page.html",
+       "http://some.domain.com/handlepage.cgi", L"submit", L"username",
+       L"password", L"second-account", L"", true, false, 1240000000},
+      {PasswordForm::SCHEME_HTML, "http://dont.remember.com/",
+       "http://dont.remember.com/", "http://dont.remember.com/handlepage.cgi",
+       L"submit", L"username", L"password", L"joe_user", L"", true, false,
+       1240000000},
+      {PasswordForm::SCHEME_HTML, "http://some.domain.com/",
+       "http://some.domain.com/path.html", "http://some.domain.com/action.cgi",
+       L"submit", L"username", L"password", NULL, NULL, true, false,
+       1212121212},
   };
   ScopedVector<autofill::PasswordForm> database_forms;
   for (unsigned int i = 0; i < arraysize(db_data); ++i) {
@@ -1115,16 +1163,15 @@
 
 TEST_F(PasswordStoreMacInternalsTest, TestBlacklistedFiltering) {
   PasswordFormData db_data[] = {
-    { PasswordForm::SCHEME_HTML, "http://dont.remember.com/",
-      "http://dont.remember.com/",
-      "http://dont.remember.com/handlepage.cgi",
-      L"submit", L"username", L"password", L"joe_user", L"non_empty_password",
-      true, false, 1240000000 },
-    { PasswordForm::SCHEME_HTML, "https://dont.remember.com/",
-      "https://dont.remember.com/",
-      "https://dont.remember.com/handlepage_secure.cgi",
-      L"submit", L"username", L"password", L"joe_user", L"non_empty_password",
-      true, false, 1240000000 },
+      {PasswordForm::SCHEME_HTML, "http://dont.remember.com/",
+       "http://dont.remember.com/", "http://dont.remember.com/handlepage.cgi",
+       L"submit", L"username", L"password", L"joe_user", L"non_empty_password",
+       true, false, 1240000000},
+      {PasswordForm::SCHEME_HTML, "https://dont.remember.com/",
+       "https://dont.remember.com/",
+       "https://dont.remember.com/handlepage_secure.cgi", L"submit",
+       L"username", L"password", L"joe_user", L"non_empty_password", true,
+       false, 1240000000},
   };
   ScopedVector<autofill::PasswordForm> database_forms;
   for (unsigned int i = 0; i < arraysize(db_data); ++i) {
@@ -1144,9 +1191,7 @@
   SecKeychainItemRef keychain_item = reinterpret_cast<SecKeychainItemRef>(1);
   PasswordForm form_without_extracted_password;
   bool parsed = internal_keychain_helpers::FillPasswordFormFromKeychainItem(
-      *keychain_,
-      keychain_item,
-      &form_without_extracted_password,
+      *keychain_, keychain_item, &form_without_extracted_password,
       false);  // Do not extract password.
   EXPECT_TRUE(parsed);
   ASSERT_TRUE(form_without_extracted_password.password_value.empty());
@@ -1158,9 +1203,7 @@
   keychain_item = reinterpret_cast<SecKeychainItemRef>(1);
   PasswordForm form_with_extracted_password;
   parsed = internal_keychain_helpers::FillPasswordFormFromKeychainItem(
-      *keychain_,
-      keychain_item,
-      &form_with_extracted_password,
+      *keychain_, keychain_item, &form_with_extracted_password,
       true);  // Extract password.
   EXPECT_TRUE(parsed);
   ASSERT_EQ(ASCIIToUTF16("sekrit"),
@@ -1173,9 +1216,7 @@
   keychain_item = reinterpret_cast<SecKeychainItemRef>(4);
   PasswordForm negative_form;
   parsed = internal_keychain_helpers::FillPasswordFormFromKeychainItem(
-      *keychain_,
-      keychain_item,
-      &negative_form,
+      *keychain_, keychain_item, &negative_form,
       true);  // Extract password.
   EXPECT_TRUE(parsed);
   ASSERT_TRUE(negative_form.username_value.empty());
@@ -1188,9 +1229,7 @@
   keychain_item = reinterpret_cast<SecKeychainItemRef>(5);
   PasswordForm form_with_empty_password_a;
   parsed = internal_keychain_helpers::FillPasswordFormFromKeychainItem(
-      *keychain_,
-      keychain_item,
-      &form_with_empty_password_a,
+      *keychain_, keychain_item, &form_with_empty_password_a,
       true);  // Extract password.
   EXPECT_TRUE(parsed);
   ASSERT_TRUE(form_with_empty_password_a.password_value.empty());
@@ -1202,13 +1241,10 @@
   keychain_item = reinterpret_cast<SecKeychainItemRef>(6);
   PasswordForm form_with_empty_password_b;
   parsed = internal_keychain_helpers::FillPasswordFormFromKeychainItem(
-      *keychain_,
-      keychain_item,
-      &form_with_empty_password_b,
+      *keychain_, keychain_item, &form_with_empty_password_b,
       true);  // Extract password.
   EXPECT_TRUE(parsed);
-  ASSERT_EQ(ASCIIToUTF16(" "),
-            form_with_empty_password_b.password_value);
+  ASSERT_EQ(ASCIIToUTF16(" "), form_with_empty_password_b.password_value);
   ASSERT_TRUE(form_with_empty_password_b.blacklisted_by_user);
 }
 
@@ -1219,15 +1255,15 @@
 
   // Add a few passwords of various types so that we own some.
   PasswordFormData owned_password_data[] = {
-    { PasswordForm::SCHEME_HTML, "http://web.site.com/",
-      "http://web.site.com/path/to/page.html", NULL, NULL, NULL, NULL,
-      L"anonymous", L"knock-knock", false, false, 0 },
-    { PasswordForm::SCHEME_BASIC, "http://a.site.com:2222/therealm",
-      "http://a.site.com:2222/", NULL, NULL, NULL, NULL,
-      L"username", L"password", false, false, 0 },
-    { PasswordForm::SCHEME_DIGEST, "https://digest.site.com/differentrealm",
-      "https://digest.site.com/secure.html", NULL, NULL, NULL, NULL,
-      L"testname", L"testpass", false, false, 0 },
+      {PasswordForm::SCHEME_HTML, "http://web.site.com/",
+       "http://web.site.com/path/to/page.html", NULL, NULL, NULL, NULL,
+       L"anonymous", L"knock-knock", false, false, 0},
+      {PasswordForm::SCHEME_BASIC, "http://a.site.com:2222/therealm",
+       "http://a.site.com:2222/", NULL, NULL, NULL, NULL, L"username",
+       L"password", false, false, 0},
+      {PasswordForm::SCHEME_DIGEST, "https://digest.site.com/differentrealm",
+       "https://digest.site.com/secure.html", NULL, NULL, NULL, NULL,
+       L"testname", L"testpass", false, false, 0},
   };
   for (unsigned int i = 0; i < arraysize(owned_password_data); ++i) {
     std::unique_ptr<PasswordForm> form =
@@ -1398,26 +1434,46 @@
   // Mock Keychain isn't smart enough to be able to support update generically,
   // so some.domain.com triggers special handling to test it that make inserting
   // fail.
-  PasswordFormData joint_data = {
-    PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-    "http://some.domain.com/insecure.html", "login.cgi",
-    L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1
-  };
+  PasswordFormData joint_data = {PasswordForm::SCHEME_HTML,
+                                 "http://some.domain.com/",
+                                 "http://some.domain.com/insecure.html",
+                                 "login.cgi",
+                                 L"username",
+                                 L"password",
+                                 L"submit",
+                                 L"joe_user",
+                                 L"sekrit",
+                                 true,
+                                 false,
+                                 1};
   std::unique_ptr<PasswordForm> joint_form =
       CreatePasswordFormFromDataForTesting(joint_data);
   EXPECT_EQ(AddChangeForForm(*joint_form), login_db()->AddLogin(*joint_form));
   MockAppleKeychain::KeychainTestData joint_keychain_data = {
-    kSecAuthenticationTypeHTMLForm, "some.domain.com",
-    kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z",
-    "joe_user", "sekrit", false };
+      kSecAuthenticationTypeHTMLForm,
+      "some.domain.com",
+      kSecProtocolTypeHTTP,
+      "/insecure.html",
+      0,
+      NULL,
+      "20020601171500Z",
+      "joe_user",
+      "sekrit",
+      false};
   keychain()->AddTestItem(joint_keychain_data);
 
   // Insert a password into the keychain only.
   MockAppleKeychain::KeychainTestData keychain_only_data = {
-    kSecAuthenticationTypeHTMLForm, "keychain.only.com",
-    kSecProtocolTypeHTTP, NULL, 0, NULL, "20020601171500Z",
-    "keychain", "only", false
-  };
+      kSecAuthenticationTypeHTMLForm,
+      "keychain.only.com",
+      kSecProtocolTypeHTTP,
+      NULL,
+      0,
+      NULL,
+      "20020601171500Z",
+      "keychain",
+      "only",
+      false};
   keychain()->AddTestItem(keychain_only_data);
 
   struct UpdateData {
@@ -1427,30 +1483,30 @@
 
   // Make a series of update calls.
   UpdateData updates[] = {
-    // Update the keychain+db passwords (the normal password update case).
-    { { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
-        "http://some.domain.com/insecure.html", "login.cgi",
-        L"username", L"password", L"submit", L"joe_user", L"53krit",
-        true, false, 2 },
-      "53krit",
-    },
-    // Update the keychain-only password; this simulates the initial use of a
-    // password stored by another browsers.
-    { { PasswordForm::SCHEME_HTML, "http://keychain.only.com/",
-        "http://keychain.only.com/login.html", "login.cgi",
-        L"username", L"password", L"submit", L"keychain", L"only",
-        true, false, 2 },
-      "only",
-    },
-    // Update a password that doesn't exist in either location. This tests the
-    // case where a form is filled, then the stored login is removed, then the
-    // form is submitted.
-    { { PasswordForm::SCHEME_HTML, "http://different.com/",
-        "http://different.com/index.html", "login.cgi",
-        L"username", L"password", L"submit", L"abc", L"123",
-        true, false, 2 },
-      NULL,
-    },
+      // Update the keychain+db passwords (the normal password update case).
+      {
+          {PasswordForm::SCHEME_HTML, "http://some.domain.com/",
+           "http://some.domain.com/insecure.html", "login.cgi", L"username",
+           L"password", L"submit", L"joe_user", L"53krit", true, false, 2},
+          "53krit",
+      },
+      // Update the keychain-only password; this simulates the initial use of a
+      // password stored by another browsers.
+      {
+          {PasswordForm::SCHEME_HTML, "http://keychain.only.com/",
+           "http://keychain.only.com/login.html", "login.cgi", L"username",
+           L"password", L"submit", L"keychain", L"only", true, false, 2},
+          "only",
+      },
+      // Update a password that doesn't exist in either location. This tests the
+      // case where a form is filled, then the stored login is removed, then the
+      // form is submitted.
+      {
+          {PasswordForm::SCHEME_HTML, "http://different.com/",
+           "http://different.com/index.html", "login.cgi", L"username",
+           L"password", L"submit", L"abc", L"123", true, false, 2},
+          NULL,
+      },
   };
   for (unsigned int i = 0; i < arraysize(updates); ++i) {
     std::unique_ptr<PasswordForm> form =
@@ -1472,7 +1528,8 @@
       EXPECT_GT(matching_items.size(), 0U) << "iteration " << i;
       if (matching_items.size() >= 1)
         EXPECT_EQ(ASCIIToUTF16(updates[i].password),
-                  matching_items[0]->password_value) << "iteration " << i;
+                  matching_items[0]->password_value)
+            << "iteration " << i;
     } else {
       EXPECT_EQ(0U, matching_items.size()) << "iteration " << i;
     }
@@ -1500,11 +1557,18 @@
   // fuzzy-matches the www.facebook.com one.)
 
   // 1. Add a password for www.facebook.com
-  PasswordFormData www_form_data = {
-    PasswordForm::SCHEME_HTML, "http://www.facebook.com/",
-    "http://www.facebook.com/index.html", "login",
-    L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1
-  };
+  PasswordFormData www_form_data = {PasswordForm::SCHEME_HTML,
+                                    "http://www.facebook.com/",
+                                    "http://www.facebook.com/index.html",
+                                    "login",
+                                    L"username",
+                                    L"password",
+                                    L"submit",
+                                    L"joe_user",
+                                    L"sekrit",
+                                    true,
+                                    false,
+                                    1};
   std::unique_ptr<PasswordForm> www_form =
       CreatePasswordFormFromDataForTesting(www_form_data);
   EXPECT_EQ(AddChangeForForm(*www_form), login_db()->AddLogin(*www_form));
@@ -1586,18 +1650,44 @@
 // |check_created|.
 void CheckRemoveLoginsBetween(PasswordStoreMacTest* test, bool check_created) {
   PasswordFormData www_form_data_facebook = {
-      PasswordForm::SCHEME_HTML, "http://www.facebook.com/",
-      "http://www.facebook.com/index.html", "login", L"submit", L"username",
-      L"password", L"joe_user", L"sekrit", true, false, 0 };
+      PasswordForm::SCHEME_HTML,
+      "http://www.facebook.com/",
+      "http://www.facebook.com/index.html",
+      "login",
+      L"submit",
+      L"username",
+      L"password",
+      L"joe_user",
+      L"sekrit",
+      true,
+      false,
+      0};
   // The old form doesn't have elements names.
   PasswordFormData www_form_data_facebook_old = {
-      PasswordForm::SCHEME_HTML, "http://www.facebook.com/",
-      "http://www.facebook.com/index.html", "login", L"", L"",
-      L"", L"joe_user", L"oldsekrit", true, false, 0 };
-  PasswordFormData www_form_data_other = {
-      PasswordForm::SCHEME_HTML, "http://different.com/",
-      "http://different.com/index.html", "login", L"submit", L"username",
-      L"password", L"different_joe_user", L"sekrit", true, false, 0 };
+      PasswordForm::SCHEME_HTML,
+      "http://www.facebook.com/",
+      "http://www.facebook.com/index.html",
+      "login",
+      L"",
+      L"",
+      L"",
+      L"joe_user",
+      L"oldsekrit",
+      true,
+      false,
+      0};
+  PasswordFormData www_form_data_other = {PasswordForm::SCHEME_HTML,
+                                          "http://different.com/",
+                                          "http://different.com/index.html",
+                                          "login",
+                                          L"submit",
+                                          L"username",
+                                          L"password",
+                                          L"different_joe_user",
+                                          L"sekrit",
+                                          true,
+                                          false,
+                                          0};
   std::unique_ptr<PasswordForm> form_facebook =
       CreatePasswordFormFromDataForTesting(www_form_data_facebook);
   std::unique_ptr<PasswordForm> form_facebook_old =
@@ -1730,28 +1820,51 @@
 
   // Add a third-party password.
   MockAppleKeychain::KeychainTestData keychain_data = {
-      kSecAuthenticationTypeHTMLForm, "some.domain.com",
-      kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z",
-      "joe_user", "sekrit", false };
+      kSecAuthenticationTypeHTMLForm,
+      "some.domain.com",
+      kSecProtocolTypeHTTP,
+      "/insecure.html",
+      0,
+      NULL,
+      "20020601171500Z",
+      "joe_user",
+      "sekrit",
+      false};
   keychain()->AddTestItem(keychain_data);
 
   // Add a password through the adapter. It has the "Chrome" creator tag.
   // However, it's not referenced by the password database.
   MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain());
   owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
-  PasswordFormData www_form_data1 = {
-      PasswordForm::SCHEME_HTML, "http://www.facebook.com/",
-      "http://www.facebook.com/index.html", "login", L"username", L"password",
-      L"submit", L"joe_user", L"sekrit", true, false, 1 };
+  PasswordFormData www_form_data1 = {PasswordForm::SCHEME_HTML,
+                                     "http://www.facebook.com/",
+                                     "http://www.facebook.com/index.html",
+                                     "login",
+                                     L"username",
+                                     L"password",
+                                     L"submit",
+                                     L"joe_user",
+                                     L"sekrit",
+                                     true,
+                                     false,
+                                     1};
   std::unique_ptr<PasswordForm> www_form =
       CreatePasswordFormFromDataForTesting(www_form_data1);
   EXPECT_TRUE(owned_keychain_adapter.AddPassword(*www_form));
 
   // Add a password from the current profile.
-  PasswordFormData www_form_data2 = {
-      PasswordForm::SCHEME_HTML, "http://www.facebook.com/",
-      "http://www.facebook.com/index.html", "login", L"username", L"password",
-      L"submit", L"not_joe_user", L"12345", true, false, 1 };
+  PasswordFormData www_form_data2 = {PasswordForm::SCHEME_HTML,
+                                     "http://www.facebook.com/",
+                                     "http://www.facebook.com/index.html",
+                                     "login",
+                                     L"username",
+                                     L"password",
+                                     L"submit",
+                                     L"not_joe_user",
+                                     L"12345",
+                                     true,
+                                     false,
+                                     1};
   www_form = CreatePasswordFormFromDataForTesting(www_form_data2);
   store_->AddLogin(*www_form);
   FinishAsyncProcessing();
@@ -1790,11 +1903,18 @@
   store()->AddObserver(&mock_observer);
 
   // 1. Add a password for www.facebook.com to the LoginDatabase.
-  PasswordFormData www_form_data = {
-    PasswordForm::SCHEME_HTML, "http://www.facebook.com/",
-    "http://www.facebook.com/index.html", "login",
-    L"username", L"password", L"submit", L"joe_user", L"", true, false, 1
-  };
+  PasswordFormData www_form_data = {PasswordForm::SCHEME_HTML,
+                                    "http://www.facebook.com/",
+                                    "http://www.facebook.com/index.html",
+                                    "login",
+                                    L"username",
+                                    L"password",
+                                    L"submit",
+                                    L"joe_user",
+                                    L"",
+                                    true,
+                                    false,
+                                    1};
   std::unique_ptr<PasswordForm> www_form(
       CreatePasswordFormFromDataForTesting(www_form_data));
   EXPECT_EQ(AddChangeForForm(*www_form), login_db()->AddLogin(*www_form));
@@ -1906,8 +2026,9 @@
   EXPECT_EQ(blacklisted_form, *matching_items[0]);
 
   // The passwords are encrypted using a key from the Keychain.
-  EXPECT_TRUE(histogram_tester_->GetHistogramSamplesSinceCreation(
-                                     "OSX.Keychain.Access")->TotalCount());
+  EXPECT_TRUE(
+      histogram_tester_->GetHistogramSamplesSinceCreation("OSX.Keychain.Access")
+          ->TotalCount());
   histogram_tester_.reset();
 }
 
diff --git a/chrome/browser/password_manager/password_store_proxy_mac_unittest.cc b/chrome/browser/password_manager/password_store_proxy_mac_unittest.cc
index ce3837a..bcdd8ce 100644
--- a/chrome/browser/password_manager/password_store_proxy_mac_unittest.cc
+++ b/chrome/browser/password_manager/password_store_proxy_mac_unittest.cc
@@ -144,8 +144,7 @@
   OSCryptMocker::SetUpWithSingleton();
 }
 
-PasswordStoreProxyMacTest::~PasswordStoreProxyMacTest() {
-}
+PasswordStoreProxyMacTest::~PasswordStoreProxyMacTest() {}
 
 void PasswordStoreProxyMacTest::SetUp() {
   std::unique_ptr<password_manager::LoginDatabase> login_db(
@@ -350,9 +349,18 @@
 
   // Add a new autofillable login + a blacklisted login.
   password_manager::PasswordFormData www_form_data = {
-      PasswordForm::SCHEME_HTML, "http://www.facebook.com/",
-      "http://www.facebook.com/index.html", "login", L"username", L"password",
-      L"submit", L"not_joe_user", L"12345", true, false, 1};
+      PasswordForm::SCHEME_HTML,
+      "http://www.facebook.com/",
+      "http://www.facebook.com/index.html",
+      "login",
+      L"username",
+      L"password",
+      L"submit",
+      L"not_joe_user",
+      L"12345",
+      true,
+      false,
+      1};
   std::unique_ptr<PasswordForm> form =
       CreatePasswordFormFromDataForTesting(www_form_data);
   std::unique_ptr<PasswordForm> blacklisted_form(new PasswordForm(*form));
@@ -456,7 +464,8 @@
   // Check the password is still there.
   if (lock_keychain && store_->password_store_mac()) {
     static_cast<crypto::MockAppleKeychain*>(
-        store_->password_store_mac()->keychain())->set_locked(false);
+        store_->password_store_mac()->keychain())
+        ->set_locked(false);
   }
   MockPasswordStoreConsumer mock_consumer;
   store()->GetLogins(form, &mock_consumer);
@@ -479,8 +488,7 @@
     EXPECT_EQ(static_cast<int>(MigrationStatus::MIGRATED), status);
   }
   histogram_tester_.ExpectUniqueSample(
-      "PasswordManager.KeychainMigration.Status",
-      status, 1);
+      "PasswordManager.KeychainMigration.Status", status, 1);
 }
 
 TEST_P(PasswordStoreProxyMacMigrationTest, TestSuccessfullMigration) {
diff --git a/chrome/browser/password_manager/password_store_win_unittest.cc b/chrome/browser/password_manager/password_store_win_unittest.cc
index ba154fd..21508c5 100644
--- a/chrome/browser/password_manager/password_store_win_unittest.cc
+++ b/chrome/browser/password_manager/password_store_win_unittest.cc
@@ -74,23 +74,24 @@
  protected:
   PasswordStoreWinTest()
       : ui_thread_(BrowserThread::UI, &message_loop_),
-        db_thread_(BrowserThread::DB) {
-  }
+        db_thread_(BrowserThread::DB) {}
 
-  bool CreateIE7PasswordInfo(const std::wstring& url, const base::Time& created,
+  bool CreateIE7PasswordInfo(const std::wstring& url,
+                             const base::Time& created,
                              IE7PasswordInfo* info) {
     // Copied from chrome/browser/importer/importer_unittest.cc
     // The username is "abcdefgh" and the password "abcdefghijkl".
-    unsigned char data[] = "\x0c\x00\x00\x00\x38\x00\x00\x00\x2c\x00\x00\x00"
-                           "\x57\x49\x43\x4b\x18\x00\x00\x00\x02\x00\x00\x00"
-                           "\x67\x00\x72\x00\x01\x00\x00\x00\x00\x00\x00\x00"
-                           "\x00\x00\x00\x00\x4e\xfa\x67\x76\x22\x94\xc8\x01"
-                           "\x08\x00\x00\x00\x12\x00\x00\x00\x4e\xfa\x67\x76"
-                           "\x22\x94\xc8\x01\x0c\x00\x00\x00\x61\x00\x62\x00"
-                           "\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00"
-                           "\x00\x00\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00"
-                           "\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00"
-                           "\x6c\x00\x00\x00";
+    unsigned char data[] =
+        "\x0c\x00\x00\x00\x38\x00\x00\x00\x2c\x00\x00\x00"
+        "\x57\x49\x43\x4b\x18\x00\x00\x00\x02\x00\x00\x00"
+        "\x67\x00\x72\x00\x01\x00\x00\x00\x00\x00\x00\x00"
+        "\x00\x00\x00\x00\x4e\xfa\x67\x76\x22\x94\xc8\x01"
+        "\x08\x00\x00\x00\x12\x00\x00\x00\x4e\xfa\x67\x76"
+        "\x22\x94\xc8\x01\x0c\x00\x00\x00\x61\x00\x62\x00"
+        "\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00"
+        "\x00\x00\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00"
+        "\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00"
+        "\x6c\x00\x00\x00";
     DATA_BLOB input = {0};
     DATA_BLOB url_key = {0};
     DATA_BLOB output = {0};
@@ -98,10 +99,10 @@
     input.pbData = data;
     input.cbData = sizeof(data);
 
-    url_key.pbData = reinterpret_cast<unsigned char*>(
-        const_cast<wchar_t*>(url.data()));
-    url_key.cbData = static_cast<DWORD>((url.size() + 1) *
-                                        sizeof(std::wstring::value_type));
+    url_key.pbData =
+        reinterpret_cast<unsigned char*>(const_cast<wchar_t*>(url.data()));
+    url_key.cbData =
+        static_cast<DWORD>((url.size() + 1) * sizeof(std::wstring::value_type));
 
     if (!CryptProtectData(&input, nullptr, &url_key, nullptr, nullptr,
                           CRYPTPROTECT_UI_FORBIDDEN, &output))
@@ -127,15 +128,14 @@
     profile_.reset(new TestingProfile());
 
     base::FilePath path = temp_dir_.path().AppendASCII("web_data_test");
-    wdbs_ = new WebDatabaseService(path,
-        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
+    wdbs_ = new WebDatabaseService(
+        path, BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB));
     // Need to add at least one table so the database gets created.
     wdbs_->AddTable(std::unique_ptr<WebDatabaseTable>(new LoginsTable()));
     wdbs_->LoadDatabase();
     wds_ = new PasswordWebDataService(
-        wdbs_,
-        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
+        wdbs_, BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
         WebDataServiceBase::ProfileErrorCallback());
     wds_->Init();
   }
@@ -153,7 +153,8 @@
     }
     base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC,
                              base::WaitableEvent::InitialState::NOT_SIGNALED);
-    BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+    BrowserThread::PostTask(
+        BrowserThread::DB, FROM_HERE,
         base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
     done.Wait();
     base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -196,8 +197,9 @@
 }
 
 MATCHER(EmptyWDResult, "") {
-  return static_cast<const WDResult<std::vector<PasswordForm*> >*>(
-      arg)->GetValue().empty();
+  return static_cast<const WDResult<std::vector<PasswordForm*>>*>(arg)
+      ->GetValue()
+      .empty();
 }
 
 // Hangs flakily, http://crbug.com/71385.
@@ -217,7 +219,8 @@
   // task to notify us that it's safe to carry on with the test.
   WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC,
                      base::WaitableEvent::InitialState::NOT_SIGNALED);
-  BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+  BrowserThread::PostTask(
+      BrowserThread::DB, FROM_HERE,
       base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
   done.Wait();
 
@@ -231,16 +234,18 @@
       .WillByDefault(QuitUIMessageLoop());
 
   PasswordFormData form_data = {
-    PasswordForm::SCHEME_HTML,
-    "http://example.com/",
-    "http://example.com/origin",
-    "http://example.com/action",
-    L"submit_element",
-    L"username_element",
-    L"password_element",
-    L"",
-    L"",
-    true, false, 1,
+      PasswordForm::SCHEME_HTML,
+      "http://example.com/",
+      "http://example.com/origin",
+      "http://example.com/action",
+      L"submit_element",
+      L"username_element",
+      L"password_element",
+      L"",
+      L"",
+      true,
+      false,
+      1,
   };
   std::unique_ptr<PasswordForm> form =
       CreatePasswordFormFromDataForTesting(form_data);
@@ -248,16 +253,18 @@
   // The returned form will not have 'action' or '*_element' fields set. This
   // is because credentials imported from IE don't have this information.
   PasswordFormData expected_form_data = {
-    PasswordForm::SCHEME_HTML,
-    "http://example.com/",
-    "http://example.com/origin",
-    "",
-    L"",
-    L"",
-    L"",
-    L"abcdefgh",
-    L"abcdefghijkl",
-    true, false, 1,
+      PasswordForm::SCHEME_HTML,
+      "http://example.com/",
+      "http://example.com/origin",
+      "",
+      L"",
+      L"",
+      L"",
+      L"abcdefgh",
+      L"abcdefghijkl",
+      true,
+      false,
+      1,
   };
   ScopedVector<autofill::PasswordForm> expected_forms;
   expected_forms.push_back(
@@ -277,16 +284,18 @@
   EXPECT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare()));
 
   PasswordFormData form_data = {
-    PasswordForm::SCHEME_HTML,
-    "http://example.com/",
-    "http://example.com/origin",
-    "http://example.com/action",
-    L"submit_element",
-    L"username_element",
-    L"password_element",
-    L"",
-    L"",
-    true, false, 1,
+      PasswordForm::SCHEME_HTML,
+      "http://example.com/",
+      "http://example.com/origin",
+      "http://example.com/action",
+      L"submit_element",
+      L"username_element",
+      L"password_element",
+      L"",
+      L"",
+      true,
+      false,
+      1,
   };
   std::unique_ptr<PasswordForm> form =
       CreatePasswordFormFromDataForTesting(form_data);
@@ -317,7 +326,8 @@
   // task to notify us that it's safe to carry on with the test.
   WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC,
                      base::WaitableEvent::InitialState::NOT_SIGNALED);
-  BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+  BrowserThread::PostTask(
+      BrowserThread::DB, FROM_HERE,
       base::Bind(&WaitableEvent::Signal, base::Unretained(&done)));
   done.Wait();
 
@@ -330,31 +340,35 @@
       .WillByDefault(QuitUIMessageLoop());
 
   PasswordFormData form_data = {
-    PasswordForm::SCHEME_HTML,
-    "http://example.com/",
-    "http://example.com/origin",
-    "http://example.com/action",
-    L"submit_element",
-    L"username_element",
-    L"password_element",
-    L"",
-    L"",
-    true, false, 1,
+      PasswordForm::SCHEME_HTML,
+      "http://example.com/",
+      "http://example.com/origin",
+      "http://example.com/action",
+      L"submit_element",
+      L"username_element",
+      L"password_element",
+      L"",
+      L"",
+      true,
+      false,
+      1,
   };
   std::unique_ptr<PasswordForm> form =
       CreatePasswordFormFromDataForTesting(form_data);
 
   PasswordFormData expected_form_data = {
-    PasswordForm::SCHEME_HTML,
-    "http://example.com/",
-    "http://example.com/origin",
-    "http://example.com/action",
-    L"submit_element",
-    L"username_element",
-    L"password_element",
-    L"abcdefgh",
-    L"abcdefghijkl",
-    true, false, 1,
+      PasswordForm::SCHEME_HTML,
+      "http://example.com/",
+      "http://example.com/origin",
+      "http://example.com/action",
+      L"submit_element",
+      L"username_element",
+      L"password_element",
+      L"abcdefgh",
+      L"abcdefghijkl",
+      true,
+      false,
+      1,
   };
   ScopedVector<autofill::PasswordForm> expected_forms;
   expected_forms.push_back(
@@ -386,16 +400,18 @@
   store_->Init(syncer::SyncableService::StartSyncFlare());
 
   PasswordFormData form_data = {
-    PasswordForm::SCHEME_HTML,
-    "http://example.com/",
-    "http://example.com/origin",
-    "http://example.com/action",
-    L"submit_element",
-    L"username_element",
-    L"password_element",
-    L"",
-    L"",
-    true, false, 1,
+      PasswordForm::SCHEME_HTML,
+      "http://example.com/",
+      "http://example.com/origin",
+      "http://example.com/action",
+      L"submit_element",
+      L"username_element",
+      L"password_element",
+      L"",
+      L"",
+      true,
+      false,
+      1,
   };
   std::unique_ptr<PasswordForm> form =
       CreatePasswordFormFromDataForTesting(form_data);
diff --git a/chrome/browser/password_manager/password_store_x_unittest.cc b/chrome/browser/password_manager/password_store_x_unittest.cc
index 3f566d3..36a99f3 100644
--- a/chrome/browser/password_manager/password_store_x_unittest.cc
+++ b/chrome/browser/password_manager/password_store_x_unittest.cc
@@ -229,7 +229,7 @@
  private:
   void erase(size_t index) {
     if (index < all_forms_.size() - 1)
-      all_forms_[index] = all_forms_[all_forms_.size() - 1];
+      all_forms_[index] = all_forms_.back();
     all_forms_.pop_back();
   }
 
diff --git a/chrome/browser/profiles/profile_avatar_icon_util.cc b/chrome/browser/profiles/profile_avatar_icon_util.cc
index b0fa75e..7c19797 100644
--- a/chrome/browser/profiles/profile_avatar_icon_util.cc
+++ b/chrome/browser/profiles/profile_avatar_icon_util.cc
@@ -13,6 +13,7 @@
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
@@ -487,7 +488,7 @@
 
 bool IsDefaultAvatarIconUrl(const std::string& url, size_t* icon_index) {
   DCHECK(icon_index);
-  if (url.find(kDefaultUrlPrefix) != 0)
+  if (!base::StartsWith(url, kDefaultUrlPrefix, base::CompareCase::SENSITIVE))
     return false;
 
   int int_value = -1;
diff --git a/chrome/browser/renderer_host/OWNERS b/chrome/browser/renderer_host/OWNERS
index e994eeee..b5e8dfa2 100644
--- a/chrome/browser/renderer_host/OWNERS
+++ b/chrome/browser/renderer_host/OWNERS
@@ -9,6 +9,7 @@
 per-file chrome_extension_message_filter.*=asargent@chromium.org
 
 per-file data_reduction_proxy_resource_throttle_android.*=sgurun@chromium.org
+per-file site_per_process_text_input_browsertest.cc=creis@chromium.org
 
 # Mac files
 per-file *.mm=avi@chromium.org
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.h b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.h
index 1f4f5fa..86bdd50 100644
--- a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.h
+++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.h
@@ -16,22 +16,11 @@
 class RenderWidgetHost;
 }
 
-namespace ChromeRenderWidgetHostViewMacDelegateInternal {
-class SpellCheckObserver;
-}
-
 @class HistorySwiper;
 @interface ChromeRenderWidgetHostViewMacDelegate
     : NSObject<RenderWidgetHostViewMacDelegate> {
  @private
   content::RenderWidgetHost* renderWidgetHost_;  // weak
-  std::unique_ptr<
-      ChromeRenderWidgetHostViewMacDelegateInternal::SpellCheckObserver>
-      spellingObserver_;
-
-  // Used for continuous spell checking.
-  BOOL spellcheckEnabled_;
-  BOOL spellcheckChecked_;
 
   // Responsible for 2-finger swipes history navigation.
   base::scoped_nsobject<HistorySwiper> historySwiper_;
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm
index 37abdf2..f3ac18ba 100644
--- a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm
+++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm
@@ -24,63 +24,18 @@
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
 
 using content::RenderViewHost;
 
 @interface ChromeRenderWidgetHostViewMacDelegate () <HistorySwiperDelegate>
-- (void)spellCheckEnabled:(BOOL)enabled checked:(BOOL)checked;
 @end
 
-namespace ChromeRenderWidgetHostViewMacDelegateInternal {
-
-// Filters the message sent by the renderer to know if spellchecking is enabled
-// or not for the currently focused element.
-class SpellCheckObserver : public content::WebContentsObserver {
- public:
-  SpellCheckObserver(
-      RenderViewHost* host,
-      ChromeRenderWidgetHostViewMacDelegate* view_delegate)
-      : content::WebContentsObserver(
-            content::WebContents::FromRenderViewHost(host)),
-        view_delegate_(view_delegate) {
-  }
-
-  ~SpellCheckObserver() override {}
-
- private:
-  bool OnMessageReceived(const IPC::Message& message) override {
-    bool handled = true;
-    IPC_BEGIN_MESSAGE_MAP(SpellCheckObserver, message)
-      IPC_MESSAGE_HANDLER(SpellCheckHostMsg_ToggleSpellCheck,
-                          OnToggleSpellCheck)
-      IPC_MESSAGE_UNHANDLED(handled = false)
-    IPC_END_MESSAGE_MAP()
-    return handled;
-  }
-
-  void OnToggleSpellCheck(bool enabled, bool checked) {
-    [view_delegate_ spellCheckEnabled:enabled checked:checked];
-  }
-
-  ChromeRenderWidgetHostViewMacDelegate* view_delegate_;
-};
-
-}  // namespace ChromeRenderWidgetHostViewMacDelegateInternal
-
 @implementation ChromeRenderWidgetHostViewMacDelegate
 
 - (id)initWithRenderWidgetHost:(content::RenderWidgetHost*)renderWidgetHost {
   self = [super init];
   if (self) {
     renderWidgetHost_ = renderWidgetHost;
-    RenderViewHost* rvh = RenderViewHost::From(renderWidgetHost_);
-    if (rvh) {
-      spellingObserver_.reset(
-          new ChromeRenderWidgetHostViewMacDelegateInternal::SpellCheckObserver(
-              rvh, self));
-    }
-
     historySwiper_.reset([[HistorySwiper alloc] initWithDelegate:self]);
   }
   return self;
@@ -175,13 +130,12 @@
       content::RenderProcessHost* host = renderWidgetHost_->GetProcess();
       Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
       DCHECK(profile);
-      spellcheckChecked_ =
-          profile->GetPrefs()->GetBoolean(prefs::kEnableContinuousSpellcheck);
       NSCellStateValue checkedState =
-          spellcheckChecked_ ? NSOnState : NSOffState;
+          profile->GetPrefs()->GetBoolean(prefs::kEnableContinuousSpellcheck) ?
+              NSOnState : NSOffState;
       [(id)item setState:checkedState];
     }
-    *valid = spellcheckEnabled_;
+    *valid = YES;
     return YES;
   }
 
@@ -254,11 +208,6 @@
                    !pref->GetBoolean(prefs::kEnableContinuousSpellcheck));
 }
 
-- (void)spellCheckEnabled:(BOOL)enabled checked:(BOOL)checked {
-  spellcheckEnabled_ = enabled;
-  spellcheckChecked_ = checked;
-}
-
 // END Spellchecking methods
 
 @end
diff --git a/chrome/browser/renderer_host/site_per_process_text_input_browsertest.cc b/chrome/browser/renderer_host/site_per_process_text_input_browsertest.cc
index 35e9c65..47eca0f 100644
--- a/chrome/browser/renderer_host/site_per_process_text_input_browsertest.cc
+++ b/chrome/browser/renderer_host/site_per_process_text_input_browsertest.cc
@@ -98,8 +98,7 @@
   }
 
  private:
-  void VerifyValue(content::TextInputManagerTester* text_input_manager_tester) {
-    ASSERT_EQ(tester(), text_input_manager_tester);
+  void VerifyValue() {
     std::string value;
     if (tester()->GetTextInputValue(&value) && expected_value_ == value)
       OnSuccess();
@@ -122,8 +121,7 @@
   }
 
  private:
-  void VerifyType(content::TextInputManagerTester* text_input_manager_tester) {
-    ASSERT_EQ(tester(), text_input_manager_tester);
+  void VerifyType() {
     ui::TextInputType type =
         tester()->GetTextInputType(&type) ? type : ui::TEXT_INPUT_TYPE_NONE;
     if (expected_type_ == type)
@@ -145,9 +143,7 @@
   }
 
  private:
-  void VerifyChange(
-      content::TextInputManagerTester* text_input_manager_tester) {
-    ASSERT_EQ(tester(), text_input_manager_tester);
+  void VerifyChange() {
     if (tester()->IsTextInputStateChanged())
       OnSuccess();
   }
@@ -170,7 +166,7 @@
   }
 
  private:
-  void VerifyType(content::TextInputManagerTester* tester) {
+  void VerifyType() {
     ui::TextInputType type;
     if (!content::GetTextInputTypeForView(web_contents_, view_, &type))
       return;
@@ -185,6 +181,31 @@
   DISALLOW_COPY_AND_ASSIGN(ViewTextInputTypeObserver);
 };
 
+// This class observes the |expected_view| for the first change in its
+// selection bounds.
+class ViewSelectionBoundsChangedObserver : public TextInputManagerObserverBase {
+ public:
+  ViewSelectionBoundsChangedObserver(
+      content::WebContents* web_contents,
+      content::RenderWidgetHostView* expected_view)
+      : TextInputManagerObserverBase(web_contents),
+        expected_view_(expected_view) {
+    tester()->SetOnSelectionBoundsChangedCallback(
+        base::Bind(&ViewSelectionBoundsChangedObserver::VerifyChange,
+                   base::Unretained(this)));
+  }
+
+ private:
+  void VerifyChange() {
+    if (expected_view_ == tester()->GetUpdatedView())
+      OnSuccess();
+  }
+
+  const content::RenderWidgetHostView* const expected_view_;
+
+  DISALLOW_COPY_AND_ASSIGN(ViewSelectionBoundsChangedObserver);
+};
+
 }  // namespace
 
 // Main class for all TextInputState and IME related tests.
@@ -456,6 +477,44 @@
   reset_state_observer.Wait();
 }
 
+// This test creates a page with multiple child frames and adds an <input> to
+// each frame. Then, sequentially, each <input> is focused by sending a tab key.
+// Then, after |TextInputState.type| for a view is changed to text, another key
+// is pressed (a character) and then the test verifies that TextInputManager
+// receives the corresponding update on the change in selection bounds on the
+// browser side.
+IN_PROC_BROWSER_TEST_F(SitePerProcessTextInputManagerTest,
+                       TrackSelectionBoundsForChildFrames) {
+  CreateIframePage("a(b,c(a,b),d)");
+  std::vector<content::RenderFrameHost*> frames{
+      GetFrame(IndexVector{}),     GetFrame(IndexVector{0}),
+      GetFrame(IndexVector{1}),    GetFrame(IndexVector{1, 0}),
+      GetFrame(IndexVector{1, 1}), GetFrame(IndexVector{2})};
+  std::vector<content::RenderWidgetHostView*> views;
+  for (auto frame : frames)
+    views.push_back(frame->GetView());
+  for (size_t i = 0; i < frames.size(); ++i)
+    AddInputFieldToFrame(frames[i], "text", "", true);
+
+  content::WebContents* web_contents = active_contents();
+
+  auto send_tab_insert_text_wait_for_bounds_change = [&web_contents](
+      content::RenderWidgetHostView* view) {
+    ViewTextInputTypeObserver type_observer(web_contents, view,
+                                            ui::TEXT_INPUT_TYPE_TEXT);
+    SimulateKeyPress(web_contents, ui::DomKey::TAB, ui::DomCode::TAB,
+                     ui::VKEY_TAB, false, false, false, false);
+    type_observer.Wait();
+    ViewSelectionBoundsChangedObserver bounds_observer(web_contents, view);
+    SimulateKeyPress(web_contents, ui::DomKey::FromCharacter('E'),
+                     ui::DomCode::US_E, ui::VKEY_E, false, false, false, false);
+    bounds_observer.Wait();
+  };
+
+  for (auto view : views)
+    send_tab_insert_text_wait_for_bounds_change(view);
+}
+
 // TODO(ekaramad): The following tests are specifically written for Aura and are
 // based on InputMethodObserver. Write similar tests for Mac/Android/Mus
 // (crbug.com/602723).
diff --git a/chrome/browser/resources/chromeos/chromevox/common/key_util.js b/chrome/browser/resources/chromeos/chromevox/common/key_util.js
index e823efe..1f64d1c 100644
--- a/chrome/browser/resources/chromeos/chromevox/common/key_util.js
+++ b/chrome/browser/resources/chromeos/chromevox/common/key_util.js
@@ -118,7 +118,8 @@
       util.prevKeySequence &&
       keySequence.equals(util.prevKeySequence)) {
     var prevTime = util.modeKeyPressTime;
-    if (prevTime > 0 && currTime - prevTime < 300) {  // Double tap
+    var delta = currTime - prevTime;
+    if (prevTime > 0 && delta > 100 && delta < 300) {  // Double tap
       keySequence = util.prevKeySequence;
       keySequence.doubleTap = true;
       util.prevKeySequence = null;
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
index 5b59259..453b1d2 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
@@ -149,7 +149,6 @@
 
   chrome.accessibilityPrivate.onAccessibilityGesture.addListener(
       this.onAccessibilityGesture_);
-  Notifications.onStartup();
 };
 
 /**
@@ -338,7 +337,6 @@
         'switch_to_next' : 'switch_to_classic');
     cvox.ChromeVox.tts.speak(
         announce, cvox.QueueMode.FLUSH, {doNotInterrupt: true});
-    Notifications.onModeChange();
 
     // If the new mode is Classic, return false now so we don't announce
     // anything more.
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/notifications.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/notifications.js
index 55e4688..cc6e387 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/notifications.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/notifications.js
@@ -74,7 +74,6 @@
  * Runs notifications that should be shown for startup.
  */
 Notifications.onStartup = function() {
-  return;
   // Only run on background page.
   if (document.location.href.indexOf('background.html') == -1)
     return;
@@ -88,7 +87,6 @@
  * Runs notifications that should be shown for mode changes.
  */
 Notifications.onModeChange = function() {
-  return;
   // Only run on background page.
   if (document.location.href.indexOf('background.html') == -1)
     return;
diff --git a/chrome/browser/resources/local_ntp/most_visited_util.js b/chrome/browser/resources/local_ntp/most_visited_util.js
index ebf6513..50c089b0 100644
--- a/chrome/browser/resources/local_ntp/most_visited_util.js
+++ b/chrome/browser/resources/local_ntp/most_visited_util.js
@@ -284,7 +284,7 @@
     data = apiHandle.getMostVisitedItemData(params.rid);
     if (!data)
       return;
-    data.tileSource: NTPLoggingTileSource.CLIENT;
+    data.tileSource = NTPLoggingTileSource.CLIENT;
   }
 
   if (isFinite(params.dummy) && parseInt(params.dummy, 10)) {
diff --git a/chrome/browser/resources/md_history/app.html b/chrome/browser/resources/md_history/app.html
index 4a170c97..a3da52df 100644
--- a/chrome/browser/resources/md_history/app.html
+++ b/chrome/browser/resources/md_history/app.html
@@ -1,4 +1,6 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/html/cr/ui.html">
+<link rel="import" href="chrome://resources/html/cr/ui/command.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html">
 <link rel="import" href="chrome://history/history_toolbar.html">
 <link rel="import" href="chrome://history/list_container.html">
diff --git a/chrome/browser/resources/md_history/app.js b/chrome/browser/resources/md_history/app.js
index 721e621..6d3f5d4 100644
--- a/chrome/browser/resources/md_history/app.js
+++ b/chrome/browser/resources/md_history/app.js
@@ -57,6 +57,10 @@
   /** @override */
   ready: function() {
     this.grouped_ = loadTimeData.getBoolean('groupByDomain');
+
+    cr.ui.decorate('command', cr.ui.Command);
+    document.addEventListener('canExecute', this.onCanExecute_.bind(this));
+    document.addEventListener('command', this.onCommand_.bind(this));
   },
 
   /** @private */
@@ -85,18 +89,8 @@
     toolbar.count = 0;
   },
 
-  /**
-   * Listens for call to delete all selected items and loops through all items
-   * to determine which ones are selected and deletes these.
-   */
   deleteSelected: function() {
-    if (!loadTimeData.getBoolean('allowDeletingHistory'))
-      return;
-
-    // TODO(hsampson): add a popup to check whether the user definitely
-    // wants to delete the selected items.
-    /** @type {HistoryListContainerElement} */ (this.$['history'])
-        .deleteSelected();
+    this.$.history.deleteSelectedWithPrompt();
   },
 
   /**
@@ -120,6 +114,23 @@
   searchDomain_: function(e) { this.$.toolbar.setSearchTerm(e.detail.domain); },
 
   /**
+   * @param {Event} e
+   * @private
+   */
+  onCanExecute_: function(e) {
+    e.canExecute = true;
+  },
+
+  /**
+   * @param {Event} e
+   * @private
+   */
+  onCommand_: function(e) {
+    if (e.command.id == 'find-command')
+      this.$.toolbar.showSearchField();
+  },
+
+  /**
    * @param {!Array<!ForeignSession>} sessionList Array of objects describing
    *     the sessions from other devices.
    * @param {boolean} isTabSyncEnabled Is tab sync enabled for this profile?
diff --git a/chrome/browser/resources/md_history/compiled_resources2.gyp b/chrome/browser/resources/md_history/compiled_resources2.gyp
index 44c5c5ab..cfc189a 100644
--- a/chrome/browser/resources/md_history/compiled_resources2.gyp
+++ b/chrome/browser/resources/md_history/compiled_resources2.gyp
@@ -90,6 +90,7 @@
       'target_name': 'app',
       'dependencies': [
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+        '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:command',
         'constants',
         'history_toolbar',
         'list_container',
diff --git a/chrome/browser/resources/md_history/history.html b/chrome/browser/resources/md_history/history.html
index f7b9dba..3178400 100644
--- a/chrome/browser/resources/md_history/history.html
+++ b/chrome/browser/resources/md_history/history.html
@@ -69,6 +69,13 @@
     <span id="loading-message">$i18n{loading}</span>
   </div>
 
+<if expr="is_macosx">
+  <command id="find-command" shortcut="Meta|f /">
+</if>
+<if expr="not is_macosx">
+  <command id="find-command" shortcut="Ctrl|f /">
+</if>
+
   <link rel="import" href="chrome://resources/html/cr.html">
   <link rel="import" href="chrome://resources/html/util.html">
   <link rel="import" href="chrome://resources/html/load_time_data.html">
diff --git a/chrome/browser/resources/md_history/history_item.html b/chrome/browser/resources/md_history/history_item.html
index c1a33dc2..0c0a971 100644
--- a/chrome/browser/resources/md_history/history_item.html
+++ b/chrome/browser/resources/md_history/history_item.html
@@ -70,6 +70,7 @@
         @apply(--layout-center);
         @apply(--layout-flex);
         @apply(--layout-horizontal);
+        height: var(--item-height);
         overflow: hidden;
       }
 
diff --git a/chrome/browser/resources/md_history/history_list.js b/chrome/browser/resources/md_history/history_list.js
index 58a3cfe..ba35812 100644
--- a/chrome/browser/resources/md_history/history_list.js
+++ b/chrome/browser/resources/md_history/history_list.js
@@ -189,7 +189,9 @@
 
   /**
    * Performs a request to the backend to delete all selected items. If
-   * successful, removes them from the view.
+   * successful, removes them from the view. Does not prompt the user before
+   * deleting -- see <history-list-container> for a version of this method which
+   * does prompt.
    */
   deleteSelected: function() {
     var toBeRemoved = this.historyData_.filter(function(item) {
diff --git a/chrome/browser/resources/md_history/history_toolbar.js b/chrome/browser/resources/md_history/history_toolbar.js
index 13f9c35d..d9e85ec 100644
--- a/chrome/browser/resources/md_history/history_toolbar.js
+++ b/chrome/browser/resources/md_history/history_toolbar.js
@@ -96,6 +96,12 @@
     this.fire('delete-selected');
   },
 
+  showSearchField: function() {
+    /** @type {!CrToolbarElement} */(this.$['main-toolbar'])
+        .getSearchField()
+        .showAndFocus();
+  },
+
   /**
    * If the user is a supervised user the delete button is not shown.
    * @private
diff --git a/chrome/browser/resources/md_history/list_container.html b/chrome/browser/resources/md_history/list_container.html
index bf01abe..eff450f5 100644
--- a/chrome/browser/resources/md_history/list_container.html
+++ b/chrome/browser/resources/md_history/list_container.html
@@ -1,11 +1,13 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html">
 <link rel="import" href="chrome://history/grouped_list.html">
 <link rel="import" href="chrome://history/history_list.html">
 
 <dom-module id="history-list-container">
   <template>
-    <style>
+    <style include="cr-shared-style">
       :host {
         display: block;
         height: 100%;
@@ -16,6 +18,10 @@
       #content > * {
         height: 100%;
       }
+
+      #dialog .body {
+        white-space: pre-wrap;
+      }
     </style>
     <iron-pages id="content" attr-for-selected="id"
         selected="[[selectedPage_]]">
@@ -29,8 +35,21 @@
             searched-term="[[queryResult.info.term]]">
         </history-grouped-list>
       </template>
-      </template>
     </iron-pages>
+
+    <cr-dialog id="dialog">
+      <div class="title">$i18n{removeSelected}</div>
+      <div class="body">$i18n{deleteWarning}</div>
+      <div class="button-container">
+        <paper-button class="cancel-button" on-tap="onDialogCancelTap_">
+          $i18n{cancel}
+        </paper-button>
+        <paper-button class="action-button" on-tap="onDialogConfirmTap_"
+            autofocus>
+          $i18n{deleteConfirm}
+        </paper-button>
+      </div>
+    </cr-dialog>
   </template>
   <script src="chrome://history/list_container.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/md_history/list_container.js b/chrome/browser/resources/md_history/list_container.js
index 76cb2f5e..f8bbac0 100644
--- a/chrome/browser/resources/md_history/list_container.js
+++ b/chrome/browser/resources/md_history/list_container.js
@@ -83,9 +83,15 @@
         .unselectAllItems(count);
   },
 
-  deleteSelected: function() {
-    /** @type {HistoryListElement} */ (this.$['infinite-list'])
-        .deleteSelected();
+  /**
+   * Delete all the currently selected history items. Will prompt the user with
+   * a dialog to confirm that the deletion should be performed.
+   */
+  deleteSelectedWithPrompt: function() {
+    if (!loadTimeData.getBoolean('allowDeletingHistory'))
+      return;
+
+    this.$.dialog.open();
   },
 
   /**
@@ -131,4 +137,15 @@
       }
     }
   },
+
+  /** @private */
+  onDialogConfirmTap_: function() {
+    this.$['infinite-list'].deleteSelected();
+    this.$.dialog.close();
+  },
+
+  /** @private */
+  onDialogCancelTap_: function() {
+    this.$.dialog.close();
+  }
 });
diff --git a/chrome/browser/resources/print_preview/print_header.js b/chrome/browser/resources/print_preview/print_header.js
index 51f25e7..4eec37f 100644
--- a/chrome/browser/resources/print_preview/print_header.js
+++ b/chrome/browser/resources/print_preview/print_header.js
@@ -188,20 +188,25 @@
       var html;
       var label;
       if (numPages != numSheets) {
-        html = loadTimeData.getStringF('printPreviewSummaryFormatLong',
-                                       '<b>' + numSheets + '</b>',
-                                       '<b>' + summaryLabel + '</b>',
-                                       numPages,
-                                       pagesLabel);
+        html = loadTimeData.getStringF(
+            'printPreviewSummaryFormatLong',
+            '<b>' + numSheets.toLocaleString() + '</b>',
+            '<b>' + summaryLabel + '</b>',
+            numPages.toLocaleString(),
+            pagesLabel);
         label = loadTimeData.getStringF('printPreviewSummaryFormatLong',
-                                        numSheets, summaryLabel,
-                                        numPages, pagesLabel);
+                                        numSheets.toLocaleString(),
+                                        summaryLabel,
+                                        numPages.toLocaleString(),
+                                        pagesLabel);
       } else {
-        html = loadTimeData.getStringF('printPreviewSummaryFormatShort',
-                                       '<b>' + numSheets + '</b>',
-                                       '<b>' + summaryLabel + '</b>');
+        html = loadTimeData.getStringF(
+            'printPreviewSummaryFormatShort',
+            '<b>' + numSheets.toLocaleString() + '</b>',
+            '<b>' + summaryLabel + '</b>');
         label = loadTimeData.getStringF('printPreviewSummaryFormatShort',
-                                        numSheets, summaryLabel);
+                                        numSheets.toLocaleString(),
+                                        summaryLabel);
       }
 
       // Removing extra spaces from within the string.
diff --git a/chrome/browser/resources/settings/animation/animation.html b/chrome/browser/resources/settings/animation/animation.html
new file mode 100644
index 0000000..ecff82f
--- /dev/null
+++ b/chrome/browser/resources/settings/animation/animation.html
@@ -0,0 +1,3 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/cr/event_target.html">
+<script src="/animation/animation.js"></script>
diff --git a/chrome/browser/resources/settings/animation/animation.js b/chrome/browser/resources/settings/animation/animation.js
new file mode 100644
index 0000000..7e07a99
--- /dev/null
+++ b/chrome/browser/resources/settings/animation/animation.js
@@ -0,0 +1,92 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Simplified API wrapping native Web Animations with some sugar.
+ * A compromise between the draft spec and Chrome's evolving support. This API
+ * will be changed (or removed) as Chrome support evolves.
+ */
+cr.define('settings.animation', function() {
+  'use strict';
+
+  /**
+   * Default timing constants.
+   * @const
+   */
+  var Timing = {
+    DURATION: 250,
+    EASING: 'cubic-bezier(0.4, 0, 0.2, 1)',  // Fast out, slow in.
+  };
+
+  /**
+   * Offers a small subset of the v1 Animation interface. The underlying
+   * animation can be reversed, canceled or immediately finished.
+   * @see https://www.w3.org/TR/web-animations-1/#animation
+   *
+   * @constructor
+   * @extends {cr.EventTarget}
+   * @param {!Element} el The element to animate.
+   * @param {!Array<!Object>|!Object<!Array>|!Object<string>} keyframes
+   *     Keyframes, as in Element.prototype.animate.
+   * @param {number|!KeyframeEffectOptions=} opt_options Duration or options
+   *     object, as in Element.prototype.animate.
+   */
+  function Animation(el, keyframes, opt_options) {
+    // Disallow direct usage of the underlying animation.
+    this.animation_ = el.animate(keyframes, opt_options);
+
+    var self = this;
+    /** @type {!Promise} */
+    this.finished = new Promise(function(resolve, reject) {
+      // If we were implementing the full spec, we'd have to support
+      // removing or resetting these listeners.
+      self.animation_.addEventListener('finish', function(e) {
+        resolve();
+        // According to the spec, queue a task to fire the event after
+        // resolving the promise.
+        self.queueDispatch_(e);
+      });
+      self.animation_.addEventListener('cancel', function(e) {
+        reject(new
+            /**
+             * @see https://heycam.github.io/webidl/#es-DOMException-call
+             * @type {function (new:DOMException, string, string)}
+             */(
+                DOMException
+            )('', 'AbortError'));
+        self.queueDispatch_(e);
+      });
+    });
+  }
+
+  Animation.prototype = {
+    __proto__: cr.EventTarget.prototype,
+
+    finish: function() {
+      assert(this.animation_);
+      this.animation_.finish();
+    },
+
+    cancel: function() {
+      assert(this.animation_);
+      this.animation_.cancel();
+    },
+
+    /**
+     * @param {!Event} e
+     * @private
+     */
+    queueDispatch_: function(e) {
+      setTimeout(function() {
+        this.dispatchEvent(e);
+        this.animation_ = undefined;
+      }.bind(this));
+    },
+  };
+
+  return {
+    Animation: Animation,
+    Timing: Timing,
+  };
+});
diff --git a/chrome/browser/resources/settings/animation/compiled_resources2.gyp b/chrome/browser/resources/settings/animation/compiled_resources2.gyp
new file mode 100644
index 0000000..89d95422
--- /dev/null
+++ b/chrome/browser/resources/settings/animation/compiled_resources2.gyp
@@ -0,0 +1,16 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'animation',
+      'dependencies': [
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+        '<(DEPTH)/ui/webui/resources/js/cr/compiled_resources2.gyp:event_target',
+        '<(EXTERNS_GYP):web_animations',
+      ],
+      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+  ],
+}
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html
index 31c06fc..aab329c73d 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html
@@ -22,16 +22,22 @@
         visibility: hidden;
       }
 
+      #dialog .button-container {
+        border-top: 1px solid rgba(0, 0, 0, 0.14);
+        margin-top: 0;
+        padding-top: 10px;
+      }
+
+      #dialog .footer {
+        background-color: #fff;
+      }
+
       .row {
         align-items: center;
         display: flex;
         min-height: 40px;
       }
 
-      .row .start {
-        flex: 1;
-      }
-
       paper-spinner {
         -webkit-margin-end: 16px;
         margin-bottom: auto;
@@ -85,6 +91,17 @@
           display: none;
         };
       }
+
+      #clearFrom {
+        display: inline;
+      }
+
+      /* Cap the height on smaller screens to avoid unfavorable clipping. */
+      @media screen and (max-height: 714px) {
+        .body {
+          max-height: 270px;
+        }
+      }
     </style>
 
     <!-- #notice correctly places its own backdrop above #dialog and under
@@ -93,11 +110,13 @@
       <div class="title">$i18n{clearBrowsingData}</div>
       <div class="body">
         <div class="row">
-          <span class="start">$i18n{clearFollowingItemsFrom}</span>
-          <settings-dropdown-menu id="clearFrom"
-              pref="{{prefs.browser.clear_data.time_period}}"
-              menu-options="[[clearFromOptions_]]" no-label-float>
-          </settings-dropdown-menu>
+          <span>
+            $i18n{clearFollowingItemsFrom}
+            <settings-dropdown-menu id="clearFrom"
+                pref="{{prefs.browser.clear_data.time_period}}"
+                menu-options="[[clearFromOptions_]]" no-label-float>
+            </settings-dropdown-menu>
+          </span>
         </div>
         <settings-checkbox id="browsingCheckbox"
             pref="{{prefs.browser.clear_data.browsing_history}}"
diff --git a/chrome/browser/resources/settings/compiled_resources2.gyp b/chrome/browser/resources/settings/compiled_resources2.gyp
index 664d925e..ba6aece 100644
--- a/chrome/browser/resources/settings/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/compiled_resources2.gyp
@@ -10,6 +10,7 @@
         'a11y_page/compiled_resources2.gyp:*',
         'about_page/compiled_resources2.gyp:*',
         'advanced_page/compiled_resources2.gyp:*',
+        'animation/compiled_resources2.gyp:*',
         'appearance_page/compiled_resources2.gyp:*',
         'basic_page/compiled_resources2.gyp:*',
         'bluetooth_page/compiled_resources2.gyp:*',
@@ -56,5 +57,12 @@
       ],
       'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
+    {
+      'target_name': 'search_settings',
+      'dependencies': [
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+      ],
+      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
   ],
 }
diff --git a/chrome/browser/resources/settings/controls/settings_dropdown_menu.html b/chrome/browser/resources/settings/controls/settings_dropdown_menu.html
index 716072b..89654d1 100644
--- a/chrome/browser/resources/settings/controls/settings_dropdown_menu.html
+++ b/chrome/browser/resources/settings/controls/settings_dropdown_menu.html
@@ -9,31 +9,7 @@
 <dom-module id="settings-dropdown-menu">
   <template>
     <style include="settings-shared">
-      .item {
-        align-items: center;
-        color: var(--paper-grey-800);
-        display: flex;
-        font-size: inherit;
-        min-height: 48px;
-        padding: 0 16px;
-      }
-
-      .item:focus {
-        background-color: var(--paper-grey-300);
-        outline: none;
-      }
-
-      paper-dropdown-menu {
-        --iron-icon-fill-color: var(--paper-grey-600);
-        --paper-font-subhead: {
-          font-size: inherit;
-        };
-        --paper-input-container-underline: {
-          background: var(--paper-grey-300);
-        };
-        width: 160px;
-      }
-     </style>
+    </style>
     <paper-dropdown-menu id="dropdownMenu" label="[[menuLabel_]]"
         on-iron-select="onSelect_" no-label-float$="[[noLabelFloat]]"
         disabled="[[shouldDisableMenu_(disabled, menuOptions.*)]]">
@@ -42,11 +18,12 @@
         <template is="dom-repeat" items="[[menuOptions]]" initial-count="5">
           <!--TODO(dpapad): Use <button class="paper-item">..</button> once it
               lands in paper-item-shared-styles.html-->
-          <div class="item" role="option" data-value$="[[item.value]]">
+          <div class="dropdown-item" role="option" data-value$="[[item.value]]">
             [[item.name]]
           </div>
         </template>
-        <div class="item" role="option" data-value$="[[notFoundValue_]]"
+        <div class="dropdown-item" role="option"
+            data-value$="[[notFoundValue_]]"
             hidden$="[[!isSelectedNotFound_(selected_)]]">
           $i18n{custom}
         </div>
diff --git a/chrome/browser/resources/settings/people_page/sync_page.html b/chrome/browser/resources/settings/people_page/sync_page.html
index 186946de..42a8d2d0 100644
--- a/chrome/browser/resources/settings/people_page/sync_page.html
+++ b/chrome/browser/resources/settings/people_page/sync_page.html
@@ -4,7 +4,6 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-dropdown-menu/paper-dropdown-menu.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-button/paper-radio-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-group/paper-radio-group.html">
diff --git a/chrome/browser/resources/settings/search_page/search_page.html b/chrome/browser/resources/settings/search_page/search_page.html
index eb12862..675c940 100644
--- a/chrome/browser/resources/settings/search_page/search_page.html
+++ b/chrome/browser/resources/settings/search_page/search_page.html
@@ -12,28 +12,6 @@
 <dom-module id="settings-search-page">
   <template>
     <style include="settings-shared">
-      paper-dropdown-menu {
-        /* TODO(dschuyler): share styling with settings-dropdown-menu */
-        --iron-icon-fill-color: var(--paper-grey-600);
-      }
-
-      paper-listbox div {
-        align-items: center;
-        color: var(--paper-grey-800);
-        display: flex;
-        font-size: inherit;
-        min-height: 48px;
-        padding: 0 16px;
-      }
-
-      paper-listbox div.iron-selected {
-        font-weight: bold;
-      }
-
-      paper-listbox div:focus {
-        background-color: var(--paper-grey-300);
-        outline: none;
-      }
     </style>
     <settings-animated-pages id="pages" current-route="{{currentRoute}}"
         section="search">
@@ -47,7 +25,7 @@
               <template is="dom-repeat" items="[[searchEngines_]]">
                 <!--TODO(dpapad): Use <button class="paper-item">..</button>
                     once it lands in paper-item-shared-styles.html-->
-                <div role="option">[[item.name]]</div>
+                <div class="dropdown-item" role="option">[[item.name]]</div>
               </template>
             </paper-listbox>
           </paper-dropdown-menu>
diff --git a/chrome/browser/resources/settings/search_settings.js b/chrome/browser/resources/settings/search_settings.js
new file mode 100644
index 0000000..53d5d22
--- /dev/null
+++ b/chrome/browser/resources/settings/search_settings.js
@@ -0,0 +1,195 @@
+// 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.
+
+cr.define('settings', function() {
+  /** @const {string} */
+  var WRAPPER_CSS_CLASS = 'search-highlight-wrapper';
+
+  /** @const {string} */
+  var HIT_CSS_CLASS = 'search-highlight-hit';
+
+  /** @const {!RegExp} */
+  var SANITIZE_REGEX = /[-[\]{}()*+?.,\\^$|#\s]/g;
+
+  /**
+   * List of elements types that should not be searched at all.
+   * The only DOM-MODULE node is in <body> which is not searched, therefore
+   * DOM-MODULE is not needed in this set.
+   * @const {!Set<string>}
+   */
+  var IGNORED_ELEMENTS = new Set([
+    'CONTENT',
+    'CR-EVENTS',
+    'IMG',
+    'IRON-ICON',
+    'IRON-LIST',
+    'PAPER-ICON-BUTTON',
+    /* TODO(dpapad): paper-item is used for dynamically populated dropdown
+     * menus. Perhaps a better approach is to mark the entire dropdown menu such
+     * that search algorithm can skip it as a whole instead.
+     */
+    'PAPER-ITEM',
+    'PAPER-RIPPLE',
+    'PAPER-SLIDER',
+    'PAPER-SPINNER',
+    'STYLE',
+    'TEMPLATE',
+  ]);
+
+  /**
+   * Finds all previous highlighted nodes under |node| (both within self and
+   * children's Shadow DOM) and removes the highlight (yellow rectangle).
+   * @param {!Node} node
+   * @private
+   */
+  function findAndRemoveHighlights_(node) {
+    var wrappers = node.querySelectorAll('* /deep/ .' + WRAPPER_CSS_CLASS);
+
+    for (var wrapper of wrappers) {
+      var hitElements = wrapper.querySelectorAll('.' + HIT_CSS_CLASS);
+      // For each hit element, remove the highlighting.
+      for (var hitElement of hitElements) {
+        wrapper.replaceChild(hitElement.firstChild, hitElement);
+      }
+
+      // Normalize so that adjacent text nodes will be combined.
+      wrapper.normalize();
+      // Restore the DOM structure as it was before the search occurred.
+      if (wrapper.previousSibling)
+        wrapper.textContent = ' ' + wrapper.textContent;
+      if (wrapper.nextSibling)
+        wrapper.textContent = wrapper.textContent + ' ';
+
+      wrapper.parentElement.replaceChild(wrapper.firstChild, wrapper);
+    }
+  }
+
+  /**
+   * Applies the highlight UI (yellow rectangle) around all matches in |node|.
+   * @param {!Node} node The text node to be highlighted. |node| ends up
+   *     being removed from the DOM tree.
+   * @param {!Array<string>} tokens The string tokens after splitting on the
+   *     relevant regExp. Even indices hold text that doesn't need highlighting,
+   *     odd indices hold the text to be highlighted. For example:
+   *     var r = new RegExp('(foo)', 'i');
+   *     'barfoobar foo bar'.split(r) => ['bar', 'foo', 'bar ', 'foo', ' bar']
+   * @private
+   */
+  function highlight_(node, tokens) {
+    var wrapper = document.createElement('span');
+    wrapper.classList.add(WRAPPER_CSS_CLASS);
+    // Use existing node as placeholder to determine where to insert the
+    // replacement content.
+    node.parentNode.replaceChild(wrapper, node);
+
+    for (var i = 0; i < tokens.length; ++i) {
+      if (i % 2 == 0) {
+        wrapper.appendChild(document.createTextNode(tokens[i]));
+      } else {
+        var span = document.createElement('span');
+        span.classList.add(HIT_CSS_CLASS);
+        span.style.backgroundColor = 'yellow';
+        span.textContent = tokens[i];
+        wrapper.appendChild(span);
+      }
+    }
+  }
+
+  /**
+   * Traverses the entire DOM (including Shadow DOM), finds text nodes that
+   * match the given regular expression and applies the highlight UI. It also
+   * ensures that <settings-section> instances become visible if any matches
+   * occurred under their subtree.
+   *
+   * @param {!Element} page The page to be searched, should be either
+   *     <settings-basic-page> or <settings-advanced-page>.
+   * @param {!RegExp} regExp The regular expression to detect matches.
+   * @private
+   */
+  function findAndHighlightMatches_(page, regExp) {
+    function doSearch(node) {
+      if (IGNORED_ELEMENTS.has(node.tagName))
+        return;
+
+      if (node.nodeType == Node.TEXT_NODE) {
+        var textContent = node.nodeValue.trim();
+        if (textContent.length == 0)
+          return;
+
+        if (regExp.test(textContent)) {
+          revealParentSection_(node);
+          highlight_(node, textContent.split(regExp));
+        }
+        // Returning early since TEXT_NODE nodes never have children.
+        return;
+      }
+
+      var child = node.firstChild;
+      while (child !== null) {
+        // Getting a reference to the |nextSibling| before calling doSearch()
+        // because |child| could be removed from the DOM within doSearch().
+        var nextSibling = child.nextSibling;
+        doSearch(child);
+        child = nextSibling;
+      }
+
+      var shadowRoot = node.shadowRoot;
+      if (shadowRoot)
+        doSearch(shadowRoot);
+    }
+
+    doSearch(page);
+  }
+
+  /**
+   * Finds and makes visible the <settings-section> parent of |node|.
+   * @param {!Node} node
+   */
+  function revealParentSection_(node) {
+    // Find corresponding SETTINGS-SECTION parent and make it visible.
+    var parent = node;
+    while (parent && parent.tagName !== 'SETTINGS-SECTION') {
+      parent = parent.nodeType == Node.DOCUMENT_FRAGMENT_NODE ?
+          parent.host : parent.parentNode;
+    }
+    if (parent)
+      parent.hidden = false;
+  }
+
+  /**
+   * @param {!Element} page
+   * @param {boolean} visible
+   * @private
+   */
+  function setSectionsVisibility_(page, visible) {
+    var sections = Polymer.dom(page.root).querySelectorAll('settings-section');
+    for (var i = 0; i < sections.length; i++)
+      sections[i].hidden = !visible;
+  }
+
+  /**
+   * Performs hierarchical search, starting at the given page element.
+   * @param {string} text
+   * @param {!Element} page Must be either <settings-basic-page> or
+   *     <settings-advanced-page>.
+   */
+  function search(text, page) {
+    findAndRemoveHighlights_(page);
+
+    // Generate search text by escaping any characters that would be problematic
+    // for regular expressions.
+    var searchText = text.trim().replace(SANITIZE_REGEX, '\\$&');
+    if (searchText.length == 0) {
+      setSectionsVisibility_(page, true);
+      return;
+    }
+
+    setSectionsVisibility_(page, false);
+    findAndHighlightMatches_(page, new RegExp('(' + searchText + ')', 'i'));
+  }
+
+  return {
+    search: search,
+  };
+});
diff --git a/chrome/browser/resources/settings/settings_main/compiled_resources2.gyp b/chrome/browser/resources/settings/settings_main/compiled_resources2.gyp
index c405595..d17a3d8 100644
--- a/chrome/browser/resources/settings/settings_main/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/settings_main/compiled_resources2.gyp
@@ -14,8 +14,10 @@
     {
       'target_name': 'settings_main',
       'dependencies': [
-        'settings_main_rendered',
+        '../compiled_resources2.gyp:search_settings',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:promise_resolver',
+        'settings_main_rendered',
         '../settings_page/compiled_resources2.gyp:main_page_behavior',
         '../settings_page/compiled_resources2.gyp:settings_router',
       ],
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.html b/chrome/browser/resources/settings/settings_main/settings_main.html
index 2256024..990c85c 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.html
+++ b/chrome/browser/resources/settings/settings_main/settings_main.html
@@ -62,4 +62,5 @@
     </template>
   </template>
   <script src="settings_main.js"></script>
+  <script src="/search_settings.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.js b/chrome/browser/resources/settings/settings_main/settings_main.js
index 254f261..75daea4 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.js
+++ b/chrome/browser/resources/settings/settings_main/settings_main.js
@@ -59,6 +59,7 @@
     },
   },
 
+  /** @override */
   created: function() {
     /** @private {!PromiseResolver} */
     this.resolver_ = new PromiseResolver;
@@ -129,4 +130,36 @@
   toggleAdvancedPage_: function() {
     this.fire('toggle-advanced-page', !this.isAdvancedMenuOpen_);
   },
+
+  /**
+   * Navigates to the default search page (if necessary).
+   * @private
+   */
+  ensureInDefaultSearchPage_: function() {
+    if (this.currentRoute.page != 'basic' ||
+        this.currentRoute.section != '' ||
+        this.currentRoute.subpage.length != 0) {
+      this.currentRoute = {page: 'basic', section: '', subpage: [], url: ''};
+    }
+  },
+
+  /**
+   * @param {string} query
+   */
+  searchContents: function(query) {
+    this.ensureInDefaultSearchPage_();
+
+    // Trigger rendering of the basic and advanced pages and search once ready.
+    // Even if those are already rendered, yield to the message loop before
+    // initiating searching.
+    this.showBasicPage_ = true;
+    setTimeout(function() {
+      settings.search(query, assert(this.$$('settings-basic-page')));
+    }.bind(this), 0);
+
+    this.showAdvancedPage_ = true;
+    setTimeout(function() {
+      settings.search(query, assert(this.$$('settings-advanced-page')));
+    }.bind(this), 0);
+  },
 });
diff --git a/chrome/browser/resources/settings/settings_menu/compiled_resources2.gyp b/chrome/browser/resources/settings/settings_menu/compiled_resources2.gyp
index 287f194..295dcc2 100644
--- a/chrome/browser/resources/settings/settings_menu/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/settings_menu/compiled_resources2.gyp
@@ -6,6 +6,7 @@
     {
       'target_name': 'settings_menu',
       'dependencies': [
+        '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-ripple/compiled_resources2.gyp:paper-ripple-extracted',
         '../settings_page/compiled_resources2.gyp:settings_router',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html
index a0eb44a3..adad5296 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.html
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -3,6 +3,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-menu/paper-menu.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-menu/paper-submenu.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-ripple/paper-ripple.html">
 <link rel="import" href="/icons.html">
 <link rel="import" href="/settings_shared_css.html">
 
@@ -53,6 +54,15 @@
         };
       }
 
+      paper-menu div {
+        position: relative;  /* Needed for paper-ripple. */
+      }
+
+      paper-ripple {
+        color: var(--google-blue-500);
+        opacity: .5;
+      }
+
       .page-menu paper-menu {
         --paper-menu-selected-item: {
           color: var(--google-blue-500);
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.js b/chrome/browser/resources/settings/settings_menu/settings_menu.js
index d2a4c905..016b1a8 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.js
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.js
@@ -63,10 +63,25 @@
   },
 
   /**
+   * @param {!Node} target
+   * @private
+   */
+  ripple_: function(target) {
+    var ripple = document.createElement('paper-ripple');
+    ripple.addEventListener('transitionend', function() {
+      ripple.remove();
+    });
+    target.appendChild(ripple);
+    ripple.downAction();
+    ripple.upAction();
+  },
+
+  /**
    * @param {!Event} event
    * @private
    */
   openPage_: function(event) {
+    this.ripple_(/** @type {!Node} */(event.currentTarget));
     var submenuRoute = event.currentTarget.parentNode.dataset.page;
     if (submenuRoute) {
       this.currentRoute = {
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index be6ba8c..61b8218 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -72,6 +72,12 @@
       <structure name="IDR_SETTINGS_ALL_SITES_JS"
                  file="site_settings/all_sites.js"
                  type="chrome_html" />
+      <structure name="IDR_SETTINGS_ANIMATION_ANIMATION_HTML"
+                 file="animation/animation.html"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_ANIMATION_ANIMATION_JS"
+                 file="animation/animation.js"
+                 type="chrome_html" />
       <structure name="IDR_SETTINGS_CR_SETTINGS_ANIMATED_PAGES_HTML"
                  file="settings_page/settings_animated_pages.html"
                  type="chrome_html" />
@@ -128,6 +134,9 @@
       <structure name="IDR_SETTINGS_ON_STARTUP_PAGE_JS"
                  file="on_startup_page/on_startup_page.js"
                  type="chrome_html" />
+      <structure name="IDR_SETTINGS_SEARCH_SETTINGS_JS"
+                 file="search_settings.js"
+                 type="chrome_html" />
       <structure name="IDR_SETTINGS_STARTUP_URLS_PAGE_HTML"
                  file="on_startup_page/startup_urls_page.html"
                  type="chrome_html" />
diff --git a/chrome/browser/resources/settings/settings_shared_css.html b/chrome/browser/resources/settings/settings_shared_css.html
index e3654ec..a04010c 100644
--- a/chrome/browser/resources/settings/settings_shared_css.html
+++ b/chrome/browser/resources/settings/settings_shared_css.html
@@ -27,6 +27,34 @@
         background-color: var(--paper-grey-300);
       }
 
+      paper-dropdown-menu {
+        --iron-icon-fill-color: var(--paper-grey-600);
+        --paper-font-subhead: {
+          font-size: inherit;
+        };
+        --paper-input-container-underline: {
+          background: var(--paper-grey-300);
+        };
+      }
+
+      paper-dropdown-menu .dropdown-item {
+        align-items: center;
+        color: var(--paper-grey-800);
+        display: flex;
+        font-size: inherit;
+        min-height: 48px;
+        padding: 0 16px;
+      }
+
+      paper-dropdown-menu .dropdown-item.iron-selected {
+        font-weight: bold;
+      }
+
+      paper-dropdown-menu .dropdown-item:focus {
+        background-color: var(--paper-grey-300);
+        outline: none;
+      }
+
       span ~ a {
         -webkit-margin-start: 4px;
       }
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.html b/chrome/browser/resources/settings/settings_ui/settings_ui.html
index f30394e7..ba3b499 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.html
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.html
@@ -3,7 +3,6 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/app-layout/app-drawer/app-drawer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-header-panel/paper-header-panel.html">
 <link rel="import" href="/direction_delegate.html">
 <link rel="import" href="/i18n_setup.html">
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js
index a503726..162a0f0 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.js
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -57,6 +57,13 @@
     this.$$('app-drawer').toggle();
   },
 
+  /** @override */
+  ready: function() {
+    this.$$('cr-toolbar').addEventListener('search-changed', function(e) {
+      this.$$('settings-main').searchContents(e.detail);
+    }.bind(this));
+  },
+
   /** @private */
   directionDelegateChanged_: function() {
     this.$$('app-drawer').align = this.directionDelegate.isRtl() ?
diff --git a/chrome/browser/resources/settings/site_settings/media_picker.html b/chrome/browser/resources/settings/site_settings/media_picker.html
index f7dd9dc1..733827e 100644
--- a/chrome/browser/resources/settings/site_settings/media_picker.html
+++ b/chrome/browser/resources/settings/site_settings/media_picker.html
@@ -1,6 +1,5 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-dropdown-menu/paper-dropdown-menu.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-listbox/paper-listbox.html">
 <link rel="import" href="/settings_shared_css.html">
 
@@ -10,16 +9,6 @@
       :host {
         display: block;
       }
-
-      paper-dropdown-menu {
-        --paper-input-container-input: {
-          font-size: inherit;
-        };
-
-        --paper-font-caption: {
-          font-size: inherit;
-        }
-      }
     </style>
     <div class="settings-box" id="picker" hidden>
       <paper-dropdown-menu>
@@ -27,9 +16,10 @@
             attr-for-selected="media-picker-value"
             on-iron-activate="onMediaPickerActivate_">
           <template is="dom-repeat" items="[[devices]]">
-            <paper-item media-picker-value$="[[item.id]]">
+            <div class="dropdown-item" role="option"
+                media-picker-value$="[[item.id]]">
               [[item.name]]
-            </paper-item>
+            </div>
           </template>
         </paper-listbox>
       </paper-dropdown-menu>
diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.html b/chrome/browser/resources/settings/site_settings/site_details_permission.html
index 42c7b56a7..a18cbdc 100644
--- a/chrome/browser/resources/settings/site_settings/site_details_permission.html
+++ b/chrome/browser/resources/settings/site_settings/site_details_permission.html
@@ -2,7 +2,6 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-dropdown-menu/paper-dropdown-menu.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-listbox/paper-listbox.html">
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
 <link rel="import" href="/i18n_setup.html">
@@ -18,16 +17,6 @@
         display: block;
       }
 
-      paper-dropdown-menu {
-        --paper-input-container-input: {
-          font-size: inherit;
-        };
-
-        --paper-font-caption: {
-          font-size: inherit;
-        }
-      }
-
       .left-column {
         -webkit-margin-start: 15px;
       }
@@ -71,14 +60,14 @@
             <paper-listbox id="permission" class="dropdown-content"
                 on-iron-activate="onPermissionMenuIronActivate_"
                 attr-for-selected="data-permission-value">
-              <paper-item id="allow"
+              <div id="allow" class="dropdown-item" role="option"
                   data-permission-value$="[[PermissionValues.ALLOW]]">
                 [[i18n_.allowAction]]
-              </paper-item>
-              <paper-item id="block"
+              </div>
+              <div id="block" class="dropdown-item" role="option"
                   data-permission-value$="[[PermissionValues.BLOCK]]">
                  [[i18n_.blockAction]]
-              </paper-item>
+              </div>
             </paper-listbox>
           </paper-dropdown-menu>
         </div>
diff --git a/chrome/browser/resources/settings/site_settings/site_list.html b/chrome/browser/resources/settings/site_settings/site_list.html
index 2bbd65e..8a94d00e 100644
--- a/chrome/browser/resources/settings/site_settings/site_list.html
+++ b/chrome/browser/resources/settings/site_settings/site_list.html
@@ -82,11 +82,14 @@
           </div>
         </template>
 
-        <div class="button-container">
-          <paper-button on-tap="onAddSiteTap_" class="primary-button no-upper">
-            $i18n{addSiteLink}
-          </paper-button>
-        </div>
+        <template is="dom-if" if="{{!allSites}}">
+          <div class="button-container">
+            <paper-button on-tap="onAddSiteTap_"
+                class="primary-button no-upper">
+              $i18n{addSiteLink}
+            </paper-button>
+          </div>
+        </template>
       </div>
     </paper-submenu>
   </template>
diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_page.html b/chrome/browser/resources/settings/site_settings_page/site_settings_page.html
index 94a485b..16afa796 100644
--- a/chrome/browser/resources/settings/site_settings_page/site_settings_page.html
+++ b/chrome/browser/resources/settings/site_settings_page/site_settings_page.html
@@ -1,5 +1,4 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html">
 <link rel="import" href="/icons.html">
 <link rel="import" href="/settings_shared_css.html">
 <link rel="import" href="/site_settings/constants.html">
diff --git a/chrome/browser/safe_browsing/safe_browsing_store_file.cc b/chrome/browser/safe_browsing/safe_browsing_store_file.cc
index b19cb236..35fe24a 100644
--- a/chrome/browser/safe_browsing/safe_browsing_store_file.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_store_file.cc
@@ -407,17 +407,17 @@
     container_merge(&add_prefixes_,
                     beg.add_prefixes_iter_,
                     end.add_prefixes_iter_,
-                    SBAddPrefixLess<SBAddPrefix,SBAddPrefix>);
+                    SBAddPrefixLess<SBAddPrefix, SBAddPrefix>);
 
     container_merge(&sub_prefixes_,
                     beg.sub_prefixes_iter_,
                     end.sub_prefixes_iter_,
-                    SBAddPrefixLess<SBSubPrefix,SBSubPrefix>);
+                    SBAddPrefixLess<SBSubPrefix, SBSubPrefix>);
 
     container_merge(&add_full_hashes_,
                     beg.add_hashes_iter_,
                     end.add_hashes_iter_,
-                    SBAddPrefixHashLess<SBAddFullHash,SBAddFullHash>);
+                    SBAddPrefixHashLess<SBAddFullHash, SBAddFullHash>);
 
     container_merge(&sub_full_hashes_,
                     beg.sub_hashes_iter_,
@@ -433,13 +433,13 @@
   // operations.
   void SortData() {
     std::sort(add_prefixes_.begin(), add_prefixes_.end(),
-              SBAddPrefixLess<SBAddPrefix,SBAddPrefix>);
+              SBAddPrefixLess<SBAddPrefix, SBAddPrefix>);
     std::sort(sub_prefixes_.begin(), sub_prefixes_.end(),
-              SBAddPrefixLess<SBSubPrefix,SBSubPrefix>);
+              SBAddPrefixLess<SBSubPrefix, SBSubPrefix>);
     std::sort(add_full_hashes_.begin(), add_full_hashes_.end(),
-              SBAddPrefixHashLess<SBAddFullHash,SBAddFullHash>);
+              SBAddPrefixHashLess<SBAddFullHash, SBAddFullHash>);
     std::sort(sub_full_hashes_.begin(), sub_full_hashes_.end(),
-              SBAddPrefixHashLess<SBSubFullHash,SBSubFullHash>);
+              SBAddPrefixHashLess<SBSubFullHash, SBSubFullHash>);
   }
 
   // Iterator from the beginning of the state's data.
diff --git a/chrome/browser/services/gcm/fake_signin_manager.cc b/chrome/browser/services/gcm/fake_signin_manager.cc
deleted file mode 100644
index aa72139..0000000
--- a/chrome/browser/services/gcm/fake_signin_manager.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/services/gcm/fake_signin_manager.h"
-
-#include "base/observer_list.h"
-#include "build/build_config.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/account_tracker_service_factory.h"
-#include "chrome/browser/signin/chrome_signin_client_factory.h"
-#include "chrome/browser/signin/gaia_cookie_manager_service_factory.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "components/prefs/pref_service.h"
-#include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/common/signin_pref_names.h"
-#include "content/public/browser/browser_context.h"
-
-#if !defined(OS_CHROMEOS)
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#endif
-
-namespace gcm {
-
-FakeSigninManager::FakeSigninManager(Profile* profile)
-#if defined(OS_CHROMEOS)
-    : SigninManagerBase(
-        ChromeSigninClientFactory::GetInstance()->GetForProfile(profile),
-        AccountTrackerServiceFactory::GetForProfile(profile)),
-#else
-    : SigninManager(
-        ChromeSigninClientFactory::GetInstance()->GetForProfile(profile),
-        ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
-        AccountTrackerServiceFactory::GetForProfile(profile),
-        GaiaCookieManagerServiceFactory::GetForProfile(profile)),
-#endif
-      profile_(profile) {
-  Initialize(NULL);
-}
-
-FakeSigninManager::~FakeSigninManager() {
-}
-
-void FakeSigninManager::SignIn(const std::string& account_id) {
-  SetAuthenticatedAccountId(account_id);
-  FOR_EACH_OBSERVER(SigninManagerBase::Observer,
-                    observer_list_,
-                    GoogleSigninSucceeded(account_id, account_id,
-                                          std::string()));
-}
-
-void FakeSigninManager::SignOut(
-    signin_metrics::ProfileSignout signout_source_metric,
-    signin_metrics::SignoutDelete signout_delete_metric) {
-  const std::string account_id = GetAuthenticatedAccountId();
-  const std::string username = GetAuthenticatedAccountInfo().email;
-  clear_authenticated_user();
-  profile_->GetPrefs()->ClearPref(prefs::kGoogleServicesAccountId);
-  FOR_EACH_OBSERVER(SigninManagerBase::Observer,
-                    observer_list_,
-                    GoogleSignedOut(account_id, username));
-}
-
-// static
-KeyedService* FakeSigninManager::Build(content::BrowserContext* context) {
-  return new FakeSigninManager(Profile::FromBrowserContext(context));
-}
-
-}  // namespace gcm
diff --git a/chrome/browser/services/gcm/fake_signin_manager.h b/chrome/browser/services/gcm/fake_signin_manager.h
deleted file mode 100644
index 7320a54..0000000
--- a/chrome/browser/services/gcm/fake_signin_manager.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_SERVICES_GCM_FAKE_SIGNIN_MANAGER_H_
-#define CHROME_BROWSER_SERVICES_GCM_FAKE_SIGNIN_MANAGER_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "build/build_config.h"
-#include "components/signin/core/browser/signin_metrics.h"
-
-#if defined(OS_CHROMEOS)
-#include "components/signin/core/browser/signin_manager_base.h"
-#else
-#include "base/compiler_specific.h"
-#include "components/signin/core/browser/signin_manager.h"
-#endif
-
-class KeyedService;
-class Profile;
-
-namespace content {
-class BrowserContext;
-}
-
-namespace gcm {
-
-#if defined(OS_CHROMEOS)
-class FakeSigninManager : public SigninManagerBase {
-#else
-class FakeSigninManager : public SigninManager {
-#endif
-
- public:
-  explicit FakeSigninManager(Profile* profile);
-  ~FakeSigninManager() override;
-
-  void SignIn(const std::string& username);
-#if defined(OS_CHROMEOS)
-  void SignOut(signin_metrics::ProfileSignout signout_source_metric,
-               signin_metrics::SignoutDelete signout_delete_metric);
-#else
-  void SignOut(signin_metrics::ProfileSignout signout_source_metric,
-               signin_metrics::SignoutDelete signout_delete_metric) override;
-#endif
-
-  static KeyedService* Build(content::BrowserContext* context);
-
- private:
-  Profile* profile_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeSigninManager);
-};
-
-}  // namespace gcm
-
-#endif  // CHROME_BROWSER_SERVICES_GCM_FAKE_SIGNIN_MANAGER_H_
diff --git a/chrome/browser/ssl/chrome_security_state_model_client.cc b/chrome/browser/ssl/chrome_security_state_model_client.cc
index 0c54067..6f242a4 100644
--- a/chrome/browser/ssl/chrome_security_state_model_client.cc
+++ b/chrome/browser/ssl/chrome_security_state_model_client.cc
@@ -114,7 +114,6 @@
   if (!security_info.scheme_is_cryptographic) {
     return security_style;
   }
-  security_style_explanations->pkp_bypassed = security_info.pkp_bypassed;
 
   if (security_info.sha1_deprecation_status ==
       SecurityStateModel::DEPRECATED_SHA1_MAJOR) {
@@ -181,6 +180,14 @@
                 IDS_SECURE_PROTOCOL_AND_CIPHERSUITE_DESCRIPTION)));
   }
 
+  security_style_explanations->pkp_bypassed = security_info.pkp_bypassed;
+  if (security_info.pkp_bypassed) {
+    security_style_explanations->info_explanations.push_back(
+        content::SecurityStyleExplanation(
+            "Public-Key Pinning Bypassed",
+            "Public-key pinning was bypassed by a local root certificate."));
+  }
+
   return security_style;
 }
 
diff --git a/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc b/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc
index 16f0350..1a4cb852 100644
--- a/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc
+++ b/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc
@@ -111,6 +111,7 @@
   EXPECT_EQ(0u, expired_explanation.unauthenticated_explanations.size());
   ASSERT_EQ(1u, expired_explanation.broken_explanations.size());
   EXPECT_FALSE(expired_explanation.pkp_bypassed);
+  EXPECT_TRUE(expired_explanation.info_explanations.empty());
 
   // Check that the summary and description are as expected.
   EXPECT_EQ(l10n_util::GetStringUTF8(IDS_CERTIFICATE_CHAIN_ERROR),
@@ -644,6 +645,7 @@
   const content::SecurityStyleExplanations& explanation =
       observer.latest_explanations();
   EXPECT_TRUE(explanation.pkp_bypassed);
+  EXPECT_FALSE(explanation.info_explanations.empty());
 }
 
 IN_PROC_BROWSER_TEST_F(PKPModelClientTest, PKPEnforced) {
@@ -796,6 +798,7 @@
   EXPECT_EQ(0u, observer.latest_explanations().secure_explanations.size());
   EXPECT_FALSE(observer.latest_explanations().scheme_is_cryptographic);
   EXPECT_FALSE(observer.latest_explanations().pkp_bypassed);
+  EXPECT_TRUE(observer.latest_explanations().info_explanations.empty());
   EXPECT_FALSE(observer.latest_explanations().ran_insecure_content);
   EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content);
 
@@ -818,6 +821,7 @@
                           VALID_CERTIFICATE, browser());
   EXPECT_TRUE(mixed_content_explanation.scheme_is_cryptographic);
   EXPECT_FALSE(observer.latest_explanations().pkp_bypassed);
+  EXPECT_TRUE(observer.latest_explanations().info_explanations.empty());
   EXPECT_TRUE(mixed_content_explanation.displayed_insecure_content);
   EXPECT_FALSE(mixed_content_explanation.ran_insecure_content);
   EXPECT_EQ(content::SECURITY_STYLE_UNAUTHENTICATED,
@@ -838,6 +842,7 @@
                           INVALID_CERTIFICATE, browser());
   EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic);
   EXPECT_FALSE(observer.latest_explanations().pkp_bypassed);
+  EXPECT_TRUE(observer.latest_explanations().info_explanations.empty());
   EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content);
   EXPECT_FALSE(observer.latest_explanations().ran_insecure_content);
 
@@ -854,6 +859,7 @@
                           VALID_CERTIFICATE, browser());
   EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic);
   EXPECT_FALSE(observer.latest_explanations().pkp_bypassed);
+  EXPECT_TRUE(observer.latest_explanations().info_explanations.empty());
   EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content);
   EXPECT_FALSE(observer.latest_explanations().ran_insecure_content);
 
@@ -867,6 +873,7 @@
                           INVALID_CERTIFICATE, browser());
   EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic);
   EXPECT_FALSE(observer.latest_explanations().pkp_bypassed);
+  EXPECT_TRUE(observer.latest_explanations().info_explanations.empty());
   EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content);
   EXPECT_FALSE(observer.latest_explanations().ran_insecure_content);
 
@@ -884,6 +891,7 @@
                           INVALID_CERTIFICATE, browser());
   EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic);
   EXPECT_FALSE(observer.latest_explanations().pkp_bypassed);
+  EXPECT_TRUE(observer.latest_explanations().info_explanations.empty());
   EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content);
   EXPECT_FALSE(observer.latest_explanations().ran_insecure_content);
 }
@@ -917,6 +925,7 @@
                           VALID_CERTIFICATE, browser());
   EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic);
   EXPECT_FALSE(observer.latest_explanations().pkp_bypassed);
+  EXPECT_TRUE(observer.latest_explanations().info_explanations.empty());
   EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content);
   EXPECT_FALSE(observer.latest_explanations().ran_insecure_content);
 
@@ -942,6 +951,7 @@
                           INVALID_CERTIFICATE, browser());
   EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic);
   EXPECT_FALSE(observer.latest_explanations().pkp_bypassed);
+  EXPECT_TRUE(observer.latest_explanations().info_explanations.empty());
   EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content);
   EXPECT_FALSE(observer.latest_explanations().ran_insecure_content);
 
@@ -961,6 +971,7 @@
                           VALID_CERTIFICATE, browser());
   EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic);
   EXPECT_FALSE(observer.latest_explanations().pkp_bypassed);
+  EXPECT_TRUE(observer.latest_explanations().info_explanations.empty());
   EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content);
   EXPECT_FALSE(observer.latest_explanations().ran_insecure_content);
 }
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc
index 298e804c..2d93d117 100644
--- a/chrome/browser/ssl/ssl_browser_tests.cc
+++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -1045,13 +1045,7 @@
 // Visit a HTTP page which request WSS connection to a server providing invalid
 // certificate. Close the page while WSS connection waits for SSLManager's
 // response from UI thread.
-// Disabled on Windows because it was flaking on XP Tests (1). crbug.com/165258
-#if defined(OS_WIN)
-#define MAYBE_TestWSSInvalidCertAndClose DISABLED_TestWSSInvalidCertAndClose
-#else
-#define MAYBE_TestWSSInvalidCertAndClose TestWSSInvalidCertAndClose
-#endif
-IN_PROC_BROWSER_TEST_F(SSLUITest, MAYBE_TestWSSInvalidCertAndClose) {
+IN_PROC_BROWSER_TEST_F(SSLUITest, TestWSSInvalidCertAndClose) {
   ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(wss_server_expired_.Start());
 
diff --git a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
index 756d7ac..34fc785 100644
--- a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
+++ b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
@@ -192,6 +192,14 @@
   // Notify ProfileSyncService that we are done with configuration.
   FinishSyncSetup();
 
+  if ((signin_type_ == SigninType::UI_SIGNIN) &&
+      !login_ui_test_utils::DismissSyncConfirmationDialog(
+          chrome::FindBrowserWithProfile(profile_),
+          base::TimeDelta::FromSeconds(30))) {
+    LOG(ERROR) << "Failed to dismiss sync confirmation dialog.";
+    return false;
+  }
+
   // Set an implicit passphrase for encryption if an explicit one hasn't already
   // been set. If an explicit passphrase has been set, immediately return false,
   // since a decryption passphrase is required.
diff --git a/chrome/browser/sync/test/integration/two_client_typed_urls_sync_test.cc b/chrome/browser/sync/test/integration/two_client_typed_urls_sync_test.cc
index a73aa4cb..1aa1f90 100644
--- a/chrome/browser/sync/test/integration/two_client_typed_urls_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_typed_urls_sync_test.cc
@@ -95,7 +95,7 @@
   // Assert that the second client has the correct new URL.
   history::URLRows urls = GetTypedUrlsFromClient(1);
   ASSERT_EQ(initial_count + 1, urls.size());
-  ASSERT_EQ(new_url, urls[urls.size() - 1].url());
+  ASSERT_EQ(new_url, urls.back().url());
 }
 
 IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, AddExpired) {
@@ -183,7 +183,7 @@
   // Assert that the second client has the correct new URL.
   history::URLRows urls = GetTypedUrlsFromClient(1);
   ASSERT_EQ(initial_count + 1, urls.size());
-  ASSERT_EQ(new_url, urls[urls.size() - 1].url());
+  ASSERT_EQ(new_url, urls.back().url());
 
   // Delete from first client, and wait for them to sync.
   DeleteUrlFromHistory(0, new_url);
diff --git a/chrome/browser/ui/app_list/app_context_menu_unittest.cc b/chrome/browser/ui/app_list/app_context_menu_unittest.cc
index dcecb117..e864e499 100644
--- a/chrome/browser/ui/app_list/app_context_menu_unittest.cc
+++ b/chrome/browser/ui/app_list/app_context_menu_unittest.cc
@@ -219,20 +219,12 @@
     if (!platform_app) {
       if (extensions::util::CanHostedAppsOpenInWindows() &&
           extensions::util::IsNewBookmarkAppsEnabled()) {
-        // MACOS has different logic for this case.
-        // See chrome/browser/extensions/launch_util.cc for more details.
-        bool checked = launch_type == extensions::LAUNCH_TYPE_WINDOW;
-#if !defined(OS_MACOSX)
-        checked |= launch_type == extensions::LAUNCH_TYPE_FULLSCREEN;
-#endif
+        bool checked = launch_type == extensions::LAUNCH_TYPE_WINDOW ||
+            launch_type == extensions::LAUNCH_TYPE_FULLSCREEN;
         states.push_back(MenuState(
             app_list::AppContextMenu::USE_LAUNCH_TYPE_WINDOW, true, checked));
       } else if (!extensions::util::IsNewBookmarkAppsEnabled()) {
         bool regular_checked = launch_type == extensions::LAUNCH_TYPE_REGULAR;
-#if defined(OS_MACOSX)
-        regular_checked |= (!extensions::util::CanHostedAppsOpenInWindows() &&
-            launch_type == extensions::LAUNCH_TYPE_WINDOW);
-#endif
         states.push_back(MenuState(
             app_list::AppContextMenu::USE_LAUNCH_TYPE_REGULAR,
             true,
diff --git a/chrome/browser/ui/app_list/app_list_controller_browsertest.cc b/chrome/browser/ui/app_list/app_list_controller_browsertest.cc
index bb0eb859..a604ba8 100644
--- a/chrome/browser/ui/app_list/app_list_controller_browsertest.cc
+++ b/chrome/browser/ui/app_list/app_list_controller_browsertest.cc
@@ -125,16 +125,9 @@
   DISALLOW_COPY_AND_ASSIGN(AppListControllerSearchResultsBrowserTest);
 };
 
-
-// Flaky on Mac. https://crbug.com/415264
-#if defined(OS_MACOSX)
-#define MAYBE_UninstallSearchResult DISABLED_UninstallSearchResult
-#else
-#define MAYBE_UninstallSearchResult UninstallSearchResult
-#endif
 // Test showing search results, and uninstalling one of them while displayed.
 IN_PROC_BROWSER_TEST_F(AppListControllerSearchResultsBrowserTest,
-                       MAYBE_UninstallSearchResult) {
+                       UninstallSearchResult) {
   base::FilePath test_extension_path;
   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_extension_path));
   test_extension_path = test_extension_path.AppendASCII("extensions")
diff --git a/chrome/browser/ui/app_list/app_list_controller_delegate.cc b/chrome/browser/ui/app_list/app_list_controller_delegate.cc
index dc4a95531..8127a3e2d 100644
--- a/chrome/browser/ui/app_list/app_list_controller_delegate.cc
+++ b/chrome/browser/ui/app_list/app_list_controller_delegate.cc
@@ -86,10 +86,6 @@
 }
 
 bool AppListControllerDelegate::CanDoShowAppInfoFlow() {
-#if defined(OS_MACOSX)
-  // Cocoa app list doesn't yet support the app info dialog.
-  return false;
-#endif
   return CanShowAppInfoDialog();
 }
 
diff --git a/chrome/browser/ui/app_list/app_list_service_cocoa_mac.h b/chrome/browser/ui/app_list/app_list_service_cocoa_mac.h
deleted file mode 100644
index 8d11241c..0000000
--- a/chrome/browser/ui/app_list/app_list_service_cocoa_mac.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_APP_LIST_APP_LIST_SERVICE_COCOA_MAC_H_
-#define CHROME_BROWSER_UI_APP_LIST_APP_LIST_SERVICE_COCOA_MAC_H_
-
-#include "base/macros.h"
-#include "chrome/browser/ui/app_list/app_list_service_mac.h"
-
-namespace test {
-class AppListServiceMacTestApi;
-}
-
-class AppListControllerDelegateImpl;
-@class AppListWindowController;
-
-namespace base {
-template <typename T>
-struct DefaultSingletonTraits;
-}  // namespace base
-
-// AppListServiceCocoaMac shows and hides the Cocoa app list on Mac.
-class AppListServiceCocoaMac : public AppListServiceMac {
- public:
-  ~AppListServiceCocoaMac() override;
-
-  static AppListServiceCocoaMac* GetInstance();
-
-  // AppListService overrides:
-  void ShowForProfile(Profile* requested_profile) override;
-  Profile* GetCurrentAppListProfile() override;
-  AppListControllerDelegate* GetControllerDelegate() override;
-
-  // AppListServiceImpl overrides:
-  void CreateForProfile(Profile* requested_profile) override;
-  void DestroyAppList() override;
-
- protected:
-  // AppListServiceMac overrides:
-  NSWindow* GetNativeWindow() const override;
-  bool ReadyToShow() override;
-
- private:
-  friend class test::AppListServiceMacTestApi;
-  friend struct base::DefaultSingletonTraits<AppListServiceCocoaMac>;
-
-  AppListServiceCocoaMac();
-
-  Profile* profile_;
-  base::scoped_nsobject<AppListWindowController> window_controller_;
-  std::unique_ptr<AppListControllerDelegateImpl> controller_delegate_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppListServiceCocoaMac);
-};
-
-#endif  // CHROME_BROWSER_UI_APP_LIST_APP_LIST_SERVICE_COCOA_MAC_H_
diff --git a/chrome/browser/ui/app_list/app_list_service_cocoa_mac.mm b/chrome/browser/ui/app_list/app_list_service_cocoa_mac.mm
deleted file mode 100644
index 38b7c66..0000000
--- a/chrome/browser/ui/app_list/app_list_service_cocoa_mac.mm
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/app_list/app_list_service_cocoa_mac.h"
-
-#include "base/memory/singleton.h"
-#include "chrome/browser/ui/app_list/app_list_controller_delegate_impl.h"
-#include "chrome/browser/ui/app_list/app_list_view_delegate.h"
-#import "ui/app_list/cocoa/app_list_view_controller.h"
-#import "ui/app_list/cocoa/app_list_window_controller.h"
-
-AppListServiceCocoaMac::~AppListServiceCocoaMac() {
-}
-
-// static
-AppListServiceCocoaMac* AppListServiceCocoaMac::GetInstance() {
-  return base::Singleton<
-      AppListServiceCocoaMac,
-      base::LeakySingletonTraits<AppListServiceCocoaMac>>::get();
-}
-
-void AppListServiceCocoaMac::ShowForProfile(Profile* requested_profile) {
-  CreateForProfile(requested_profile);
-  DCHECK(ReadyToShow());
-  ShowWindowNearDock();
-}
-
-Profile* AppListServiceCocoaMac::GetCurrentAppListProfile() {
-  return profile_;
-}
-
-AppListControllerDelegate* AppListServiceCocoaMac::GetControllerDelegate() {
-  return controller_delegate_.get();
-}
-
-void AppListServiceCocoaMac::CreateForProfile(Profile* requested_profile) {
-  DCHECK(requested_profile);
-
-  // App list profiles should not be off-the-record.
-  DCHECK(!requested_profile->IsOffTheRecord());
-  DCHECK(!requested_profile->IsGuestSession());
-
-  InvalidatePendingProfileLoads();
-  if (profile_ && requested_profile->IsSameProfile(profile_))
-    return;
-
-  profile_ = requested_profile->GetOriginalProfile();
-  SetProfilePath(profile_->GetPath());
-
-  if (!window_controller_)
-    window_controller_.reset([[AppListWindowController alloc] init]);
-
-  [[window_controller_ appListViewController] setDelegate:nil];
-  [[window_controller_ appListViewController]
-      setDelegate:GetViewDelegate(profile_)];
-}
-
-void AppListServiceCocoaMac::DestroyAppList() {
-  // Due to reference counting, Mac can't guarantee that the widget is deleted,
-  // but mac supports a visible app list with a NULL profile, so there's also no
-  // need to tear it down completely.
-  DismissAppList();
-  [[window_controller_ appListViewController] setDelegate:NULL];
-
-  profile_ = NULL;
-}
-
-NSWindow* AppListServiceCocoaMac::GetNativeWindow() const {
-  return [window_controller_ window];
-}
-
-bool AppListServiceCocoaMac::ReadyToShow() {
-  if (!window_controller_) {
-    // Note that this will start showing an unpopulated window, the caller needs
-    // to ensure it will be populated later.
-    window_controller_.reset([[AppListWindowController alloc] init]);
-  }
-  return true;  // Cocoa app list can be shown empty.
-}
-
-AppListServiceCocoaMac::AppListServiceCocoaMac()
-    : profile_(nullptr),
-      controller_delegate_(new AppListControllerDelegateImpl(this)) {
-}
diff --git a/chrome/browser/ui/app_list/app_list_service_mac.h b/chrome/browser/ui/app_list/app_list_service_mac.h
deleted file mode 100644
index b9eb8de..0000000
--- a/chrome/browser/ui/app_list/app_list_service_mac.h
+++ /dev/null
@@ -1,98 +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.
-
-#ifndef CHROME_BROWSER_UI_APP_LIST_APP_LIST_SERVICE_MAC_H_
-#define CHROME_BROWSER_UI_APP_LIST_APP_LIST_SERVICE_MAC_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include <memory>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#include "chrome/browser/apps/app_shim/app_shim_handler_mac.h"
-#include "chrome/browser/ui/app_list/app_list_service_impl.h"
-
-@class AppListAnimationController;
-
-namespace display {
-class Display;
-}
-
-namespace gfx {
-class Point;
-}
-
-// AppListServiceMac manages global resources needed for the app list to
-// operate, and controls when and how the app list is opened and closed.
-class AppListServiceMac : public AppListServiceImpl,
-                          public apps::AppShimHandler {
- public:
-  ~AppListServiceMac() override;
-
-  // Finds the position for a window to anchor it to the dock. This chooses the
-  // most appropriate position for the window based on whether the dock exists,
-  // the position of the dock (calculated by the difference between the display
-  // bounds and display work area), whether the mouse cursor is visible and its
-  // position. Sets |target_origin| to the coordinates for the window to appear
-  // at, and |start_origin| to the coordinates the window should begin animating
-  // from. Coordinates are for the bottom-left coordinate of the window, in
-  // AppKit space (Y positive is up).
-  static void FindAnchorPoint(const gfx::Size& window_size,
-                              const display::Display& display,
-                              int primary_display_height,
-                              bool cursor_is_visible,
-                              const gfx::Point& cursor,
-                              NSPoint* target_origin,
-                              NSPoint* start_origin);
-
-  void ShowWindowNearDock();
-  void WindowAnimationDidEnd();
-  void InitWithProfilePath(Profile* initial_profile,
-                           const base::FilePath& profile_path);
-
-  // AppListService overrides:
-  void Init(Profile* initial_profile) override;
-  void DismissAppList() override;
-  void ShowForCustomLauncherPage(Profile* profile) override;
-  void HideCustomLauncherPage() override;
-  bool IsAppListVisible() const override;
-  void EnableAppList(Profile* initial_profile,
-                     AppListEnableSource enable_source) override;
-  gfx::NativeWindow GetAppListWindow() override;
-  void CreateShortcut() override;
-
-    // AppShimHandler overrides:
-  void OnShimLaunch(apps::AppShimHandler::Host* host,
-                    apps::AppShimLaunchType launch_type,
-                    const std::vector<base::FilePath>& files) override;
-  void OnShimClose(apps::AppShimHandler::Host* host) override;
-  void OnShimFocus(apps::AppShimHandler::Host* host,
-                   apps::AppShimFocusType focus_type,
-                   const std::vector<base::FilePath>& files) override;
-  void OnShimSetHidden(apps::AppShimHandler::Host* host, bool hidden) override;
-  void OnShimQuit(apps::AppShimHandler::Host* host) override;
-
- protected:
-  AppListServiceMac();
-
-  // Returns the native window for the app list, or nil if can't be shown yet.
-  // Note that, unlike GetAppListWindow(), this does not return null when the
-  // app list is loaded, but not visible.
-  virtual NSWindow* GetNativeWindow() const = 0;
-
-  // If the app list is loaded, return true. Otherwise, if supported,
-  // synchronously prepare an unpopulated app list window to begin showing on
-  // screen and return true. If that's not supported, return false.
-  virtual bool ReadyToShow() = 0;
-
- private:
-  base::scoped_nsobject<AppListAnimationController> animation_controller_;
-  base::scoped_nsobject<NSRunningApplication> previously_active_application_;
-  NSPoint last_start_origin_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppListServiceMac);
-};
-
-#endif  // CHROME_BROWSER_UI_APP_LIST_APP_LIST_SERVICE_MAC_H_
diff --git a/chrome/browser/ui/app_list/app_list_service_mac.mm b/chrome/browser/ui/app_list/app_list_service_mac.mm
deleted file mode 100644
index a38f753..0000000
--- a/chrome/browser/ui/app_list/app_list_service_mac.mm
+++ /dev/null
@@ -1,581 +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.
-
-#import "chrome/browser/ui/app_list/app_list_service_mac.h"
-
-#include <ApplicationServices/ApplicationServices.h>
-#import <Cocoa/Cocoa.h>
-#include <stddef.h>
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/files/file_util.h"
-#include "base/lazy_instance.h"
-#import "base/mac/foundation_util.h"
-#include "base/memory/singleton.h"
-#include "base/message_loop/message_loop.h"
-#import "chrome/browser/app_controller_mac.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/profiles/profile_attributes_entry.h"
-#include "chrome/browser/profiles/profile_attributes_storage.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/app_list/app_list_positioner.h"
-#include "chrome/browser/ui/app_list/app_list_service.h"
-#include "chrome/browser/ui/app_list/app_list_service_cocoa_mac.h"
-#include "chrome/browser/ui/app_list/app_list_service_impl.h"
-#include "chrome/browser/ui/app_list/app_list_util.h"
-#include "chrome/browser/ui/browser_commands.h"
-#include "chrome/browser/ui/extensions/application_launch.h"
-#include "chrome/browser/web_applications/web_app.h"
-#include "chrome/browser/web_applications/web_app_mac.h"
-#include "chrome/common/channel_info.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
-#include "chrome/common/mac/app_mode_common.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/grit/google_chrome_strings.h"
-#include "components/prefs/pref_service.h"
-#include "components/version_info/version_info.h"
-#include "content/public/browser/browser_thread.h"
-#include "extensions/browser/extension_system.h"
-#include "extensions/common/manifest_handlers/file_handler_info.h"
-#include "grit/chrome_unscaled_resources.h"
-#include "net/base/url_util.h"
-#include "ui/app_list/app_list_switches.h"
-#include "ui/app_list/search_box_model.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/display/display.h"
-#include "ui/display/screen.h"
-
-namespace gfx {
-class ImageSkia;
-}
-
-// Controller for animations that show or hide the app list.
-@interface AppListAnimationController : NSObject<NSAnimationDelegate> {
- @private
-  // When closing, the window to close. Retained until the animation ends.
-  base::scoped_nsobject<NSWindow> window_;
-  // The animation started and owned by |self|. Reset when the animation ends.
-  base::scoped_nsobject<NSViewAnimation> animation_;
-}
-
-// Returns whether |window_| is scheduled to be closed when the animation ends.
-- (BOOL)isClosing;
-
-// Animate |window| to show or close it, after cancelling any current animation.
-// Translates from the current location to |targetOrigin| and fades in or out.
-- (void)animateWindow:(NSWindow*)window
-         targetOrigin:(NSPoint)targetOrigin
-              closing:(BOOL)closing;
-
-// Called on the UI thread once the animation has completed to reset the
-// animation state, close the window (if it is a close animation), and possibly
-// terminate Chrome.
-- (void)cleanupOnUIThread;
-
-@end
-
-namespace {
-
-// Version of the app list shortcut version installed.
-const int kShortcutVersion = 4;
-
-// Duration of show and hide animations.
-const NSTimeInterval kAnimationDuration = 0.2;
-
-// Distance towards the screen edge that the app list moves from when showing.
-const CGFloat kDistanceMovedOnShow = 20;
-
-std::unique_ptr<web_app::ShortcutInfo> GetAppListShortcutInfo(
-    const base::FilePath& profile_path) {
-  std::unique_ptr<web_app::ShortcutInfo> shortcut_info(
-      new web_app::ShortcutInfo);
-  version_info::Channel channel = chrome::GetChannel();
-  if (channel == version_info::Channel::CANARY) {
-    shortcut_info->title =
-        l10n_util::GetStringUTF16(IDS_APP_LIST_SHORTCUT_NAME_CANARY);
-  } else {
-    shortcut_info->title =
-        l10n_util::GetStringUTF16(IDS_APP_LIST_SHORTCUT_NAME);
-  }
-
-  shortcut_info->extension_id = app_mode::kAppListModeId;
-  shortcut_info->description = shortcut_info->title;
-  shortcut_info->profile_path = profile_path;
-
-  return shortcut_info;
-}
-
-void CreateAppListShim(const base::FilePath& profile_path) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  WebApplicationInfo web_app_info;
-  std::unique_ptr<web_app::ShortcutInfo> shortcut_info =
-      GetAppListShortcutInfo(profile_path);
-
-  ResourceBundle& resource_bundle = ResourceBundle::GetSharedInstance();
-  version_info::Channel channel = chrome::GetChannel();
-  if (channel == version_info::Channel::CANARY) {
-#if defined(GOOGLE_CHROME_BUILD)
-    shortcut_info->favicon.Add(
-        *resource_bundle.GetImageSkiaNamed(IDR_APP_LIST_CANARY_16));
-    shortcut_info->favicon.Add(
-        *resource_bundle.GetImageSkiaNamed(IDR_APP_LIST_CANARY_32));
-    shortcut_info->favicon.Add(
-        *resource_bundle.GetImageSkiaNamed(IDR_APP_LIST_CANARY_128));
-    shortcut_info->favicon.Add(
-        *resource_bundle.GetImageSkiaNamed(IDR_APP_LIST_CANARY_256));
-#else
-    NOTREACHED();
-#endif
-  } else {
-    shortcut_info->favicon.Add(
-        *resource_bundle.GetImageSkiaNamed(IDR_APP_LIST_16));
-    shortcut_info->favicon.Add(
-        *resource_bundle.GetImageSkiaNamed(IDR_APP_LIST_32));
-    shortcut_info->favicon.Add(
-        *resource_bundle.GetImageSkiaNamed(IDR_APP_LIST_128));
-    shortcut_info->favicon.Add(
-        *resource_bundle.GetImageSkiaNamed(IDR_APP_LIST_256));
-  }
-
-  web_app::ShortcutLocations shortcut_locations;
-  PrefService* local_state = g_browser_process->local_state();
-  int installed_version =
-      local_state->GetInteger(prefs::kAppLauncherShortcutVersion);
-
-  // If this is a first-time install, add a dock icon. Otherwise just update
-  // the target, and wait for OSX to refresh its icon caches. This might not
-  // occur until a reboot, but OSX does not offer a nicer way. Deleting cache
-  // files on disk and killing processes can easily result in icon corruption.
-  if (installed_version == 0)
-    shortcut_locations.in_quick_launch_bar = true;
-
-  web_app::CreateNonAppShortcut(shortcut_locations, std::move(shortcut_info));
-
-  local_state->SetInteger(prefs::kAppLauncherShortcutVersion,
-                          kShortcutVersion);
-}
-
-NSRunningApplication* ActiveApplicationNotChrome() {
-  NSArray* applications = [[NSWorkspace sharedWorkspace] runningApplications];
-  for (NSRunningApplication* application in applications) {
-    if (![application isActive])
-      continue;
-
-    if ([application isEqual:[NSRunningApplication currentApplication]])
-      return nil;  // Chrome is active.
-
-    return application;
-  }
-
-  return nil;
-}
-
-// Determines which screen edge the dock is aligned to.
-AppListPositioner::ScreenEdge DockLocationInDisplay(
-    const display::Display& display) {
-  // Assume the dock occupies part of the work area either on the left, right or
-  // bottom of the display. Note in the autohide case, it is always 4 pixels.
-  const gfx::Rect work_area = display.work_area();
-  const gfx::Rect display_bounds = display.bounds();
-  if (work_area.bottom() != display_bounds.bottom())
-    return AppListPositioner::SCREEN_EDGE_BOTTOM;
-
-  if (work_area.x() != display_bounds.x())
-    return AppListPositioner::SCREEN_EDGE_LEFT;
-
-  if (work_area.right() != display_bounds.right())
-    return AppListPositioner::SCREEN_EDGE_RIGHT;
-
-  return AppListPositioner::SCREEN_EDGE_UNKNOWN;
-}
-
-// If |display|'s work area is too close to its boundary on |dock_edge|, adjust
-// the work area away from the edge by a constant amount to reduce overlap and
-// ensure the dock icon can still be clicked to dismiss the app list.
-void AdjustWorkAreaForDock(const display::Display& display,
-                           AppListPositioner* positioner,
-                           AppListPositioner::ScreenEdge dock_edge) {
-  const int kAutohideDockThreshold = 10;
-  const int kExtraDistance = 50;  // A dock with 40 items is about this size.
-
-  const gfx::Rect work_area = display.work_area();
-  const gfx::Rect display_bounds = display.bounds();
-
-  switch (dock_edge) {
-    case AppListPositioner::SCREEN_EDGE_LEFT:
-      if (work_area.x() - display_bounds.x() <= kAutohideDockThreshold)
-        positioner->WorkAreaInset(kExtraDistance, 0, 0, 0);
-      break;
-    case AppListPositioner::SCREEN_EDGE_RIGHT:
-      if (display_bounds.right() - work_area.right() <= kAutohideDockThreshold)
-        positioner->WorkAreaInset(0, 0, kExtraDistance, 0);
-      break;
-    case AppListPositioner::SCREEN_EDGE_BOTTOM:
-      if (display_bounds.bottom() - work_area.bottom() <=
-          kAutohideDockThreshold) {
-        positioner->WorkAreaInset(0, 0, 0, kExtraDistance);
-      }
-      break;
-    case AppListPositioner::SCREEN_EDGE_UNKNOWN:
-    case AppListPositioner::SCREEN_EDGE_TOP:
-      NOTREACHED();
-      break;
-  }
-}
-
-void GetAppListWindowOrigins(
-    NSWindow* window, NSPoint* target_origin, NSPoint* start_origin) {
-  display::Screen* const screen = display::Screen::GetScreen();
-  // Ensure y coordinates are flipped back into AppKit's coordinate system.
-  bool cursor_is_visible = CGCursorIsVisible();
-  display::Display display;
-  gfx::Point cursor;
-  if (!cursor_is_visible) {
-    // If Chrome is the active application, display on the same display as
-    // Chrome's keyWindow since this will catch activations triggered, e.g, via
-    // WebStore install. If another application is active, OSX doesn't provide a
-    // reliable way to get the display in use. Fall back to the primary display
-    // since it has the menu bar and is likely to be correct, e.g., for
-    // activations from Spotlight.
-    const gfx::NativeView key_view = [[NSApp keyWindow] contentView];
-    display = key_view && [NSApp isActive] ?
-        screen->GetDisplayNearestWindow(key_view) :
-        screen->GetPrimaryDisplay();
-  } else {
-    cursor = screen->GetCursorScreenPoint();
-    display = screen->GetDisplayNearestPoint(cursor);
-  }
-
-  const NSSize ns_window_size = [window frame].size;
-  gfx::Size window_size(ns_window_size.width, ns_window_size.height);
-  int primary_display_height =
-      NSMaxY([[[NSScreen screens] firstObject] frame]);
-  AppListServiceMac::FindAnchorPoint(window_size,
-                                     display,
-                                     primary_display_height,
-                                     cursor_is_visible,
-                                     cursor,
-                                     target_origin,
-                                     start_origin);
-}
-
-}  // namespace
-
-AppListServiceMac::AppListServiceMac() {
-  animation_controller_.reset([[AppListAnimationController alloc] init]);
-}
-
-AppListServiceMac::~AppListServiceMac() {}
-
-// static
-void AppListServiceMac::FindAnchorPoint(const gfx::Size& window_size,
-                                        const display::Display& display,
-                                        int primary_display_height,
-                                        bool cursor_is_visible,
-                                        const gfx::Point& cursor,
-                                        NSPoint* target_origin,
-                                        NSPoint* start_origin) {
-  AppListPositioner positioner(display, window_size, 0);
-  AppListPositioner::ScreenEdge dock_location = DockLocationInDisplay(display);
-
-  gfx::Point anchor;
-  // Snap to the dock edge. If the cursor is greater than the window
-  // width/height away or not visible, anchor to the center of the dock.
-  // Otherwise, anchor to the cursor position.
-  if (dock_location == AppListPositioner::SCREEN_EDGE_UNKNOWN) {
-    anchor = positioner.GetAnchorPointForScreenCorner(
-        AppListPositioner::SCREEN_CORNER_BOTTOM_LEFT);
-  } else {
-    int snap_distance =
-        dock_location == AppListPositioner::SCREEN_EDGE_BOTTOM ||
-                dock_location == AppListPositioner::SCREEN_EDGE_TOP ?
-            window_size.height() :
-            window_size.width();
-    // Subtract the dock area since the display's default work_area will not
-    // subtract it if the dock is set to auto-hide, and the app list should
-    // never overlap the dock.
-    AdjustWorkAreaForDock(display, &positioner, dock_location);
-    if (!cursor_is_visible || positioner.GetCursorDistanceFromShelf(
-                                  dock_location, cursor) > snap_distance) {
-      anchor = positioner.GetAnchorPointForShelfCenter(dock_location);
-    } else {
-      anchor = positioner.GetAnchorPointForShelfCursor(dock_location, cursor);
-    }
-  }
-
-  *target_origin = NSMakePoint(
-      anchor.x() - window_size.width() / 2,
-      primary_display_height - anchor.y() - window_size.height() / 2);
-  *start_origin = *target_origin;
-
-  // If the launcher is anchored to the dock (regardless of whether the cursor
-  // is visible), animate in inwards from the edge of screen
-  switch (dock_location) {
-    case AppListPositioner::SCREEN_EDGE_UNKNOWN:
-      break;
-    case AppListPositioner::SCREEN_EDGE_LEFT:
-      start_origin->x -= kDistanceMovedOnShow;
-      break;
-    case AppListPositioner::SCREEN_EDGE_RIGHT:
-      start_origin->x += kDistanceMovedOnShow;
-      break;
-    case AppListPositioner::SCREEN_EDGE_TOP:
-      NOTREACHED();
-      break;
-    case AppListPositioner::SCREEN_EDGE_BOTTOM:
-      start_origin->y -= kDistanceMovedOnShow;
-      break;
-  }
-}
-
-void AppListServiceMac::Init(Profile* initial_profile) {
-  InitWithProfilePath(initial_profile, initial_profile->GetPath());
-}
-
-void AppListServiceMac::InitWithProfilePath(
-    Profile* initial_profile,
-    const base::FilePath& profile_path) {
-  // On Mac, Init() is called multiple times for a process: any time there is no
-  // browser window open and a new window is opened, and during process startup
-  // to handle the silent launch case (e.g. for app shims). In the startup case,
-  // a profile has not yet been determined so |initial_profile| will be NULL.
-  static bool init_called_with_profile = false;
-  if (initial_profile && !init_called_with_profile) {
-    init_called_with_profile = true;
-    PerformStartupChecks(initial_profile);
-    PrefService* local_state = g_browser_process->local_state();
-    if (!IsAppLauncherEnabled()) {
-      local_state->SetInteger(prefs::kAppLauncherShortcutVersion, 0);
-    } else {
-      int installed_shortcut_version =
-          local_state->GetInteger(prefs::kAppLauncherShortcutVersion);
-
-      if (kShortcutVersion > installed_shortcut_version)
-        CreateShortcut();
-    }
-  }
-
-  static bool init_called = false;
-  if (init_called)
-    return;
-
-  init_called = true;
-  apps::AppShimHandler::RegisterHandler(app_mode::kAppListModeId, this);
-
-  // Handle the case where Chrome was not running and was started with the app
-  // launcher shim. The profile has not yet been loaded. To improve response
-  // times, start animating an empty window which will be populated via
-  // OnShimLaunch(). Note that if --silent-launch is not also passed, the window
-  // will instead populate via StartupBrowserCreator::Launch(). Shim-initiated
-  // launches will always have --silent-launch.
-  if (base::CommandLine::ForCurrentProcess()->
-      HasSwitch(switches::kShowAppList)) {
-    // Do not show the launcher window when the profile is locked, or if it
-    // can't be displayed unpopulated. In the latter case, the Show will occur
-    // in OnShimLaunch() or AppListService::HandleLaunchCommandLine().
-    ProfileAttributesEntry* entry = nullptr;
-    bool has_entry = g_browser_process->profile_manager()->
-        GetProfileAttributesStorage().
-        GetProfileAttributesWithPath(profile_path, &entry);
-    if (has_entry && !entry->IsSigninRequired() && ReadyToShow())
-      ShowWindowNearDock();
-  }
-}
-
-void AppListServiceMac::DismissAppList() {
-  if (!IsAppListVisible())
-    return;
-
-  NSWindow* app_list_window = GetNativeWindow();
-  // If the app list is currently the main window, it will activate the next
-  // Chrome window when dismissed. But if a different application was active
-  // when the app list was shown, activate that instead.
-  base::scoped_nsobject<NSRunningApplication> prior_app;
-  if ([app_list_window isMainWindow])
-    prior_app.swap(previously_active_application_);
-  else
-    previously_active_application_.reset();
-
-  // If activation is successful, the app list will lose main status and try to
-  // close itself again. It can't be closed in this runloop iteration without
-  // OSX deciding to raise the next Chrome window, and _then_ activating the
-  // application on top. This also occurs if no activation option is given.
-  if ([prior_app activateWithOptions:NSApplicationActivateIgnoringOtherApps])
-    return;
-
-  [animation_controller_ animateWindow:app_list_window
-                          targetOrigin:last_start_origin_
-                               closing:YES];
-}
-
-void AppListServiceMac::ShowForCustomLauncherPage(Profile* profile) {
-  NOTIMPLEMENTED();
-}
-
-void AppListServiceMac::HideCustomLauncherPage() {
-  NOTIMPLEMENTED();
-}
-
-bool AppListServiceMac::IsAppListVisible() const {
-  return [GetNativeWindow() isVisible] &&
-      ![animation_controller_ isClosing];
-}
-
-void AppListServiceMac::EnableAppList(Profile* initial_profile,
-                                      AppListEnableSource enable_source) {
-  AppListServiceImpl::EnableAppList(initial_profile, enable_source);
-  AppController* controller =
-      base::mac::ObjCCastStrict<AppController>([NSApp delegate]);
-  [controller initAppShimMenuController];
-}
-
-void AppListServiceMac::CreateShortcut() {
-  CreateAppListShim(GetProfilePath(
-      g_browser_process->profile_manager()->user_data_dir()));
-}
-
-NSWindow* AppListServiceMac::GetAppListWindow() {
-  return GetNativeWindow();
-}
-
-void AppListServiceMac::OnShimLaunch(apps::AppShimHandler::Host* host,
-                                     apps::AppShimLaunchType launch_type,
-                                     const std::vector<base::FilePath>& files) {
-  if (GetCurrentAppListProfile() && IsAppListVisible()) {
-    DismissAppList();
-  } else {
-    // Start by showing a possibly empty window to handle the case where Chrome
-    // is running, but hasn't yet loaded the app launcher profile.
-    if (ReadyToShow())
-      ShowWindowNearDock();
-    Show();
-  }
-
-  // Always close the shim process immediately.
-  host->OnAppLaunchComplete(apps::APP_SHIM_LAUNCH_DUPLICATE_HOST);
-}
-
-void AppListServiceMac::OnShimClose(apps::AppShimHandler::Host* host) {}
-
-void AppListServiceMac::OnShimFocus(apps::AppShimHandler::Host* host,
-                                    apps::AppShimFocusType focus_type,
-                                    const std::vector<base::FilePath>& files) {}
-
-void AppListServiceMac::OnShimSetHidden(apps::AppShimHandler::Host* host,
-                                        bool hidden) {}
-
-void AppListServiceMac::OnShimQuit(apps::AppShimHandler::Host* host) {}
-
-void AppListServiceMac::ShowWindowNearDock() {
-  if (IsAppListVisible())
-    return;
-
-  NSWindow* window = GetAppListWindow();
-  DCHECK(window);
-  NSPoint target_origin;
-  GetAppListWindowOrigins(window, &target_origin, &last_start_origin_);
-  [window setFrameOrigin:last_start_origin_];
-
-  // Before activating, see if an application other than Chrome is currently the
-  // active application, so that it can be reactivated when dismissing.
-  previously_active_application_.reset([ActiveApplicationNotChrome() retain]);
-
-  [animation_controller_ animateWindow:window
-                          targetOrigin:target_origin
-                               closing:NO];
-  [window makeKeyAndOrderFront:nil];
-  [NSApp activateIgnoringOtherApps:YES];
-  RecordAppListLaunch();
-}
-
-void AppListServiceMac::WindowAnimationDidEnd() {
-  [animation_controller_ cleanupOnUIThread];
-}
-
-// static
-AppListService* AppListService::Get() {
-  return AppListServiceCocoaMac::GetInstance();
-}
-
-// static
-void AppListService::InitAll(Profile* initial_profile,
-                             const base::FilePath& profile_path) {
-  AppListServiceCocoaMac::GetInstance()->InitWithProfilePath(initial_profile,
-                                                             profile_path);
-}
-
-@implementation AppListAnimationController
-
-- (BOOL)isClosing {
-  return !!window_;
-}
-
-- (void)animateWindow:(NSWindow*)window
-         targetOrigin:(NSPoint)targetOrigin
-              closing:(BOOL)closing {
-  // First, stop the existing animation, if there is one.
-  [animation_ stopAnimation];
-
-  NSRect targetFrame = [window frame];
-  targetFrame.origin = targetOrigin;
-
-  // NSViewAnimation has a quirk when setting the curve to NSAnimationEaseOut
-  // where it attempts to auto-reverse the animation. FadeOut becomes FadeIn
-  // (good), but FrameKey is also switched (bad). So |targetFrame| needs to be
-  // put on the StartFrameKey when using NSAnimationEaseOut for showing.
-  NSArray* animationArray = @[
-    @{
-      NSViewAnimationTargetKey : window,
-      NSViewAnimationEffectKey : NSViewAnimationFadeOutEffect,
-      (closing ? NSViewAnimationEndFrameKey : NSViewAnimationStartFrameKey) :
-          [NSValue valueWithRect:targetFrame]
-    }
-  ];
-  animation_.reset(
-      [[NSViewAnimation alloc] initWithViewAnimations:animationArray]);
-  [animation_ setDuration:kAnimationDuration];
-  [animation_ setDelegate:self];
-
-  if (closing) {
-    [animation_ setAnimationCurve:NSAnimationEaseIn];
-    window_.reset([window retain]);
-  } else {
-    [window setAlphaValue:0.0f];
-    [animation_ setAnimationCurve:NSAnimationEaseOut];
-    window_.reset();
-  }
-  // This once used a threaded animation, but AppKit would too often ignore
-  // -[NSView canDrawConcurrently:] and just redraw whole view hierarchies on
-  // the animation thread anyway, creating a minefield of race conditions.
-  // Non-threaded means the animation isn't as smooth and doesn't begin unless
-  // the UI runloop has spun up (after profile loading).
-  [animation_ setAnimationBlockingMode:NSAnimationNonblocking];
-
-  [animation_ startAnimation];
-}
-
-- (void)cleanupOnUIThread {
-  bool closing = [self isClosing];
-  [window_ close];
-  window_.reset();
-  animation_.reset();
-
-  if (closing)
-    apps::AppShimHandler::MaybeTerminate();
-}
-
-- (void)animationDidEnd:(NSAnimation*)animation {
-  content::BrowserThread::PostTask(
-      content::BrowserThread::UI, FROM_HERE,
-      base::Bind(&AppListServiceMac::WindowAnimationDidEnd,
-                 base::Unretained(AppListServiceCocoaMac::GetInstance())));
-}
-
-@end
diff --git a/chrome/browser/ui/app_list/app_list_service_mac_interactive_uitest.mm b/chrome/browser/ui/app_list/app_list_service_mac_interactive_uitest.mm
deleted file mode 100644
index 1c35da8b..0000000
--- a/chrome/browser/ui/app_list/app_list_service_mac_interactive_uitest.mm
+++ /dev/null
@@ -1,130 +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.
-
-#import "chrome/browser/ui/app_list/app_list_service_cocoa_mac.h"
-
-#include <vector>
-
-#include "base/command_line.h"
-#include "base/macros.h"
-#include "chrome/browser/apps/app_shim/app_shim_handler_mac.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/mac/app_mode_common.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#import "ui/app_list/cocoa/app_list_window_controller.h"
-
-using apps::AppShimHandler;
-
-namespace test {
-
-class AppListServiceMacTestApi {
- public:
-  static AppListWindowController* window_controller() {
-    return AppListServiceCocoaMac::GetInstance()->window_controller_;
-  }
-};
-
-}  // namespace test
-
-namespace {
-
-// Browser test for mac-specific AppListService functionality.
-class AppListServiceMacInteractiveTest : public InProcessBrowserTest,
-                                         public AppShimHandler::Host {
- public:
-  AppListServiceMacInteractiveTest() : launch_count_(0) {}
-
- protected:
-  void LaunchShim() {
-    // AppList shims always launch normally (never relaunched via dock icon).
-    AppShimHandler::GetForAppMode(app_mode::kAppListModeId)->
-        OnShimLaunch(this,
-                     apps::APP_SHIM_LAUNCH_NORMAL,
-                     std::vector<base::FilePath>());
-  }
-
-  AppListViewController* GetViewController() {
-    return [test::AppListServiceMacTestApi::window_controller()
-        appListViewController];
-  }
-
-  // testing::Test overrides:
-  void TearDown() override {
-    // At tear-down, NOTIFICATION_APP_TERMINATING should have been sent for the
-    // browser shutdown. References to browser-owned objects must be removed
-    // from the app list UI.
-    AppListViewController* view_controller = GetViewController();
-    // Note this first check will fail if the test doesn't ever show the
-    // app list, but currently all tests in this file do.
-    EXPECT_TRUE(view_controller);
-    EXPECT_FALSE([view_controller delegate]);
-  }
-
-  // AppShimHandler::Host overrides:
-  void OnAppLaunchComplete(apps::AppShimLaunchResult result) override {
-    // AppList shims are always given APP_SHIM_LAUNCH_DUPLICATE_HOST, indicating
-    // that the shim process should immediately close.
-    EXPECT_EQ(apps::APP_SHIM_LAUNCH_DUPLICATE_HOST, result);
-    ++launch_count_;
-  }
-  void OnAppClosed() override { NOTREACHED(); }
-  void OnAppHide() override {}
-  void OnAppUnhideWithoutActivation() override {}
-  void OnAppRequestUserAttention(apps::AppShimAttentionType type) override {}
-  base::FilePath GetProfilePath() const override {
-    NOTREACHED();  // Currently unused in this test.
-    return base::FilePath();
-  }
-  std::string GetAppId() const override { return app_mode::kAppListModeId; }
-
-  int launch_count_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AppListServiceMacInteractiveTest);
-};
-
-}  // namespace
-
-IN_PROC_BROWSER_TEST_F(AppListServiceMacInteractiveTest, ShowAppListUsingShim) {
-  // Check that AppListService has registered as a shim handler for "app_list".
-  EXPECT_TRUE(AppShimHandler::GetForAppMode(app_mode::kAppListModeId));
-
-  AppListService* service = AppListService::Get();
-  EXPECT_FALSE(service->IsAppListVisible());
-
-  // Creation should be lazy.
-  EXPECT_FALSE(GetViewController());
-
-  // With no saved profile, the default profile should be chosen and saved.
-  service->Show();
-  EXPECT_EQ(browser()->profile(), service->GetCurrentAppListProfile());
-  EXPECT_TRUE(service->IsAppListVisible());
-  EXPECT_EQ(0, launch_count_);
-  service->DismissAppList();
-  EXPECT_FALSE(service->IsAppListVisible());
-
-  // Test showing the app list via the shim. The shim should immediately close
-  // leaving the app list visible.
-  LaunchShim();
-  EXPECT_TRUE(service->IsAppListVisible());
-  EXPECT_EQ(1, launch_count_);
-
-  // Launching again should toggle the app list.
-  LaunchShim();
-  EXPECT_FALSE(service->IsAppListVisible());
-  EXPECT_EQ(2, launch_count_);
-
-  // Test showing the app list via the shim, then dismissing the app list.
-  LaunchShim();
-  EXPECT_TRUE(service->IsAppListVisible());
-  EXPECT_EQ(3, launch_count_);
-  service->DismissAppList();
-  EXPECT_FALSE(service->IsAppListVisible());
-
-  // View sticks around until shutdown.
-  AppListViewController* view_controller = GetViewController();
-  EXPECT_TRUE(view_controller);
-  EXPECT_TRUE([view_controller delegate]);
-}
diff --git a/chrome/browser/ui/app_list/app_list_service_mac_unittest.mm b/chrome/browser/ui/app_list/app_list_service_mac_unittest.mm
deleted file mode 100644
index 978e143..0000000
--- a/chrome/browser/ui/app_list/app_list_service_mac_unittest.mm
+++ /dev/null
@@ -1,316 +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.
-
-#import "chrome/browser/ui/app_list/app_list_service_mac.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "ui/display/display.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace {
-
-const int kScreenWidth = 800;
-const int kScreenHeight = 600;
-
-const int kWindowWidth = 100;
-const int kWindowHeight = 200;
-
-// Size of the menu bar along the top of the screen.
-const int kMenuBarSize = 22;
-// Size of the normal (non-hidden) dock.
-const int kDockSize = 30;
-// Size of the hidden dock.
-const int kHiddenDockSize = 4;
-
-// Distance to move during the opening animation.
-const int kAnimationOffset = 20;
-
-// The assumed size of the hidden dock.
-const int kExtraDistance = 50;
-
-// A cursor position that is within the dock. This must be < kDockSize.
-const int kCursorOnDock = kDockSize / 2;
-// A cursor position that is within kWindowWidth pixels of the dock.
-const int kCursorNearDockX = kDockSize + kWindowWidth;
-// A cursor position that is more than kWindowWidth pixels away from the dock.
-const int kCursorAwayFromDockX = kCursorNearDockX + 1;
-// A cursor position that is within kWindowHeight pixels of the dock.
-const int kCursorNearDockY = kDockSize + kWindowHeight;
-// A cursor position that is more than kWindowHeight pixels away from the dock.
-const int kCursorAwayFromDockY = kCursorNearDockY + 1;
-
-// A position for the center of the window that causes the window to overlap the
-// edge of the screen. This must be < kWindowWidth / 2 and < kWindowHeight / 2.
-const int kWindowNearEdge = kWindowWidth / 4;
-// A position for the center of the window that places the window away from all
-// edges of the screen. This must be > kWindowWidth / 2, > kWindowHeight / 2, <
-// kScreenWidth - kWindowWidth / 2 and < kScreenHeight - kWindowHeight / 2.
-const int kWindowAwayFromEdge = 158;
-
-enum DockLocation {
-  DOCK_LOCATION_BOTTOM,
-  DOCK_LOCATION_LEFT,
-  DOCK_LOCATION_RIGHT,
-};
-
-// Returns |point| offset by (|x_offset|, |y_offset|).
-NSPoint OffsetPoint(const NSPoint& point, CGFloat x_offset, CGFloat y_offset) {
-  return NSMakePoint(point.x + x_offset, point.y + y_offset);
-}
-
-}  // namespace
-
-class AppListServiceMacUnitTest : public testing::Test {
- public:
-  void SetUp() override {
-    display_.set_bounds(gfx::Rect(0, 0, kScreenWidth, kScreenHeight));
-    display_.set_work_area(
-        gfx::Rect(0, kMenuBarSize, kScreenWidth, kScreenHeight - kMenuBarSize));
-    window_size_ = gfx::Size(kWindowWidth, kWindowHeight);
-    cursor_is_visible_ = true;
-    cursor_ = gfx::Point();
-  }
-
-  // Sets up the test environment with the dock in a given location.
-  void PlaceDock(DockLocation location, bool hidden) {
-    int dock_size = hidden ? kHiddenDockSize : kDockSize;
-    switch (location) {
-      case DOCK_LOCATION_BOTTOM:
-        display_.set_work_area(
-            gfx::Rect(0,
-                      kMenuBarSize,
-                      kScreenWidth,
-                      kScreenHeight - kMenuBarSize - dock_size));
-        break;
-      case DOCK_LOCATION_LEFT:
-        display_.set_work_area(gfx::Rect(dock_size,
-                                         kMenuBarSize,
-                                         kScreenWidth - dock_size,
-                                         kScreenHeight - kMenuBarSize));
-        break;
-      case DOCK_LOCATION_RIGHT:
-        display_.set_work_area(gfx::Rect(0,
-                                         kMenuBarSize,
-                                         kScreenWidth - dock_size,
-                                         kScreenHeight - kMenuBarSize));
-        break;
-    }
-  }
-
-  // Set whether the test mouse cursor is visible.
-  void SetCursorVisible(bool visible) {
-    cursor_is_visible_ = visible;
-  }
-
-  // Set up the test mouse cursor in a given location.
-  void PlaceCursor(int x, int y) {
-    cursor_ = gfx::Point(x, y);
-  }
-
-  void DoFindAnchorPoint(NSPoint* target_origin,
-                         NSPoint* start_origin) {
-    AppListServiceMac::FindAnchorPoint(window_size_,
-                                       display_,
-                                       kScreenHeight,
-                                       cursor_is_visible_,
-                                       cursor_,
-                                       target_origin,
-                                       start_origin);
-  }
-
- private:
-  display::Display display_;
-  gfx::Size window_size_;
-  bool cursor_is_visible_;
-  gfx::Point cursor_;
-};
-
-// Tests positioning the app list when there is no visible mouse cursor.
-TEST_F(AppListServiceMacUnitTest, FindAnchorPointNoCursor) {
-  SetCursorVisible(false);
-  PlaceCursor(0, 0);
-  NSPoint target_origin;
-  NSPoint start_origin;
-
-  // Bottom dock. Expect the app list to be centered on the dock.
-  PlaceDock(DOCK_LOCATION_BOTTOM, false);
-  DoFindAnchorPoint(&target_origin, &start_origin);
-  EXPECT_NSEQ(NSMakePoint(kScreenWidth / 2 - kWindowWidth / 2, kDockSize),
-              target_origin);
-  EXPECT_NSEQ(OffsetPoint(target_origin, 0, -kAnimationOffset), start_origin);
-
-  // Left dock. Expect the app list to be centered on the dock.
-  PlaceDock(DOCK_LOCATION_LEFT, false);
-  DoFindAnchorPoint(&target_origin, &start_origin);
-  EXPECT_NSEQ(NSMakePoint(kDockSize, (kScreenHeight - kMenuBarSize) / 2 -
-                                         kWindowHeight / 2),
-              target_origin);
-  EXPECT_NSEQ(OffsetPoint(target_origin, -kAnimationOffset, 0), start_origin);
-
-  // Right dock. Expect the app list to be centered on the dock.
-  PlaceDock(DOCK_LOCATION_RIGHT, false);
-  DoFindAnchorPoint(&target_origin, &start_origin);
-  EXPECT_NSEQ(
-      NSMakePoint(kScreenWidth - kDockSize - kWindowWidth,
-                  (kScreenHeight - kMenuBarSize) / 2 - kWindowHeight / 2),
-      target_origin);
-  EXPECT_NSEQ(OffsetPoint(target_origin, kAnimationOffset, 0), start_origin);
-}
-
-// Tests positioning the app list when there is no dock on the display.
-TEST_F(AppListServiceMacUnitTest, FindAnchorPointNoDock) {
-  SetCursorVisible(true);
-  PlaceCursor(0, 0);
-  NSPoint target_origin;
-  NSPoint start_origin;
-
-  // Expect the app list to be in the bottom-left corner.
-  DoFindAnchorPoint(&target_origin, &start_origin);
-  EXPECT_NSEQ(NSMakePoint(0, 0), target_origin);
-  EXPECT_NSEQ(target_origin, start_origin);
-
-  // No mouse cursor. This should have no effect.
-  SetCursorVisible(false);
-  DoFindAnchorPoint(&target_origin, &start_origin);
-  EXPECT_NSEQ(NSMakePoint(0, 0), target_origin);
-  EXPECT_NSEQ(target_origin, start_origin);
-}
-
-// Tests positioning the app list when the mouse is away from the dock.
-TEST_F(AppListServiceMacUnitTest, FindAnchorPointMouseOffDock) {
-  SetCursorVisible(true);
-  NSPoint target_origin;
-  NSPoint start_origin;
-
-  // Bottom dock. Expect the app list to be centered on the dock.
-  PlaceDock(DOCK_LOCATION_BOTTOM, false);
-  PlaceCursor(kWindowAwayFromEdge, kScreenHeight - kCursorAwayFromDockY);
-  DoFindAnchorPoint(&target_origin, &start_origin);
-  EXPECT_NSEQ(NSMakePoint(kScreenWidth / 2 - kWindowWidth / 2, kDockSize),
-              target_origin);
-  EXPECT_NSEQ(OffsetPoint(target_origin, 0, -kAnimationOffset), start_origin);
-
-  // Left dock. Expect the app list to be centered on the dock.
-  PlaceDock(DOCK_LOCATION_LEFT, false);
-  PlaceCursor(kCursorAwayFromDockX, kWindowAwayFromEdge);
-  DoFindAnchorPoint(&target_origin, &start_origin);
-  EXPECT_NSEQ(NSMakePoint(kDockSize, (kScreenHeight - kMenuBarSize) / 2 -
-                                         kWindowHeight / 2),
-              target_origin);
-  EXPECT_NSEQ(OffsetPoint(target_origin, -kAnimationOffset, 0), start_origin);
-
-  // Right dock. Expect the app list to be centered on the dock.
-  PlaceDock(DOCK_LOCATION_RIGHT, false);
-  PlaceCursor(kScreenWidth - kCursorAwayFromDockX, kWindowAwayFromEdge);
-  DoFindAnchorPoint(&target_origin, &start_origin);
-  EXPECT_NSEQ(
-      NSMakePoint(kScreenWidth - kDockSize - kWindowWidth,
-                  (kScreenHeight - kMenuBarSize) / 2 - kWindowHeight / 2),
-      target_origin);
-  EXPECT_NSEQ(OffsetPoint(target_origin, kAnimationOffset, 0), start_origin);
-}
-
-// Tests positioning the app list when the dock is hidden.
-TEST_F(AppListServiceMacUnitTest, FindAnchorPointHiddenDock) {
-  SetCursorVisible(true);
-  NSPoint target_origin;
-  NSPoint start_origin;
-
-  // Bottom dock. Expect the app list to be kExtraDistance pixels from the dock
-  // centered on the mouse X coordinate.
-  PlaceDock(DOCK_LOCATION_BOTTOM, true);
-  PlaceCursor(kWindowAwayFromEdge, kScreenHeight - kCursorAwayFromDockY);
-  DoFindAnchorPoint(&target_origin, &start_origin);
-  EXPECT_NSEQ(NSMakePoint(kWindowAwayFromEdge - kWindowWidth / 2,
-                          kHiddenDockSize + kExtraDistance),
-              target_origin);
-  EXPECT_NSEQ(OffsetPoint(target_origin, 0, -kAnimationOffset), start_origin);
-
-  // Left dock. Expect the app list to be kExtraDistance pixels from the dock
-  // centered on the mouse Y coordinate.
-  PlaceDock(DOCK_LOCATION_LEFT, true);
-  PlaceCursor(kCursorAwayFromDockX, kWindowAwayFromEdge);
-  DoFindAnchorPoint(&target_origin, &start_origin);
-  EXPECT_NSEQ(
-      NSMakePoint(kHiddenDockSize + kExtraDistance,
-                  kScreenHeight - kWindowAwayFromEdge - kWindowHeight / 2),
-      target_origin);
-  EXPECT_NSEQ(OffsetPoint(target_origin, -kAnimationOffset, 0), start_origin);
-
-  // Right dock. Expect the app list to be kExtraDistance pixels from the dock
-  // centered on the mouse Y coordinate.
-  PlaceDock(DOCK_LOCATION_RIGHT, true);
-  PlaceCursor(kScreenWidth - kCursorAwayFromDockX, kWindowAwayFromEdge);
-  DoFindAnchorPoint(&target_origin, &start_origin);
-  EXPECT_NSEQ(
-      NSMakePoint(
-          kScreenWidth - kHiddenDockSize - kWindowWidth - kExtraDistance,
-          kScreenHeight - kWindowAwayFromEdge - kWindowHeight / 2),
-      target_origin);
-  EXPECT_NSEQ(OffsetPoint(target_origin, kAnimationOffset, 0), start_origin);
-}
-
-// Tests positioning the app list when the mouse is over the dock.
-TEST_F(AppListServiceMacUnitTest, FindAnchorPointMouseOnDock) {
-  SetCursorVisible(true);
-  NSPoint target_origin;
-  NSPoint start_origin;
-
-  // Bottom dock (mouse well within dock). Expect the app list to be at the
-  // bottom centered on the mouse X coordinate.
-  PlaceDock(DOCK_LOCATION_BOTTOM, false);
-  PlaceCursor(kWindowAwayFromEdge, kScreenHeight - kCursorOnDock);
-  DoFindAnchorPoint(&target_origin, &start_origin);
-  EXPECT_NSEQ(NSMakePoint(kWindowAwayFromEdge - kWindowWidth / 2, kDockSize),
-              target_origin);
-  EXPECT_NSEQ(OffsetPoint(target_origin, 0, -kAnimationOffset), start_origin);
-
-  // Bottom dock (outside the dock but still close enough). Expect the app list
-  // to be at the bottom centered on the mouse X coordinate.
-  PlaceDock(DOCK_LOCATION_BOTTOM, false);
-  PlaceCursor(kWindowAwayFromEdge, kScreenHeight - kCursorNearDockY);
-  DoFindAnchorPoint(&target_origin, &start_origin);
-  EXPECT_NSEQ(NSMakePoint(kWindowAwayFromEdge - kWindowWidth / 2, kDockSize),
-              target_origin);
-  EXPECT_NSEQ(OffsetPoint(target_origin, 0, -kAnimationOffset), start_origin);
-
-  // Left dock. Expect the app list to be at the left centered on the mouse Y
-  // coordinate.
-  PlaceDock(DOCK_LOCATION_LEFT, false);
-  PlaceCursor(kCursorNearDockX, kWindowAwayFromEdge);
-  DoFindAnchorPoint(&target_origin, &start_origin);
-  EXPECT_NSEQ(NSMakePoint(kDockSize, kScreenHeight - kWindowAwayFromEdge -
-                                         kWindowHeight / 2),
-              target_origin);
-  EXPECT_NSEQ(OffsetPoint(target_origin, -kAnimationOffset, 0), start_origin);
-
-  // Right dock. Expect the app list to be at the right centered on the mouse Y
-  // coordinate.
-  PlaceDock(DOCK_LOCATION_RIGHT, false);
-  PlaceCursor(kScreenWidth - kCursorNearDockX, kWindowAwayFromEdge);
-  DoFindAnchorPoint(&target_origin, &start_origin);
-  EXPECT_NSEQ(
-      NSMakePoint(kScreenWidth - kDockSize - kWindowWidth,
-                  kScreenHeight - kWindowAwayFromEdge - kWindowHeight / 2),
-      target_origin);
-  EXPECT_NSEQ(OffsetPoint(target_origin, kAnimationOffset, 0), start_origin);
-
-  // Bottom dock. Mouse near left edge. App list must not go off screen.
-  PlaceDock(DOCK_LOCATION_BOTTOM, false);
-  PlaceCursor(kWindowNearEdge, kScreenHeight - kCursorOnDock);
-  DoFindAnchorPoint(&target_origin, &start_origin);
-  EXPECT_NSEQ(NSMakePoint(0, kDockSize), target_origin);
-  EXPECT_NSEQ(OffsetPoint(target_origin, 0, -kAnimationOffset), start_origin);
-
-  // Bottom dock. Mouse near right edge. App list must not go off screen.
-  PlaceDock(DOCK_LOCATION_BOTTOM, false);
-  PlaceCursor(kScreenWidth - kWindowNearEdge, kScreenHeight - kCursorOnDock);
-  DoFindAnchorPoint(&target_origin, &start_origin);
-  EXPECT_NSEQ(NSMakePoint(kScreenWidth - kWindowWidth, kDockSize),
-              target_origin);
-  EXPECT_NSEQ(OffsetPoint(target_origin, 0, -kAnimationOffset), start_origin);
-}
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
index 6a1ad09..bcbc88c 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
@@ -38,6 +38,8 @@
 const char kLastLaunchTime[] = "lastlaunchtime";
 const char kShouldSync[] = "should_sync";
 const char kSystem[] = "system";
+const char kOrientationLock[] = "orientation_lock";
+
 constexpr int kSetNotificationsEnabledMinVersion = 6;
 
 // Provider of write access to a dictionary storing ARC prefs.
@@ -451,6 +453,7 @@
   bool sticky = false;
   bool notifications_enabled = true;
   bool shortcut = false;
+  int orientation_lock_value = 0;
   app->GetString(kName, &name);
   app->GetString(kPackageName, &package_name);
   app->GetString(kActivity, &activity);
@@ -459,6 +462,7 @@
   app->GetBoolean(kSticky, &sticky);
   app->GetBoolean(kNotificationsEnabled, &notifications_enabled);
   app->GetBoolean(kShortcut, &shortcut);
+  app->GetInteger(kOrientationLock, &orientation_lock_value);
 
   DCHECK(!name.empty());
   DCHECK(!shortcut || activity.empty());
@@ -474,12 +478,14 @@
   if (SetNotificationsEnabledDeferred(prefs_).Get(app_id, &deferred)) {
     notifications_enabled = deferred;
   }
+  arc::mojom::OrientationLock orientation_lock =
+      static_cast<arc::mojom::OrientationLock>(orientation_lock_value);
 
-  return base::MakeUnique<AppInfo>(name, package_name, activity, intent_uri,
-                                   icon_resource_id, last_launch_time, sticky,
-                                   notifications_enabled,
-                                   ready_apps_.count(app_id) > 0,
-                                   arc::ShouldShowInLauncher(app_id), shortcut);
+  return base::MakeUnique<AppInfo>(
+      name, package_name, activity, intent_uri, icon_resource_id,
+      last_launch_time, sticky, notifications_enabled,
+      ready_apps_.count(app_id) > 0, arc::ShouldShowInLauncher(app_id),
+      shortcut, orientation_lock);
 }
 
 bool ArcAppListPrefs::IsRegistered(const std::string& app_id) const {
@@ -581,14 +587,16 @@
   ready_apps_.clear();
 }
 
-void ArcAppListPrefs::AddAppAndShortcut(const std::string& name,
-                                        const std::string& package_name,
-                                        const std::string& activity,
-                                        const std::string& intent_uri,
-                                        const std::string& icon_resource_id,
-                                        const bool sticky,
-                                        const bool notifications_enabled,
-                                        const bool shortcut) {
+void ArcAppListPrefs::AddAppAndShortcut(
+    const std::string& name,
+    const std::string& package_name,
+    const std::string& activity,
+    const std::string& intent_uri,
+    const std::string& icon_resource_id,
+    const bool sticky,
+    const bool notifications_enabled,
+    const bool shortcut,
+    const arc::mojom::OrientationLock orientation_lock) {
   std::string app_id = shortcut ? GetAppId(package_name, intent_uri)
                                 : GetAppId(package_name, activity);
   bool was_registered = IsRegistered(app_id);
@@ -611,6 +619,7 @@
   app_dict->SetBoolean(kSticky, sticky);
   app_dict->SetBoolean(kNotificationsEnabled, notifications_enabled);
   app_dict->SetBoolean(kShortcut, shortcut);
+  app_dict->SetInteger(kOrientationLock, static_cast<int>(orientation_lock));
 
   // From now, app is available.
   if (!ready_apps_.count(app_id))
@@ -623,7 +632,8 @@
   } else {
     AppInfo app_info(name, package_name, activity, intent_uri, icon_resource_id,
                      base::Time(), sticky, notifications_enabled, true,
-                     arc::ShouldShowInLauncher(app_id), shortcut);
+                     arc::ShouldShowInLauncher(app_id), shortcut,
+                     orientation_lock);
     FOR_EACH_OBSERVER(Observer,
                       observer_list_,
                       OnAppRegistered(app_id, app_info));
@@ -681,10 +691,12 @@
 
   ready_apps_.clear();
   for (const auto& app : apps) {
+    // TODO(oshima): Do we have to update orientation?
     AddAppAndShortcut(app->name, app->package_name, app->activity,
                       std::string() /* intent_uri */,
                       std::string() /* icon_resource_id */, app->sticky,
-                      app->notifications_enabled, false /* shortcut */);
+                      app->notifications_enabled, false /* shortcut */,
+                      app->orientation_lock);
   }
 
   // Detect removed ARC apps after current refresh.
@@ -706,6 +718,13 @@
   }
 }
 
+void ArcAppListPrefs::OnTaskOrientationLockRequested(
+    int32_t task_id,
+    const arc::mojom::OrientationLock orientation_lock) {
+  FOR_EACH_OBSERVER(Observer, observer_list_,
+                    OnTaskOrientationLockRequested(task_id, orientation_lock));
+}
+
 void ArcAppListPrefs::OnAppAdded(arc::mojom::AppInfoPtr app) {
   if ((app->name.get().empty() || app->package_name.get().empty() ||
        app->activity.get().empty())) {
@@ -716,7 +735,8 @@
   AddAppAndShortcut(app->name, app->package_name, app->activity,
                     std::string() /* intent_uri */,
                     std::string() /* icon_resource_id */, app->sticky,
-                    app->notifications_enabled, false /* shortcut */);
+                    app->notifications_enabled, false /* shortcut */,
+                    app->orientation_lock);
 }
 
 void ArcAppListPrefs::OnInstallShortcut(arc::mojom::ShortcutInfoPtr shortcut) {
@@ -728,7 +748,8 @@
   AddAppAndShortcut(shortcut->name, shortcut->package_name,
                     std::string() /* activity */, shortcut->intent_uri,
                     shortcut->icon_resource_id, false /* sticky */,
-                    false /* notifications_enabled */, true /* shortcut */);
+                    false /* notifications_enabled */, true /* shortcut */,
+                    arc::mojom::OrientationLock::NONE);
 }
 
 void ArcAppListPrefs::OnPackageRemoved(const mojo::String& package_name) {
@@ -916,7 +937,8 @@
                                   bool notifications_enabled,
                                   bool ready,
                                   bool showInLauncher,
-                                  bool shortcut)
+                                  bool shortcut,
+                                  arc::mojom::OrientationLock orientation_lock)
     : name(name),
       package_name(package_name),
       activity(activity),
@@ -927,7 +949,8 @@
       notifications_enabled(notifications_enabled),
       ready(ready),
       showInLauncher(showInLauncher),
-      shortcut(shortcut) {}
+      shortcut(shortcut),
+      orientation_lock(orientation_lock) {}
 
 // Need to add explicit destructor for chromium style checker error:
 // Complex class/struct needs an explicit out-of-line destructor
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h
index b00e1659..0357525 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h
+++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h
@@ -60,7 +60,8 @@
             bool notifications_enabled,
             bool ready,
             bool showInLauncher,
-            bool shortcut);
+            bool shortcut,
+            arc::mojom::OrientationLock orientation_lock);
     ~AppInfo();
 
     std::string name;
@@ -74,6 +75,7 @@
     bool ready;
     bool showInLauncher;
     bool shortcut;
+    arc::mojom::OrientationLock orientation_lock;
   };
 
   struct PackageInfo {
@@ -120,6 +122,10 @@
     virtual void OnNotificationsEnabledChanged(
         const std::string& package_name, bool enabled) {}
 
+    virtual void OnTaskOrientationLockRequested(
+        int32_t task_id,
+        const arc::mojom::OrientationLock orientation_lock) {}
+
    protected:
     virtual ~Observer() {}
   };
@@ -194,7 +200,7 @@
   void RemoveApp(const std::string& app_id);
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(ChromeLauncherControllerImplTest, ArcAppPinPolicy);
+  friend class ChromeLauncherControllerImplTest;
 
   // See the Create methods.
   ArcAppListPrefs(const base::FilePath& base_path, PrefService* prefs);
@@ -227,6 +233,9 @@
   void OnPackageModified(arc::mojom::ArcPackageInfoPtr package_info) override;
   void OnPackageListRefreshed(
       mojo::Array<arc::mojom::ArcPackageInfoPtr> packages) override;
+  void OnTaskOrientationLockRequested(
+      int32_t task_id,
+      const arc::mojom::OrientationLock orientation_lock) override;
 
   void AddAppAndShortcut(const std::string& name,
                          const std::string& package_name,
@@ -235,7 +244,8 @@
                          const std::string& icon_resource_id,
                          const bool sticky,
                          const bool notifications_enabled,
-                         const bool shortcut);
+                         const bool shortcut,
+                         arc::mojom::OrientationLock orientation_lock);
   void DisableAllApps();
   void RemoveAllApps();
   std::vector<std::string> GetAppIdsNoArcEnabledCheck() const;
diff --git a/chrome/browser/ui/app_list/extension_app_context_menu.cc b/chrome/browser/ui/app_list/extension_app_context_menu.cc
index 39d939b6..ca05fca 100644
--- a/chrome/browser/ui/app_list/extension_app_context_menu.cc
+++ b/chrome/browser/ui/app_list/extension_app_context_menu.cc
@@ -105,18 +105,11 @@
               USE_LAUNCH_TYPE_WINDOW,
               IDS_APP_CONTEXT_MENU_OPEN_WINDOW);
         }
-#if defined(OS_MACOSX)
-        // Mac does not support standalone web app browser windows or maximize.
-        menu_model->AddCheckItemWithStringId(
-            USE_LAUNCH_TYPE_FULLSCREEN,
-            IDS_APP_CONTEXT_MENU_OPEN_FULLSCREEN);
-#else
         // Even though the launch type is Full Screen it is more accurately
         // described as Maximized in Ash.
         menu_model->AddCheckItemWithStringId(
             USE_LAUNCH_TYPE_FULLSCREEN,
             IDS_APP_CONTEXT_MENU_OPEN_MAXIMIZED);
-#endif
       }
       menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
     }
@@ -160,11 +153,6 @@
 
   DCHECK_EQ(LAUNCH_NEW, command_id);
 
-#if defined(OS_MACOSX)
-  // Full screen on Mac launches in a tab.
-  bool launches_in_window = extensions::util::CanHostedAppsOpenInWindows() &&
-                            IsCommandIdChecked(USE_LAUNCH_TYPE_WINDOW);
-#else
   // If --enable-new-bookmark-apps is enabled, then only check if
   // USE_LAUNCH_TYPE_WINDOW is checked, as USE_LAUNCH_TYPE_PINNED (i.e. open
   // as pinned tab) and fullscreen-by-default windows do not exist.
@@ -173,7 +161,6 @@
            ? IsCommandIdChecked(USE_LAUNCH_TYPE_WINDOW)
            : !(IsCommandIdChecked(USE_LAUNCH_TYPE_PINNED) ||
                IsCommandIdChecked(USE_LAUNCH_TYPE_REGULAR)));
-#endif
 
   return launches_in_window ?
       l10n_util::GetStringUTF16(IDS_APP_LIST_CONTEXT_MENU_NEW_WINDOW) :
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
index 439cf70..ecdc856 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
@@ -3,9 +3,13 @@
 // found in the LICENSE file.
 #include "chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h"
 
+#include "ash/common/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/common/wm/window_state.h"
+#include "ash/common/wm_shell.h"
+#include "ash/display/screen_orientation_controller_chromeos.h"
 #include "ash/shelf/shelf_delegate.h"
 #include "ash/shelf/shelf_util.h"
+#include "ash/shell.h"
 #include "ash/wm/window_state_aura.h"
 #include "ash/wm/window_util.h"
 #include "base/bind.h"
@@ -20,6 +24,7 @@
 #include "components/exo/shell_surface.h"
 #include "components/signin/core/account_id/account_id.h"
 #include "components/user_manager/user_manager.h"
+#include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/env.h"
 #include "ui/base/base_window.h"
@@ -33,6 +38,17 @@
   NON_ACTIVE,   // Fullscreen was not activated for an app.
 };
 
+blink::WebScreenOrientationLockType BlinkOrientationLockFromMojom(
+    arc::mojom::OrientationLock orientation_lock) {
+  if (orientation_lock == arc::mojom::OrientationLock::PORTRAIT) {
+    return blink::WebScreenOrientationLockPortrait;
+  } else if (orientation_lock == arc::mojom::OrientationLock::LANDSCAPE) {
+    return blink::WebScreenOrientationLockLandscape;
+  } else {
+    return blink::WebScreenOrientationLockAny;
+  }
+}
+
 }  // namespace
 
 class ArcAppWindowLauncherController::AppWindow : public ui::BaseWindow {
@@ -155,6 +171,19 @@
 
   void SetAlwaysOnTop(bool always_on_top) override { NOTREACHED(); }
 
+  arc::mojom::OrientationLock requested_orientation_lock() const {
+    return requested_orientation_lock_;
+  }
+
+  void set_requested_orientation_lock(arc::mojom::OrientationLock lock) {
+    has_requested_orientation_lock_ = true;
+    requested_orientation_lock_ = lock;
+  }
+
+  bool has_requested_orientation_lock() const {
+    return has_requested_orientation_lock_;
+  }
+
  private:
   arc::mojom::AppInstance* GetAppInstance() {
     arc::ArcBridgeService* bridge_service = arc::ArcBridgeService::Get();
@@ -183,6 +212,10 @@
   // Unowned pointer, represents host Arc window.
   views::Widget* widget_ = nullptr;
 
+  arc::mojom::OrientationLock requested_orientation_lock_ =
+      arc::mojom::OrientationLock::NONE;
+  bool has_requested_orientation_lock_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(AppWindow);
 };
 
@@ -199,6 +232,8 @@
 ArcAppWindowLauncherController::~ArcAppWindowLauncherController() {
   if (observed_profile_)
     StopObserving(observed_profile_);
+  if (observing_shell_)
+    ash::WmShell::Get()->RemoveShellObserver(this);
 }
 
 // static
@@ -284,6 +319,14 @@
     return;
 
   if (task_id) {
+    // We need to add the observer after exo started observing shell
+    // because we want to update the orientation after exo send
+    // the layout switch information.
+    if (!observing_shell_) {
+      observing_shell_ = true;
+      ash::WmShell::Get()->AddShellObserver(this);
+    }
+
     AppWindow* app_window = GetAppWindowForTask(task_id);
     if (app_window) {
       app_window->set_widget(views::Widget::GetWidgetForNativeWindow(window));
@@ -293,6 +336,11 @@
       chrome::MultiUserWindowManager::GetInstance()->SetWindowOwner(
           window,
           user_manager::UserManager::Get()->GetPrimaryUser()->GetAccountId());
+      if (ash::WmShell::Get()
+              ->maximize_mode_controller()
+              ->IsMaximizeModeWindowManagerEnabled()) {
+        SetOrientationLockForAppWindow(app_window);
+      }
     }
   }
 }
@@ -391,6 +439,23 @@
   }
 }
 
+void ArcAppWindowLauncherController::OnTaskOrientationLockRequested(
+    int32_t task_id,
+    const arc::mojom::OrientationLock orientation_lock) {
+  // Don't save to AppInfo because this is requested in runtime.
+  TaskIdToAppWindow::iterator app_it = task_id_to_app_window_.find(task_id);
+  if (app_it == task_id_to_app_window_.end())
+    return;
+  AppWindow* app_window = app_it->second.get();
+  app_window->set_requested_orientation_lock(orientation_lock);
+
+  if (ash::WmShell::Get()
+          ->maximize_mode_controller()
+          ->IsMaximizeModeWindowManagerEnabled()) {
+    SetOrientationLockForAppWindow(app_window);
+  }
+}
+
 AppWindowLauncherItemController*
 ArcAppWindowLauncherController::ControllerForWindow(aura::Window* window) {
   AppWindow* app_window = GetAppWindowForTask(active_task_id_);
@@ -414,6 +479,18 @@
   OnTaskSetActive(active_task_id_);
 }
 
+void ArcAppWindowLauncherController::OnMaximizeModeStarted() {
+  for (auto& it : task_id_to_app_window_)
+    SetOrientationLockForAppWindow(it.second.get());
+}
+
+void ArcAppWindowLauncherController::OnMaximizeModeEnded() {
+  ash::ScreenOrientationController* orientation_controller =
+      ash::Shell::GetInstance()->screen_orientation_controller();
+  // Don't unlock one by one because it'll switch to next rotation.
+  orientation_controller->UnlockAll();
+}
+
 void ArcAppWindowLauncherController::StartObserving(Profile* profile) {
   aura::Env* env = aura::Env::GetInstanceDontCreate();
   if (env)
@@ -477,3 +554,24 @@
   }
   app_window->ResetController();
 }
+
+void ArcAppWindowLauncherController::SetOrientationLockForAppWindow(
+    AppWindow* app_window) {
+  ash::Shell* shell = ash::Shell::GetInstance();
+  aura::Window* window = app_window->widget()->GetNativeWindow();
+  if (!window)
+    return;
+  arc::mojom::OrientationLock orientation_lock;
+  if (app_window->has_requested_orientation_lock()) {
+    orientation_lock = app_window->requested_orientation_lock();
+  } else {
+    ArcAppListPrefs* prefs = ArcAppListPrefs::Get(observed_profile_);
+    std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
+        prefs->GetApp(app_window->app_id());
+    if (!app_info)
+      return;
+    orientation_lock = app_info->orientation_lock;
+  }
+  shell->screen_orientation_controller()->LockOrientationForWindow(
+      window, BlinkOrientationLockFromMojom(orientation_lock));
+}
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h
index cd70f28..68a6babf 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h
@@ -9,6 +9,7 @@
 #include <memory>
 #include <vector>
 
+#include "ash/common/shell_observer.h"
 #include "base/macros.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/ash/launcher/app_window_launcher_controller.h"
@@ -36,6 +37,7 @@
 class ArcAppWindowLauncherController : public AppWindowLauncherController,
                                        public aura::EnvObserver,
                                        public aura::WindowObserver,
+                                       public ash::ShellObserver,
                                        public ArcAppListPrefs::Observer {
  public:
   ArcAppWindowLauncherController(ChromeLauncherController* owner,
@@ -65,6 +67,10 @@
       aura::Window* gained_active,
       aura::Window* lost_active) override;
 
+  // ash::ShellObserver:
+  void OnMaximizeModeStarted() override;
+  void OnMaximizeModeEnded() override;
+
   // ArcAppListPrefs::Observer:
   void OnAppReadyChanged(const std::string& app_id, bool ready) override;
   void OnAppRemoved(const std::string& app_id) override;
@@ -73,6 +79,9 @@
                      const std::string& activity) override;
   void OnTaskDestroyed(int task_id) override;
   void OnTaskSetActive(int32_t task_id) override;
+  void OnTaskOrientationLockRequested(
+      int32_t task_id,
+      const arc::mojom::OrientationLock orientation_lock) override;
 
  private:
   class AppWindow;
@@ -91,6 +100,8 @@
 
   void CheckForAppWindowWidget(aura::Window* window);
 
+  void SetOrientationLockForAppWindow(AppWindow* app_window);
+
   // AppWindowLauncherController:
   AppWindowLauncherItemController* ControllerForWindow(
       aura::Window* window) override;
@@ -102,6 +113,7 @@
   AppControllerMap app_controller_map_;
   std::vector<aura::Window*> observed_windows_;
   Profile* observed_profile_ = nullptr;
+  bool observing_shell_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(ArcAppWindowLauncherController);
 };
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc
index 84f657ad..174b770 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc
@@ -59,5 +59,7 @@
     const content::NotificationDetails& details) {
   DCHECK_EQ(chrome::NOTIFICATION_BROWSER_CLOSING, type);
   DCHECK_EQ(browser_, content::Source<Browser>(source).ptr());
+  registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_CLOSING,
+                    content::Source<Browser>(browser_));
   browser_ = nullptr;
 }
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
index 95f9574..c39afdf9 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
@@ -18,12 +18,15 @@
 #include "ash/common/shelf/shelf_item_delegate_manager.h"
 #include "ash/common/shelf/shelf_model.h"
 #include "ash/common/shelf/shelf_model_observer.h"
+#include "ash/common/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/common/wm_shell.h"
+#include "ash/display/screen_orientation_controller_chromeos.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_helper.h"
 #include "ash/test/shelf_item_delegate_manager_test_api.h"
 #include "ash/test/test_session_state_delegate.h"
 #include "ash/test/test_shell_delegate.h"
+#include "ash/wm/window_util.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/files/file_path.h"
@@ -98,12 +101,15 @@
 #include "ui/aura/client/window_tree_client.h"
 #include "ui/aura/window.h"
 #include "ui/base/models/menu_model.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
 #include "ui/views/widget/widget.h"
 
 using base::ASCIIToUTF16;
 using extensions::Extension;
 using extensions::Manifest;
 using extensions::UnloadedExtensionInfo;
+using arc::mojom::OrientationLock;
 
 namespace {
 const char* offline_gmail_url = "https://mail.google.com/mail/mu/u";
@@ -306,6 +312,10 @@
   ~ChromeLauncherControllerImplTest() override {}
 
   void SetUp() override {
+    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+    command_line->AppendSwitch(ash::switches::kAshUseFirstDisplayAsInternal);
+    command_line->AppendSwitch(ash::switches::kAshEnableTouchViewTesting);
+
     app_list::AppListSyncableServiceFactory::SetUseInTesting();
 
     BrowserWithTestWindowTest::SetUp();
@@ -832,6 +842,12 @@
     base::RunLoop().RunUntilIdle();
   }
 
+  void EnableTabletMode(bool enable) {
+    ash::MaximizeModeController* controller =
+        ash::WmShell::Get()->maximize_mode_controller();
+    controller->EnableMaximizeModeWindowManager(enable);
+  }
+
   void ValidateArcState(bool arc_enabled,
                         bool arc_managed,
                         arc::ArcAuthService::State state,
@@ -843,20 +859,57 @@
   }
 
   // Creates app window and set optional Arc application id.
-  views::Widget* CreateAppWindow(std::string* window_app_id) {
+  views::Widget* CreateArcWindow(std::string& window_app_id) {
     views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
     params.bounds = gfx::Rect(5, 5, 20, 20);
+    params.context = GetContext();
     views::Widget* widget = new views::Widget();
     widget->Init(params);
     widget->Show();
     widget->Activate();
-    if (window_app_id) {
-      exo::ShellSurface::SetApplicationId(widget->GetNativeWindow(),
-                                          window_app_id);
-    }
+    exo::ShellSurface::SetApplicationId(widget->GetNativeWindow(),
+                                        &window_app_id);
     return widget;
   }
 
+  arc::mojom::AppInfo CreateAppInfo(const std::string& name,
+                                    const std::string& activity,
+                                    const std::string& package_name,
+                                    OrientationLock lock) {
+    arc::mojom::AppInfo appinfo;
+    appinfo.name = name;
+    appinfo.package_name = package_name;
+    appinfo.activity = activity;
+    appinfo.orientation_lock = lock;
+    return appinfo;
+  }
+
+  std::string AddArcAppAndShortcut(const arc::mojom::AppInfo& app_info) {
+    ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
+    // Adding app to the prefs, and check that the app is accessible by id.
+    prefs->AddAppAndShortcut(
+        app_info.name, app_info.package_name, app_info.activity,
+        std::string() /* intent_uri */, std::string() /* icon_resource_id */,
+        false /* sticky */, true /* notifications_enabled */,
+        false /* shortcut */, app_info.orientation_lock);
+    const std::string app_id =
+        ArcAppListPrefs::GetAppId(app_info.package_name, app_info.activity);
+    EXPECT_TRUE(prefs->GetApp(app_id));
+    return app_id;
+  }
+
+  void NotifyOnTaskCreated(const arc::mojom::AppInfo& appinfo,
+                           int32_t task_id) {
+    ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
+    prefs->OnTaskCreated(task_id, appinfo.package_name, appinfo.activity);
+  }
+
+  void NotifyOnTaskOrientationLockRequested(int32_t task_id,
+                                            OrientationLock lock) {
+    ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
+    prefs->OnTaskOrientationLockRequested(task_id, lock);
+  }
+
   // Needed for extension service & friends to work.
   scoped_refptr<Extension> extension1_;
   scoped_refptr<Extension> extension2_;
@@ -3345,24 +3398,9 @@
 TEST_F(ChromeLauncherControllerImplTest, ArcAppPinPolicy) {
   arc_test_.SetUp(profile());
   InitLauncherControllerWithBrowser();
-
-  arc::mojom::AppInfo appinfo;
-  appinfo.name = "Some App";
-  appinfo.activity = "SomeActivity";
-  appinfo.package_name = "com.example.app";
-
-  ArcAppListPrefs* const prefs = arc_test_.arc_app_list_prefs();
-  ASSERT_TRUE(prefs);
-
-  // Adding app to the prefs, and check that the app is accessible by id.
-  prefs->AddAppAndShortcut(appinfo.name, appinfo.package_name, appinfo.activity,
-                           std::string() /* intent_uri */,
-                           std::string() /* icon_resource_id */,
-                           false /* sticky */, true /* notifications_enabled */,
-                           false /* shortcut */);
-  const std::string app_id =
-      ArcAppListPrefs::GetAppId(appinfo.package_name, appinfo.activity);
-  EXPECT_TRUE(prefs->GetApp(app_id));
+  arc::mojom::AppInfo appinfo = CreateAppInfo(
+      "Some App", "SomeActivity", "com.example.app", OrientationLock::NONE);
+  const std::string app_id = AddArcAppAndShortcut(appinfo);
 
   // Set policy, that makes pins ARC app. Unlike native extension, for ARC app
   // package_name (not hash) specified as id. In this test we check that
@@ -3427,3 +3465,137 @@
   ValidateArcState(true, false, arc::ArcAuthService::State::FETCHING_CODE,
                    "AppList, Chrome");
 }
+
+TEST_F(ChromeLauncherControllerImplTest, ArcOrientationLock) {
+  DCHECK(display::Display::HasInternalDisplay());
+
+  extension_service_->AddExtension(arc_support_host_.get());
+  arc_test_.SetUp(profile());
+  EnableArc(true);
+  EnableTabletMode(true);
+
+  InitLauncherController();
+  arc::ArcAuthService::SetShelfDelegateForTesting(launcher_controller_.get());
+  arc::mojom::AppInfo appinfo_none =
+      CreateAppInfo("None", "None", "com.example.app", OrientationLock::NONE);
+  arc::mojom::AppInfo appinfo_landscape = CreateAppInfo(
+      "Landscape", "Landscape", "com.example.app", OrientationLock::LANDSCAPE);
+  arc::mojom::AppInfo appinfo_portrait = CreateAppInfo(
+      "Portrait", "Portrait", "com.example.app", OrientationLock::PORTRAIT);
+
+  const std::string app_id_none = AddArcAppAndShortcut(appinfo_none);
+  const std::string app_id_landscape = AddArcAppAndShortcut(appinfo_landscape);
+  const std::string app_id_portrait = AddArcAppAndShortcut(appinfo_portrait);
+
+  int32_t task_id_none = 1;
+  int32_t task_id_landscape = 2;
+  int32_t task_id_portrait = 3;
+
+  // This needs to be kept on stack because window's property has
+  // refeference to this.
+  std::string window_app_id_none("org.chromium.arc.1");
+  std::string window_app_id_landscape("org.chromium.arc.2");
+  std::string window_app_id_portrait("org.chromium.arc.3");
+
+  ash::ScreenOrientationController* controller =
+      ash::Shell::GetInstance()->screen_orientation_controller();
+
+  // Creating a window with NONE orientation will not lock the screen.
+  views::Widget* window_none = CreateArcWindow(window_app_id_none);
+  NotifyOnTaskCreated(appinfo_none, task_id_none);
+  EXPECT_FALSE(controller->rotation_locked());
+  EXPECT_EQ(display::Display::ROTATE_0,
+            display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
+
+  // Create a arc window with PORTRAIT orientation locks the screen to 90.
+  views::Widget* window_portrait = CreateArcWindow(window_app_id_portrait);
+  NotifyOnTaskCreated(appinfo_portrait, task_id_portrait);
+  EXPECT_TRUE(controller->rotation_locked());
+  EXPECT_EQ(display::Display::ROTATE_90,
+            display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
+
+  // Create a arc window with LANDSCAPE orientation locks the screen to 0.
+  views::Widget* window_landscape = CreateArcWindow(window_app_id_landscape);
+  NotifyOnTaskCreated(appinfo_landscape, task_id_landscape);
+  EXPECT_TRUE(controller->rotation_locked());
+  EXPECT_EQ(display::Display::ROTATE_0,
+            display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
+
+  // Activating a window with NON orientation unlocks the screen.
+  window_none->Activate();
+  EXPECT_FALSE(controller->rotation_locked());
+  EXPECT_EQ(display::Display::ROTATE_0,
+            display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
+
+  // Activating a window with PORTRAIT orientation locks the screen to 90.
+  window_portrait->Activate();
+  EXPECT_TRUE(controller->rotation_locked());
+  EXPECT_EQ(display::Display::ROTATE_90,
+            display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
+
+  // Disable Tablet mode, and make sure the screen is unlocked.
+  EnableTabletMode(false);
+  EXPECT_FALSE(controller->rotation_locked());
+  EXPECT_EQ(display::Display::ROTATE_0,
+            display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
+
+  // Re-enable Tablet mode, and make sure the screen is locked to 90.
+  EnableTabletMode(true);
+  EXPECT_TRUE(controller->rotation_locked());
+  EXPECT_EQ(display::Display::ROTATE_90,
+            display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
+
+  window_portrait->Activate();
+  EXPECT_TRUE(controller->rotation_locked());
+  EXPECT_EQ(display::Display::ROTATE_90,
+            display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
+
+  window_landscape->Activate();
+  EXPECT_TRUE(controller->rotation_locked());
+  EXPECT_EQ(display::Display::ROTATE_0,
+            display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
+
+  // OnTaskOrientationLockRequested can overwrite the current lock.
+  NotifyOnTaskOrientationLockRequested(task_id_landscape,
+                                       OrientationLock::NONE);
+  EXPECT_FALSE(controller->rotation_locked());
+  EXPECT_EQ(display::Display::ROTATE_0,
+            display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
+
+  NotifyOnTaskOrientationLockRequested(task_id_landscape,
+                                       OrientationLock::PORTRAIT);
+  EXPECT_TRUE(controller->rotation_locked());
+  EXPECT_EQ(display::Display::ROTATE_90,
+            display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
+
+  // Non active window won't change the lock.
+  NotifyOnTaskOrientationLockRequested(task_id_none,
+                                       OrientationLock::LANDSCAPE);
+  EXPECT_TRUE(controller->rotation_locked());
+  EXPECT_EQ(display::Display::ROTATE_90,
+            display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
+
+  // But activating it will change the locked orinetation.
+  window_none->Activate();
+  EXPECT_TRUE(controller->rotation_locked());
+  EXPECT_EQ(display::Display::ROTATE_0,
+            display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
+
+  // OnTaskOrientationLockRequested will not lock the screen in non Tablet mode.
+  EnableTabletMode(false);
+  EXPECT_FALSE(controller->rotation_locked());
+  EXPECT_EQ(display::Display::ROTATE_0,
+            display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
+
+  NotifyOnTaskOrientationLockRequested(task_id_none, OrientationLock::PORTRAIT);
+  EXPECT_FALSE(controller->rotation_locked());
+  EXPECT_EQ(display::Display::ROTATE_0,
+            display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
+
+  // But it remembers the orientation lock and use it when Tablet mode is
+  // enabled.
+  EnableTabletMode(true);
+  EXPECT_TRUE(controller->rotation_locked());
+  EXPECT_EQ(display::Display::ROTATE_90,
+            display::Screen::GetScreen()->GetPrimaryDisplay().rotation());
+}
diff --git a/chrome/browser/ui/browser_navigator_browsertest.cc b/chrome/browser/ui/browser_navigator_browsertest.cc
index 4c8c1d9..efae8f1 100644
--- a/chrome/browser/ui/browser_navigator_browsertest.cc
+++ b/chrome/browser/ui/browser_navigator_browsertest.cc
@@ -68,7 +68,7 @@
   std::string url_string = url.spec();
   const std::string long_prefix = "chrome://chrome/";
   const std::string short_prefix = "chrome://";
-  if (url_string.find(long_prefix) != 0)
+  if (!base::StartsWith(url_string, long_prefix, base::CompareCase::SENSITIVE))
     return url;
   url_string.replace(0, long_prefix.length(), short_prefix);
   return GURL(url_string);
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.mm
index 3976e0f..3e268749 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_model_observer_for_cocoa.mm
@@ -65,7 +65,7 @@
 void BookmarkModelObserverForCocoa::BookmarkNodeChanged(
     BookmarkModel* model,
     const BookmarkNode* node) {
-  if (!nodes_.size() || nodes_.find(node) != nodes_.end())
+  if (nodes_.empty() || nodes_.find(node) != nodes_.end())
     Notify();
 }
 
diff --git a/chrome/browser/ui/find_bar/find_bar_controller.cc b/chrome/browser/ui/find_bar/find_bar_controller.cc
index 909749f..f30cf92 100644
--- a/chrome/browser/ui/find_bar/find_bar_controller.cc
+++ b/chrome/browser/ui/find_bar/find_bar_controller.cc
@@ -8,6 +8,7 @@
 
 #include "base/i18n/rtl.h"
 #include "base/logging.h"
+#include "base/strings/string_util.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
@@ -143,8 +144,10 @@
         const base::string16& last_search =
             find_tab_helper->previous_find_text();
         const base::string16& current_search = find_tab_helper->find_text();
-        if (last_search.find(current_search) != 0)
+        if (base::StartsWith(last_search, current_search,
+                             base::CompareCase::SENSITIVE)) {
           find_bar_->AudibleAlert();
+        }
       }
     }
   } else if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) {
diff --git a/chrome/browser/ui/signin_view_controller_delegate.h b/chrome/browser/ui/signin_view_controller_delegate.h
index f2e767a..445a60f4 100644
--- a/chrome/browser/ui/signin_view_controller_delegate.h
+++ b/chrome/browser/ui/signin_view_controller_delegate.h
@@ -48,6 +48,10 @@
   // content::WebContentsDelegate:
   bool HandleContextMenu(const content::ContextMenuParams& params) override;
 
+  // WebContents is used for executing javascript in the context of a modal sync
+  // confirmation dialog.
+  content::WebContents* web_contents_for_testing() { return web_contents_; }
+
  protected:
   SigninViewControllerDelegate(SigninViewController* signin_view_controller,
                                content::WebContents* web_contents);
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index d7d4fbc..3c621fd8 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -1029,20 +1029,15 @@
   DCHECK(ContainsIndex(index));
   DCHECK(id == CommandCloseTabsToRight || id == CommandCloseOtherTabs);
   bool is_selected = IsTabSelected(index);
-  int start;
+  int last_unclosed_tab = -1;
   if (id == CommandCloseTabsToRight) {
-    if (is_selected) {
-      start = selection_model_.selected_indices()[
-          selection_model_.selected_indices().size() - 1] + 1;
-    } else {
-      start = index + 1;
-    }
-  } else {
-    start = 0;
+    last_unclosed_tab =
+        is_selected ? selection_model_.selected_indices().back() : index;
   }
+
   // NOTE: callers expect the vector to be sorted in descending order.
   std::vector<int> indices;
-  for (int i = count() - 1; i >= start; --i) {
+  for (int i = count() - 1; i > last_unclosed_tab; --i) {
     if (i != index && !IsTabPinned(i) && (!is_selected || !IsTabSelected(i)))
       indices.push_back(i);
   }
diff --git a/chrome/browser/ui/views/ime/input_ime_apitest_nonchromeos.cc b/chrome/browser/ui/views/ime/input_ime_apitest_nonchromeos.cc
index 6243afd..0e20516 100644
--- a/chrome/browser/ui/views/ime/input_ime_apitest_nonchromeos.cc
+++ b/chrome/browser/ui/views/ime/input_ime_apitest_nonchromeos.cc
@@ -7,7 +7,6 @@
 #include "chrome/browser/extensions/api/input_ime/input_ime_api_nonchromeos.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -17,7 +16,6 @@
 #include "ui/base/ime/composition_text.h"
 #include "ui/base/ime/dummy_text_input_client.h"
 #include "ui/base/ime/input_method.h"
-#include "url/origin.h"
 
 namespace extensions {
 
@@ -109,8 +107,7 @@
 
 IN_PROC_BROWSER_TEST_F(InputImeApiTest, SendKeyEventsOnNormalPage) {
   // Navigates to special page that sendKeyEvents API has limition with.
-  GURL test_url(chrome::kChromeUINewTabURL);
-  ui_test_utils::NavigateToURL(browser(), test_url);
+  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
   // Manipulates the focused text input client because the follow cursor
   // window requires the text input focus.
   ui::InputMethod* input_method =
@@ -125,34 +122,26 @@
 
   ASSERT_TRUE(RunExtensionTest("input_ime_nonchromeos")) << message_;
 
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  url::Origin origin(web_contents->GetLastCommittedURL());
+  std::vector<std::unique_ptr<ui::KeyEvent>> key_events;
+  key_events.push_back(std::unique_ptr<ui::KeyEvent>(
+      new ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE)));
+  key_events.push_back(std::unique_ptr<ui::KeyEvent>(
+      new ui::KeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_A, ui::EF_NONE)));
+  key_events.push_back(std::unique_ptr<ui::KeyEvent>(
+      new ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_CONTROL_DOWN)));
+  key_events.push_back(std::unique_ptr<ui::KeyEvent>(
+      new ui::KeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_A, ui::EF_CONTROL_DOWN)));
+  key_events.push_back(std::unique_ptr<ui::KeyEvent>(
+      new ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_TAB, ui::EF_NONE)));
 
-  // Don't check events if the url has not been correctly set.
-  if (url::Origin(test_url).IsSameOriginWith(origin)) {
-    std::vector<std::unique_ptr<ui::KeyEvent>> key_events;
-    key_events.push_back(std::unique_ptr<ui::KeyEvent>(
-        new ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE)));
-    key_events.push_back(std::unique_ptr<ui::KeyEvent>(
-        new ui::KeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_A, ui::EF_NONE)));
-    key_events.push_back(std::unique_ptr<ui::KeyEvent>(
-        new ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_CONTROL_DOWN)));
-    key_events.push_back(std::unique_ptr<ui::KeyEvent>(new ui::KeyEvent(
-        ui::ET_KEY_RELEASED, ui::VKEY_A, ui::EF_CONTROL_DOWN)));
-    key_events.push_back(std::unique_ptr<ui::KeyEvent>(
-        new ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_TAB, ui::EF_NONE)));
-
-    EXPECT_TRUE(CompareKeyEvents(key_events, input_method));
-  }
+  EXPECT_TRUE(CompareKeyEvents(key_events, input_method));
 
   input_method->DetachTextInputClient(client.get());
 }
 
 IN_PROC_BROWSER_TEST_F(InputImeApiTest, SendKeyEventsOnSpecialPage) {
   // Navigates to special page that sendKeyEvents API has limition with.
-  GURL test_url("chrome://flags");
-  ui_test_utils::NavigateToURL(browser(), test_url);
+  ui_test_utils::NavigateToURL(browser(), GURL("chrome://flags"));
 
   ui::InputMethod* input_method =
       browser()->window()->GetNativeWindow()->GetHost()->GetInputMethod();
@@ -166,20 +155,13 @@
 
   ASSERT_TRUE(RunExtensionTest("input_ime_nonchromeos")) << message_;
 
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  url::Origin origin(web_contents->GetLastCommittedURL());
+  std::vector<std::unique_ptr<ui::KeyEvent>> key_events;
+  key_events.push_back(std::unique_ptr<ui::KeyEvent>(
+      new ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE)));
+  key_events.push_back(std::unique_ptr<ui::KeyEvent>(
+      new ui::KeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_A, ui::EF_NONE)));
 
-  // Don't check events if the url has not been correctly set.
-  if (url::Origin(test_url).IsSameOriginWith(origin)) {
-    std::vector<std::unique_ptr<ui::KeyEvent>> key_events;
-    key_events.push_back(std::unique_ptr<ui::KeyEvent>(
-        new ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE)));
-    key_events.push_back(std::unique_ptr<ui::KeyEvent>(
-        new ui::KeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_A, ui::EF_NONE)));
-
-    EXPECT_TRUE(CompareKeyEvents(key_events, input_method));
-  }
+  EXPECT_TRUE(CompareKeyEvents(key_events, input_method));
   input_method->DetachTextInputClient(client.get());
 }
 
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 7885a46..6c192ae 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -734,7 +734,7 @@
         do_move = false;
     }
     if (do_move) {
-      WebContents* last_contents = drag_data_[drag_data_.size() - 1].contents;
+      WebContents* last_contents = drag_data_.back().contents;
       int index_of_last_item =
           attached_model->GetIndexOfWebContents(last_contents);
       if (initial_move_) {
diff --git a/chrome/browser/ui/website_settings/mock_permission_bubble_factory.cc b/chrome/browser/ui/website_settings/mock_permission_bubble_factory.cc
index dc935b4..94955902 100644
--- a/chrome/browser/ui/website_settings/mock_permission_bubble_factory.cc
+++ b/chrome/browser/ui/website_settings/mock_permission_bubble_factory.cc
@@ -6,14 +6,13 @@
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
 #include "chrome/browser/ui/website_settings/mock_permission_bubble_view.h"
 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
 
 MockPermissionBubbleFactory::MockPermissionBubbleFactory(
-    bool is_browser_test,
     PermissionBubbleManager* manager)
-    : is_browser_test_(is_browser_test),
-      can_update_ui_(false),
+    : can_update_ui_(false),
       show_count_(0),
       requests_count_(0),
       total_requests_count_(0),
@@ -35,7 +34,7 @@
 std::unique_ptr<PermissionBubbleView> MockPermissionBubbleFactory::Create(
     Browser* browser) {
   MockPermissionBubbleView* view =
-      new MockPermissionBubbleView(this, manager_, is_browser_test_);
+      new MockPermissionBubbleView(this, manager_);
   view->can_update_ui_ = can_update_ui_;
   return base::WrapUnique(view);
 }
@@ -64,12 +63,22 @@
   return false;
 }
 
+void MockPermissionBubbleFactory::WaitForPermissionBubble() {
+  if (is_visible())
+    return;
+  DCHECK(show_bubble_quit_closure_.is_null());
+  base::RunLoop loop;
+  show_bubble_quit_closure_ = loop.QuitClosure();
+  loop.Run();
+  show_bubble_quit_closure_ = base::Closure();
+}
+
 // static
 std::unique_ptr<PermissionBubbleView> MockPermissionBubbleFactory::DoNotCreate(
     Browser* browser) {
   NOTREACHED();
   return base::WrapUnique(
-      new MockPermissionBubbleView(nullptr, nullptr, false));
+      new MockPermissionBubbleView(nullptr, nullptr));
 }
 
 void MockPermissionBubbleFactory::UpdateResponseType() {
@@ -83,6 +92,9 @@
       return;
   }
   views_.push_back(view);
+
+  if (!show_bubble_quit_closure_.is_null())
+    show_bubble_quit_closure_.Run();
 }
 
 void MockPermissionBubbleFactory::HideView(MockPermissionBubbleView* view) {
diff --git a/chrome/browser/ui/website_settings/mock_permission_bubble_factory.h b/chrome/browser/ui/website_settings/mock_permission_bubble_factory.h
index d3572d3a..471039f 100644
--- a/chrome/browser/ui/website_settings/mock_permission_bubble_factory.h
+++ b/chrome/browser/ui/website_settings/mock_permission_bubble_factory.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/callback.h"
 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
 
 class Browser;
@@ -21,10 +22,7 @@
 // chrome/browser/ui/website_settings/permission_bubble_manager_unittest.cc
 class MockPermissionBubbleFactory {
  public:
-  // Set |is_browser_test| if in a browser test in order to interact with the
-  // message loop. That shouldn't be done in unit tests.
-  MockPermissionBubbleFactory(bool is_browser_test,
-                              PermissionBubbleManager* manager);
+  explicit MockPermissionBubbleFactory(PermissionBubbleManager* manager);
   ~MockPermissionBubbleFactory();
 
   // Create method called by the PBM to show a bubble.
@@ -49,6 +47,8 @@
   // Number of requests seen.
   int total_request_count() { return total_requests_count_; }
 
+  void WaitForPermissionBubble();
+
  private:
   friend class MockPermissionBubbleView;
 
@@ -60,7 +60,6 @@
   void ShowView(MockPermissionBubbleView* view);
   void HideView(MockPermissionBubbleView* view);
 
-  bool is_browser_test_;
   bool can_update_ui_;
   int show_count_;
   int requests_count_;
@@ -68,6 +67,8 @@
   std::vector<MockPermissionBubbleView*> views_;
   PermissionBubbleManager::AutoResponseType response_type_;
 
+  base::Closure show_bubble_quit_closure_;
+
   // The bubble manager that will be associated with this factory.
   PermissionBubbleManager* manager_;
 
diff --git a/chrome/browser/ui/website_settings/mock_permission_bubble_view.cc b/chrome/browser/ui/website_settings/mock_permission_bubble_view.cc
index 631cb35..470ac0a4 100644
--- a/chrome/browser/ui/website_settings/mock_permission_bubble_view.cc
+++ b/chrome/browser/ui/website_settings/mock_permission_bubble_view.cc
@@ -22,9 +22,6 @@
   factory_->total_requests_count_ += manager_->requests_.size();
   factory_->UpdateResponseType();
   is_visible_ = true;
-
-  if (browser_test_)
-    base::MessageLoopForUI::current()->QuitWhenIdle();
 }
 
 bool MockPermissionBubbleView::CanAcceptRequestUpdate() {
@@ -51,10 +48,8 @@
 
 MockPermissionBubbleView::MockPermissionBubbleView(
     MockPermissionBubbleFactory* factory,
-    PermissionBubbleManager* manager,
-    bool browser_test)
+    PermissionBubbleManager* manager)
     : factory_(factory),
       manager_(manager),
-      browser_test_(browser_test),
       can_update_ui_(true),
       is_visible_(false) {}
diff --git a/chrome/browser/ui/website_settings/mock_permission_bubble_view.h b/chrome/browser/ui/website_settings/mock_permission_bubble_view.h
index 980d9083..2a27f997 100644
--- a/chrome/browser/ui/website_settings/mock_permission_bubble_view.h
+++ b/chrome/browser/ui/website_settings/mock_permission_bubble_view.h
@@ -32,12 +32,10 @@
   friend class MockPermissionBubbleFactory;
 
   MockPermissionBubbleView(MockPermissionBubbleFactory* factory,
-                           PermissionBubbleManager* manager,
-                           bool browser_test);
+                           PermissionBubbleManager* manager);
 
   MockPermissionBubbleFactory* factory_;
   PermissionBubbleManager* manager_;
-  bool browser_test_;
   bool can_update_ui_;
   bool is_visible_;
 };
diff --git a/chrome/browser/ui/website_settings/permission_bubble_manager_browsertest.cc b/chrome/browser/ui/website_settings/permission_bubble_manager_browsertest.cc
index 9e2436c..01155cb 100644
--- a/chrome/browser/ui/website_settings/permission_bubble_manager_browsertest.cc
+++ b/chrome/browser/ui/website_settings/permission_bubble_manager_browsertest.cc
@@ -37,7 +37,7 @@
     InProcessBrowserTest::SetUpOnMainThread();
     PermissionBubbleManager* manager = GetPermissionBubbleManager();
     mock_permission_bubble_factory_.reset(
-        new MockPermissionBubbleFactory(true, manager));
+        new MockPermissionBubbleFactory(manager));
     manager->DisplayPendingRequests();
   }
 
@@ -51,12 +51,6 @@
         browser()->tab_strip_model()->GetActiveWebContents());
   }
 
-  void WaitForPermissionBubble() {
-    if (bubble_factory()->is_visible())
-      return;
-    content::RunMessageLoop();
-  }
-
   MockPermissionBubbleFactory* bubble_factory() {
     return mock_permission_bubble_factory_.get();
   }
@@ -86,7 +80,7 @@
       browser(),
       embedded_test_server()->GetURL("/permissions/requests-before-load.html"),
       1);
-  WaitForPermissionBubble();
+  bubble_factory()->WaitForPermissionBubble();
 
   EXPECT_EQ(1, bubble_factory()->show_count());
   EXPECT_EQ(2, bubble_factory()->total_request_count());
@@ -102,7 +96,7 @@
       embedded_test_server()->GetURL(
           "/permissions/requests-before-after-load.html"),
       1);
-  WaitForPermissionBubble();
+  bubble_factory()->WaitForPermissionBubble();
 
   EXPECT_EQ(1, bubble_factory()->show_count());
   EXPECT_EQ(1, bubble_factory()->total_request_count());
@@ -123,13 +117,13 @@
       browser(),
       embedded_test_server()->GetURL("/permissions/requests-before-load.html"),
       1);
-  WaitForPermissionBubble();
+  bubble_factory()->WaitForPermissionBubble();
 
   ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
       browser(),
       embedded_test_server()->GetURL("/permissions/requests-before-load.html"),
       1);
-  WaitForPermissionBubble();
+  bubble_factory()->WaitForPermissionBubble();
 
   EXPECT_EQ(2, bubble_factory()->show_count());
   EXPECT_EQ(4, bubble_factory()->total_request_count());
@@ -151,14 +145,14 @@
       browser(),
       embedded_test_server()->GetURL("/permissions/requests-before-load.html"),
       1);
-  WaitForPermissionBubble();
+  bubble_factory()->WaitForPermissionBubble();
 
   ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
       browser(),
       embedded_test_server()->GetURL(
           "/permissions/requests-before-load.html#0"),
       1);
-  WaitForPermissionBubble();
+  bubble_factory()->WaitForPermissionBubble();
 
   EXPECT_EQ(1, bubble_factory()->show_count());
   EXPECT_EQ(2, bubble_factory()->total_request_count());
@@ -182,7 +176,7 @@
   ExecuteScriptAndGetValue(
       browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(),
       "navigator.geolocation.getCurrentPosition(function(){});");
-  WaitForPermissionBubble();
+  bubble_factory()->WaitForPermissionBubble();
 
   EXPECT_EQ(1, bubble_factory()->show_count());
   EXPECT_EQ(1, bubble_factory()->total_request_count());
@@ -219,7 +213,7 @@
       embedded_test_server()->GetURL("/permissions/killswitch_tester.html"));
 
   EXPECT_TRUE(content::ExecuteScript(web_contents, "requestGeolocation();"));
-  WaitForPermissionBubble();
+  bubble_factory()->WaitForPermissionBubble();
   EXPECT_EQ(1, bubble_factory()->show_count());
   EXPECT_EQ(1, bubble_factory()->total_request_count());
 }
@@ -249,7 +243,7 @@
   variations::testing::ClearAllVariationParams();
 
   EXPECT_TRUE(content::ExecuteScript(web_contents, "requestNotification();"));
-  WaitForPermissionBubble();
+  bubble_factory()->WaitForPermissionBubble();
   EXPECT_EQ(1, bubble_factory()->show_count());
   EXPECT_EQ(1, bubble_factory()->total_request_count());
 }
diff --git a/chrome/browser/ui/website_settings/permission_bubble_manager_unittest.cc b/chrome/browser/ui/website_settings/permission_bubble_manager_unittest.cc
index e2bf89d..a75aab1 100644
--- a/chrome/browser/ui/website_settings/permission_bubble_manager_unittest.cc
+++ b/chrome/browser/ui/website_settings/permission_bubble_manager_unittest.cc
@@ -36,7 +36,7 @@
     NavigateAndCommit(GURL("http://www.google.com"));
 
     manager_.reset(new PermissionBubbleManager(web_contents()));
-    view_factory_.reset(new MockPermissionBubbleFactory(false, manager_.get()));
+    view_factory_.reset(new MockPermissionBubbleFactory(manager_.get()));
   }
 
   void TearDown() override {
diff --git a/chrome/browser/ui/webui/browsing_history_handler.cc b/chrome/browser/ui/webui/browsing_history_handler.cc
index 82fd5d3..338e1a6 100644
--- a/chrome/browser/ui/webui/browsing_history_handler.cc
+++ b/chrome/browser/ui/webui/browsing_history_handler.cc
@@ -905,7 +905,10 @@
   exploded.day_of_month = 1;
 
   if (offset == 0) {
-    options->begin_time = base::Time::FromLocalExploded(exploded);
+    if (!base::Time::FromLocalExploded(exploded, &options->begin_time)) {
+      // TODO(maksims): implement errors handling here.
+      NOTIMPLEMENTED();
+    }
 
     // Set the end time of this first search to null (which will
     // show results from the future, should the user's clock have
@@ -919,12 +922,18 @@
     exploded.month -= offset - 1;
     // Set the correct year.
     NormalizeMonths(&exploded);
-    options->end_time = base::Time::FromLocalExploded(exploded);
+    if (!base::Time::FromLocalExploded(exploded, &options->begin_time)) {
+      // TODO(maksims): implement errors handling here.
+      NOTIMPLEMENTED();
+    }
 
     exploded.month -= 1;
     // Set the correct year
     NormalizeMonths(&exploded);
-    options->begin_time = base::Time::FromLocalExploded(exploded);
+    if (!base::Time::FromLocalExploded(exploded, &options->begin_time)) {
+      // TODO(maksims): implement errors handling here.
+      NOTIMPLEMENTED();
+    }
   }
 }
 
diff --git a/chrome/browser/ui/webui/history_ui.cc b/chrome/browser/ui/webui/history_ui.cc
index 5e0ec9e..c80543e 100644
--- a/chrome/browser/ui/webui/history_ui.cc
+++ b/chrome/browser/ui/webui/history_ui.cc
@@ -101,13 +101,8 @@
   source->AddLocalizedString("clearAllHistory",
                              IDS_HISTORY_OPEN_CLEAR_BROWSING_DATA_DIALOG);
 
-  auto availability = IncognitoModePrefs::GetAvailability(profile->GetPrefs());
-  base::string16 delete_warning = availability == IncognitoModePrefs::ENABLED ?
-      l10n_util::GetStringFUTF16(IDS_HISTORY_DELETE_PRIOR_VISITS_WARNING,
-                                 base::UTF8ToUTF16(kIncognitoModeShortcut)) :
-      l10n_util::GetStringUTF16(
-          IDS_HISTORY_DELETE_PRIOR_VISITS_WARNING_NO_INCOGNITO);
-  source->AddString("deleteWarning", delete_warning);
+  source->AddString("deleteWarning",
+                    HistoryUI::GetDeleteWarningString(profile));
 
   source->AddLocalizedString("removeBookmark", IDS_HISTORY_REMOVE_BOOKMARK);
   source->AddLocalizedString("actionMenuDescription",
@@ -204,3 +199,14 @@
   return ResourceBundle::GetSharedInstance().
       LoadDataResourceBytesForScale(IDR_HISTORY_FAVICON, scale_factor);
 }
+
+// static
+base::string16 HistoryUI::GetDeleteWarningString(Profile* profile) {
+  auto availability = IncognitoModePrefs::GetAvailability(profile->GetPrefs());
+  return availability == IncognitoModePrefs::ENABLED
+             ? l10n_util::GetStringFUTF16(
+                   IDS_HISTORY_DELETE_PRIOR_VISITS_WARNING,
+                   base::UTF8ToUTF16(kIncognitoModeShortcut))
+             : l10n_util::GetStringUTF16(
+                   IDS_HISTORY_DELETE_PRIOR_VISITS_WARNING_NO_INCOGNITO);
+}
diff --git a/chrome/browser/ui/webui/history_ui.h b/chrome/browser/ui/webui/history_ui.h
index 0b576bc8..5f4eb1b 100644
--- a/chrome/browser/ui/webui/history_ui.h
+++ b/chrome/browser/ui/webui/history_ui.h
@@ -9,6 +9,8 @@
 #include "content/public/browser/web_ui_controller.h"
 #include "ui/base/layout.h"
 
+class Profile;
+
 namespace base {
 class RefCountedMemory;
 }
@@ -21,6 +23,10 @@
   static base::RefCountedMemory* GetFaviconResourceBytes(
       ui::ScaleFactor scale_factor);
 
+  // Returns a localized string warning about deleting history. Takes into
+  // account whether or not incognito mode is available.
+  static base::string16 GetDeleteWarningString(Profile* profile);
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HistoryUI);
 };
diff --git a/chrome/browser/ui/webui/md_history_ui.cc b/chrome/browser/ui/webui/md_history_ui.cc
index e2dac02..425f197c 100644
--- a/chrome/browser/ui/webui/md_history_ui.cc
+++ b/chrome/browser/ui/webui/md_history_ui.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/ui/webui/browsing_history_handler.h"
 #include "chrome/browser/ui/webui/foreign_session_handler.h"
 #include "chrome/browser/ui/webui/history_login_handler.h"
+#include "chrome/browser/ui/webui/history_ui.h"
 #include "chrome/browser/ui/webui/metrics_handler.h"
 #include "chrome/browser/ui/webui/settings/people_handler.h"
 #include "chrome/common/chrome_features.h"
@@ -43,6 +44,8 @@
                              IDS_CLEAR_BROWSING_DATA_TITLE);
   source->AddLocalizedString("clearSearch", IDS_MD_HISTORY_CLEAR_SEARCH);
   source->AddLocalizedString("delete", IDS_MD_HISTORY_DELETE);
+  source->AddLocalizedString("deleteConfirm",
+                             IDS_HISTORY_DELETE_PRIOR_VISITS_CONFIRM_BUTTON);
   source->AddLocalizedString("foundSearchResults",
                              IDS_HISTORY_FOUND_SEARCH_RESULTS);
   source->AddLocalizedString("historyInterval", IDS_HISTORY_INTERVAL);
@@ -68,6 +71,8 @@
   source->AddLocalizedString("rangePrevious", IDS_HISTORY_RANGE_PREVIOUS);
   source->AddLocalizedString("removeBookmark", IDS_HISTORY_REMOVE_BOOKMARK);
   source->AddLocalizedString("removeFromHistory", IDS_HISTORY_REMOVE_PAGE);
+  source->AddLocalizedString("removeSelected",
+                             IDS_HISTORY_REMOVE_SELECTED_ITEMS);
   source->AddLocalizedString("searchPrompt", IDS_MD_HISTORY_SEARCH_PROMPT);
   source->AddLocalizedString("searchResult", IDS_HISTORY_SEARCH_RESULT);
   source->AddLocalizedString("searchResults", IDS_HISTORY_SEARCH_RESULTS);
@@ -77,6 +82,9 @@
                              IDS_MD_HISTORY_SIGN_IN_PROMO_DESC);
   source->AddLocalizedString("title", IDS_HISTORY_TITLE);
 
+  source->AddString("deleteWarning",
+                    HistoryUI::GetDeleteWarningString(profile));
+
   bool allow_deleting_history =
       prefs->GetBoolean(prefs::kAllowDeletingBrowserHistory);
   source->AddBoolean("allowDeletingHistory", allow_deleting_history);
diff --git a/chrome/browser/ui/webui/media/webrtc_logs_ui.cc b/chrome/browser/ui/webui/media/webrtc_logs_ui.cc
index e048f3a..03a2524e 100644
--- a/chrome/browser/ui/webui/media/webrtc_logs_ui.cc
+++ b/chrome/browser/ui/webui/media/webrtc_logs_ui.cc
@@ -181,9 +181,12 @@
       double seconds_since_epoch;
       if (base::StringToDouble(i->local_id, &seconds_since_epoch)) {
         base::Time capture_time = base::Time::FromDoubleT(seconds_since_epoch);
-        base::Time::Exploded lower_limit = {2012, 1, 0, 1, 0, 0, 0, 0};
-        if (capture_time > base::Time::FromUTCExploded(lower_limit) &&
-            capture_time < base::Time::Now()) {
+        const base::Time::Exploded lower_limit = {2012, 1, 0, 1, 0, 0, 0, 0};
+        base::Time out_time;
+        bool conversion_success =
+            base::Time::FromUTCExploded(lower_limit, &out_time);
+        DCHECK(conversion_success);
+        if (capture_time > out_time && capture_time < base::Time::Now()) {
           value_w = base::TimeFormatFriendlyDateAndTime(capture_time);
         }
       }
diff --git a/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc b/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc
index f19e8bc..ad698087 100644
--- a/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc
@@ -40,16 +40,14 @@
 using content::WebUIMessageHandler;
 using ui::WebDialogDelegate;
 
-namespace {
-const int kMaxHeight = 2000;
-const int kMinHeight = 80;
-const int kWidth = 340;
-}
-
 namespace media_router {
 
 namespace {
 
+constexpr const int kMaxHeight = 2000;
+constexpr const int kMinHeight = 80;
+constexpr const int kWidth = 340;
+
 // WebDialogDelegate that specifies what the Media Router dialog
 // will look like.
 class MediaRouterDialogDelegate : public WebDialogDelegate {
@@ -169,7 +167,7 @@
 }
 
 WebContents* MediaRouterDialogControllerImpl::GetMediaRouterDialog() const {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   return dialog_observer_.get() ? dialog_observer_->web_contents() : nullptr;
 }
 
@@ -280,7 +278,7 @@
 
 void MediaRouterDialogControllerImpl::OnDialogNavigated(
     const content::LoadCommittedDetails& details) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   WebContents* media_router_dialog = GetMediaRouterDialog();
   CHECK(media_router_dialog);
   ui::PageTransition transition_type = details.entry->GetTransitionType();
@@ -301,7 +299,7 @@
 
 void MediaRouterDialogControllerImpl::PopulateDialog(
     content::WebContents* media_router_dialog) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(media_router_dialog);
   if (!initiator() || !media_router_dialog->GetWebUI()) {
     Reset();
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.cc b/chrome/browser/ui/webui/media_router/media_router_ui.cc
index 4a8afb4d..6b8fba8 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.cc
@@ -339,7 +339,7 @@
 
 void MediaRouterUI::UpdateCastModes() {
   // Gets updated cast modes from |query_result_manager_| and forwards it to UI.
-  query_result_manager_->GetSupportedCastModes(&cast_modes_);
+  cast_modes_ = query_result_manager_->GetSupportedCastModes();
   if (ui_initialized_) {
     handler_->UpdateCastModes(cast_modes_, GetPresentationRequestSourceName());
   }
diff --git a/chrome/browser/ui/webui/media_router/query_result_manager.cc b/chrome/browser/ui/webui/media_router/query_result_manager.cc
index e7f76d6d..ba2f04a7 100644
--- a/chrome/browser/ui/webui/media_router/query_result_manager.cc
+++ b/chrome/browser/ui/webui/media_router/query_result_manager.cc
@@ -8,6 +8,7 @@
 #include "base/stl_util.h"
 #include "chrome/browser/media/router/media_router.h"
 #include "chrome/browser/media/router/media_sinks_observer.h"
+#include "content/public/browser/browser_thread.h"
 
 namespace media_router {
 
@@ -48,9 +49,9 @@
   MediaCastMode cast_mode() const { return cast_mode_; }
 
  private:
-  MediaCastMode cast_mode_;
+  const MediaCastMode cast_mode_;
   std::vector<MediaSink::Id> latest_sink_ids_;
-  QueryResultManager* result_manager_;
+  QueryResultManager* const result_manager_;
 };
 
 QueryResultManager::QueryResultManager(MediaRouter* router) : router_(router) {
@@ -58,17 +59,17 @@
 }
 
 QueryResultManager::~QueryResultManager() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 }
 
 void QueryResultManager::AddObserver(Observer* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(observer);
   observers_.AddObserver(observer);
 }
 
 void QueryResultManager::RemoveObserver(Observer* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(observer);
   observers_.RemoveObserver(observer);
 }
@@ -76,7 +77,7 @@
 void QueryResultManager::StartSinksQuery(MediaCastMode cast_mode,
                                          const MediaSource& source,
                                          const GURL& origin) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (source.Empty()) {
     LOG(WARNING) << "StartSinksQuery called with empty source for "
                  << cast_mode;
@@ -97,7 +98,7 @@
 }
 
 void QueryResultManager::StopSinksQuery(MediaCastMode cast_mode) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   RemoveObserverForCastMode(cast_mode);
   SetSourceForCastMode(cast_mode, MediaSource());
   UpdateWithSinksQueryResult(cast_mode, std::vector<MediaSink>());
@@ -106,7 +107,7 @@
 
 void QueryResultManager::SetSourceForCastMode(
       MediaCastMode cast_mode, const MediaSource& source) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   cast_mode_sources_[cast_mode] = source;
 }
 
@@ -151,17 +152,16 @@
   }
 }
 
-void QueryResultManager::GetSupportedCastModes(CastModeSet* cast_modes) const {
-  DCHECK(cast_modes);
-  cast_modes->clear();
-  for (const auto& observer_pair : sinks_observers_) {
-    cast_modes->insert(observer_pair.first);
-  }
+CastModeSet QueryResultManager::GetSupportedCastModes() const {
+  CastModeSet modes;
+  for (const auto& observer_pair : sinks_observers_)
+    modes.insert(observer_pair.first);
+  return modes;
 }
 
 MediaSource QueryResultManager::GetSourceForCastMode(
       MediaCastMode cast_mode) const {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   auto source_it = cast_mode_sources_.find(cast_mode);
   return source_it == cast_mode_sources_.end() ?
     MediaSource() : source_it->second;
diff --git a/chrome/browser/ui/webui/media_router/query_result_manager.h b/chrome/browser/ui/webui/media_router/query_result_manager.h
index b56211b..ecffaec 100644
--- a/chrome/browser/ui/webui/media_router/query_result_manager.h
+++ b/chrome/browser/ui/webui/media_router/query_result_manager.h
@@ -13,7 +13,6 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
-#include "base/threading/thread_checker.h"
 #include "chrome/browser/media/router/media_routes_observer.h"
 #include "chrome/browser/media/router/media_sink.h"
 #include "chrome/browser/media/router/media_source.h"
@@ -47,8 +46,7 @@
 //   [Updates will be received by observer via OnResultsUpdated()]
 //   ...
 //   [When info on MediaSource is needed, i.e. when requesting route for a mode]
-//   CastModeSet cast_modes;
-//   result_manager.GetSupportedCastModes(&cast_modes);
+//   CastModeSet cast_modes = result_manager.GetSupportedCastModes();
 //   [Logic to select a MediaCastMode from the set]
 //   MediaSource source = result_manager.GetSourceForCastMode(
 //       MediaCastMode::TAB_MIRROR);
@@ -56,7 +54,7 @@
 //     ...
 //   }
 //
-// Not thread-safe.  Must be used on a single thread.
+// Not thread-safe.  Must be used on the UI thread.
 class QueryResultManager {
  public:
   class Observer {
@@ -92,9 +90,8 @@
   // Stops notifying observers for |cast_mode|.
   void StopSinksQuery(MediaCastMode cast_mode);
 
-  // Gets the set of cast modes that are being actively queried. |cast_mode_set|
-  // should be empty.
-  void GetSupportedCastModes(CastModeSet* cast_modes) const;
+  // Gets the set of cast modes that are being actively queried.
+  CastModeSet GetSupportedCastModes() const;
 
   // Returns the MediaSource registered for |cast_mode|.  Returns an empty
   // MediaSource if there is none.
@@ -140,9 +137,7 @@
   base::ObserverList<Observer> observers_;
 
   // Not owned by this object.
-  MediaRouter* router_;
-
-  base::ThreadChecker thread_checker_;
+  MediaRouter* const router_;
 
   DISALLOW_COPY_AND_ASSIGN(QueryResultManager);
 };
diff --git a/chrome/browser/ui/webui/media_router/query_result_manager_unittest.cc b/chrome/browser/ui/webui/media_router/query_result_manager_unittest.cc
index 5ede9e7..0d580191 100644
--- a/chrome/browser/ui/webui/media_router/query_result_manager_unittest.cc
+++ b/chrome/browser/ui/webui/media_router/query_result_manager_unittest.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/media/router/media_source_helper.h"
 #include "chrome/browser/media/router/mock_media_router.h"
 #include "chrome/browser/ui/webui/media_router/query_result_manager.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -48,6 +49,7 @@
     query_result_manager_.StartSinksQuery(cast_mode, source, GURL(kOrigin));
   }
 
+  content::TestBrowserThreadBundle thread_bundle_;
   MockMediaRouter mock_router_;
   QueryResultManager query_result_manager_;
   MockObserver mock_observer_;
@@ -60,7 +62,7 @@
   if (expected.size() != arg.size()) {
     return false;
   }
-  for (int i = 0; i < static_cast<int>(expected.size()); i++) {
+  for (size_t i = 0; i < expected.size(); ++i) {
     if (!expected[i].Equals(arg[i])) {
       return false;
     }
@@ -88,9 +90,7 @@
 
 TEST_F(QueryResultManagerTest, StartStopSinksQuery) {
   GURL origin(kOrigin);
-  CastModeSet cast_modes;
-
-  query_result_manager_.GetSupportedCastModes(&cast_modes);
+  CastModeSet cast_modes = query_result_manager_.GetSupportedCastModes();
   EXPECT_TRUE(cast_modes.empty());
   MediaSource actual_source =
       query_result_manager_.GetSourceForCastMode(MediaCastMode::DEFAULT);
@@ -101,7 +101,7 @@
       .WillOnce(Return(true));
   query_result_manager_.StartSinksQuery(MediaCastMode::DEFAULT, source, origin);
 
-  query_result_manager_.GetSupportedCastModes(&cast_modes);
+  cast_modes = query_result_manager_.GetSupportedCastModes();
   EXPECT_EQ(1u, cast_modes.size());
   EXPECT_TRUE(ContainsKey(cast_modes, MediaCastMode::DEFAULT));
   actual_source = query_result_manager_.GetSourceForCastMode(
@@ -116,7 +116,7 @@
   query_result_manager_.StartSinksQuery(MediaCastMode::DEFAULT, another_source,
                                         origin);
 
-  query_result_manager_.GetSupportedCastModes(&cast_modes);
+  cast_modes = query_result_manager_.GetSupportedCastModes();
   EXPECT_EQ(1u, cast_modes.size());
   EXPECT_TRUE(ContainsKey(cast_modes, MediaCastMode::DEFAULT));
   actual_source = query_result_manager_.GetSourceForCastMode(
@@ -126,7 +126,7 @@
   EXPECT_CALL(mock_router_, UnregisterMediaSinksObserver(_)).Times(1);
   query_result_manager_.StopSinksQuery(MediaCastMode::DEFAULT);
 
-  query_result_manager_.GetSupportedCastModes(&cast_modes);
+  cast_modes = query_result_manager_.GetSupportedCastModes();
   EXPECT_TRUE(cast_modes.empty());
   actual_source = query_result_manager_.GetSourceForCastMode(
       MediaCastMode::DEFAULT);
diff --git a/chrome/browser/ui/webui/ntp/OWNERS b/chrome/browser/ui/webui/ntp/OWNERS
index 2dcd941..66c06dfd 100644
--- a/chrome/browser/ui/webui/ntp/OWNERS
+++ b/chrome/browser/ui/webui/ntp/OWNERS
@@ -2,3 +2,4 @@
 dbeam@chromium.org
 
 per-file ntp_user_data_logger*=beaudoin@chromium.org
+per-file ntp_user_data_logger*=file://chrome/browser/search/OWNERS
diff --git a/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.cc b/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.cc
index 7f387ee..8234e141 100644
--- a/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.cc
@@ -11,6 +11,16 @@
 #include "base/files/file_util.h"
 #include "base/sys_info.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/browsing_data/browsing_data_appcache_helper.h"
+#include "chrome/browser/browsing_data/browsing_data_cache_storage_helper.h"
+#include "chrome/browser/browsing_data/browsing_data_channel_id_helper.h"
+#include "chrome/browser/browsing_data/browsing_data_cookie_helper.h"
+#include "chrome/browser/browsing_data/browsing_data_database_helper.h"
+#include "chrome/browser/browsing_data/browsing_data_file_system_helper.h"
+#include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h"
+#include "chrome/browser/browsing_data/browsing_data_indexed_db_helper.h"
+#include "chrome/browser/browsing_data/browsing_data_local_storage_helper.h"
+#include "chrome/browser/browsing_data/browsing_data_service_worker_helper.h"
 #include "chrome/browser/chromeos/arc/arc_auth_service.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/file_manager/path_util.h"
@@ -23,6 +33,7 @@
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/storage_partition.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/text/bytes_formatting.h"
 
@@ -50,8 +61,10 @@
 }  // namespace
 
 StorageManagerHandler::StorageManagerHandler()
-    : browser_cache_size_(0),
-      browser_site_data_size_(0),
+    : browser_cache_size_(-1),
+      has_browser_cache_size_(false),
+      browser_site_data_size_(-1),
+      has_browser_site_data_size_(false),
       weak_ptr_factory_(this) {
 }
 
@@ -258,6 +271,8 @@
 }
 
 void StorageManagerHandler::UpdateBrowsingDataSize() {
+  has_browser_cache_size_ = false;
+  has_browser_site_data_size_ = false;
   Profile* const profile = Profile::FromWebUI(web_ui());
   // Fetch the size of http cache in browsing data.
   // StoragePartitionHttpCacheDataRemover deletes itself when it is done.
@@ -268,20 +283,54 @@
           base::Bind(&StorageManagerHandler::OnGetBrowsingDataSize,
                      weak_ptr_factory_.GetWeakPtr(), false));
 
-  // TODO(fukino): fetch the size of site data in browsing data.
+  // Fetch the size of site data in browsing data.
+  if (!site_data_size_collector_.get()) {
+    content::StoragePartition* storage_partition =
+        content::BrowserContext::GetDefaultStoragePartition(profile);
+    site_data_size_collector_.reset(new SiteDataSizeCollector(
+        storage_partition->GetPath(),
+        new BrowsingDataCookieHelper(profile->GetRequestContext()),
+        new BrowsingDataDatabaseHelper(profile),
+        new BrowsingDataLocalStorageHelper(profile),
+        new BrowsingDataAppCacheHelper(profile),
+        new BrowsingDataIndexedDBHelper(
+            storage_partition->GetIndexedDBContext()),
+        BrowsingDataFileSystemHelper::Create(
+            storage_partition->GetFileSystemContext()),
+        BrowsingDataChannelIDHelper::Create(profile->GetRequestContext()),
+        new BrowsingDataServiceWorkerHelper(
+            storage_partition->GetServiceWorkerContext()),
+        new BrowsingDataCacheStorageHelper(
+            storage_partition->GetCacheStorageContext()),
+        BrowsingDataFlashLSOHelper::Create(profile)));
+  }
+  site_data_size_collector_->Fetch(
+      base::Bind(&StorageManagerHandler::OnGetBrowsingDataSize,
+                 weak_ptr_factory_.GetWeakPtr(), true));
 }
 
 void StorageManagerHandler::OnGetBrowsingDataSize(bool is_site_data,
                                                   int64_t size) {
-  if (is_site_data)
+  if (is_site_data) {
+    has_browser_site_data_size_ = true;
     browser_site_data_size_ = size;
-  else
+  } else {
+    has_browser_cache_size_ = true;
     browser_cache_size_ = size;
-
-  web_ui()->CallJavascriptFunctionUnsafe(
-     "options.StorageManager.setBrowsingDataSize",
-     base::StringValue(ui::FormatBytes(static_cast<int64_t>(
-         browser_cache_size_ + browser_site_data_size_))));
+  }
+  if (has_browser_cache_size_ && has_browser_site_data_size_) {
+    base::string16 size_string;
+    if (browser_cache_size_ >= 0 && browser_site_data_size_ >= 0) {
+      size_string = ui::FormatBytes(
+          browser_site_data_size_ + browser_cache_size_);
+    } else {
+      size_string = l10n_util::GetStringUTF16(
+          IDS_OPTIONS_SETTINGS_STORAGE_SIZE_UNKNOWN);
+    }
+    web_ui()->CallJavascriptFunctionUnsafe(
+        "options.StorageManager.setBrowsingDataSize",
+        base::StringValue(size_string));
+  }
 }
 
 void StorageManagerHandler::UpdateOtherUsersSize() {
@@ -303,15 +352,18 @@
 void StorageManagerHandler::OnGetOtherUserSize(bool success, int64_t size) {
   user_sizes_.push_back(success ? size : -1);
   if (user_sizes_.size() == other_users_.size()) {
-    base::StringValue other_users_size(l10n_util::GetStringUTF16(
-        IDS_OPTIONS_SETTINGS_STORAGE_SIZE_UNKNOWN));
+    base::string16 size_string;
     // If all the requests succeed, shows the total bytes in the UI.
     if (std::count(user_sizes_.begin(), user_sizes_.end(), -1) == 0) {
-      other_users_size = base::StringValue(ui::FormatBytes(
-          std::accumulate(user_sizes_.begin(), user_sizes_.end(), 0LL)));
+      size_string = ui::FormatBytes(
+          std::accumulate(user_sizes_.begin(), user_sizes_.end(), 0LL));
+    } else {
+      size_string = l10n_util::GetStringUTF16(
+          IDS_OPTIONS_SETTINGS_STORAGE_SIZE_UNKNOWN);
     }
     web_ui()->CallJavascriptFunctionUnsafe(
-       "options.StorageManager.setOtherUsersSize", other_users_size);
+        "options.StorageManager.setOtherUsersSize",
+        base::StringValue(size_string));
   }
 }
 
@@ -341,16 +393,18 @@
 
 void StorageManagerHandler::OnGetArcSize(bool succeeded,
                                          arc::mojom::ApplicationsSizePtr size) {
-  base::StringValue arc_size(l10n_util::GetStringUTF16(
-      IDS_OPTIONS_SETTINGS_STORAGE_SIZE_UNKNOWN));
+  base::string16 size_string;
   if (succeeded) {
     uint64_t total_bytes = size->total_code_bytes +
                            size->total_data_bytes +
                            size->total_cache_bytes;
-    arc_size = base::StringValue(ui::FormatBytes(total_bytes));
+    size_string = ui::FormatBytes(total_bytes);
+  } else {
+    size_string = l10n_util::GetStringUTF16(
+        IDS_OPTIONS_SETTINGS_STORAGE_SIZE_UNKNOWN);
   }
   web_ui()->CallJavascriptFunctionUnsafe("options.StorageManager.setArcSize",
-                                         arc_size);
+                                         base::StringValue(size_string));
 }
 
 void StorageManagerHandler::OnClearDriveCacheDone(bool success) {
diff --git a/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.h b/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.h
index c6e1629..6103948 100644
--- a/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.h
+++ b/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.h
@@ -7,10 +7,12 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <vector>
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/browsing_data/site_data_size_collector.h"
 #include "chrome/browser/ui/webui/options/options_ui.h"
 #include "components/arc/storage_manager/arc_storage_manager.h"
 #include "components/user_manager/user.h"
@@ -88,9 +90,15 @@
   // Total size of cache data in browsing data.
   int64_t browser_cache_size_;
 
+  // True if we have already received the size of http cache.
+  bool has_browser_cache_size_;
+
   // Total size of site data in browsing data.
   int64_t browser_site_data_size_;
 
+  // True if we have already received the size of site data.
+  bool has_browser_site_data_size_;
+
   // The list of other users whose directory sizes will be accumulated as the
   // size of "Other users".
   user_manager::UserList other_users_;
@@ -98,6 +106,9 @@
   // Fetched sizes of user directories.
   std::vector<int64_t> user_sizes_;
 
+  // Helper to compute the total size of all types of site date.
+  std::unique_ptr<SiteDataSizeCollector> site_data_size_collector_;
+
   base::WeakPtrFactory<StorageManagerHandler> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(StorageManagerHandler);
diff --git a/chrome/browser/ui/webui/signin/login_ui_test_utils.cc b/chrome/browser/ui/webui/signin/login_ui_test_utils.cc
index 9dd309b..b2dc9716 100644
--- a/chrome/browser/ui/webui/signin/login_ui_test_utils.cc
+++ b/chrome/browser/ui/webui/signin/login_ui_test_utils.cc
@@ -2,9 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/ui/webui/signin/login_ui_test_utils.h"
+
+#include "base/run_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/signin/signin_promo.h"
 #include "chrome/browser/signin/signin_tracker_factory.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/signin_view_controller_delegate.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/webui/signin/get_auth_frame.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -95,6 +100,13 @@
   scoped_refptr<MessageLoopRunner> message_loop_runner_;
 };
 
+void RunLoopFor(base::TimeDelta duration) {
+  base::RunLoop run_loop;
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, run_loop.QuitClosure(), duration);
+  run_loop.Run();
+}
+
 }  // anonymous namespace
 
 
@@ -242,4 +254,37 @@
                       signin_metrics::Reason::REASON_SIGNIN_PRIMARY_ACCOUNT);
 }
 
+bool TryDismissSyncConfirmationDialog(Browser* browser) {
+  SigninViewController* signin_view_controller =
+      browser->signin_view_controller();
+  DCHECK_NE(signin_view_controller, nullptr);
+  SigninViewControllerDelegate* delegate = signin_view_controller->delegate();
+  if (delegate == nullptr)
+    return false;
+  content::WebContents* dialog_web_contents =
+      delegate->web_contents_for_testing();
+  DCHECK_NE(dialog_web_contents, nullptr);
+  std::string message;
+  std::string js =
+      "if (document.getElementById('confirmButton') == null) {"
+      "  window.domAutomationController.send('NotFound');"
+      "} else {"
+      "  document.getElementById('confirmButton').click();"
+      "  window.domAutomationController.send('Ok');"
+      "}";
+  EXPECT_TRUE(content::ExecuteScriptAndExtractString(dialog_web_contents, js,
+                                                     &message));
+  return message == "Ok";
+}
+
+bool DismissSyncConfirmationDialog(Browser* browser, base::TimeDelta timeout) {
+  const base::Time expire_time = base::Time::Now() + timeout;
+  while (base::Time::Now() <= expire_time) {
+    if (TryDismissSyncConfirmationDialog(browser))
+      return true;
+    RunLoopFor(base::TimeDelta::FromMilliseconds(1000));
+  }
+  return false;
+}
+
 }  // namespace login_ui_test_utils
diff --git a/chrome/browser/ui/webui/signin/login_ui_test_utils.h b/chrome/browser/ui/webui/signin/login_ui_test_utils.h
index 6749654d..71c21725 100644
--- a/chrome/browser/ui/webui/signin/login_ui_test_utils.h
+++ b/chrome/browser/ui/webui/signin/login_ui_test_utils.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/time/time.h"
 #include "components/signin/core/browser/signin_metrics.h"
 
 class Browser;
@@ -59,6 +60,11 @@
                   const std::string& email,
                   const std::string& password);
 
+// Waits for sync confirmation dialog to get displayed, then executes javascript
+// to click on confirm button. Returns false if dialog wasn't dismissed before
+// |timeout|.
+bool DismissSyncConfirmationDialog(Browser* browser, base::TimeDelta timeout);
+
 }  // namespace login_ui_test_utils
 
 #endif  // CHROME_BROWSER_UI_WEBUI_SIGNIN_LOGIN_UI_TEST_UTILS_H_
diff --git a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
index 97712cfb..8c7387c 100644
--- a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
+++ b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
@@ -140,16 +140,12 @@
 }
 
 bool IsGuestModeEnabled() {
-  if (switches::IsMaterialDesignUserManager())
-    return true;
   PrefService* service = g_browser_process->local_state();
   DCHECK(service);
   return service->GetBoolean(prefs::kBrowserGuestModeEnabled);
 }
 
 bool IsAddPersonEnabled() {
-  if (switches::IsMaterialDesignUserManager())
-    return true;
   PrefService* service = g_browser_process->local_state();
   DCHECK(service);
   return service->GetBoolean(prefs::kBrowserAddPersonEnabled);
diff --git a/chrome/browser/usb/usb_chooser_context.cc b/chrome/browser/usb/usb_chooser_context.cc
index 5a32788d..44c6884f 100644
--- a/chrome/browser/usb/usb_chooser_context.cc
+++ b/chrome/browser/usb/usb_chooser_context.cc
@@ -53,7 +53,7 @@
 
 UsbChooserContext::UsbChooserContext(Profile* profile)
     : ChooserContextBase(profile, CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA),
-      is_off_the_record_(profile->IsOffTheRecord()),
+      is_incognito_(profile->IsOffTheRecord()),
       observer_(this) {
   usb_service_ = device::DeviceClient::Get()->GetUsbService();
   if (usb_service_)
@@ -102,7 +102,7 @@
       object.SetString(kGuidKey, device->guid());
       objects.push_back(base::WrapUnique(new ChooserContextBase::Object(
           requesting_origin, embedding_origin, &object, "preference",
-          is_off_the_record_)));
+          is_incognito_)));
     }
   }
 
diff --git a/chrome/browser/usb/usb_chooser_context.h b/chrome/browser/usb/usb_chooser_context.h
index 39d6605..09b009c0 100644
--- a/chrome/browser/usb/usb_chooser_context.h
+++ b/chrome/browser/usb/usb_chooser_context.h
@@ -56,7 +56,7 @@
   // device::UsbService::Observer implementation.
   void OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) override;
 
-  bool is_off_the_record_;
+  bool is_incognito_;
   std::map<std::pair<GURL, GURL>, std::set<std::string>> ephemeral_devices_;
   device::UsbService* usb_service_;
   ScopedObserver<device::UsbService, device::UsbService::Observer> observer_;
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc
index ee28b485..aa377066 100644
--- a/chrome/browser/web_applications/web_app.cc
+++ b/chrome/browser/web_applications/web_app.cc
@@ -437,13 +437,6 @@
                                  file_handlers_info);
 }
 
-void CreateNonAppShortcut(const ShortcutLocations& locations,
-                          std::unique_ptr<ShortcutInfo> shortcut_info) {
-  ScheduleCreatePlatformShortcut(SHORTCUT_CREATION_AUTOMATED, locations,
-                                 std::move(shortcut_info),
-                                 extensions::FileHandlersInfo());
-}
-
 void CreateShortcuts(ShortcutCreationReason reason,
                      const ShortcutLocations& locations,
                      Profile* profile,
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h
index 61d099c..3f28b86 100644
--- a/chrome/browser/web_applications/web_app.h
+++ b/chrome/browser/web_applications/web_app.h
@@ -187,11 +187,6 @@
     std::unique_ptr<ShortcutInfo> shortcut_info,
     const extensions::FileHandlersInfo& file_handlers_info);
 
-// Currently only called by app_list_service_mac to create a shim for the
-// app launcher.
-void CreateNonAppShortcut(const ShortcutLocations& locations,
-                          std::unique_ptr<ShortcutInfo> shortcut_info);
-
 // Creates shortcuts for an app. This loads the app's icon from disk, and calls
 // CreateShortcutsWithInfo(). If you already have a ShortcutInfo with the app's
 // icon loaded, you should use CreateShortcutsWithInfo() directly.
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index fc290659..c452006 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -1501,7 +1501,7 @@
       'browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.h',
       'browser/ui/cocoa/media_picker/desktop_media_picker_cocoa.mm',
       'browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated.h',
-      'browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated.mm',      
+      'browser/ui/cocoa/media_picker/desktop_media_picker_controller_deprecated.mm',
       'browser/ui/cocoa/media_picker/desktop_media_picker_controller.h',
       'browser/ui/cocoa/media_picker/desktop_media_picker_controller.mm',
       'browser/ui/cocoa/media_picker/desktop_media_picker_item.h',
@@ -2621,12 +2621,8 @@
       'browser/ui/app_list/app_list_prefs_factory.h',
       'browser/ui/app_list/app_list_service.cc',
       'browser/ui/app_list/app_list_service.h',
-      'browser/ui/app_list/app_list_service_cocoa_mac.h',
-      'browser/ui/app_list/app_list_service_cocoa_mac.mm',
       'browser/ui/app_list/app_list_service_impl.cc',
       'browser/ui/app_list/app_list_service_impl.h',
-      'browser/ui/app_list/app_list_service_mac.h',
-      'browser/ui/app_list/app_list_service_mac.mm',
       'browser/ui/app_list/app_list_presenter_delegate.h',
       'browser/ui/app_list/app_list_syncable_service.cc',
       'browser/ui/app_list/app_list_syncable_service.h',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 51a8142..7a39751 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -43,8 +43,15 @@
       '../extensions/browser/api/display_source/display_source_apitestbase.h',
       'browser/extensions/api/display_source/display_source_wifi_display_apitest.cc',
     ],
+    # TODO(jbudorick): Move tests here from other lists as Android support is
+    # implemented. See crbug.com/611756
     'chrome_browser_tests_sources': [
-      # The list of sources which is only used by chrome browser tests.
+      # The list of sources which is used by chrome browser tests on all
+      # platforms.
+    ],
+    'chrome_browser_tests_desktop_only_sources': [
+      # The list of sources which is only used by chrome browser tests on
+      # desktop platforms.
       '../apps/app_restore_service_browsertest.cc',
       '../apps/load_and_launch_browsertest.cc',
       'app/chrome_command_ids.h',
@@ -1018,6 +1025,7 @@
       'test/data/webui/print_preview.js',
       'test/data/webui/sandboxstatus_browsertest.js',
       'test/data/webui/settings/advanced_page_browsertest.js',
+      'test/data/webui/settings/animation_browsertest.js',
       'test/data/webui/settings/basic_page_browsertest.js',
       'test/data/webui/settings/bluetooth_page_browsertest_chromeos.js',
       'test/data/webui/settings/cr_settings_browsertest.js',
@@ -1155,7 +1163,6 @@
     ],
     'chrome_interactive_ui_test_app_list_sources': [
       'browser/ui/app_list/app_list_service_interactive_uitest.cc',
-      'browser/ui/app_list/app_list_service_mac_interactive_uitest.mm',
     ],
     'chrome_interactive_ui_test_win_sources': [
       '../ui/resources/cursors/aliasb.cur',
@@ -2236,6 +2243,7 @@
         'HAS_OUT_OF_PROC_TEST_RUNNER',
       ],
       'sources': [
+        '<@(chrome_browser_tests_desktop_only_sources)',
         '<@(chrome_browser_tests_extensions_sources)',
         '<@(chrome_browser_tests_sources)',
         '<@(chrome_browser_tests_webui_js_sources)',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 88c00c9..f9e8296 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -236,8 +236,6 @@
       'browser/service_process/service_process_control_mac_unittest.mm',
       'browser/services/gcm/fake_gcm_profile_service.cc',
       'browser/services/gcm/fake_gcm_profile_service.h',
-      'browser/services/gcm/fake_signin_manager.cc',
-      'browser/services/gcm/fake_signin_manager.h',
       'browser/sessions/restore_on_startup_policy_handler_unittest.cc',
       'browser/shell_integration_win_unittest.cc',
       'browser/signin/account_reconcilor_unittest.cc',
@@ -1623,7 +1621,6 @@
       'browser/apps/drive/drive_app_mapping_unittest.cc',
       'browser/ui/app_list/app_context_menu_unittest.cc',
       'browser/ui/app_list/app_list_positioner_unittest.cc',
-      'browser/ui/app_list/app_list_service_mac_unittest.mm',
       'browser/ui/app_list/app_list_service_unittest.cc',
       'browser/ui/app_list/app_list_test_util.cc',
       'browser/ui/app_list/app_list_test_util.h',
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 3745c85..f9134ad 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -89,7 +89,7 @@
 #if defined(OS_CHROMEOS)
 // Enables or disables the opt-in IME menu in the language settings page.
 const base::Feature kOptInImeMenu{"OptInImeMenu",
-                                  base::FEATURE_ENABLED_BY_DEFAULT};
+                                  base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_CHROMEOS)
 
 }  // namespace features
diff --git a/chrome/gpu/arc_gpu_video_decode_accelerator.cc b/chrome/gpu/arc_gpu_video_decode_accelerator.cc
index 75c60f533..d86aa67 100644
--- a/chrome/gpu/arc_gpu_video_decode_accelerator.cc
+++ b/chrome/gpu/arc_gpu_video_decode_accelerator.cc
@@ -181,50 +181,49 @@
   input_info->length = length;
 }
 
-bool ArcGpuVideoDecodeAccelerator::VerifyStride(const base::ScopedFD& dmabuf_fd,
-                                                int32_t stride) const {
+bool ArcGpuVideoDecodeAccelerator::VerifyDmabuf(
+    const base::ScopedFD& dmabuf_fd,
+    const std::vector<DmabufPlane>& dmabuf_planes) const {
+  size_t num_planes = media::VideoFrame::NumPlanes(output_pixel_format_);
+  if (dmabuf_planes.size() != num_planes) {
+    DLOG(ERROR) << "Invalid number of dmabuf planes passed: "
+                << dmabuf_planes.size() << ", expected: " << num_planes;
+    return false;
+  }
+
   off_t size = lseek(dmabuf_fd.get(), 0, SEEK_END);
   lseek(dmabuf_fd.get(), 0, SEEK_SET);
-
   if (size < 0) {
     DPLOG(ERROR) << "fail to find the size of dmabuf";
     return false;
   }
 
-  int height = coded_size_.height();
-  switch (output_pixel_format_) {
-    case media::PIXEL_FORMAT_I420:
-    case media::PIXEL_FORMAT_YV12:
-    case media::PIXEL_FORMAT_NV12:
-    case media::PIXEL_FORMAT_NV21:
-      // Adjusts the height for UV plane.
-      // The coded height should always be even. But for security reason,  we
-      // still round up to two here in case VDA reports an incorrect value.
-      height += (height + 1) / 2;
-      break;
-    case media::PIXEL_FORMAT_ARGB:
-      // No need to adjust height.
-      break;
-    default:
-      DLOG(ERROR) << "Format not supported: " << output_pixel_format_;
-      return false;
-  }
-  base::CheckedNumeric<off_t> used_bytes(height);
-  used_bytes *= stride;
+  size_t i = 0;
+  for (const auto& plane : dmabuf_planes) {
+    DVLOG(4) << "Plane " << i << ", offset: " << plane.offset
+             << ", stride: " << plane.stride;
 
-  if (stride < 0 || !used_bytes.IsValid() || used_bytes.ValueOrDie() > size) {
-    DLOG(ERROR) << "invalid stride: " << stride << ", height: " << height
-                << ", size of dmabuf: " << size;
-    return false;
+    size_t rows =
+        media::VideoFrame::Rows(i, output_pixel_format_, coded_size_.height());
+    base::CheckedNumeric<off_t> current_size(plane.offset);
+    current_size += plane.stride * rows;
+
+    if (!current_size.IsValid() || current_size.ValueOrDie() > size) {
+      DLOG(ERROR) << "Invalid strides/offsets";
+      return false;
+    }
+
+    ++i;
   }
 
   return true;
 }
 
-void ArcGpuVideoDecodeAccelerator::BindDmabuf(PortType port,
-                                              uint32_t index,
-                                              base::ScopedFD dmabuf_fd,
-                                              int32_t stride) {
+void ArcGpuVideoDecodeAccelerator::BindDmabuf(
+    PortType port,
+    uint32_t index,
+    base::ScopedFD dmabuf_fd,
+    const std::vector<DmabufPlane>& dmabuf_planes) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   if (!vda_) {
@@ -241,14 +240,14 @@
     arc_client_->OnError(INVALID_ARGUMENT);
     return;
   }
-  if (!VerifyStride(dmabuf_fd, stride)) {
+  if (!VerifyDmabuf(dmabuf_fd, dmabuf_planes)) {
     arc_client_->OnError(INVALID_ARGUMENT);
     return;
   }
 
   OutputBufferInfo& info = buffers_pending_import_[index];
   info.handle = std::move(dmabuf_fd);
-  info.stride = stride;
+  info.planes = dmabuf_planes;
 }
 
 void ArcGpuVideoDecodeAccelerator::UseBuffer(PortType port,
@@ -294,7 +293,10 @@
 #if defined(USE_OZONE)
         handle.native_pixmap_handle.fds.emplace_back(
             base::FileDescriptor(info.handle.release(), true));
-        handle.native_pixmap_handle.planes.emplace_back(info.stride, 0, 0);
+        for (const auto& plane : info.planes) {
+          handle.native_pixmap_handle.planes.emplace_back(
+              plane.stride, plane.offset, 0);
+        }
 #endif
         vda_->ImportBufferForPicture(index, handle);
       } else {
diff --git a/chrome/gpu/arc_gpu_video_decode_accelerator.h b/chrome/gpu/arc_gpu_video_decode_accelerator.h
index 89ca2d5..57dd2ea 100644
--- a/chrome/gpu/arc_gpu_video_decode_accelerator.h
+++ b/chrome/gpu/arc_gpu_video_decode_accelerator.h
@@ -44,7 +44,7 @@
   void BindDmabuf(PortType port,
                   uint32_t index,
                   base::ScopedFD dmabuf_fd,
-                  int32_t stride) override;
+                  const std::vector<DmabufPlane>& dmabuf_planes) override;
   void UseBuffer(PortType port,
                  uint32_t index,
                  const BufferMetadata& metadata) override;
@@ -97,7 +97,7 @@
   // The information about the dmabuf used as an output buffer.
   struct OutputBufferInfo {
     base::ScopedFD handle;
-    int32_t stride = 0;  // In bytes.
+    std::vector<DmabufPlane> planes;
 
     OutputBufferInfo();
     OutputBufferInfo(OutputBufferInfo&& other);
@@ -107,8 +107,9 @@
   // Helper function to validate |port| and |index|.
   bool ValidatePortAndIndex(PortType port, uint32_t index) const;
 
-  // Helper function to verify the length of stride is legal.
-  bool VerifyStride(const base::ScopedFD& fd, int32_t stride) const;
+  // Return true if |dmabuf_planes| is valid for a dmabuf |fd|.
+  bool VerifyDmabuf(const base::ScopedFD& fd,
+                    const std::vector<DmabufPlane>& dmabuf_planes) const;
 
   // Creates an InputRecord for the given |bitstream_buffer_id|. The
   // |buffer_index| is the index of the associated input buffer. The |timestamp|
diff --git a/chrome/gpu/arc_video_accelerator.h b/chrome/gpu/arc_video_accelerator.h
index 079edfb..b60619a 100644
--- a/chrome/gpu/arc_video_accelerator.h
+++ b/chrome/gpu/arc_video_accelerator.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_GPU_ARC_VIDEO_ACCELERATOR_H_
 #define CHROME_GPU_ARC_VIDEO_ACCELERATOR_H_
 
+#include <vector>
+
 #include "base/files/scoped_file.h"
 
 namespace chromeos {
@@ -74,6 +76,11 @@
     //                format of each VDA on Chromium is supported.
   };
 
+  struct DmabufPlane {
+    int32_t offset;  // in bytes
+    int32_t stride;  // in bytes
+  };
+
   // The callbacks of the ArcVideoAccelerator. The user of this class should
   // implement this interface.
   class Client {
@@ -122,12 +129,11 @@
   // Assigns a buffer to be used for the accelerator at the specified
   // port and index. A buffer must be successfully bound before it can be
   // passed to the accelerator via UseBuffer(). Already bound buffers may be
-  // reused multiple times without additional bindings. |stride| is counted in
-  // bytes.
+  // reused multiple times without additional bindings.
   virtual void BindDmabuf(PortType port,
                           uint32_t index,
                           base::ScopedFD dmabuf_fd,
-                          int32_t stride) = 0;
+                          const std::vector<DmabufPlane>& dmabuf_planes) = 0;
 
   // Passes a buffer to the accelerator. For input buffer, the accelerator
   // will process it. For output buffer, the accelerator will output content
diff --git a/chrome/gpu/gpu_arc_video_service.cc b/chrome/gpu/gpu_arc_video_service.cc
index 70c2b7d..bb20aad 100644
--- a/chrome/gpu/gpu_arc_video_service.cc
+++ b/chrome/gpu/gpu_arc_video_service.cc
@@ -109,6 +109,24 @@
   }
 };
 
+template <>
+struct TypeConverter<chromeos::arc::ArcVideoAccelerator::DmabufPlane,
+                     arc::mojom::ArcVideoAcceleratorDmabufPlanePtr> {
+  static chromeos::arc::ArcVideoAccelerator::DmabufPlane Convert(
+      const arc::mojom::ArcVideoAcceleratorDmabufPlanePtr& input) {
+    chromeos::arc::ArcVideoAccelerator::DmabufPlane result = {0};
+    if (input->offset < 0 || input->stride < 0) {
+      DVLOG(1) << "Invalid offset/stride: " << input->offset << "/"
+               << input->stride;
+      return result;
+    }
+
+    result.offset = input->offset;
+    result.stride = input->stride;
+    return result;
+  }
+};
+
 }  // namespace mojo
 
 namespace chromeos {
@@ -241,17 +259,34 @@
                                  std::move(fd), offset, length);
 }
 
-void GpuArcVideoService::BindDmabuf(::arc::mojom::PortType port,
-                                    uint32_t index,
-                                    mojo::ScopedHandle dmabuf_handle,
-                                    int32_t stride) {
+void GpuArcVideoService::DeprecatedBindDmabuf(::arc::mojom::PortType port,
+                                              uint32_t index,
+                                              mojo::ScopedHandle dmabuf_handle,
+                                              int32_t stride) {
+  mojo::Array<::arc::mojom::ArcVideoAcceleratorDmabufPlanePtr> planes(1);
+  planes[0]->offset = 0;
+  planes[0]->stride = stride;
+
+  BindDmabuf(port, index, std::move(dmabuf_handle), std::move(planes));
+}
+
+void GpuArcVideoService::BindDmabuf(
+    ::arc::mojom::PortType port,
+    uint32_t index,
+    mojo::ScopedHandle dmabuf_handle,
+    mojo::Array<::arc::mojom::ArcVideoAcceleratorDmabufPlanePtr>
+        dmabuf_planes) {
   DVLOG(2) << "BindDmabuf port=" << port << ", index=" << index;
 
   base::ScopedFD fd = UnwrapFdFromMojoHandle(std::move(dmabuf_handle));
   if (!fd.is_valid())
     return;
+
+  std::vector<ArcVideoAccelerator::DmabufPlane> converted_planes =
+      dmabuf_planes.To<std::vector<ArcVideoAccelerator::DmabufPlane>>();
+
   accelerator_->BindDmabuf(static_cast<PortType>(port), index, std::move(fd),
-                           stride);
+                           std::move(converted_planes));
 }
 
 void GpuArcVideoService::UseBuffer(::arc::mojom::PortType port,
diff --git a/chrome/gpu/gpu_arc_video_service.h b/chrome/gpu/gpu_arc_video_service.h
index fc9b2e00..38fb13e 100644
--- a/chrome/gpu/gpu_arc_video_service.h
+++ b/chrome/gpu/gpu_arc_video_service.h
@@ -55,10 +55,15 @@
                         mojo::ScopedHandle ashmem_handle,
                         uint32_t offset,
                         uint32_t length) override;
+  void DeprecatedBindDmabuf(::arc::mojom::PortType port,
+                            uint32_t index,
+                            mojo::ScopedHandle dmabuf_handle,
+                            int32_t stride) override;
   void BindDmabuf(::arc::mojom::PortType port,
                   uint32_t index,
                   mojo::ScopedHandle dmabuf_handle,
-                  int32_t stride) override;
+                  mojo::Array<::arc::mojom::ArcVideoAcceleratorDmabufPlanePtr>
+                      dmabuf_planes) override;
   void UseBuffer(::arc::mojom::PortType port,
                  uint32_t index,
                  ::arc::mojom::BufferMetadataPtr metadata) override;
diff --git a/chrome/installer/gcapi/gcapi_omaha_experiment.cc b/chrome/installer/gcapi/gcapi_omaha_experiment.cc
index 5235afd2..a34a146f 100644
--- a/chrome/installer/gcapi/gcapi_omaha_experiment.cc
+++ b/chrome/installer/gcapi/gcapi_omaha_experiment.cc
@@ -18,9 +18,12 @@
 
 // Returns the number of weeks since 2/3/2003.
 int GetCurrentRlzWeek(const base::Time& current_time) {
-  base::Time::Exploded february_third_2003_exploded =
+  const base::Time::Exploded february_third_2003_exploded =
       {2003, 2, 1, 3, 0, 0, 0, 0};
-  base::Time f = base::Time::FromUTCExploded(february_third_2003_exploded);
+  base::Time f;
+  bool conversion_success =
+      base::Time::FromUTCExploded(february_third_2003_exploded, &f);
+  DCHECK(conversion_success);
   base::TimeDelta delta = current_time - f;
   return delta.InDays() / 7;
 }
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc
index 5f11575..41c306d 100644
--- a/chrome/installer/setup/setup_main.cc
+++ b/chrome/installer/setup/setup_main.cc
@@ -699,7 +699,7 @@
   if (installer_state.FindProduct(BrowserDistribution::CHROME_BINARIES)) {
     // Chrome Binaries should be last; if something else is cancelled, they
     // should stay.
-    DCHECK(products[products.size() - 1]->is_chrome_binaries());
+    DCHECK(products.back()->is_chrome_binaries());
   }
 
   installer::InstallStatus install_status = installer::UNINSTALL_SUCCESSFUL;
diff --git a/chrome/installer/util/installer_state.cc b/chrome/installer/util/installer_state.cc
index d9d9faec..1a53a774 100644
--- a/chrome/installer/util/installer_state.cc
+++ b/chrome/installer/util/installer_state.cc
@@ -279,17 +279,15 @@
   }
 
   if (target_path_.empty()) {
-    if (product_dir == NULL)
-      target_path_ = GetDefaultProductInstallPath(the_product.distribution());
-    else
-      target_path_ = *product_dir;
+    target_path_ = product_dir ? *product_dir : GetDefaultProductInstallPath(
+                                                    the_product.distribution());
   }
 
   if (state_key_.empty())
     state_key_ = the_product.distribution()->GetStateKey();
 
   products_.push_back(product->release());
-  return products_[products_.size() - 1];
+  return products_.back();
 }
 
 Product* InstallerState::AddProduct(std::unique_ptr<Product>* product) {
diff --git a/chrome/renderer/autofill/autofill_renderer_browsertest.cc b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
index c9d71ed..ead2cf8 100644
--- a/chrome/renderer/autofill/autofill_renderer_browsertest.cc
+++ b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
@@ -134,8 +134,8 @@
       "newForm.appendChild(newLastname);"
       "newForm.appendChild(newEmail);"
       "document.body.appendChild(newForm);");
-  base::RunLoop().RunUntilIdle();
 
+  WaitForAutofillDidAssociateFormControl();
   message = render_thread_->sink().GetFirstMessageMatching(
       AutofillHostMsg_FormsSeen::ID);
   ASSERT_NE(nullptr, message);
@@ -212,8 +212,8 @@
   render_thread_->sink().ClearMessages();
 
   ExecuteJavaScriptForTests("AddFields()");
-  base::RunLoop().RunUntilIdle();
 
+  WaitForAutofillDidAssociateFormControl();
   message = render_thread_->sink().GetFirstMessageMatching(
       AutofillHostMsg_FormsSeen::ID);
   ASSERT_NE(nullptr, message);
diff --git a/chrome/renderer/autofill/password_generation_agent_browsertest.cc b/chrome/renderer/autofill/password_generation_agent_browsertest.cc
index d376f05..30306f0 100644
--- a/chrome/renderer/autofill/password_generation_agent_browsertest.cc
+++ b/chrome/renderer/autofill/password_generation_agent_browsertest.cc
@@ -503,7 +503,7 @@
       "form.appendChild(first_password);"
       "form.appendChild(second_password);"
       "document.body.appendChild(form);");
-  ProcessPendingMessages();
+  WaitForAutofillDidAssociateFormControl();
 
   // This needs to come after the DOM has been modified.
   SetAccountCreationFormsDetectedMessage(password_generation_,
diff --git a/chrome/renderer/net/net_error_helper.cc b/chrome/renderer/net/net_error_helper.cc
index fc9d263..acb98ccc 100644
--- a/chrome/renderer/net/net_error_helper.cc
+++ b/chrome/renderer/net/net_error_helper.cc
@@ -31,6 +31,7 @@
 #include "grit/components_resources.h"
 #include "ipc/ipc_message.h"
 #include "ipc/ipc_message_macros.h"
+#include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
 #include "third_party/WebKit/public/platform/WebURL.h"
 #include "third_party/WebKit/public/platform/WebURLError.h"
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
@@ -315,7 +316,7 @@
 
   blink::WebURLRequest request(page_url);
   request.setCachePolicy(blink::WebCachePolicy::ReturnCacheDataDontLoad);
-
+  request.setRequestorOrigin(blink::WebSecurityOrigin::createUnique());
   web_frame->loadRequest(request);
 }
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index b62091b0..318e092 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -859,26 +859,157 @@
       ":browser_tests",
     ]
   }
+}
 
-  test("browser_tests") {
-    sources = [
-      "base/browser_tests_main.cc",
+test("browser_tests") {
+  sources = [
+    "base/browser_tests_main.cc",
+  ]
+  sources += rebase_path(chrome_tests_gypi_values.chrome_browser_tests_sources,
+                         ".",
+                         "//chrome")
+
+  configs += [
+    "//build/config:precompiled_headers",
+    "//third_party/WebKit/public:debug_devtools",
+  ]
+
+  deps = [
+    ":test_support",
+    "//base",
+    "//sync:test_support_sync_api",
+  ]
+
+  data_deps = []
+
+  data = []
+
+  defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
+
+  if (is_win) {
+    data += [ "$root_out_dir/chrome_200_percent.pak" ]
+  }
+  if (is_mac) {
+    data += [
+      "$root_out_dir/chrome_material_100_percent.pak",
+      "$root_out_dir/chrome_material_200_percent.pak",
     ]
-    sources +=
-        rebase_path(chrome_tests_gypi_values.chrome_browser_tests_sources,
-                    ".",
-                    "//chrome")
+  }
+  if (is_chromeos) {
+    data += [
+      # TODO(GYP): figure out which of these things are
+      # actually needed and also which should be pulled in via
+      # data or data_deps and through which dependencies.
+      "//chrome/browser/chromeos/login/test/https_forwarder.py",
+      "//chrome/browser/resources/chromeos/wallpaper_manager/",
+      "//chromeos/test/data/",
+      "//components/chrome_apps/webstore_widget/cws_widget/",
+      "//ui/file_manager/file_manager/",
+      "//ui/file_manager/gallery/",
+      "//ui/file_manager/image_loader/",
+      "//ui/file_manager/integration_tests/",
+      "//third_party/analytics/",
+      "//third_party/polymer/v1_0/components-chromium/polymer/",
+      "$root_out_dir/chromevox_test_data/",
+      "$root_out_dir/content_shell.pak",
+      "$root_out_dir/locales/",
+      "$root_out_dir/resources/chromeos/",
+    ]
+
+    data_deps += [ "//ui/keyboard:resources" ]
+
+    if (enable_nacl) {
+      data_deps += [
+        "//components/nacl/loader:nacl_helper",
+        "//ppapi/native_client:irt",
+      ]
+    }
+  }
+
+  # TODO(jbudorick): In progress. See crbug.com/611756
+  if (is_android) {
+    deps += [
+      "//chrome/android:chrome_java",
+      "//v8:v8_external_startup_data_assets",
+    ]
+
+    enable_multidex = true
+  } else {
     sources += rebase_path(
-            chrome_tests_gypi_values.chrome_browser_extensions_test_support_sources,
+            chrome_tests_gypi_values.chrome_browser_tests_desktop_only_sources,
             ".",
             "//chrome")
 
-    configs += [
-      "//build/config:precompiled_headers",
-      "//third_party/WebKit/public:debug_devtools",
+    deps += [
+      ":browser_tests_js_webui",
+      ":sync_integration_test_support",
+      ":test_support_ui",
+      "//base:i18n",
+      "//base/test:test_support",
+      "//chrome:browser_tests_pak",
+      "//chrome:packed_extra_resources",
+      "//chrome:packed_resources",
+      "//chrome:resources",
+      "//chrome:strings",
+      "//chrome/browser",
+      "//chrome/browser/resources:extension_resource_demo",
+      "//chrome/renderer",
+      "//components/autofill/content/browser:risk_proto",
+      "//components/autofill/content/renderer:test_support",
+      "//components/captive_portal:test_support",
+      "//components/dom_distiller/content/browser",
+      "//components/dom_distiller/content/renderer",
+      "//components/dom_distiller/core:test_support",
+      "//components/guest_view/browser:test_support",
+      "//components/resources",
+      "//components/safe_browsing_db:test_database_manager",
+      "//components/strings",
+      "//components/translate/core/common",
+      "//content/public/common:features",
+      "//content/test:browsertest_base",
+      "//crypto:platform",
+      "//crypto:test_support",
+      "//device/bluetooth:mocks",
+      "//device/serial:test_support",
+      "//device/usb:test_support",
+      "//google_apis:test_support",
+      "//media",
+      "//media/base:test_support",
+      "//media/cast:test_support",
+      "//net",
+      "//net:test_support",
+      "//sdch",
+      "//skia",
+      "//sync",
+      "//testing/gmock",
+      "//testing/gtest",
+      "//testing/perf",
+      "//third_party/cacheinvalidation",
+      "//third_party/icu",
+      "//third_party/leveldatabase",
+      "//third_party/libjingle",
+      "//third_party/webrtc/modules/desktop_capture",
+      "//third_party/widevine/cdm:version_h",
+      "//ui/accessibility:test_support",
+      "//ui/base:test_support",
+      "//ui/compositor:test_support",
+      "//ui/resources",
+      "//ui/web_dialogs:test_support",
+      "//v8",
     ]
 
-    data = [
+    # Runtime dependencies
+    data_deps += [
+      "//chrome",
+      "//ppapi:ppapi_tests",
+      "//ppapi:power_saver_test_plugin",
+      "//remoting/webapp:browser_test_resources",
+      "//remoting/webapp:unit_tests",
+      "//third_party/mesa:osmesa",
+      "//third_party/widevine/cdm:widevine_test_license_server",
+    ]
+
+    data += [
       "data/",
       "//chrome/browser/policy/test/asn1der.py",
       "//chrome/browser/policy/test/policy_testserver.py",
@@ -914,136 +1045,12 @@
       "$root_out_dir/test_page.css.mock-http-headers",
       "$root_out_dir/test_url_loader_data/",
     ]
-    if (is_win) {
-      data += [ "$root_out_dir/chrome_200_percent.pak" ]
-    }
-    if (is_mac) {
-      data += [
-        "$root_out_dir/chrome_material_100_percent.pak",
-        "$root_out_dir/chrome_material_200_percent.pak",
-      ]
-    }
-    if (is_chromeos) {
-      data += [
-        # TODO(GYP): figure out which of these things are
-        # actually needed and also which should be pulled in via
-        # data or data_deps and through which dependencies.
-        "//chrome/browser/chromeos/login/test/https_forwarder.py",
-        "//chrome/browser/resources/chromeos/wallpaper_manager/",
-        "//chromeos/test/data/",
-        "//components/chrome_apps/webstore_widget/cws_widget/",
-        "//ui/file_manager/file_manager/",
-        "//ui/file_manager/gallery/",
-        "//ui/file_manager/image_loader/",
-        "//ui/file_manager/integration_tests/",
-        "//third_party/analytics/",
-        "//third_party/polymer/v1_0/components-chromium/polymer/",
-        "$root_out_dir/chromevox_test_data/",
-        "$root_out_dir/content_shell.pak",
-        "$root_out_dir/locales/",
-        "$root_out_dir/resources/chromeos/",
-      ]
-
-      data_deps = [
-        "//ui/keyboard:resources",
-      ]
-
-      if (enable_nacl) {
-        data_deps += [
-          "//components/nacl/loader:nacl_helper",
-          "//ppapi/native_client:irt",
-        ]
-      }
-    } else {
-      data_deps = []
-    }
-
-    deps = [
-      ":browser_tests_js_webui",
-      ":sync_integration_test_support",
-      ":test_support",
-      ":test_support_ui",
-      "//base",
-      "//base:i18n",
-      "//base/test:test_support",
-      "//chrome:browser_tests_pak",
-      "//chrome:packed_extra_resources",
-      "//chrome:packed_resources",
-      "//chrome:resources",
-      "//chrome:strings",
-      "//chrome/browser",
-      "//chrome/browser/resources:extension_resource_demo",
-      "//chrome/common/extensions/api",
-      "//chrome/renderer",
-      "//components/autofill/content/browser:risk_proto",
-      "//components/autofill/content/renderer:test_support",
-      "//components/captive_portal:test_support",
-      "//components/dom_distiller/content/browser",
-      "//components/dom_distiller/content/renderer",
-      "//components/dom_distiller/core:test_support",
-      "//components/guest_view/browser:test_support",
-      "//components/resources",
-      "//components/safe_browsing_db:test_database_manager",
-      "//components/strings",
-      "//components/translate/core/common",
-      "//content/public/common:features",
-      "//content/test:browsertest_base",
-      "//crypto:platform",
-      "//crypto:test_support",
-      "//device/bluetooth:mocks",
-      "//device/serial:test_support",
-      "//device/usb:test_support",
-      "//extensions/common/api",
-      "//google_apis:test_support",
-      "//media",
-      "//media/base:test_support",
-      "//media/cast:test_support",
-      "//net",
-      "//net:test_support",
-      "//sdch",
-      "//skia",
-      "//sync",
-      "//sync:test_support_sync_api",
-      "//testing/gmock",
-      "//testing/gtest",
-      "//testing/perf",
-      "//third_party/cacheinvalidation",
-      "//third_party/icu",
-      "//third_party/leveldatabase",
-      "//third_party/libjingle",
-      "//third_party/webrtc/modules/desktop_capture",
-      "//third_party/widevine/cdm:version_h",
-      "//ui/accessibility:test_support",
-      "//ui/base:test_support",
-      "//ui/compositor:test_support",
-      "//ui/resources",
-      "//ui/web_dialogs:test_support",
-      "//v8",
-    ]
-
-    # TODO(rockot) bug 505926: The chrome_extensions_browsertests target should
-    # be deleted and this line removed. See the chrome_extensions_browsertests
-    # target for more.
-    deps += [ "//extensions:chrome_extensions_browsertests" ]
-
-    # Runtime dependencies
-    data_deps += [
-      "//chrome",
-      "//ppapi:ppapi_tests",
-      "//ppapi:power_saver_test_plugin",
-      "//remoting/webapp:browser_test_resources",
-      "//remoting/webapp:unit_tests",
-      "//third_party/mesa:osmesa",
-      "//third_party/widevine/cdm:widevine_test_license_server",
-    ]
 
     if (!is_mac) {
       data += [ "$root_out_dir/locales/" ]
       data_deps += [ "//chrome:packed_extra_resources" ]
     }
 
-    defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
-
     if (!enable_one_click_signin) {
       sources -= [ "../browser/ui/sync/one_click_signin_links_delegate_impl_browsertest.cc" ]
     }
@@ -1096,6 +1103,24 @@
         ]
       }
     }
+
+    if (enable_extensions) {
+      sources += rebase_path(
+              chrome_tests_gypi_values.chrome_browser_extensions_test_support_sources,
+              ".",
+              "//chrome")
+
+      deps += [
+        "//chrome/common/extensions/api",
+
+        # TODO(rockot) bug 505926: The chrome_extensions_browsertests target
+        # should be deleted and this line removed. See the
+        # chrome_extensions_browsertests target for more.
+        "//extensions:chrome_extensions_browsertests",
+        "//extensions/common/api",
+      ]
+    }
+
     if (use_ash) {
       sources +=
           rebase_path(chrome_tests_gypi_values.chrome_browser_tests_ash_sources,
@@ -1351,14 +1376,6 @@
     if (!is_posix || is_chromeos) {
       sources -= [ "../common/time_format_browsertest.cc" ]
     }
-    if (is_android) {
-      sources -= [
-        "../browser/policy/cloud/component_cloud_policy_browsertest.cc",
-        "../browser/prefs/pref_hash_browsertest.cc",
-        "../renderer/spellchecker/spellcheck_provider_hunspell_unittest.cc",
-        "../renderer/spellchecker/spellcheck_unittest.cc",
-      ]
-    }
     if (is_chromeos) {
       sources += [
         "../browser/extensions/api/networking_private/networking_private_apitest.cc",
@@ -1450,8 +1467,6 @@
         "../renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc",
       ]
     }
-    if (is_android || is_ios) {
-    }
     if (enable_remoting) {
       sources += rebase_path(
               chrome_tests_gypi_values.chrome_browser_tests_remoting_sources,
@@ -1491,7 +1506,9 @@
       }
     }
   }
+}
 
+if (!is_android) {
   test("sync_integration_tests") {
     sources =
         rebase_path(chrome_tests_gypi_values.sync_integration_tests_sources,
diff --git a/chrome/test/base/chrome_render_view_test.cc b/chrome/test/base/chrome_render_view_test.cc
index 4496416..acd1492 100644
--- a/chrome/test/base/chrome_render_view_test.cc
+++ b/chrome/test/base/chrome_render_view_test.cc
@@ -69,9 +69,25 @@
 
   ~MockAutofillAgent() override {}
 
+  void WaitForAutofillDidAssociateFormControl() {
+    DCHECK(run_loop_ == nullptr);
+    run_loop_.reset(new base::RunLoop);
+    run_loop_->Run();
+    run_loop_.reset();
+  }
+
   MOCK_CONST_METHOD0(IsUserGesture, bool());
 
  private:
+  void didAssociateFormControls(
+      const blink::WebVector<blink::WebNode>& nodes) override {
+    AutofillAgent::didAssociateFormControls(nodes);
+    if (run_loop_)
+      run_loop_->Quit();
+  }
+
+  std::unique_ptr<base::RunLoop> run_loop_;
+
   DISALLOW_COPY_AND_ASSIGN(MockAutofillAgent);
 };
 
@@ -165,3 +181,8 @@
   EXPECT_CALL(*(static_cast<MockAutofillAgent*>(autofill_agent_)),
               IsUserGesture()).WillRepeatedly(Return(false));
 }
+
+void ChromeRenderViewTest::WaitForAutofillDidAssociateFormControl() {
+  static_cast<MockAutofillAgent*>(autofill_agent_)
+      ->WaitForAutofillDidAssociateFormControl();
+}
diff --git a/chrome/test/base/chrome_render_view_test.h b/chrome/test/base/chrome_render_view_test.h
index 7c579eea..3929c9b 100644
--- a/chrome/test/base/chrome_render_view_test.h
+++ b/chrome/test/base/chrome_render_view_test.h
@@ -42,6 +42,7 @@
 
   void EnableUserGestureSimulationForAutofill();
   void DisableUserGestureSimulationForAutofill();
+  void WaitForAutofillDidAssociateFormControl();
 
 #if defined(ENABLE_EXTENSIONS)
   std::unique_ptr<extensions::DispatcherDelegate>
diff --git a/chrome/test/base/mash_browser_tests_main.cc b/chrome/test/base/mash_browser_tests_main.cc
index 6dea6ad..e23e754 100644
--- a/chrome/test/base/mash_browser_tests_main.cc
+++ b/chrome/test/base/mash_browser_tests_main.cc
@@ -17,7 +17,7 @@
 #include "content/public/test/test_launcher.h"
 #include "services/shell/public/cpp/connector.h"
 #include "services/shell/public/cpp/service.h"
-#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service_context.h"
 #include "services/shell/runner/common/switches.h"
 #include "services/shell/runner/host/child_process.h"
 #include "services/shell/runner/init.h"
@@ -81,7 +81,7 @@
     if (!mojo_test_connector_) {
       mojo_test_connector_.reset(new MojoTestConnector);
       service_.reset(new shell::Service);
-      shell_connection_.reset(new shell::ShellConnection(
+      shell_connection_.reset(new shell::ServiceContext(
           service_.get(), mojo_test_connector_->Init()));
       ConnectToDefaultApps(shell_connection_->connector());
     }
@@ -99,7 +99,7 @@
   std::unique_ptr<MashTestSuite> test_suite_;
   std::unique_ptr<MojoTestConnector> mojo_test_connector_;
   std::unique_ptr<shell::Service> service_;
-  std::unique_ptr<shell::ShellConnection> shell_connection_;
+  std::unique_ptr<shell::ServiceContext> shell_connection_;
 
   DISALLOW_COPY_AND_ASSIGN(MashTestLauncherDelegate);
 };
diff --git a/chrome/test/base/mojo_test_connector.cc b/chrome/test/base/mojo_test_connector.cc
index 30cb63d8..e6428fb 100644
--- a/chrome/test/base/mojo_test_connector.cc
+++ b/chrome/test/base/mojo_test_connector.cc
@@ -23,7 +23,7 @@
 #include "services/shell/native_runner_delegate.h"
 #include "services/shell/public/cpp/connector.h"
 #include "services/shell/public/cpp/service.h"
-#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service_context.h"
 #include "services/shell/runner/common/client_util.h"
 #include "services/shell/runner/common/switches.h"
 #include "services/shell/service_manager.h"
diff --git a/chrome/test/base/mojo_test_connector.h b/chrome/test/base/mojo_test_connector.h
index a42209e..bd34addf 100644
--- a/chrome/test/base/mojo_test_connector.h
+++ b/chrome/test/base/mojo_test_connector.h
@@ -21,11 +21,6 @@
 class TestState;
 }
 
-namespace mojo {
-class Service;
-class ShellConnection;
-}
-
 // MojoTestConnector in responsible for providing the necessary wiring for
 // test processes to get a mojo channel passed to them.  To use this class
 // call PrepareForTest() prior to launching each test. It is expected
diff --git a/chrome/test/chromedriver/net/adb_client_socket.cc b/chrome/test/chromedriver/net/adb_client_socket.cc
index 0a398acf..9a5a672 100644
--- a/chrome/test/chromedriver/net/adb_client_socket.cc
+++ b/chrome/test/chromedriver/net/adb_client_socket.cc
@@ -271,7 +271,8 @@
     bool is_void = current_query_ < queries_.size() - 1;
     // The |shell| command is a special case because it is the only command that
     // doesn't include a length at the beginning of the data stream.
-    bool has_length = query.find("shell:") != 0;
+    bool has_length =
+        !base::StartsWith(query, "shell:", base::CompareCase::SENSITIVE);
     SendCommand(query, is_void, has_length,
         base::Bind(&AdbQuerySocket::OnResponse, base::Unretained(this)));
   }
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc
index ecfe4a7..48ad77d7 100644
--- a/chrome/test/chromedriver/session_commands.cc
+++ b/chrome/test/chromedriver/session_commands.cc
@@ -12,6 +12,7 @@
 #include "base/files/file_util.h"
 #include "base/logging.h"  // For CHECK macros.
 #include "base/memory/ref_counted.h"
+#include "base/strings/string_util.h"
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -62,10 +63,11 @@
 
 bool WindowHandleToWebViewId(const std::string& window_handle,
                              std::string* web_view_id) {
-  if (window_handle.find(kWindowHandlePrefix) != 0u)
+  if (!base::StartsWith(window_handle, kWindowHandlePrefix,
+                        base::CompareCase::SENSITIVE)) {
     return false;
-  *web_view_id = window_handle.substr(
-      std::string(kWindowHandlePrefix).length());
+  }
+  *web_view_id = window_handle.substr(sizeof(kWindowHandlePrefix) - 1);
   return true;
 }
 
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index 7a2518b..8963d84 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -113,6 +113,15 @@
     'CombinedInputActionsTest.testCombiningShiftAndClickResultsInANewWindow',
     # Flaky: https://code.google.com/p/chromedriver/issues/detail?id=1150
     'BasicKeyboardInterfaceTest.testBasicKeyboardInputOnActiveElement',
+
+    # Flaky on Linux32:
+    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1418
+    'ClickTest.testShouldOnlyFollowHrefOnce',
+    'JavascriptEnabledDriverTest.testShouldFireOnChangeEventWhenSettingAnElementsValue',
+    'WindowSwitchingTest.testCanCloseWindowWhenMultipleWindowsAreOpen',
+    'WindowSwitchingTest.testCanCallGetWindowHandlesAfterClosingAWindow',
+    'WindowSwitchingTest.testCanCloseWindowAndSwitchBackToMainWindow',
+    'XPathElementFindingTest.testShouldFindElementsByXPath',
 ]
 _OS_NEGATIVE_FILTER['mac'] = [
     # https://code.google.com/p/chromedriver/issues/detail?id=26
diff --git a/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/guest.html b/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/guest.html
new file mode 100644
index 0000000..4de94b45
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/guest.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<!--
+   * 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.
+-->
+<html id='root'>
+  <!-- Since the body of an app is not scrollable by default, explicitly
+       set it to be scrollable. -->
+  <head>
+    <script type="text/javascript" src="guest.js"></script>
+  </head>
+  <body style="margin: auto">
+    Test guest.<br>
+  </body>
+</html>
diff --git a/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/guest.js b/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/guest.js
new file mode 100644
index 0000000..5a8b67f
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/guest.js
@@ -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.
+
+var LOG = function(msg) {
+  window.console.log(msg);
+};
+
+var embedder;
+
+function sendMessageToEmbedder(message) {
+  if (!embedder) {
+    LOG('no embedder channel to send postMessage');
+    return;
+  }
+  embedder.postMessage(JSON.stringify([message]), '*');
+}
+
+window.addEventListener('message', function(e) {
+  embedder = e.source;
+  var data = JSON.parse(e.data);
+  if (data[0] == 'connect') {
+    sendMessageToEmbedder('connected');
+  }
+});
diff --git a/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/main.html b/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/main.html
new file mode 100644
index 0000000..298e2a8
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/main.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<!--
+   * 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.
+-->
+<html>
+  <body style=
+    "width: 400px; height: 400px; margin: 0px; padding: 0px;">
+    <div>
+      <input type='text' id='other-focusable-element'
+       style="position: absolute; left: 5px; top: 5px; width: 10px; height: 10px;">
+    </div>
+    <div id="webview-tag-container"></div>
+    <script src="main.js"></script>
+  </body>
+</html>
diff --git a/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/main.js b/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/main.js
new file mode 100644
index 0000000..1a733ac
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/main.js
@@ -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.
+
+var LOG = function(msg) {
+    window.console.log(msg);
+};
+
+var startTest = function() {
+  document.getElementById('other-focusable-element').onfocus =
+      function() {
+        console.log('guest_focus_test: text input got focus.');
+      };
+
+  var webview = document.createElement('webview');
+  var onLoadStop = function(e) {
+    webview.contentWindow.postMessage(JSON.stringify(['connect']),'*');
+  };
+
+  webview.addEventListener('loadstop', onLoadStop);
+  webview.addEventListener('consolemessage', function(e) {
+    LOG('g: ' + e.message);
+  });
+  webview.partition = 'partition1';
+  webview.style.width = '300px';
+  webview.style.height = '200px';
+  webview.style.margin = '0px';
+  webview.style.padding = '0px';
+  webview.style.position = 'absolute';
+  webview.style.left = '50px';
+  webview.style.top = '100px';
+  webview.src = 'guest.html';
+  document.querySelector('#webview-tag-container').appendChild(webview);
+};
+
+window.addEventListener('message', function(e) {
+  var data = JSON.parse(e.data);
+  LOG('data: ' + data);
+    switch (data[0]) {
+      case 'connected':
+        chrome.test.sendMessage('WebViewTest.LAUNCHED');
+        break;
+    }
+});
+
+if (chrome.test !== undefined) {
+  chrome.test.getConfig(function(config) {
+    startTest();
+  });
+} else {
+  // Allow interactive debugging.
+  // Need timeout to allow the WebView prototype to be setup.
+  window.setTimeout(startTest, 100);
+}
diff --git a/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/manifest.json b/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/manifest.json
new file mode 100644
index 0000000..77c2ec0
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/manifest.json
@@ -0,0 +1,23 @@
+{
+  "name": "<webview> guest focus test.",
+  "version": "1",
+  "permissions": [
+    "webview"
+  ],
+  "app": {
+     "background": {
+       "scripts": ["test.js"]
+     }
+   },
+   "webview": {
+     "partitions": [
+       {
+         "name": "partition1",
+         "accessible_resources": [
+           "guest.js",
+           "guest.html"
+         ]
+       }
+    ]
+  }
+}
diff --git a/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/test.js b/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/test.js
new file mode 100644
index 0000000..1515400
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/guest_focus_test/test.js
@@ -0,0 +1,9 @@
+// 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.
+
+chrome.app.runtime.onLaunched.addListener(function() {
+  chrome.app.window.create('main.html', {
+    bounds: { width: 400, height: 400 }
+  }, function() {});
+});
diff --git a/chrome/test/data/webrtc/video_extraction.js b/chrome/test/data/webrtc/video_extraction.js
index 5bfa923..95f83bd 100644
--- a/chrome/test/data/webrtc/video_extraction.js
+++ b/chrome/test/data/webrtc/video_extraction.js
@@ -36,10 +36,9 @@
 var gHasThrownAwayFirstTwoFrames = false;
 
 /**
- * We need this global variable to synchronize with the test how long to run the
- * call between the two peers.
+ * A string to be returned to the test about the current status of capture.
  */
-var gDoneFrameCapturing = false;
+var gCapturingStatus = 'capturing-not-started';
 
 /**
  * Starts the frame capturing.
@@ -55,6 +54,7 @@
   inputElement = document.getElementById("local-view");
   var width = inputElement.videoWidth;
   var height = inputElement.videoHeight;
+
   // The WebRTC code is free to start in VGA, so make sure that the output video
   // tag scales up to whatever the input size is (otherwise the video quality
   // comparison will go poorly.
@@ -62,13 +62,16 @@
   videoTag.height = height;
 
   if (width == 0 || height == 0) {
-    throw failTest('Trying to capture from ' + videoTag.id +
-                   ' but it is not playing any video.');
+    // Video must be playing at this point since this function is invoked from
+    // onplay on the <video> tag. See http://crbug.com/625943.
+    gCapturingStatus = 'failed-video-was-0x0-after-onplay'
+    return;
   }
 
   console.log('Received width is: ' + width + ', received height is: ' + height
               + ', capture interval is: ' + gFrameCaptureInterval +
               ', duration is: ' + gCaptureDuration);
+  gCapturingStatus = 'still-capturing';
 
   var remoteCanvas = document.createElement('canvas');
   remoteCanvas.width = width;
@@ -85,11 +88,7 @@
  * Queries if we're done with the frame capturing yet.
  */
 function doneFrameCapturing() {
-  if (gDoneFrameCapturing) {
-    returnToTest('done-capturing');
-  } else {
-    returnToTest('still-capturing');
-  }
+  returnToTest(gCapturingStatus);
 }
 
 /**
@@ -169,7 +168,7 @@
                gFrameCaptureInterval - diff);
   } else {
     // Done capturing!
-    gDoneFrameCapturing = true;
+    gCapturingStatus = 'done-capturing';
     prepareProgressBar_();
   }
 }
diff --git a/chrome/test/data/webui/md_history/history_list_test.js b/chrome/test/data/webui/md_history/history_list_test.js
index d43bde1..0ccad6a 100644
--- a/chrome/test/data/webui/md_history/history_list_test.js
+++ b/chrome/test/data/webui/md_history/history_list_test.js
@@ -196,6 +196,7 @@
       });
 
       test('delete items end to end', function(done) {
+        var listContainer = app.$.history;
         app.historyResult(createHistoryInfo(), TEST_HISTORY_RESULTS);
         app.historyResult(createHistoryInfo(), ADDITIONAL_RESULTS);
         flush().then(function() {
@@ -216,11 +217,17 @@
                            '2016-03-13');
               assertEquals(element.historyData_[4].dateRelativeDay,
                            '2016-03-11');
+              assertFalse(listContainer.$.dialog.opened);
               done();
             });
           });
 
           MockInteractions.tap(app.$.toolbar.$$('#delete-button'));
+
+          // Confirmation dialog should appear.
+          assertTrue(listContainer.$.dialog.opened);
+
+          MockInteractions.tap(listContainer.$$('.action-button'));
         });
       });
 
diff --git a/chrome/test/data/webui/md_history/history_overflow_menu_test.js b/chrome/test/data/webui/md_history/history_overflow_menu_test.js
index 5fee6506..01836a7f 100644
--- a/chrome/test/data/webui/md_history/history_overflow_menu_test.js
+++ b/chrome/test/data/webui/md_history/history_overflow_menu_test.js
@@ -66,7 +66,7 @@
         // actual page, it will take two presses to close the menu due to focus.
         // TODO(yingran): Fix this behavior to only require one key press.
         element.toggleMenu_(MENU_EVENT);
-        MockInteractions.pressAndReleaseKeyOn(document, 27);
+        MockInteractions.pressAndReleaseKeyOn(document.body, 27);
         assertEquals(false, element.$.sharedMenu.menuOpen);
       });
 
diff --git a/chrome/test/data/webui/md_history/history_toolbar_test.js b/chrome/test/data/webui/md_history/history_toolbar_test.js
index 86f6f02b4..6eb61f6 100644
--- a/chrome/test/data/webui/md_history/history_toolbar_test.js
+++ b/chrome/test/data/webui/md_history/history_toolbar_test.js
@@ -52,6 +52,26 @@
         toolbar.$$('cr-toolbar').fire('search-changed', 'Test');
       });
 
+      test('shortcuts to open search field', function() {
+        var field = toolbar.$['main-toolbar'].getSearchField();
+        assertFalse(field.showingSearch);
+
+        MockInteractions.pressAndReleaseKeyOn(
+            document.body, 191, '', '/');
+        assertTrue(field.showingSearch);
+        assertEquals(field.$.searchInput, field.root.activeElement);
+
+        MockInteractions.pressAndReleaseKeyOn(
+            field.$.searchInput, 27, '', 'Escape');
+        assertFalse(field.showingSearch, 'Pressing escape closes field.');
+        assertNotEquals(field.$.searchInput, field.root.activeElement);
+
+        MockInteractions.pressAndReleaseKeyOn(
+            document.body, 70, 'ctrl', 'f');
+        assertTrue(field.showingSearch);
+        assertEquals(field.$.searchInput, field.root.activeElement);
+     });
+
       teardown(function() {
         element.historyData_ = [];
         element.searchedTerm = '';
diff --git a/chrome/test/data/webui/mocha_adapter.js b/chrome/test/data/webui/mocha_adapter.js
index 7e544b47..696d938 100644
--- a/chrome/test/data/webui/mocha_adapter.js
+++ b/chrome/test/data/webui/mocha_adapter.js
@@ -35,10 +35,14 @@
     var message = 'Mocha test failed: ' + test.fullTitle() + '\n';
 
     // Remove unhelpful mocha lines from stack trace.
-    var stack = err.stack.split('\n');
-    for (var i = 0; i < stack.length; i++) {
-      if (stack[i].indexOf('mocha.js:') == -1)
-        message += stack[i] + '\n';
+    if (err.stack) {
+      var stack = err.stack.split('\n');
+      for (var i = 0; i < stack.length; i++) {
+        if (stack[i].indexOf('mocha.js:') == -1)
+          message += stack[i] + '\n';
+      }
+    } else {
+      message += err.toString();
     }
 
     console.error(message);
diff --git a/chrome/test/data/webui/settings/animation_browsertest.js b/chrome/test/data/webui/settings/animation_browsertest.js
new file mode 100644
index 0000000..5ee559a
--- /dev/null
+++ b/chrome/test/data/webui/settings/animation_browsertest.js
@@ -0,0 +1,147 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/** @fileoverview Tests for settings.animation. */
+
+/** @const {string} Path to root from chrome/test/data/webui/settings/. */
+var ROOT_PATH = '../../../../../';
+
+/**
+ * @constructor
+ * @extends testing.Test
+*/
+function SettingsAnimationBrowserTest() {}
+
+SettingsAnimationBrowserTest.prototype = {
+  __proto__: testing.Test.prototype,
+
+  /** @override */
+  browsePreload: 'chrome://md-settings/animation/animation.html',
+
+  /** @override */
+  extraLibraries: [
+    ROOT_PATH + 'third_party/mocha/mocha.js',
+    '../mocha_adapter.js',
+  ],
+
+  /** @override */
+  isAsync: true,
+
+  /** @override */
+  runAccessibilityChecks: false,
+};
+
+TEST_F('SettingsAnimationBrowserTest', 'Animation', function() {
+  var self = this;
+
+  var Animation = settings.animation.Animation;
+
+  var onFinishBeforePromise = function() {
+    assertNotReached('Animation fired finish event before resolving promise');
+  };
+
+  var onCancelUnexpectedly = function() {
+    assertNotReached('Animation should have finished, but fired cancel event');
+  };
+
+  // Register mocha tests.
+  suite('settings.animation.Animation', function() {
+    var div;
+    var keyframes;
+    var options;
+
+    setup(function() {
+      keyframes = [{
+        height: '100px',
+        easing: 'ease-in',
+      }, {
+        height: '200px',
+      }];
+
+      options = {
+        duration: 1000,
+        // Use fill: both so we can test the animation start and end states.
+        fill: 'both',
+      };
+
+      div = document.createElement('div');
+      document.body.appendChild(div);
+    });
+
+    teardown(function() {
+      div.remove();
+    });
+
+    test('Animation plays', function(done) {
+      var animation = new Animation(div, keyframes, options);
+      animation.addEventListener('cancel', onCancelUnexpectedly);
+      animation.addEventListener('finish', onFinishBeforePromise);
+
+      requestAnimationFrame(function() {
+        expectEquals(100, div.clientHeight);
+
+        animation.finished.then(function() {
+          expectEquals(200, div.clientHeight);
+          animation.removeEventListener('finish', onFinishBeforePromise);
+          animation.addEventListener('finish', function() {
+            done();
+          });
+        });
+      });
+    });
+
+    test('Animation finishes', function(done) {
+      // Absurdly large finite value to ensure we call finish() before the
+      // animation finishes automatically.
+      options.duration = Number.MAX_VALUE;
+      var animation = new Animation(div, keyframes, options);
+      animation.addEventListener('cancel', onCancelUnexpectedly);
+      animation.addEventListener('finish', onFinishBeforePromise);
+
+      // TODO(michaelpg): rAF seems more appropriate, but crbug.com/620160.
+      setTimeout(function() {
+        expectEquals(100, div.clientHeight);
+
+        animation.finish();
+
+        // The promise should resolve before the finish event is scheduled.
+        animation.finished.then(function() {
+          expectEquals(200, div.clientHeight);
+          animation.removeEventListener('finish', onFinishBeforePromise);
+          animation.addEventListener('finish', function() {
+            done();
+          });
+        });
+      });
+    });
+
+    test('Animation cancels', function(done) {
+      // Absurdly large finite value to ensure we call cancel() before the
+      // animation finishes automatically.
+      options.duration = Number.MAX_VALUE;
+      var animation = new Animation(div, keyframes, options);
+      animation.addEventListener('cancel', onCancelUnexpectedly);
+      animation.addEventListener('finish', onFinishBeforePromise);
+
+      // TODO(michaelpg): rAF seems more appropriate, but crbug.com/620160.
+      setTimeout(function() {
+        expectEquals(100, div.clientHeight);
+
+        animation.cancel();
+
+        // The promise should resolve before the finish event is scheduled.
+        animation.finished.catch(function() {
+          expectEquals(0, div.clientHeight);
+          animation.removeEventListener('cancel', onCancelUnexpectedly);
+          animation.addEventListener('cancel', function() {
+            done();
+          });
+        });
+      });
+    });
+  });
+
+  // Run all registered tests.
+  mocha.run();
+});
diff --git a/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js b/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js
index ce2a7c9..4afa4250 100644
--- a/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js
+++ b/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js
@@ -173,6 +173,8 @@
       browserProxy.setEnabledStatus(true);
       document.body.appendChild(page);
 
+      var turnOffDialog = null;
+
       return browserProxy.whenCalled('getEnabledStatus').then(function() {
         assertTrue(page.easyUnlockAllowed_);
         expectTrue(page.easyUnlockEnabled_);
@@ -184,31 +186,30 @@
         expectFalse(turnOffButton.hidden)
 
         MockInteractions.tap(turnOffButton);
-        return browserProxy.whenCalled('getTurnOffFlowStatus').then(function() {
-          Polymer.dom.flush();
+        return browserProxy.whenCalled('getTurnOffFlowStatus');
+      }).then(function() {
+        Polymer.dom.flush();
 
-          var turnOffDialog = page.$$('#easyUnlockTurnOffDialog');
-          assertTrue(!!turnOffDialog);
+        turnOffDialog = page.$$('#easyUnlockTurnOffDialog');
+        assertTrue(!!turnOffDialog);
 
-          var turnOffDialogConfirmButton = turnOffDialog.$$('#turnOff');
-          assertTrue(!!turnOffDialogConfirmButton);
-          expectFalse(turnOffDialogConfirmButton.hidden);
+        var turnOffDialogConfirmButton = turnOffDialog.$$('#turnOff');
+        assertTrue(!!turnOffDialogConfirmButton);
+        expectFalse(turnOffDialogConfirmButton.hidden);
 
-          MockInteractions.tap(turnOffDialogConfirmButton);
+        MockInteractions.tap(turnOffDialogConfirmButton);
 
-          return browserProxy.whenCalled('startTurnOffFlow').then(function() {
-            // To signal successful turnoff, the enabled status is broadcast
-            // as false. At that point, the dialog should close and cancel
-            // any in-progress turnoff flow. The cancellation should be
-            // a no-op assuming the turnoff originated from this tab.
-            cr.webUIListenerCallback('easy-unlock-enabled-status', false);
-            return browserProxy.whenCalled('cancelTurnOffFlow').then(
-                function() {
-                  Polymer.dom.flush();
-                  expectFalse(turnOffDialog.$.dialog.opened);
-                });
-          });
-        });
+        return browserProxy.whenCalled('startTurnOffFlow');
+      }).then(function() {
+        // To signal successful turnoff, the enabled status is broadcast
+        // as false. At that point, the dialog should close and cancel
+        // any in-progress turnoff flow. The cancellation should be
+        // a no-op assuming the turnoff originated from this tab.
+        cr.webUIListenerCallback('easy-unlock-enabled-status', false);
+        return browserProxy.whenCalled('cancelTurnOffFlow');
+      }).then(function() {
+        Polymer.dom.flush();
+        expectFalse(turnOffDialog.$.dialog.opened);
       });
     });
   });
diff --git a/chrome/test/data/webui/settings/people_page_test.js b/chrome/test/data/webui/settings/people_page_test.js
index 7492612..51a85f6 100644
--- a/chrome/test/data/webui/settings/people_page_test.js
+++ b/chrome/test/data/webui/settings/people_page_test.js
@@ -149,9 +149,10 @@
       teardown(function() { peoplePage.remove(); });
 
       test('GetProfileInfo', function() {
+        var disconnectButton = null;
         return browserProxy.whenCalled('getSyncStatus').then(function() {
           Polymer.dom.flush();
-          var disconnectButton = peoplePage.$$('#disconnectButton');
+          disconnectButton = peoplePage.$$('#disconnectButton');
           assertTrue(!!disconnectButton);
 
           MockInteractions.tap(disconnectButton);
@@ -165,38 +166,36 @@
           assertFalse(disconnectConfirm.hidden);
           MockInteractions.tap(disconnectConfirm);
 
-          return browserProxy.whenCalled('signOut').then(
-              function(deleteProfile) {
-                Polymer.dom.flush();
+          return browserProxy.whenCalled('signOut');
+        }).then(function(deleteProfile) {
+          Polymer.dom.flush();
 
-                assertFalse(deleteProfile);
+          assertFalse(deleteProfile);
 
-                cr.webUIListenerCallback('sync-status-changed', {
-                  signedIn: true,
-                  domain: 'example.com',
-                });
-                Polymer.dom.flush();
+          cr.webUIListenerCallback('sync-status-changed', {
+            signedIn: true,
+            domain: 'example.com',
+          });
+          Polymer.dom.flush();
 
-                assertFalse(peoplePage.$.disconnectDialog.opened);
-                MockInteractions.tap(disconnectButton);
-                Polymer.dom.flush();
+          assertFalse(peoplePage.$.disconnectDialog.opened);
+          MockInteractions.tap(disconnectButton);
+          Polymer.dom.flush();
 
-                assertTrue(peoplePage.$.disconnectDialog.opened);
-                assertTrue(peoplePage.$.deleteProfile.hidden);
+          assertTrue(peoplePage.$.disconnectDialog.opened);
+          assertTrue(peoplePage.$.deleteProfile.hidden);
 
-                var disconnectManagedProfileConfirm =
-                    peoplePage.$.disconnectManagedProfileConfirm;
-                assertTrue(!!disconnectManagedProfileConfirm);
-                assertFalse(disconnectManagedProfileConfirm.hidden);
+          var disconnectManagedProfileConfirm =
+              peoplePage.$.disconnectManagedProfileConfirm;
+          assertTrue(!!disconnectManagedProfileConfirm);
+          assertFalse(disconnectManagedProfileConfirm.hidden);
 
-                browserProxy.resetResolver('signOut');
-                MockInteractions.tap(disconnectManagedProfileConfirm);
+          browserProxy.resetResolver('signOut');
+          MockInteractions.tap(disconnectManagedProfileConfirm);
 
-                return browserProxy.whenCalled('signOut').then(
-                    function(deleteProfile) {
-                      assertTrue(deleteProfile);
-                    });
-              });
+          return browserProxy.whenCalled('signOut');
+        }).then(function(deleteProfile) {
+          assertTrue(deleteProfile);
         });
       });
     });
diff --git a/chrome/test/data/webui/settings/reset_page_test.js b/chrome/test/data/webui/settings/reset_page_test.js
index 8b6b8c0..befb90e9 100644
--- a/chrome/test/data/webui/settings/reset_page_test.js
+++ b/chrome/test/data/webui/settings/reset_page_test.js
@@ -151,43 +151,51 @@
         MockInteractions.tap(resetPage.$.resetProfile);
         var dialog = resetPage.$$('settings-reset-profile-dialog');
         assertTrue(!!dialog);
+        assertTrue(dialog.$.dialog.opened);
         var onDialogClosed = new Promise(
             function(resolve, reject) {
-              dialog.addEventListener('iron-overlay-closed', resolve);
+              dialog.addEventListener('iron-overlay-closed', function() {
+                assertFalse(dialog.$.dialog.opened);
+                resolve();
+              });
             });
 
-        return resetPageBrowserProxy.whenCalled(
-            'onShowResetProfileDialog').then(
-            function() {
+        return new Promise(function(resolve, reject) {
+          resetPageBrowserProxy.whenCalled(
+              'onShowResetProfileDialog').then(function() {
+            // Need to call requestAnimationFrame here, otherwise the dialog has
+            // not been registered to the IronOverlayManager at the time we
+            // attempt to close it (which prevents closing by 'esc' key from
+            // working).
+            window.requestAnimationFrame(function() {
               closeDialogFn(dialog);
-              return Promise.all([
+              Promise.all([
                 onDialogClosed,
                 resetPageBrowserProxy.whenCalled('onHideResetProfileDialog'),
-              ]);
+              ]).then(resolve, reject);
             });
+          });
+        });
       }
 
       // Tests that the reset profile dialog opens and closes correctly and that
       // resetPageBrowserProxy calls are occurring as expected.
       test(TestNames.ResetProfileDialogOpenClose, function() {
-        return Promise.all([
+        return testOpenCloseResetProfileDialog(function(dialog) {
           // Test case where the 'cancel' button is clicked.
-          testOpenCloseResetProfileDialog(
-              function(dialog) {
-                MockInteractions.tap(dialog.$.cancel);
-              }),
-          // Test case where the 'close' button is clicked.
-          testOpenCloseResetProfileDialog(
-              function(dialog) {
-                MockInteractions.tap(dialog.$.dialog.getCloseButton());
-              }),
-          // Test case where the 'Esc' key is pressed.
-          testOpenCloseResetProfileDialog(
-              function(dialog) {
-                MockInteractions.pressAndReleaseKeyOn(
-                    dialog, 27 /* 'Esc' key code */);
-              }),
-        ]);
+          MockInteractions.tap(dialog.$.cancel);
+        }).then(function() {
+          return testOpenCloseResetProfileDialog(function(dialog) {
+            // Test case where the 'close' button is clicked.
+            MockInteractions.tap(dialog.$.dialog.getCloseButton());
+          });
+        }).then(function() {
+          return testOpenCloseResetProfileDialog(function(dialog) {
+            // Test case where the 'Esc' key is pressed.
+            MockInteractions.pressAndReleaseKeyOn(
+                dialog, 27 /* 'Esc' key code */);
+          });
+        });
       });
 
       // Tests that when user request to reset the profile the appropriate
diff --git a/chrome/test/data/webui/settings/site_details_permission_tests.js b/chrome/test/data/webui/settings/site_details_permission_tests.js
index 1e4febb..d9ad53f7 100644
--- a/chrome/test/data/webui/settings/site_details_permission_tests.js
+++ b/chrome/test/data/webui/settings/site_details_permission_tests.js
@@ -77,7 +77,7 @@
 
         return browserProxy.whenCalled('getExceptionList').then(function() {
           assertTrue(testElement.$.details.hidden);
-        }.bind(this));
+        });
       });
 
       test('camera category', function() {
@@ -98,15 +98,14 @@
               'Widget should be labelled correctly');
 
           // Flip the permission and validate that prefs stay in sync.
-          return validatePermissionFlipWorks(origin, true).then(function() {
-            browserProxy.resetResolver('setCategoryPermissionForOrigin');
-            return validatePermissionFlipWorks(origin, false).then(function() {
-              browserProxy.resetResolver('setCategoryPermissionForOrigin');
-              return validatePermissionFlipWorks(origin, true).then(function() {
-              }.bind(this));
-            }.bind(this));
-          }.bind(this));
-        }.bind(this));
+          return validatePermissionFlipWorks(origin, true);
+        }).then(function() {
+          browserProxy.resetResolver('setCategoryPermissionForOrigin');
+          return validatePermissionFlipWorks(origin, false);
+        }).then(function() {
+          browserProxy.resetResolver('setCategoryPermissionForOrigin');
+          return validatePermissionFlipWorks(origin, true);
+        });
       });
 
       test('disappear on empty', function() {
@@ -122,10 +121,10 @@
           assertFalse(testElement.$.details.hidden);
 
           browserProxy.setPrefs(prefsEmpty);
-          return browserProxy.whenCalled('getExceptionList').then(function() {
-            assertTrue(testElement.$.details.hidden);
-          }.bind(this));
-        }.bind(this));
+          return browserProxy.whenCalled('getExceptionList');
+        }).then(function() {
+          assertTrue(testElement.$.details.hidden);
+        });
       });
     });
   }
diff --git a/chrome/test/data/webui/settings/site_list_tests.js b/chrome/test/data/webui/settings/site_list_tests.js
index 22b9cca70..8e48d95 100644
--- a/chrome/test/data/webui/settings/site_list_tests.js
+++ b/chrome/test/data/webui/settings/site_list_tests.js
@@ -333,12 +333,11 @@
               assertFalse(testElement.$.category.hidden);
               browserProxy.resetResolver('getExceptionList');
               testElement.categoryEnabled = false;
-              return browserProxy.whenCalled('getExceptionList').then(
-                  function(contentType) {
-                    assertFalse(testElement.$.category.hidden);
-                    assertEquals('Exceptions - 0',
-                        testElement.$.header.innerText.trim());
-                  });
+              return browserProxy.whenCalled('getExceptionList');
+            }).then(function(contentType) {
+              assertFalse(testElement.$.category.hidden);
+              assertEquals('Exceptions - 0',
+                  testElement.$.header.innerText.trim());
             });
       });
 
@@ -364,12 +363,11 @@
               assertFalse(testElement.$.category.hidden);
               browserProxy.resetResolver('getExceptionList');
               testElement.categoryEnabled = false;
-              return browserProxy.whenCalled('getExceptionList').then(
-                  function(contentType) {
-                    assertFalse(testElement.$.category.hidden);
-                    assertEquals('Exceptions - 2',
-                        testElement.$.header.innerText.trim());
-                  });
+              return browserProxy.whenCalled('getExceptionList');
+            }).then(function(contentType) {
+              assertFalse(testElement.$.category.hidden);
+              assertEquals('Exceptions - 2',
+                  testElement.$.header.innerText.trim());
             });
       });
 
@@ -395,10 +393,9 @@
               assertFalse(testElement.$.category.hidden);
               browserProxy.resetResolver('getExceptionList');
               testElement.categoryEnabled = false;
-              return browserProxy.whenCalled('getExceptionList').then(
-                  function(contentType) {
-                    assertTrue(testElement.$.category.hidden);
-                  });
+              return browserProxy.whenCalled('getExceptionList');
+            }).then(function(contentType) {
+              assertTrue(testElement.$.category.hidden);
             });
       });
 
@@ -426,12 +423,10 @@
               assertFalse(testElement.$.category.hidden);
               browserProxy.resetResolver('getExceptionList');
               testElement.categoryEnabled = false;
-              return browserProxy.whenCalled('getExceptionList').then(
-                  function(contentType) {
-                    assertFalse(testElement.$.category.hidden);
-                    assertEquals('Clear on exit - 1',
-                        testElement.$.header.innerText);
-                  });
+              return browserProxy.whenCalled('getExceptionList');
+            }).then(function(contentType) {
+              assertFalse(testElement.$.category.hidden);
+              assertEquals('Clear on exit - 1', testElement.$.header.innerText);
             });
       });
 
diff --git a/chrome/test/data/webui/settings/site_settings_category_tests.js b/chrome/test/data/webui/settings/site_settings_category_tests.js
index ed1da65..d926b56d 100644
--- a/chrome/test/data/webui/settings/site_settings_category_tests.js
+++ b/chrome/test/data/webui/settings/site_settings_category_tests.js
@@ -79,17 +79,15 @@
                 settings.ContentSettingsTypes.GEOLOCATION, contentType);
             assertEquals(enabled, testElement.categoryEnabled);
             MockInteractions.tap(testElement.$.toggle);
-            return browserProxy.whenCalled(
-                'setDefaultValueForContentType').then(
-              function(arguments) {
-                  assertEquals(
-                      settings.ContentSettingsTypes.GEOLOCATION, arguments[0]);
-                assertEquals(
-                    enabled ? settings.PermissionValues.BLOCK :
-                        settings.PermissionValues.ASK,
-                    arguments[1]);
-                assertNotEquals(enabled, testElement.categoryEnabled);
-              });
+            return browserProxy.whenCalled('setDefaultValueForContentType');
+          }).then(function(arguments) {
+            assertEquals(
+                settings.ContentSettingsTypes.GEOLOCATION, arguments[0]);
+            assertEquals(
+                enabled ? settings.PermissionValues.BLOCK :
+                    settings.PermissionValues.ASK,
+                arguments[1]);
+            assertNotEquals(enabled, testElement.categoryEnabled);
           });
       }
 
diff --git a/chrome/utility/importer/ie_importer_win.cc b/chrome/utility/importer/ie_importer_win.cc
index 2ef4b47..aadfd5b 100644
--- a/chrome/utility/importer/ie_importer_win.cc
+++ b/chrome/utility/importer/ie_importer_win.cc
@@ -627,9 +627,9 @@
         ac.key.erase(i);
         ac.is_url = (ac.key.find(L"://") != base::string16::npos);
         ac_list.push_back(ac);
-        ac_list[ac_list.size() - 1].data = base::SplitString(
-            data, base::string16(1, '\0'),
-            base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+        ac_list.back().data =
+            base::SplitString(data, base::string16(1, '\0'),
+                              base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
       }
       CoTaskMemFree(buffer);
     }
diff --git a/chrome/utility/media_galleries/picasa_album_table_reader.cc b/chrome/utility/media_galleries/picasa_album_table_reader.cc
index a02b03f..b8b5d9b8 100644
--- a/chrome/utility/media_galleries/picasa_album_table_reader.cc
+++ b/chrome/utility/media_galleries/picasa_album_table_reader.cc
@@ -24,7 +24,12 @@
   base::TimeDelta variant_delta = base::TimeDelta::FromMicroseconds(
       static_cast<int64_t>(variant_time * base::Time::kMicrosecondsPerDay));
 
-  return base::Time::FromLocalExploded(kPmpVariantTimeEpoch) + variant_delta;
+  base::Time out_time;
+  bool conversion_success =
+      base::Time::FromLocalExploded(kPmpVariantTimeEpoch, &out_time);
+  DCHECK(conversion_success);
+
+  return out_time + variant_delta;
 }
 
 }  // namespace
diff --git a/chromecast/browser/cast_memory_pressure_monitor.cc b/chromecast/browser/cast_memory_pressure_monitor.cc
index 75d8d0e6..ed70148 100644
--- a/chromecast/browser/cast_memory_pressure_monitor.cc
+++ b/chromecast/browser/cast_memory_pressure_monitor.cc
@@ -46,6 +46,8 @@
 CastMemoryPressureMonitor::CastMemoryPressureMonitor()
     : current_level_(base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
       system_reserved_kb_(GetSystemReservedKb()),
+      dispatch_callback_(
+          base::Bind(&base::MemoryPressureListener::NotifyMemoryPressure)),
       weak_ptr_factory_(this) {
   PollPressureLevel();
 }
@@ -111,7 +113,7 @@
 void CastMemoryPressureMonitor::UpdateMemoryPressureLevel(
     MemoryPressureLevel new_level) {
   if (new_level != base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE)
-    base::MemoryPressureListener::NotifyMemoryPressure(new_level);
+    dispatch_callback_.Run(new_level);
 
   if (new_level == current_level_)
     return;
@@ -121,4 +123,9 @@
       "Memory.Pressure.LevelChange", new_level);
 }
 
+void CastMemoryPressureMonitor::SetDispatchCallback(
+    const DispatchCallback& callback) {
+  dispatch_callback_ = callback;
+}
+
 }  // namespace chromecast
diff --git a/chromecast/browser/cast_memory_pressure_monitor.h b/chromecast/browser/cast_memory_pressure_monitor.h
index b24702c..bb6ed92 100644
--- a/chromecast/browser/cast_memory_pressure_monitor.h
+++ b/chromecast/browser/cast_memory_pressure_monitor.h
@@ -22,6 +22,7 @@
 
   // base::MemoryPressureMonitor implementation:
   MemoryPressureLevel GetCurrentPressureLevel() const override;
+  void SetDispatchCallback(const DispatchCallback& callback) override;
 
  private:
   void PollPressureLevel();
@@ -29,6 +30,7 @@
 
   MemoryPressureLevel current_level_;
   const int system_reserved_kb_;
+  DispatchCallback dispatch_callback_;
   base::WeakPtrFactory<CastMemoryPressureMonitor> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(CastMemoryPressureMonitor);
diff --git a/chromecast/media/audio/cast_audio_output_stream_unittest.cc b/chromecast/media/audio/cast_audio_output_stream_unittest.cc
index e65aa25..106a25cc 100644
--- a/chromecast/media/audio/cast_audio_output_stream_unittest.cc
+++ b/chromecast/media/audio/cast_audio_output_stream_unittest.cc
@@ -168,7 +168,7 @@
 class FakeAudioManager : public CastAudioManager {
  public:
   FakeAudioManager(scoped_refptr<base::SingleThreadTaskRunner> task_runner)
-      : CastAudioManager(task_runner, task_runner, nullptr, nullptr),
+      : CastAudioManager(task_runner, task_runner, nullptr, nullptr, nullptr),
         media_pipeline_backend_(nullptr) {}
   ~FakeAudioManager() override {}
 
diff --git a/chromecast/media/cdm/cast_cdm.cc b/chromecast/media/cdm/cast_cdm.cc
index 30965c11..5125648 100644
--- a/chromecast/media/cdm/cast_cdm.cc
+++ b/chromecast/media/cdm/cast_cdm.cc
@@ -11,6 +11,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "chromecast/media/base/decrypt_context_impl.h"
 #include "chromecast/media/base/media_resource_tracker.h"
 #include "media/base/cdm_key_information.h"
 #include "media/base/decryptor.h"
@@ -18,10 +19,48 @@
 
 namespace chromecast {
 namespace media {
+namespace {
+
+class CastCdmContextImpl : public CastCdmContext {
+ public:
+  explicit CastCdmContextImpl(CastCdm* cast_cdm) : cast_cdm_(cast_cdm) {
+    DCHECK(cast_cdm_);
+  }
+  ~CastCdmContextImpl() override {}
+
+  // CastCdmContext implementation:
+  int RegisterPlayer(const base::Closure& new_key_cb,
+                     const base::Closure& cdm_unset_cb) override  {
+    return cast_cdm_->RegisterPlayer(new_key_cb, cdm_unset_cb);
+  }
+
+  void UnregisterPlayer(int registration_id) override {
+    cast_cdm_->UnregisterPlayer(registration_id);
+  }
+
+  std::unique_ptr<DecryptContextImpl> GetDecryptContext(
+      const std::string& key_id) override {
+    return cast_cdm_->GetDecryptContext(key_id);
+  }
+
+  void SetKeyStatus(const std::string& key_id,
+                    CastKeyStatus key_status,
+                    uint32_t system_code) override {
+    cast_cdm_->SetKeyStatus(key_id, key_status, system_code);
+  }
+
+ private:
+  // The CastCdm object which owns |this|.
+  CastCdm* const cast_cdm_;
+
+  DISALLOW_COPY_AND_ASSIGN(CastCdmContextImpl);
+};
+
+}  // namespace
 
 CastCdm::CastCdm(MediaResourceTracker* media_resource_tracker)
     : media_resource_tracker_(media_resource_tracker),
-      cast_cdm_context_(new CastCdmContext(this)) {
+      cast_cdm_context_(new CastCdmContextImpl(this)) {
   DCHECK(media_resource_tracker);
   thread_checker_.DetachFromThread();
 }
diff --git a/chromecast/media/cdm/cast_cdm_context.cc b/chromecast/media/cdm/cast_cdm_context.cc
index 742516ca..949f5da 100644
--- a/chromecast/media/cdm/cast_cdm_context.cc
+++ b/chromecast/media/cdm/cast_cdm_context.cc
@@ -4,20 +4,9 @@
 
 #include "chromecast/media/cdm/cast_cdm_context.h"
 
-#include "base/logging.h"
-#include "chromecast/media/base/decrypt_context_impl.h"
-#include "chromecast/media/cdm/cast_cdm.h"
-#include "chromecast/public/media/decrypt_context.h"
-
 namespace chromecast {
 namespace media {
 
-CastCdmContext::CastCdmContext(CastCdm* cast_cdm) : cast_cdm_(cast_cdm) {
-  DCHECK(cast_cdm_);
-}
-
-CastCdmContext::~CastCdmContext() {}
-
 ::media::Decryptor* CastCdmContext::GetDecryptor() {
   // Subclasses providing CdmContext for a ClearKey CDM implementation must
   // override this method to provide the Decryptor. Subclasses providing DRM
@@ -30,25 +19,5 @@
   return ::media::CdmContext::kInvalidCdmId;
 }
 
-int CastCdmContext::RegisterPlayer(const base::Closure& new_key_cb,
-                                   const base::Closure& cdm_unset_cb) {
-  return cast_cdm_->RegisterPlayer(new_key_cb, cdm_unset_cb);
-}
-
-void CastCdmContext::UnregisterPlayer(int registration_id) {
-  cast_cdm_->UnregisterPlayer(registration_id);
-}
-
-std::unique_ptr<DecryptContextImpl> CastCdmContext::GetDecryptContext(
-    const std::string& key_id) {
-  return cast_cdm_->GetDecryptContext(key_id);
-}
-
-void CastCdmContext::SetKeyStatus(const std::string& key_id,
-                                  CastKeyStatus key_status,
-                                  uint32_t system_code) {
-  cast_cdm_->SetKeyStatus(key_id, key_status, system_code);
-}
-
 }  // namespace media
 }  // namespace chromecast
diff --git a/chromecast/media/cdm/cast_cdm_context.h b/chromecast/media/cdm/cast_cdm_context.h
index 70fa26ba9..ad98119 100644
--- a/chromecast/media/cdm/cast_cdm_context.h
+++ b/chromecast/media/cdm/cast_cdm_context.h
@@ -11,54 +11,40 @@
 #include "chromecast/public/media/cast_key_status.h"
 #include "media/base/cdm_context.h"
 
-namespace media {
-class Decryptor;
-}
-
 namespace chromecast {
 namespace media {
 
-class CastCdm;
 class DecryptContextImpl;
 
-// This class exposes only what's needed by CastRenderer.
+// CdmContext implementation + some extra APIs needed by CastRenderer.
 class CastCdmContext : public ::media::CdmContext {
  public:
-  explicit CastCdmContext(CastCdm* cast_cdm);
-  ~CastCdmContext() override;
-
   // ::media::CdmContext implementation.
   ::media::Decryptor* GetDecryptor() override;
   int GetCdmId() const override;
 
   // Register a player with this CDM. |new_key_cb| will be called when a new
   // key is available. |cdm_unset_cb| will be called when the CDM is destroyed.
-  int RegisterPlayer(const base::Closure& new_key_cb,
-                     const base::Closure& cdm_unset_cb);
+  virtual int RegisterPlayer(const base::Closure& new_key_cb,
+                             const base::Closure& cdm_unset_cb) = 0;
 
   // Unregiester a player with this CDM. |registration_id| should be the id
   // returned by RegisterPlayer().
-  void UnregisterPlayer(int registration_id);
+  virtual void UnregisterPlayer(int registration_id) = 0;
 
   // Returns the decryption context needed to decrypt frames encrypted with
   // |key_id|. Returns null if |key_id| is not available.
-  std::unique_ptr<DecryptContextImpl> GetDecryptContext(
-      const std::string& key_id);
+  virtual std::unique_ptr<DecryptContextImpl> GetDecryptContext(
+      const std::string& key_id) = 0;
 
   // Notifies that key status has changed (e.g. if expiry is detected by
   // hardware decoder).
-  void SetKeyStatus(const std::string& key_id,
-                    CastKeyStatus key_status,
-                    uint32_t system_code);
-
- private:
-  // The CastCdm object which owns |this|.
-  CastCdm* const cast_cdm_;
-
-  DISALLOW_COPY_AND_ASSIGN(CastCdmContext);
+  virtual void SetKeyStatus(const std::string& key_id,
+                            CastKeyStatus key_status,
+                            uint32_t system_code) = 0;
 };
 
 }  // namespace media
 }  // namespace chromecast
 
-#endif  // CHROMECAST_MEDIA_CDM_CAST_CDM_CONTEXT_H_
\ No newline at end of file
+#endif  // CHROMECAST_MEDIA_CDM_CAST_CDM_CONTEXT_H_
diff --git a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
index 6ea235c..2e186c9 100644
--- a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
+++ b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
@@ -8,6 +8,8 @@
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
+#include "chromecast/media/base/decrypt_context_impl.h"
+#include "chromecast/media/cdm/cast_cdm_context.h"
 #include "chromecast/media/cma/backend/audio_decoder_default.h"
 #include "chromecast/media/cma/backend/media_pipeline_backend_default.h"
 #include "chromecast/media/cma/backend/video_decoder_default.h"
@@ -19,6 +21,7 @@
 #include "media/base/audio_decoder_config.h"
 #include "media/base/media_util.h"
 #include "media/base/video_decoder_config.h"
+#include "media/cdm/player_tracker_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -33,14 +36,98 @@
 namespace chromecast {
 namespace media {
 
-using AudioVideoTuple = ::testing::tuple<bool, bool>;
-
-class AudioVideoPipelineImplTest
-    : public ::testing::TestWithParam<AudioVideoTuple> {
+class CastCdmContextForTest : public CastCdmContext {
  public:
-  AudioVideoPipelineImplTest() : pipeline_backend_(nullptr) {
+  CastCdmContextForTest() : license_installed_(false) {}
+  void SetLicenseInstalled() {
+    license_installed_ = true;
+    player_tracker_.NotifyNewKey();
+  }
+
+  // CastCdmContext implementation:
+  int RegisterPlayer(const base::Closure& new_key_cb,
+                     const base::Closure& cdm_unset_cb) override {
+    return player_tracker_.RegisterPlayer(new_key_cb, cdm_unset_cb);
+  }
+
+  void UnregisterPlayer(int registration_id) override {
+    return player_tracker_.UnregisterPlayer(registration_id);
+  }
+
+  std::unique_ptr<DecryptContextImpl> GetDecryptContext(
+      const std::string& key_id) override {
+    if (license_installed_) {
+      return std::unique_ptr<DecryptContextImpl>(
+          new DecryptContextImpl(KEY_SYSTEM_CLEAR_KEY));
+    } else {
+      return std::unique_ptr<DecryptContextImpl>();
+    }
+  }
+
+  void SetKeyStatus(const std::string& key_id,
+                    CastKeyStatus key_status,
+                    uint32_t system_code) override {}
+
+ private:
+  bool license_installed_;
+  base::Closure new_key_cb_;
+  ::media::PlayerTrackerImpl player_tracker_;
+
+  DISALLOW_COPY_AND_ASSIGN(CastCdmContextForTest);
+};
+
+// Helper class for managing pipeline setup, teardown, feeding data, stop/start
+// etc in a simple API for tests to use.
+class PipelineHelper {
+ public:
+  PipelineHelper(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+                 bool audio,
+                 bool video,
+                 bool encrypted)
+      : have_audio_(audio),
+        have_video_(video),
+        encrypted_(encrypted),
+        pipeline_backend_(nullptr) {
     eos_[STREAM_AUDIO] = eos_[STREAM_VIDEO] = false;
   }
+
+  void Setup() {
+    if (encrypted_) {
+      cdm_context_.reset(new CastCdmContextForTest());
+    }
+    std::unique_ptr<MediaPipelineBackendDefault> backend =
+        base::WrapUnique(new MediaPipelineBackendDefault());
+    pipeline_backend_ = backend.get();
+    media_pipeline_.Initialize(kLoadTypeURL, std::move(backend));
+
+    if (have_audio_) {
+      ::media::AudioDecoderConfig audio_config(
+          ::media::kCodecMP3, ::media::kSampleFormatS16,
+          ::media::CHANNEL_LAYOUT_STEREO, 44100, ::media::EmptyExtraData(),
+          ::media::Unencrypted());
+      AvPipelineClient client;
+      client.eos_cb = base::Bind(&PipelineHelper::OnEos, base::Unretained(this),
+                                 STREAM_AUDIO);
+      ::media::PipelineStatus status = media_pipeline_.InitializeAudio(
+          audio_config, client, CreateFrameProvider());
+      ASSERT_EQ(::media::PIPELINE_OK, status);
+    }
+    if (have_video_) {
+      std::vector<::media::VideoDecoderConfig> video_configs;
+      video_configs.push_back(::media::VideoDecoderConfig(
+          ::media::kCodecH264, ::media::H264PROFILE_MAIN,
+          ::media::PIXEL_FORMAT_I420, ::media::COLOR_SPACE_UNSPECIFIED,
+          gfx::Size(640, 480), gfx::Rect(0, 0, 640, 480), gfx::Size(640, 480),
+          ::media::EmptyExtraData(), ::media::EncryptionScheme()));
+      VideoPipelineClient client;
+      client.av_pipeline_client.eos_cb = base::Bind(
+          &PipelineHelper::OnEos, base::Unretained(this), STREAM_VIDEO);
+      ::media::PipelineStatus status = media_pipeline_.InitializeVideo(
+          video_configs, client, CreateFrameProvider());
+      ASSERT_EQ(::media::PIPELINE_OK, status);
+    }
+  }
+
   void Start(const base::Closure& eos_cb) {
     eos_cb_ = eos_cb;
     eos_[STREAM_AUDIO] = !media_pipeline_.HasAudio();
@@ -48,55 +135,18 @@
     base::TimeDelta start_time = base::TimeDelta::FromMilliseconds(0);
     media_pipeline_.StartPlayingFrom(start_time);
   }
+  void SetCdm() { media_pipeline_.SetCdm(cdm_context_.get()); }
   void Flush(const base::Closure& flush_cb) { media_pipeline_.Flush(flush_cb); }
   void Stop() {
     media_pipeline_.Stop();
     base::MessageLoop::current()->QuitWhenIdle();
   }
+  void SetCdmLicenseInstalled() { cdm_context_->SetLicenseInstalled(); }
 
   MediaPipelineBackendDefault* pipeline_backend() { return pipeline_backend_; }
 
- protected:
-  void SetUp() override {
-    std::unique_ptr<MediaPipelineBackendDefault> backend =
-        base::WrapUnique(new MediaPipelineBackendDefault());
-    pipeline_backend_ = backend.get();
-    media_pipeline_.Initialize(kLoadTypeURL, std::move(backend));
-
-    if (::testing::get<0>(GetParam())) {
-      ::media::AudioDecoderConfig audio_config(
-          ::media::kCodecMP3, ::media::kSampleFormatS16,
-          ::media::CHANNEL_LAYOUT_STEREO, 44100, ::media::EmptyExtraData(),
-          ::media::Unencrypted());
-      AvPipelineClient client;
-      client.eos_cb = base::Bind(&AudioVideoPipelineImplTest::OnEos,
-                                 base::Unretained(this), STREAM_AUDIO);
-      ::media::PipelineStatus status = media_pipeline_.InitializeAudio(
-          audio_config, client, CreateFrameProvider());
-      ASSERT_EQ(::media::PIPELINE_OK, status);
-    }
-    if (::testing::get<1>(GetParam())) {
-      std::vector<::media::VideoDecoderConfig> video_configs;
-      video_configs.push_back(::media::VideoDecoderConfig(
-          ::media::kCodecH264, ::media::H264PROFILE_MAIN,
-          ::media::PIXEL_FORMAT_I420, ::media::COLOR_SPACE_UNSPECIFIED,
-          gfx::Size(640, 480), gfx::Rect(0, 0, 640, 480), gfx::Size(640, 480),
-          ::media::EmptyExtraData(), ::media::Unencrypted()));
-      VideoPipelineClient client;
-      client.av_pipeline_client.eos_cb =
-          base::Bind(&AudioVideoPipelineImplTest::OnEos, base::Unretained(this),
-                     STREAM_VIDEO);
-      ::media::PipelineStatus status = media_pipeline_.InitializeVideo(
-          video_configs, client, CreateFrameProvider());
-      ASSERT_EQ(::media::PIPELINE_OK, status);
-    }
-  }
-
-  base::MessageLoop message_loop_;
-
  private:
   enum Stream { STREAM_AUDIO, STREAM_VIDEO };
-  DISALLOW_COPY_AND_ASSIGN(AudioVideoPipelineImplTest);
 
   std::unique_ptr<CodedFrameProvider> CreateFrameProvider() {
     std::vector<FrameGeneratorForTest::FrameSpec> frame_specs;
@@ -106,7 +156,7 @@
       frame_specs[k].timestamp =
           base::TimeDelta::FromMicroseconds(kFrameDurationUs) * k;
       frame_specs[k].size = kFrameSize;
-      frame_specs[k].has_decrypt_config = false;
+      frame_specs[k].has_decrypt_config = encrypted_;
     }
     frame_specs[frame_specs.size() - 1].is_eos = true;
 
@@ -129,15 +179,42 @@
       eos_cb_.Run();
   }
 
+  bool have_audio_;
+  bool have_video_;
+  bool encrypted_;
   bool eos_[2];
   base::Closure eos_cb_;
   MediaPipelineImpl media_pipeline_;
+  std::unique_ptr<CastCdmContextForTest> cdm_context_;
   MediaPipelineBackendDefault* pipeline_backend_;
+
+  DISALLOW_COPY_AND_ASSIGN(PipelineHelper);
 };
 
-static void VerifyPlay(AudioVideoPipelineImplTest* pipeline_test) {
+using AudioVideoTuple = ::testing::tuple<bool, bool>;
+
+class AudioVideoPipelineImplTest
+    : public ::testing::TestWithParam<AudioVideoTuple> {
+ public:
+  AudioVideoPipelineImplTest() {}
+
+ protected:
+  void SetUp() override {
+    pipeline_helper_.reset(new PipelineHelper(
+        message_loop_.task_runner(), ::testing::get<0>(GetParam()),
+        ::testing::get<1>(GetParam()), false));
+    pipeline_helper_->Setup();
+  }
+
+  base::MessageLoop message_loop_;
+  std::unique_ptr<PipelineHelper> pipeline_helper_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioVideoPipelineImplTest);
+};
+
+static void VerifyPlay(PipelineHelper* pipeline_helper) {
   // The backend must still be running.
-  MediaPipelineBackendDefault* backend = pipeline_test->pipeline_backend();
+  MediaPipelineBackendDefault* backend = pipeline_helper->pipeline_backend();
   EXPECT_TRUE(backend->running());
 
   // The decoders must have received a few frames.
@@ -149,20 +226,22 @@
   if (video_decoder)
     EXPECT_EQ(kLastFrameTimestamp, video_decoder->last_push_pts());
 
-  pipeline_test->Stop();
+  pipeline_helper->Stop();
 }
 
 TEST_P(AudioVideoPipelineImplTest, Play) {
-  base::Closure verify_task = base::Bind(&VerifyPlay, base::Unretained(this));
-  message_loop_.PostTask(FROM_HERE,
-                         base::Bind(&AudioVideoPipelineImplTest::Start,
-                                    base::Unretained(this), verify_task));
+  base::Closure verify_task =
+      base::Bind(&VerifyPlay, base::Unretained(pipeline_helper_.get()));
+  message_loop_.PostTask(
+      FROM_HERE,
+      base::Bind(&PipelineHelper::Start,
+                 base::Unretained(pipeline_helper_.get()), verify_task));
   message_loop_.Run();
 }
 
-static void VerifyFlush(AudioVideoPipelineImplTest* pipeline_test) {
+static void VerifyFlush(PipelineHelper* pipeline_helper) {
   // The backend must have been stopped.
-  MediaPipelineBackendDefault* backend = pipeline_test->pipeline_backend();
+  MediaPipelineBackendDefault* backend = pipeline_helper->pipeline_backend();
   EXPECT_FALSE(backend->running());
 
   // The decoders must not have received any frame.
@@ -174,7 +253,7 @@
   if (video_decoder)
     EXPECT_LT(video_decoder->last_push_pts(), 0);
 
-  pipeline_test->Stop();
+  pipeline_helper->Stop();
 }
 
 static void VerifyNotReached() {
@@ -182,27 +261,30 @@
 }
 
 TEST_P(AudioVideoPipelineImplTest, Flush) {
-  base::Closure verify_task = base::Bind(&VerifyFlush, base::Unretained(this));
+  base::Closure verify_task =
+      base::Bind(&VerifyFlush, base::Unretained(pipeline_helper_.get()));
+  message_loop_.PostTask(FROM_HERE,
+                         base::Bind(&PipelineHelper::Start,
+                                    base::Unretained(pipeline_helper_.get()),
+                                    base::Bind(&VerifyNotReached)));
   message_loop_.PostTask(
       FROM_HERE,
-      base::Bind(&AudioVideoPipelineImplTest::Start, base::Unretained(this),
-                 base::Bind(&VerifyNotReached)));
-  message_loop_.PostTask(FROM_HERE,
-                         base::Bind(&AudioVideoPipelineImplTest::Flush,
-                                    base::Unretained(this), verify_task));
+      base::Bind(&PipelineHelper::Flush,
+                 base::Unretained(pipeline_helper_.get()), verify_task));
 
   message_loop_.Run();
 }
 
 TEST_P(AudioVideoPipelineImplTest, FullCycle) {
-  base::Closure stop_task =
-      base::Bind(&AudioVideoPipelineImplTest::Stop, base::Unretained(this));
-  base::Closure eos_cb = base::Bind(&AudioVideoPipelineImplTest::Flush,
-                                    base::Unretained(this), stop_task);
+  base::Closure stop_task = base::Bind(
+      &PipelineHelper::Stop, base::Unretained(pipeline_helper_.get()));
+  base::Closure eos_cb =
+      base::Bind(&PipelineHelper::Flush,
+                 base::Unretained(pipeline_helper_.get()), stop_task);
 
-  message_loop_.PostTask(FROM_HERE,
-                         base::Bind(&AudioVideoPipelineImplTest::Start,
-                                    base::Unretained(this), eos_cb));
+  message_loop_.PostTask(
+      FROM_HERE, base::Bind(&PipelineHelper::Start,
+                            base::Unretained(pipeline_helper_.get()), eos_cb));
   message_loop_.Run();
 };
 
@@ -214,5 +296,79 @@
                       AudioVideoTuple(false, true),   // Video only.
                       AudioVideoTuple(true, true)));  // Audio and Video.
 
+// These tests verify that the pipeline handles encrypted media playback
+// events (in particular, CDM and license installation) correctly.
+class EncryptedAVPipelineImplTest : public ::testing::Test {
+ public:
+  EncryptedAVPipelineImplTest() {}
+
+ protected:
+  void SetUp() override {
+    pipeline_helper_.reset(
+        new PipelineHelper(message_loop_.task_runner(), true, true, true));
+    pipeline_helper_->Setup();
+  }
+
+  base::MessageLoop message_loop_;
+  std::unique_ptr<PipelineHelper> pipeline_helper_;
+
+  DISALLOW_COPY_AND_ASSIGN(EncryptedAVPipelineImplTest);
+};
+
+// Sets a CDM with license already installed before starting the pipeline.
+TEST_F(EncryptedAVPipelineImplTest, SetCdmWithLicenseBeforeStart) {
+  base::Closure verify_task =
+      base::Bind(&VerifyPlay, base::Unretained(pipeline_helper_.get()));
+  message_loop_.PostTask(FROM_HERE,
+                         base::Bind(&PipelineHelper::SetCdm,
+                                    base::Unretained(pipeline_helper_.get())));
+  message_loop_.PostTask(FROM_HERE,
+                         base::Bind(&PipelineHelper::SetCdmLicenseInstalled,
+                                    base::Unretained(pipeline_helper_.get())));
+  message_loop_.PostTask(
+      FROM_HERE,
+      base::Bind(&PipelineHelper::Start,
+                 base::Unretained(pipeline_helper_.get()), verify_task));
+  message_loop_.Run();
+}
+
+// Start the pipeline, then set a CDM with existing license.
+TEST_F(EncryptedAVPipelineImplTest, SetCdmWithLicenseAfterStart) {
+  base::Closure verify_task =
+      base::Bind(&VerifyPlay, base::Unretained(pipeline_helper_.get()));
+  message_loop_.PostTask(
+      FROM_HERE,
+      base::Bind(&PipelineHelper::Start,
+                 base::Unretained(pipeline_helper_.get()), verify_task));
+
+  message_loop_.RunUntilIdle();
+  message_loop_.PostTask(FROM_HERE,
+                         base::Bind(&PipelineHelper::SetCdmLicenseInstalled,
+                                    base::Unretained(pipeline_helper_.get())));
+  message_loop_.PostTask(FROM_HERE,
+                         base::Bind(&PipelineHelper::SetCdm,
+                                    base::Unretained(pipeline_helper_.get())));
+  message_loop_.Run();
+}
+
+// Start the pipeline, set a CDM, and then install the license.
+TEST_F(EncryptedAVPipelineImplTest, SetCdmAndInstallLicenseAfterStart) {
+  base::Closure verify_task =
+      base::Bind(&VerifyPlay, base::Unretained(pipeline_helper_.get()));
+  message_loop_.PostTask(
+      FROM_HERE,
+      base::Bind(&PipelineHelper::Start,
+                 base::Unretained(pipeline_helper_.get()), verify_task));
+  message_loop_.PostTask(FROM_HERE,
+                         base::Bind(&PipelineHelper::SetCdm,
+                                    base::Unretained(pipeline_helper_.get())));
+
+  message_loop_.RunUntilIdle();
+  message_loop_.PostTask(FROM_HERE,
+                         base::Bind(&PipelineHelper::SetCdmLicenseInstalled,
+                                    base::Unretained(pipeline_helper_.get())));
+  message_loop_.Run();
+}
+
 }  // namespace media
 }  // namespace chromecast
diff --git a/chromeos/settings/timezone_settings.cc b/chromeos/settings/timezone_settings.cc
index b8ce973c..dcc9eda 100644
--- a/chromeos/settings/timezone_settings.cc
+++ b/chromeos/settings/timezone_settings.cc
@@ -223,7 +223,8 @@
 
   std::string timezone(buf, len);
   // Remove kTimezoneFilesDir from the beginning.
-  if (timezone.find(kTimezoneFilesDir) != 0) {
+  if (!base::StartsWith(timezone, kTimezoneFilesDir,
+                        base::CompareCase::SENSITIVE)) {
     LOG(ERROR) << "GetTimezoneID: Timezone symlink is wrong "
                << timezone;
     return std::string();
diff --git a/components/BUILD.gn b/components/BUILD.gn
index abf71d07..75b05aa7 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -483,6 +483,7 @@
       "scheduler/base/task_queue_manager_delegate_for_test.cc",
       "scheduler/base/task_queue_manager_delegate_for_test.h",
       "scheduler/base/task_queue_manager_perftest.cc",
+      "scheduler/base/test_task_time_tracker.h",
       "visitedlink/test/visitedlink_perftest.cc",
     ]
 
diff --git a/components/arc/common/app.mojom b/components/arc/common/app.mojom
index f9aed0b..d3d3039 100644
--- a/components/arc/common/app.mojom
+++ b/components/arc/common/app.mojom
@@ -9,6 +9,14 @@
 import "scale_factor.mojom";
 import "screen_rect.mojom";
 
+// Describes OrientationLock request.
+[Extensible]
+enum OrientationLock {
+  NONE = 0,
+  PORTRAIT = 1,
+  LANDSCAPE = 2,
+};
+
 // Describes ARC app.
 struct AppInfo {
   string name;
@@ -16,6 +24,7 @@
   string activity;
   [MinVersion=2] bool sticky;  // true if the app cannot be uninstalled
   [MinVersion=7] bool notifications_enabled;
+  [MinVersion=11] OrientationLock orientation_lock;
 };
 
 // Describes ARC package.
@@ -46,7 +55,7 @@
   MANAGE_LINKS = 1,
 };
 
-// Next method ID: 12
+// Next method ID: 13
 interface AppHost {
   // Sends newly added ARC app to Chrome. This message is sent when ARC receives
   // package added notification. Multiple apps may be added in the one package.
@@ -96,6 +105,10 @@
 
   // Notifies that an application shortcut needs to be created.
   [MinVersion=9] OnInstallShortcut@11(ShortcutInfo shortcut);
+
+  // Notifies that task requested orientation lock.
+  [MinVersion=11] OnTaskOrientationLockRequested@12(int32 task_id,
+                                                    OrientationLock lock);
 };
 
 // TODO(lhchavez): Migrate all request/response messages to Mojo.
diff --git a/components/arc/common/video.mojom b/components/arc/common/video.mojom
index b371d6d..8b859af 100644
--- a/components/arc/common/video.mojom
+++ b/components/arc/common/video.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Next MinVersion: 4
+// Next MinVersion: 5
 
 module arc.mojom;
 
@@ -23,7 +23,7 @@
   // Requests an IPC channel from Chrome's browser process to bootstrap a new
   // mojo child process and a token which can be used to create a message pipe
   // connected to a new VideoAcceleratorFactory.
-  [MinVersion=3]
+  [MinVersion=4]
   OnBootstrapVideoAcceleratorFactory@1() => (handle channel_handle,
                                              string token);
 };
diff --git a/components/arc/common/video_accelerator.mojom b/components/arc/common/video_accelerator.mojom
index 6a581dd..2cb1abd 100644
--- a/components/arc/common/video_accelerator.mojom
+++ b/components/arc/common/video_accelerator.mojom
@@ -49,6 +49,11 @@
   uint32 input_pixel_format;
 };
 
+struct ArcVideoAcceleratorDmabufPlane {
+  int32 offset;
+  int32 stride;
+};
+
 interface VideoAcceleratorService {
   enum Result {
     SUCCESS = 0,
@@ -69,7 +74,12 @@
   BindSharedMemory@1(PortType port, uint32 index, handle ashmem_fd,
                      uint32 offset, uint32 length);
 
-  BindDmabuf@2(PortType port, uint32 index, handle dmabuf_fd, int32 stride);
+  DeprecatedBindDmabuf@2(PortType port, uint32 index, handle dmabuf_fd,
+                         int32 stride);
+
+  [MinVersion=3]
+  BindDmabuf@9(PortType port, uint32 index, handle dmabuf_fd,
+               array<ArcVideoAcceleratorDmabufPlane> dmabuf_planes);
 
   UseBuffer@3(PortType port, uint32 index, BufferMetadata metadata);
 
diff --git a/components/autofill/content/browser/risk/fingerprint.cc b/components/autofill/content/browser/risk/fingerprint.cc
index 08ed54e..67d4847 100644
--- a/components/autofill/content/browser/risk/fingerprint.cc
+++ b/components/autofill/content/browser/risk/fingerprint.cc
@@ -66,7 +66,11 @@
   base::Time::Exploded local;
   utc.LocalExplode(&local);
 
-  return base::Time::FromUTCExploded(local) - utc;
+  base::Time out_time;
+  bool conversion_success = base::Time::FromUTCExploded(local, &out_time);
+  DCHECK(conversion_success);
+
+  return out_time - utc;
 }
 
 // Returns the concatenation of the operating system name and version, e.g.
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index 1254112a..44cee7f 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -120,10 +120,8 @@
     std::vector<base::string16> parts = base::SplitString(
         prefix, base::ASCIIToUTF16(","), base::TRIM_WHITESPACE,
         base::SPLIT_WANT_ALL);
-    if (!parts.empty()) {
-      base::TrimWhitespace(parts[parts.size() - 1], base::TRIM_LEADING,
-                           &prefix);
-    }
+    if (!parts.empty())
+      base::TrimWhitespace(parts.back(), base::TRIM_LEADING, &prefix);
   }
 
   // Prefix filtering.
@@ -500,7 +498,7 @@
       }
     }
     last_part.append(suggested_value);
-    parts[parts.size() - 1] = last_part;
+    parts.back() = last_part;
 
     new_value = base::JoinString(parts, base::ASCIIToUTF16(","));
   }
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h
index e6863f34..1fa267a1 100644
--- a/components/autofill/content/renderer/autofill_agent.h
+++ b/components/autofill/content/renderer/autofill_agent.h
@@ -59,6 +59,11 @@
 
   void BindRequest(mojom::AutofillAgentRequest request);
 
+ protected:
+  // blink::WebAutofillClient:
+  void didAssociateFormControls(
+      const blink::WebVector<blink::WebNode>& nodes) override;
+
  private:
   // Functor used as a simplified comparison function for FormData. Only
   // compares forms at a high level (notably name, origin, action).
@@ -156,8 +161,6 @@
       const blink::WebInputElement& element,
       const blink::WebKeyboardEvent& event) override;
   void setIgnoreTextChanges(bool ignore) override;
-  void didAssociateFormControls(
-      const blink::WebVector<blink::WebNode>& nodes) override;
   void openTextDataListChooser(const blink::WebInputElement& element) override;
   void dataListOptionsChanged(const blink::WebInputElement& element) override;
   void firstUserGestureObserved() override;
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index 61bcd71..4306f8c3 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -448,10 +448,7 @@
     encoded_signatures->push_back(signature);
   }
 
-  if (!encoded_signatures->size())
-    return false;
-
-  return true;
+  return !encoded_signatures->empty();
 }
 
 // static
diff --git a/components/cast_certificate/cast_cert_validator.cc b/components/cast_certificate/cast_cert_validator.cc
index 6a81c84d..ec1fae2e 100644
--- a/components/cast_certificate/cast_cert_validator.cc
+++ b/components/cast_certificate/cast_cert_validator.cc
@@ -13,15 +13,16 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/memory/singleton.h"
+#include "net/cert/internal/cert_issuer_source_static.h"
 #include "net/cert/internal/certificate_policies.h"
 #include "net/cert/internal/extended_key_usage.h"
 #include "net/cert/internal/parse_certificate.h"
 #include "net/cert/internal/parse_name.h"
 #include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/path_builder.h"
 #include "net/cert/internal/signature_algorithm.h"
 #include "net/cert/internal/signature_policy.h"
 #include "net/cert/internal/trust_store.h"
-#include "net/cert/internal/verify_certificate_chain.h"
 #include "net/cert/internal/verify_signed_data.h"
 #include "net/der/input.h"
 
@@ -245,20 +246,6 @@
   return result;
 }
 
-class ScopedCheckUnreferencedCerts {
- public:
-  explicit ScopedCheckUnreferencedCerts(
-      std::vector<scoped_refptr<net::ParsedCertificate>>* certs)
-      : certs_(certs) {}
-  ~ScopedCheckUnreferencedCerts() {
-    for (const auto& cert : *certs_)
-      DCHECK(cert->HasOneRef());
-  }
-
- private:
-  std::vector<scoped_refptr<net::ParsedCertificate>>* certs_;
-};
-
 // Returns the parsing options used for Cast certificates.
 net::ParseCertificateOptions GetCertParsingOptions() {
   net::ParseCertificateOptions options;
@@ -281,38 +268,46 @@
                       const base::Time::Exploded& time,
                       std::unique_ptr<CertVerificationContext>* context,
                       CastDeviceCertPolicy* policy) {
-  // The underlying verification function expects a sequence of
-  // ParsedCertificate.
-  std::vector<scoped_refptr<net::ParsedCertificate>> input_chain;
-  // Verify that nothing saves a reference to the input certs, since the backing
-  // data will go out of scope when the function finishes.
-  ScopedCheckUnreferencedCerts ref_checker(&input_chain);
+  if (certs.empty())
+    return false;
 
-  for (const auto& cert_der : certs) {
-    // No reference to the ParsedCertificate is kept past the end of this
-    // function, so using EXTERNAL_REFERENCE here is safe.
-    if (!net::ParsedCertificate::CreateAndAddToVector(
-            reinterpret_cast<const uint8_t*>(cert_der.data()), cert_der.size(),
+  // No reference to these ParsedCertificates is kept past the end of this
+  // function, so using EXTERNAL_REFERENCE here is safe.
+  scoped_refptr<net::ParsedCertificate> target_cert;
+  net::CertIssuerSourceStatic intermediate_cert_issuer_source;
+  for (size_t i = 0; i < certs.size(); ++i) {
+    scoped_refptr<net::ParsedCertificate> cert(
+        net::ParsedCertificate::CreateFromCertificateData(
+            reinterpret_cast<const uint8_t*>(certs[i].data()), certs[i].size(),
             net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE,
-            GetCertParsingOptions(), &input_chain)) {
+            GetCertParsingOptions()));
+    if (!cert)
       return false;
-    }
+
+    if (i == 0)
+      target_cert = std::move(cert);
+    else
+      intermediate_cert_issuer_source.AddCert(std::move(cert));
   }
 
   // Use a signature policy compatible with Cast's PKI.
   auto signature_policy = CreateCastSignaturePolicy();
 
-  // Do RFC 5280 compatible certificate verification using the two Cast
-  // trust anchors and Cast signature policy.
-  if (!net::VerifyCertificateChain(input_chain, CastTrustStore::Get(),
-                                   signature_policy.get(),
-                                   ConvertExplodedTime(time), nullptr)) {
+  // Do path building and RFC 5280 compatible certificate verification using the
+  // two Cast trust anchors and Cast signature policy.
+  net::CertPathBuilder::Result result;
+  net::CertPathBuilder path_builder(target_cert.get(), &CastTrustStore::Get(),
+                                    signature_policy.get(),
+                                    ConvertExplodedTime(time), &result);
+  path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source);
+  net::CompletionStatus rv = path_builder.Run(base::Closure());
+  DCHECK_EQ(rv, net::CompletionStatus::SYNC);
+  if (!result.is_success())
     return false;
-  }
 
   // Check properties of the leaf certificate (key usage, policy), and construct
   // a CertVerificationContext that uses its public key.
-  return CheckTargetCertificate(input_chain[0].get(), context, policy);
+  return CheckTargetCertificate(target_cert.get(), context, policy);
 }
 
 std::unique_ptr<CertVerificationContext> CertVerificationContextImplForTest(
diff --git a/components/cast_certificate/cast_cert_validator.h b/components/cast_certificate/cast_cert_validator.h
index 1c335ae..23378cb 100644
--- a/components/cast_certificate/cast_cert_validator.h
+++ b/components/cast_certificate/cast_cert_validator.h
@@ -54,9 +54,9 @@
 // Inputs:
 //
 // * |certs| is a chain of DER-encoded certificates:
-//   * |certs[0]| is the target certificate (i.e. the device certificate)
-//   * |certs[i]| is the certificate that issued certs[i-1]
-//   * |certs.back()| must be signed by a trust anchor
+//   * |certs[0]| is the target certificate (i.e. the device certificate).
+//   * |certs[1..n-1]| are intermediates certificates to use in path building.
+//     Their ordering does not matter.
 //
 // * |time| is the UTC time to use for determining if the certificate
 //   is expired.
diff --git a/components/certificate_transparency.gypi b/components/certificate_transparency.gypi
index 00a6e96..cfdfe4b 100644
--- a/components/certificate_transparency.gypi
+++ b/components/certificate_transparency.gypi
@@ -13,6 +13,7 @@
       ],
       'dependencies': [
         '../base/base.gyp:base',
+        '../components/components.gyp:base32',
         '../components/components.gyp:safe_json',
         '../components/components.gyp:url_matcher',
         '../components/prefs/prefs.gyp:prefs',
@@ -23,6 +24,8 @@
       'sources': [
         'certificate_transparency/ct_policy_manager.cc',
         'certificate_transparency/ct_policy_manager.h',
+        'certificate_transparency/log_dns_client.h',
+        'certificate_transparency/log_dns_client.cc',
         'certificate_transparency/log_proof_fetcher.h',
         'certificate_transparency/log_proof_fetcher.cc',
         'certificate_transparency/pref_names.cc',
diff --git a/components/certificate_transparency/BUILD.gn b/components/certificate_transparency/BUILD.gn
index 15cb99f..3bba1a1 100644
--- a/components/certificate_transparency/BUILD.gn
+++ b/components/certificate_transparency/BUILD.gn
@@ -6,6 +6,8 @@
   sources = [
     "ct_policy_manager.cc",
     "ct_policy_manager.h",
+    "log_dns_client.cc",
+    "log_dns_client.h",
     "log_proof_fetcher.cc",
     "log_proof_fetcher.h",
     "pref_names.cc",
@@ -18,6 +20,7 @@
 
   deps = [
     "//base",
+    "//components/base32",
     "//components/prefs",
     "//components/safe_json",
     "//components/url_formatter",
@@ -31,6 +34,7 @@
   testonly = true
   sources = [
     "ct_policy_manager_unittest.cc",
+    "log_dns_client_unittest.cc",
     "log_proof_fetcher_unittest.cc",
     "single_tree_tracker_unittest.cc",
   ]
@@ -41,6 +45,7 @@
     "//components/prefs:test_support",
     "//components/safe_json:test_support",
     "//net:test_support",
+    "//testing/gmock",
     "//testing/gtest",
   ]
 }
diff --git a/components/certificate_transparency/DEPS b/components/certificate_transparency/DEPS
index b3d5f275..575b1501 100644
--- a/components/certificate_transparency/DEPS
+++ b/components/certificate_transparency/DEPS
@@ -1,7 +1,9 @@
 include_rules = [
+  "+components/base32",
   "+components/prefs",
   "+components/safe_json",
   "+components/url_formatter",
   "+components/url_matcher",
+  "+crypto",
   "+net",
 ]
diff --git a/components/certificate_transparency/log_dns_client.cc b/components/certificate_transparency/log_dns_client.cc
new file mode 100644
index 0000000..77da9f8
--- /dev/null
+++ b/components/certificate_transparency/log_dns_client.cc
@@ -0,0 +1,294 @@
+// 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 "components/certificate_transparency/log_dns_client.h"
+
+#include <sstream>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/base32/base32.h"
+#include "crypto/sha2.h"
+#include "net/base/net_errors.h"
+#include "net/cert/merkle_audit_proof.h"
+#include "net/dns/dns_client.h"
+#include "net/dns/dns_protocol.h"
+#include "net/dns/dns_response.h"
+#include "net/dns/dns_transaction.h"
+#include "net/dns/record_parsed.h"
+#include "net/dns/record_rdata.h"
+
+namespace certificate_transparency {
+
+namespace {
+
+bool ParseTxtResponse(const net::DnsResponse& response, std::string* txt) {
+  DCHECK(txt);
+
+  net::DnsRecordParser parser = response.Parser();
+  // We don't care about the creation time, since we're going to throw
+  // |parsed_record| away as soon as we've extracted the payload, so provide
+  // the "null" time.
+  auto parsed_record = net::RecordParsed::CreateFrom(&parser, base::Time());
+  if (parsed_record == nullptr)
+    return false;
+
+  auto txt_record = parsed_record->rdata<net::TxtRecordRdata>();
+  if (txt_record == nullptr)
+    return false;
+
+  *txt = base::JoinString(txt_record->texts(), "");
+  return true;
+}
+
+bool ParseLeafIndex(const net::DnsResponse& response, uint64_t* index) {
+  DCHECK(index);
+
+  std::string index_str;
+  if (!ParseTxtResponse(response, &index_str))
+    return false;
+
+  return base::StringToUint64(index_str, index);
+}
+
+bool ParseAuditPath(const net::DnsResponse& response,
+                    net::ct::MerkleAuditProof* proof) {
+  DCHECK(proof);
+
+  std::string audit_path;
+  if (!ParseTxtResponse(response, &audit_path))
+    return false;
+  // If empty or not a multiple of the node size, it is considered invalid.
+  // It's important to consider empty audit paths as invalid, as otherwise an
+  // infinite loop could occur if the server consistently returned empty
+  // responses.
+  if (audit_path.empty() || audit_path.size() % crypto::kSHA256Length != 0)
+    return false;
+
+  for (size_t i = 0; i < audit_path.size(); i += crypto::kSHA256Length) {
+    proof->nodes.push_back(audit_path.substr(i, crypto::kSHA256Length));
+  }
+
+  return true;
+}
+
+}  // namespace
+
+LogDnsClient::LogDnsClient(std::unique_ptr<net::DnsClient> dns_client,
+                           const net::BoundNetLog& net_log)
+    : dns_client_(std::move(dns_client)),
+      net_log_(net_log),
+      weak_ptr_factory_(this) {
+  CHECK(dns_client_);
+}
+
+LogDnsClient::~LogDnsClient() {}
+
+void LogDnsClient::QueryLeafIndex(base::StringPiece domain_for_log,
+                                  base::StringPiece leaf_hash,
+                                  const LeafIndexCallback& callback) {
+  if (domain_for_log.empty() || leaf_hash.size() != crypto::kSHA256Length) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, 0));
+    return;
+  }
+
+  std::string encoded_leaf_hash =
+      base32::Base32Encode(leaf_hash, base32::Base32EncodePolicy::OMIT_PADDING);
+  DCHECK_EQ(encoded_leaf_hash.size(), 52u);
+
+  net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory();
+  if (factory == nullptr) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(callback, net::Error::ERR_NAME_RESOLUTION_FAILED, 0));
+    return;
+  }
+
+  std::ostringstream qname;
+  qname << encoded_leaf_hash << ".hash." << domain_for_log << ".";
+
+  net::DnsTransactionFactory::CallbackType transaction_callback = base::Bind(
+      &LogDnsClient::QueryLeafIndexComplete, weak_ptr_factory_.GetWeakPtr());
+
+  std::unique_ptr<net::DnsTransaction> dns_transaction =
+      factory->CreateTransaction(qname.str(), net::dns_protocol::kTypeTXT,
+                                 transaction_callback, net_log_);
+
+  dns_transaction->Start();
+  leaf_index_queries_.push_back({std::move(dns_transaction), callback});
+}
+
+// The performance of this could be improved by sending all of the expected
+// queries up front. Each response can contain a maximum of 7 audit path nodes,
+// so for an audit proof of size 20, it could send 3 queries (for nodes 0-6,
+// 7-13 and 14-19) immediately. Currently, it sends only the first and then,
+// based on the number of nodes received, sends the next query. The complexity
+// of the code would increase though, as it would need to detect gaps in the
+// audit proof caused by the server not responding with the anticipated number
+// of nodes. Ownership of the proof would need to change, as it would be shared
+// between simultaneous DNS transactions.
+void LogDnsClient::QueryAuditProof(base::StringPiece domain_for_log,
+                                   uint64_t leaf_index,
+                                   uint64_t tree_size,
+                                   const AuditProofCallback& callback) {
+  if (domain_for_log.empty() || leaf_index >= tree_size) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(callback, net::Error::ERR_INVALID_ARGUMENT, nullptr));
+    return;
+  }
+
+  std::unique_ptr<net::ct::MerkleAuditProof> proof(
+      new net::ct::MerkleAuditProof);
+  proof->leaf_index = leaf_index;
+  // TODO(robpercival): Once a "tree_size" field is added to MerkleAuditProof,
+  // pass |tree_size| to QueryAuditProofNodes using that.
+
+  // Query for the first batch of audit proof nodes (i.e. starting from 0).
+  QueryAuditProofNodes(std::move(proof), domain_for_log, tree_size, 0,
+                       callback);
+}
+
+void LogDnsClient::QueryLeafIndexComplete(net::DnsTransaction* transaction,
+                                          int net_error,
+                                          const net::DnsResponse* response) {
+  auto query_iterator =
+      std::find_if(leaf_index_queries_.begin(), leaf_index_queries_.end(),
+                   [transaction](const Query<LeafIndexCallback>& query) {
+                     return query.transaction.get() == transaction;
+                   });
+  if (query_iterator == leaf_index_queries_.end()) {
+    NOTREACHED();
+    return;
+  }
+  const Query<LeafIndexCallback> query = std::move(*query_iterator);
+  leaf_index_queries_.erase(query_iterator);
+
+  // If we've received no response but no net::error either (shouldn't happen),
+  // report the response as invalid.
+  if (response == nullptr && net_error == net::OK) {
+    net_error = net::ERR_INVALID_RESPONSE;
+  }
+
+  if (net_error != net::OK) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(query.callback, net_error, 0));
+    return;
+  }
+
+  uint64_t leaf_index;
+  if (!ParseLeafIndex(*response, &leaf_index)) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(query.callback, net::ERR_DNS_MALFORMED_RESPONSE, 0));
+    return;
+  }
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(query.callback, net::OK, leaf_index));
+}
+
+void LogDnsClient::QueryAuditProofNodes(
+    std::unique_ptr<net::ct::MerkleAuditProof> proof,
+    base::StringPiece domain_for_log,
+    uint64_t tree_size,
+    uint64_t node_index,
+    const AuditProofCallback& callback) {
+  // Preconditions that should be guaranteed internally by this class.
+  DCHECK(proof);
+  DCHECK(!domain_for_log.empty());
+  DCHECK_LT(proof->leaf_index, tree_size);
+  DCHECK_LT(node_index,
+            net::ct::CalculateAuditPathLength(proof->leaf_index, tree_size));
+
+  net::DnsTransactionFactory* factory = dns_client_->GetTransactionFactory();
+  if (factory == nullptr) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(callback, net::Error::ERR_NAME_RESOLUTION_FAILED, nullptr));
+    return;
+  }
+
+  std::ostringstream qname;
+  qname << node_index << "." << proof->leaf_index << "." << tree_size
+        << ".tree." << domain_for_log << ".";
+
+  net::DnsTransactionFactory::CallbackType transaction_callback =
+      base::Bind(&LogDnsClient::QueryAuditProofNodesComplete,
+                 weak_ptr_factory_.GetWeakPtr(), base::Passed(std::move(proof)),
+                 domain_for_log, tree_size);
+
+  std::unique_ptr<net::DnsTransaction> dns_transaction =
+      factory->CreateTransaction(qname.str(), net::dns_protocol::kTypeTXT,
+                                 transaction_callback, net_log_);
+  dns_transaction->Start();
+  audit_proof_queries_.push_back({std::move(dns_transaction), callback});
+}
+
+void LogDnsClient::QueryAuditProofNodesComplete(
+    std::unique_ptr<net::ct::MerkleAuditProof> proof,
+    base::StringPiece domain_for_log,
+    uint64_t tree_size,
+    net::DnsTransaction* transaction,
+    int net_error,
+    const net::DnsResponse* response) {
+  // Preconditions that should be guaranteed internally by this class.
+  DCHECK(proof);
+  DCHECK(!domain_for_log.empty());
+
+  auto query_iterator =
+      std::find_if(audit_proof_queries_.begin(), audit_proof_queries_.end(),
+                   [transaction](const Query<AuditProofCallback>& query) {
+                     return query.transaction.get() == transaction;
+                   });
+
+  if (query_iterator == audit_proof_queries_.end()) {
+    NOTREACHED();
+    return;
+  }
+  const Query<AuditProofCallback> query = std::move(*query_iterator);
+  audit_proof_queries_.erase(query_iterator);
+
+  // If we've received no response but no net::error either (shouldn't happen),
+  // report the response as invalid.
+  if (response == nullptr && net_error == net::OK) {
+    net_error = net::ERR_INVALID_RESPONSE;
+  }
+
+  if (net_error != net::OK) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(query.callback, net_error, nullptr));
+    return;
+  }
+
+  const uint64_t audit_path_length =
+      net::ct::CalculateAuditPathLength(proof->leaf_index, tree_size);
+  proof->nodes.reserve(audit_path_length);
+
+  if (!ParseAuditPath(*response, proof.get())) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(query.callback, net::ERR_DNS_MALFORMED_RESPONSE, nullptr));
+    return;
+  }
+
+  const uint64_t audit_path_nodes_received = proof->nodes.size();
+  if (audit_path_nodes_received < audit_path_length) {
+    QueryAuditProofNodes(std::move(proof), domain_for_log, tree_size,
+                         audit_path_nodes_received, query.callback);
+    return;
+  }
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(query.callback, net::OK, base::Passed(std::move(proof))));
+}
+
+}  // namespace certificate_transparency
diff --git a/components/certificate_transparency/log_dns_client.h b/components/certificate_transparency/log_dns_client.h
new file mode 100644
index 0000000..e00cefd
--- /dev/null
+++ b/components/certificate_transparency/log_dns_client.h
@@ -0,0 +1,120 @@
+// 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 COMPONENTS_CERTIFICATE_TRANSPARENCY_LOG_DNS_CLIENT_H_
+#define COMPONENTS_CERTIFICATE_TRANSPARENCY_LOG_DNS_CLIENT_H_
+
+#include <stdint.h>
+
+#include <list>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "net/log/net_log.h"
+
+namespace net {
+class DnsClient;
+class DnsResponse;
+class DnsTransaction;
+namespace ct {
+struct MerkleAuditProof;
+}  // namespace ct
+}  // namespace net
+
+namespace certificate_transparency {
+
+// Queries Certificate Transparency (CT) log servers via DNS.
+// All queries are performed asynchronously.
+// For more information, see
+// https://github.com/google/certificate-transparency-rfcs/blob/master/dns/draft-ct-over-dns.md.
+class LogDnsClient {
+ public:
+  // Invoked when a leaf index query completes.
+  // If an error occured, |net_error| will be a net::Error code, otherwise it
+  // will be net::OK and |leaf_index| will be the leaf index that was received.
+  using LeafIndexCallback =
+      base::Callback<void(int net_error, uint64_t leaf_index)>;
+  // Invoked when an audit proof query completes.
+  // If an error occurred, |net_error| will be a net::Error code, otherwise it
+  // will be net::OK and |proof| will be the audit proof that was received.
+  // The log ID of |proof| will not be set, as that is not known by this class,
+  // but the leaf index will be set.
+  using AuditProofCallback =
+      base::Callback<void(int net_error,
+                          std::unique_ptr<net::ct::MerkleAuditProof> proof)>;
+
+  // Creates a log client that will take ownership of |dns_client| and use it
+  // to perform DNS queries. Queries will be logged to |net_log|.
+  LogDnsClient(std::unique_ptr<net::DnsClient> dns_client,
+               const net::BoundNetLog& net_log);
+  virtual ~LogDnsClient();
+
+  // Queries a CT log to discover the index of the leaf with |leaf_hash|.
+  // The log is identified by |domain_for_log|, which is the DNS name used as a
+  // suffix for all queries.
+  // The |leaf_hash| is the SHA-256 hash of a Merkle tree leaf in that log.
+  // The |callback| is invoked when the query is complete, or an error occurs.
+  void QueryLeafIndex(base::StringPiece domain_for_log,
+                      base::StringPiece leaf_hash,
+                      const LeafIndexCallback& callback);
+
+  // Queries a CT log to retrieve an audit proof for the leaf at |leaf_index|.
+  // The size of the CT log tree must be provided in |tree_size|.
+  // The log is identified by |domain_for_log|, which is the DNS name used as a
+  // suffix for all queries.
+  // The |callback| is invoked when the query is complete, or an error occurs.
+  void QueryAuditProof(base::StringPiece domain_for_log,
+                       uint64_t leaf_index,
+                       uint64_t tree_size,
+                       const AuditProofCallback& callback);
+
+ private:
+  void QueryLeafIndexComplete(net::DnsTransaction* transaction,
+                              int neterror,
+                              const net::DnsResponse* response);
+
+  // Queries a CT log to retrieve part of an audit |proof|. The |node_index|
+  // indicates which node of the audit proof/ should be requested. The CT log
+  // may return up to 7 nodes, starting from |node_index| (this is the maximum
+  // that will fit in a DNS UDP packet). The nodes will be appended to
+  // |proof->nodes|.
+  void QueryAuditProofNodes(std::unique_ptr<net::ct::MerkleAuditProof> proof,
+                            base::StringPiece domain_for_log,
+                            uint64_t tree_size,
+                            uint64_t node_index,
+                            const AuditProofCallback& callback);
+
+  void QueryAuditProofNodesComplete(
+      std::unique_ptr<net::ct::MerkleAuditProof> proof,
+      base::StringPiece domain_for_log,
+      uint64_t tree_size,
+      net::DnsTransaction* transaction,
+      int net_error,
+      const net::DnsResponse* response);
+
+  // A DNS query that is in flight.
+  template <typename CallbackType>
+  struct Query {
+    std::unique_ptr<net::DnsTransaction> transaction;
+    CallbackType callback;
+  };
+
+  // Used to perform DNS queries.
+  std::unique_ptr<net::DnsClient> dns_client_;
+  // Passed to the DNS client for logging.
+  net::BoundNetLog net_log_;
+  // Leaf index queries that haven't completed yet.
+  std::list<Query<LeafIndexCallback>> leaf_index_queries_;
+  // Audit proof queries that haven't completed yet.
+  std::list<Query<AuditProofCallback>> audit_proof_queries_;
+  // Creates weak_ptrs to this, for callback purposes.
+  base::WeakPtrFactory<LogDnsClient> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(LogDnsClient);
+};
+
+}  // namespace certificate_transparency
+#endif  // COMPONENTS_CERTIFICATE_TRANSPARENCY_LOG_DNS_CLIENT_H_
diff --git a/components/certificate_transparency/log_dns_client_unittest.cc b/components/certificate_transparency/log_dns_client_unittest.cc
new file mode 100644
index 0000000..d8f11da
--- /dev/null
+++ b/components/certificate_transparency/log_dns_client_unittest.cc
@@ -0,0 +1,746 @@
+// 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 "components/certificate_transparency/log_dns_client.h"
+
+#include <algorithm>
+#include <numeric>
+#include <utility>
+#include <vector>
+
+#include "base/big_endian.h"
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/sys_byteorder.h"
+#include "base/test/test_timeouts.h"
+#include "crypto/sha2.h"
+#include "net/base/net_errors.h"
+#include "net/cert/merkle_audit_proof.h"
+#include "net/cert/merkle_tree_leaf.h"
+#include "net/cert/signed_certificate_timestamp.h"
+#include "net/dns/dns_client.h"
+#include "net/dns/dns_config_service.h"
+#include "net/dns/dns_protocol.h"
+#include "net/log/net_log.h"
+#include "net/socket/socket_test_util.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace certificate_transparency {
+namespace {
+
+using ::testing::IsNull;
+using ::testing::NotNull;
+using net::test::IsError;
+using net::test::IsOk;
+
+constexpr char kLeafHash[] =
+    "\x1f\x25\xe1\xca\xba\x4f\xf9\xb8\x27\x24\x83\x0f\xca\x60\xe4\xc2\xbe\xa8"
+    "\xc3\xa9\x44\x1c\x27\xb0\xb4\x3e\x6a\x96\x94\xc7\xb8\x04";
+
+// Always return min, to simplify testing.
+// This should result in the DNS query ID always being 0.
+int FakeRandInt(int min, int max) {
+  return min;
+}
+
+std::vector<char> CreateDnsTxtRequest(base::StringPiece qname) {
+  std::string encoded_qname;
+  EXPECT_TRUE(net::DNSDomainFromDot(qname, &encoded_qname));
+
+  const size_t query_section_size = encoded_qname.size() + 4;
+
+  std::vector<char> request(sizeof(net::dns_protocol::Header) +
+                            query_section_size);
+  base::BigEndianWriter writer(request.data(), request.size());
+
+  // Header
+  net::dns_protocol::Header header = {};
+  header.flags = base::HostToNet16(net::dns_protocol::kFlagRD);
+  header.qdcount = base::HostToNet16(1);
+  EXPECT_TRUE(writer.WriteBytes(&header, sizeof(header)));
+  // Query section
+  EXPECT_TRUE(writer.WriteBytes(encoded_qname.data(), encoded_qname.size()));
+  EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kTypeTXT));
+  EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kClassIN));
+  EXPECT_EQ(0, writer.remaining());
+
+  return request;
+}
+
+std::vector<char> CreateDnsTxtResponse(const std::vector<char>& request,
+                                       base::StringPiece answer) {
+  const size_t answers_section_size = 12 + answer.size();
+  constexpr uint32_t ttl = 86400;  // seconds
+
+  std::vector<char> response(request.size() + answers_section_size);
+  std::copy(request.begin(), request.end(), response.begin());
+  // Modify the header
+  net::dns_protocol::Header* header =
+      reinterpret_cast<net::dns_protocol::Header*>(response.data());
+  header->ancount = base::HostToNet16(1);
+  header->flags |= base::HostToNet16(net::dns_protocol::kFlagResponse);
+
+  // Write the answer section
+  base::BigEndianWriter writer(response.data() + request.size(),
+                               response.size() - request.size());
+  EXPECT_TRUE(writer.WriteU8(0xc0));  // qname is a pointer
+  EXPECT_TRUE(writer.WriteU8(
+      sizeof(*header)));  // address of qname (start of query section)
+  EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kTypeTXT));
+  EXPECT_TRUE(writer.WriteU16(net::dns_protocol::kClassIN));
+  EXPECT_TRUE(writer.WriteU32(ttl));
+  EXPECT_TRUE(writer.WriteU16(answer.size()));
+  EXPECT_TRUE(writer.WriteBytes(answer.data(), answer.size()));
+  EXPECT_EQ(0, writer.remaining());
+
+  return response;
+}
+
+std::vector<char> CreateDnsErrorResponse(const std::vector<char>& request,
+                                         uint8_t rcode) {
+  std::vector<char> response(request);
+  // Modify the header
+  net::dns_protocol::Header* header =
+      reinterpret_cast<net::dns_protocol::Header*>(response.data());
+  header->ancount = base::HostToNet16(1);
+  header->flags |= base::HostToNet16(net::dns_protocol::kFlagResponse | rcode);
+
+  return response;
+}
+
+std::vector<std::string> GetSampleAuditProof(size_t length) {
+  std::vector<std::string> audit_proof(length);
+  // Makes each node of the audit proof different, so that tests are able to
+  // confirm that the audit proof is reconstructed in the correct order.
+  for (size_t i = 0; i < length; ++i) {
+    std::string node(crypto::kSHA256Length, '\0');
+    // Each node is 32 bytes, with each byte having a different value.
+    for (size_t j = 0; j < crypto::kSHA256Length; ++j) {
+      node[j] = static_cast<char>((-127 + i + j) % 128);
+    }
+    audit_proof[i].assign(std::move(node));
+  }
+
+  return audit_proof;
+}
+
+class MockLeafIndexCallback {
+ public:
+  MockLeafIndexCallback() : called_(false) {}
+
+  bool called() const { return called_; }
+  int net_error() const { return net_error_; }
+  uint64_t leaf_index() const { return leaf_index_; }
+
+  void Run(int net_error, uint64_t leaf_index) {
+    EXPECT_TRUE(!called_);
+    called_ = true;
+    net_error_ = net_error;
+    leaf_index_ = leaf_index;
+    run_loop_.Quit();
+  }
+
+  LogDnsClient::LeafIndexCallback AsCallback() {
+    return base::Bind(&MockLeafIndexCallback::Run, base::Unretained(this));
+  }
+
+  void WaitUntilRun() { run_loop_.Run(); }
+
+ private:
+  bool called_;
+  int net_error_;
+  uint64_t leaf_index_;
+  base::RunLoop run_loop_;
+};
+
+class MockAuditProofCallback {
+ public:
+  MockAuditProofCallback() : called_(false) {}
+
+  bool called() const { return called_; }
+  int net_error() const { return net_error_; }
+  const net::ct::MerkleAuditProof* proof() const { return proof_.get(); }
+
+  void Run(int net_error, std::unique_ptr<net::ct::MerkleAuditProof> proof) {
+    EXPECT_TRUE(!called_);
+    called_ = true;
+    net_error_ = net_error;
+    proof_ = std::move(proof);
+    run_loop_.Quit();
+  }
+
+  LogDnsClient::AuditProofCallback AsCallback() {
+    return base::Bind(&MockAuditProofCallback::Run, base::Unretained(this));
+  }
+
+  void WaitUntilRun() { run_loop_.Run(); }
+
+ private:
+  bool called_;
+  int net_error_;
+  std::unique_ptr<net::ct::MerkleAuditProof> proof_;
+  base::RunLoop run_loop_;
+};
+
+// A container for all of the data we need to keep alive for a mock socket.
+// This is useful because Mock{Read,Write}, SequencedSocketData and
+// MockClientSocketFactory all do not take ownership of or copy their arguments,
+// so we have to manage the lifetime of those arguments ourselves. Wrapping all
+// of that up in a single class simplifies this.
+class MockSocketData {
+ public:
+  // A socket that expects one write and one read operation.
+  MockSocketData(const std::vector<char>& write, const std::vector<char>& read)
+      : expected_write_payload_(write),
+        expected_read_payload_(read),
+        expected_write_(net::SYNCHRONOUS,
+                        expected_write_payload_.data(),
+                        expected_write_payload_.size(),
+                        0),
+        expected_reads_{net::MockRead(net::ASYNC,
+                                      expected_read_payload_.data(),
+                                      expected_read_payload_.size(),
+                                      1),
+                        eof_},
+        socket_data_(expected_reads_, 2, &expected_write_, 1) {}
+
+  // A socket that expects one write and a read error.
+  MockSocketData(const std::vector<char>& write, int net_error)
+      : expected_write_payload_(write),
+        expected_write_(net::SYNCHRONOUS,
+                        expected_write_payload_.data(),
+                        expected_write_payload_.size(),
+                        0),
+        expected_reads_{net::MockRead(net::ASYNC, net_error, 1), eof_},
+        socket_data_(expected_reads_, 2, &expected_write_, 1) {}
+
+  // A socket that expects one write and no response.
+  explicit MockSocketData(const std::vector<char>& write)
+      : expected_write_payload_(write),
+        expected_write_(net::SYNCHRONOUS,
+                        expected_write_payload_.data(),
+                        expected_write_payload_.size(),
+                        0),
+        expected_reads_{net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING, 1),
+                        eof_},
+        socket_data_(expected_reads_, 2, &expected_write_, 1) {}
+
+  void SetWriteMode(net::IoMode mode) { expected_write_.mode = mode; }
+  void SetReadMode(net::IoMode mode) { expected_reads_[0].mode = mode; }
+
+  void AddToFactory(net::MockClientSocketFactory* socket_factory) {
+    socket_factory->AddSocketDataProvider(&socket_data_);
+  }
+
+ private:
+  // Prevents read overruns and makes a socket timeout the default behaviour.
+  static const net::MockRead eof_;
+
+  const std::vector<char> expected_write_payload_;
+  const std::vector<char> expected_read_payload_;
+  // Encapsulates the data that is expected to be written to a socket.
+  net::MockWrite expected_write_;
+  // Encapsulates the data/error that should be returned when reading from a
+  // socket. The expected response is followed by |eof_|, to catch further,
+  // unexpected read attempts.
+  net::MockRead expected_reads_[2];
+  net::SequencedSocketData socket_data_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockSocketData);
+};
+
+const net::MockRead MockSocketData::eof_(net::SYNCHRONOUS,
+                                         net::ERR_IO_PENDING,
+                                         2);
+
+class LogDnsClientTest : public ::testing::TestWithParam<net::IoMode> {
+ protected:
+  LogDnsClientTest() {
+    // Use an invalid nameserver address. This prevents the tests accidentally
+    // sending real DNS queries. The mock sockets don't care that the address
+    // is invalid.
+    dns_config_.nameservers.push_back(net::IPEndPoint());
+    // Don't attempt retransmissions - just fail.
+    dns_config_.attempts = 1;
+    // This ensures timeouts are long enough for memory tests.
+    dns_config_.timeout = TestTimeouts::action_timeout();
+    // Simplify testing - don't require random numbers for the source port.
+    // This means our FakeRandInt function should only be called to get query
+    // IDs.
+    dns_config_.randomize_ports = false;
+  }
+
+  void ExpectRequestAndErrorResponse(base::StringPiece qname, uint8_t rcode) {
+    std::vector<char> request = CreateDnsTxtRequest(qname);
+    std::vector<char> response = CreateDnsErrorResponse(request, rcode);
+
+    mock_socket_data_.emplace_back(new MockSocketData(request, response));
+    mock_socket_data_.back()->SetReadMode(GetParam());
+    mock_socket_data_.back()->AddToFactory(&socket_factory_);
+  }
+
+  void ExpectRequestAndSocketError(base::StringPiece qname, int net_error) {
+    std::vector<char> request = CreateDnsTxtRequest(qname);
+
+    mock_socket_data_.emplace_back(new MockSocketData(request, net_error));
+    mock_socket_data_.back()->SetReadMode(GetParam());
+    mock_socket_data_.back()->AddToFactory(&socket_factory_);
+  }
+
+  void ExpectRequestAndTimeout(base::StringPiece qname) {
+    std::vector<char> request = CreateDnsTxtRequest(qname);
+
+    mock_socket_data_.emplace_back(new MockSocketData(request));
+    mock_socket_data_.back()->SetReadMode(GetParam());
+    mock_socket_data_.back()->AddToFactory(&socket_factory_);
+
+    // Speed up timeout tests.
+    dns_config_.timeout = TestTimeouts::tiny_timeout();
+  }
+
+  void ExpectLeafIndexRequestAndResponse(base::StringPiece qname,
+                                         base::StringPiece leaf_index) {
+    // Prepend size to leaf_index to create the query answer (rdata)
+    ASSERT_LE(leaf_index.size(), 0xFFul);  // size must fit into a single byte
+    std::string answer = leaf_index.as_string();
+    answer.insert(answer.begin(), static_cast<char>(leaf_index.size()));
+
+    ExpectRequestAndResponse(qname, answer);
+  }
+
+  void ExpectAuditProofRequestAndResponse(
+      base::StringPiece qname,
+      std::vector<std::string>::const_iterator audit_path_start,
+      std::vector<std::string>::const_iterator audit_path_end) {
+    // Join nodes in the audit path into a single string.
+    std::string proof =
+        std::accumulate(audit_path_start, audit_path_end, std::string());
+
+    // Prepend size to proof to create the query answer (rdata)
+    ASSERT_LE(proof.size(), 0xFFul);  // size must fit into a single byte
+    proof.insert(proof.begin(), static_cast<char>(proof.size()));
+
+    ExpectRequestAndResponse(qname, proof);
+  }
+
+  void QueryLeafIndex(base::StringPiece log_domain,
+                      base::StringPiece leaf_hash,
+                      MockLeafIndexCallback* callback) {
+    std::unique_ptr<net::DnsClient> dns_client = CreateDnsClient();
+    LogDnsClient log_client(std::move(dns_client), net::BoundNetLog());
+
+    log_client.QueryLeafIndex(log_domain, leaf_hash, callback->AsCallback());
+    callback->WaitUntilRun();
+  }
+
+  void QueryAuditProof(base::StringPiece log_domain,
+                       uint64_t leaf_index,
+                       uint64_t tree_size,
+                       MockAuditProofCallback* callback) {
+    std::unique_ptr<net::DnsClient> dns_client = CreateDnsClient();
+    LogDnsClient log_client(std::move(dns_client), net::BoundNetLog());
+
+    log_client.QueryAuditProof(log_domain, leaf_index, tree_size,
+                               callback->AsCallback());
+    callback->WaitUntilRun();
+  }
+
+ private:
+  std::unique_ptr<net::DnsClient> CreateDnsClient() {
+    std::unique_ptr<net::DnsClient> client =
+        net::DnsClient::CreateClientForTesting(nullptr, &socket_factory_,
+                                               base::Bind(&FakeRandInt));
+    client->SetConfig(dns_config_);
+    return client;
+  }
+
+  void ExpectRequestAndResponse(base::StringPiece qname,
+                                base::StringPiece answer) {
+    std::vector<char> request = CreateDnsTxtRequest(qname);
+    std::vector<char> response = CreateDnsTxtResponse(request, answer);
+
+    mock_socket_data_.emplace_back(new MockSocketData(request, response));
+    mock_socket_data_.back()->SetReadMode(GetParam());
+    mock_socket_data_.back()->AddToFactory(&socket_factory_);
+  }
+
+  net::DnsConfig dns_config_;
+  base::MessageLoopForIO message_loop_;
+  std::vector<std::unique_ptr<MockSocketData>> mock_socket_data_;
+  net::MockClientSocketFactory socket_factory_;
+};
+
+TEST_P(LogDnsClientTest, QueryLeafIndex) {
+  ExpectLeafIndexRequestAndResponse(
+      "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+      "123456");
+
+  MockLeafIndexCallback callback;
+  QueryLeafIndex("ct.test", kLeafHash, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsOk());
+  EXPECT_THAT(callback.leaf_index(), 123456);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsThatLogDomainDoesNotExist) {
+  ExpectRequestAndErrorResponse(
+      "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+      net::dns_protocol::kRcodeNXDOMAIN);
+
+  MockLeafIndexCallback callback;
+  QueryLeafIndex("ct.test", kLeafHash, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_NAME_NOT_RESOLVED));
+  EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsServerFailure) {
+  ExpectRequestAndErrorResponse(
+      "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+      net::dns_protocol::kRcodeSERVFAIL);
+
+  MockLeafIndexCallback callback;
+  QueryLeafIndex("ct.test", kLeafHash, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_SERVER_FAILED));
+  EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsServerRefusal) {
+  ExpectRequestAndErrorResponse(
+      "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+      net::dns_protocol::kRcodeREFUSED);
+
+  MockLeafIndexCallback callback;
+  QueryLeafIndex("ct.test", kLeafHash, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_SERVER_FAILED));
+  EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest,
+       QueryLeafIndexReportsMalformedResponseIfLeafIndexIsNotNumeric) {
+  ExpectLeafIndexRequestAndResponse(
+      "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+      "foo");
+
+  MockLeafIndexCallback callback;
+  QueryLeafIndex("ct.test", kLeafHash, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+  EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest,
+       QueryLeafIndexReportsMalformedResponseIfLeafIndexIsFloatingPoint) {
+  ExpectLeafIndexRequestAndResponse(
+      "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+      "123456.0");
+
+  MockLeafIndexCallback callback;
+  QueryLeafIndex("ct.test", kLeafHash, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+  EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest,
+       QueryLeafIndexReportsMalformedResponseIfLeafIndexIsEmpty) {
+  ExpectLeafIndexRequestAndResponse(
+      "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.", "");
+
+  MockLeafIndexCallback callback;
+  QueryLeafIndex("ct.test", kLeafHash, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+  EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest,
+       QueryLeafIndexReportsMalformedResponseIfLeafIndexHasNonNumericPrefix) {
+  ExpectLeafIndexRequestAndResponse(
+      "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+      "foo123456");
+
+  MockLeafIndexCallback callback;
+  QueryLeafIndex("ct.test", kLeafHash, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+  EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest,
+       QueryLeafIndexReportsMalformedResponseIfLeafIndexHasNonNumericSuffix) {
+  ExpectLeafIndexRequestAndResponse(
+      "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+      "123456foo");
+
+  MockLeafIndexCallback callback;
+  QueryLeafIndex("ct.test", kLeafHash, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+  EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLogDomainIsEmpty) {
+  MockLeafIndexCallback callback;
+  QueryLeafIndex("", kLeafHash, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+  EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLogDomainIsNull) {
+  MockLeafIndexCallback callback;
+  QueryLeafIndex(nullptr, kLeafHash, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+  EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsInvalid) {
+  MockLeafIndexCallback callback;
+  QueryLeafIndex("ct.test", "foo", &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+  EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsEmpty) {
+  MockLeafIndexCallback callback;
+  QueryLeafIndex("ct.test", "", &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+  EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsInvalidArgIfLeafHashIsNull) {
+  MockLeafIndexCallback callback;
+  QueryLeafIndex("ct.test", nullptr, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+  EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsSocketError) {
+  ExpectRequestAndSocketError(
+      "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.",
+      net::ERR_CONNECTION_REFUSED);
+
+  MockLeafIndexCallback callback;
+  QueryLeafIndex("ct.test", kLeafHash, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_CONNECTION_REFUSED));
+  EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryLeafIndexReportsTimeout) {
+  ExpectRequestAndTimeout(
+      "D4S6DSV2J743QJZEQMH4UYHEYK7KRQ5JIQOCPMFUHZVJNFGHXACA.hash.ct.test.");
+
+  MockLeafIndexCallback callback;
+  QueryLeafIndex("ct.test", kLeafHash, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_TIMED_OUT));
+  EXPECT_THAT(callback.leaf_index(), 0);
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProof) {
+  const std::vector<std::string> audit_proof = GetSampleAuditProof(20);
+
+  // It should require 3 queries to collect the entire audit proof, as there is
+  // only space for 7 nodes per UDP packet.
+  ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
+                                     audit_proof.begin(),
+                                     audit_proof.begin() + 7);
+  ExpectAuditProofRequestAndResponse("7.123456.999999.tree.ct.test.",
+                                     audit_proof.begin() + 7,
+                                     audit_proof.begin() + 14);
+  ExpectAuditProofRequestAndResponse("14.123456.999999.tree.ct.test.",
+                                     audit_proof.begin() + 14,
+                                     audit_proof.end());
+
+  MockAuditProofCallback callback;
+  QueryAuditProof("ct.test", 123456, 999999, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsOk());
+  ASSERT_THAT(callback.proof(), NotNull());
+  EXPECT_THAT(callback.proof()->leaf_index, 123456);
+  // EXPECT_THAT(callback.proof()->tree_size, 999999);
+  EXPECT_THAT(callback.proof()->nodes, audit_proof);
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofHandlesResponsesWithShortAuditPaths) {
+  const std::vector<std::string> audit_proof = GetSampleAuditProof(20);
+
+  // Make some of the responses contain fewer proof nodes than they can hold.
+  ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
+                                     audit_proof.begin(),
+                                     audit_proof.begin() + 1);
+  ExpectAuditProofRequestAndResponse("1.123456.999999.tree.ct.test.",
+                                     audit_proof.begin() + 1,
+                                     audit_proof.begin() + 3);
+  ExpectAuditProofRequestAndResponse("3.123456.999999.tree.ct.test.",
+                                     audit_proof.begin() + 3,
+                                     audit_proof.begin() + 6);
+  ExpectAuditProofRequestAndResponse("6.123456.999999.tree.ct.test.",
+                                     audit_proof.begin() + 6,
+                                     audit_proof.begin() + 10);
+  ExpectAuditProofRequestAndResponse("10.123456.999999.tree.ct.test.",
+                                     audit_proof.begin() + 10,
+                                     audit_proof.begin() + 13);
+  ExpectAuditProofRequestAndResponse("13.123456.999999.tree.ct.test.",
+                                     audit_proof.begin() + 13,
+                                     audit_proof.end());
+
+  MockAuditProofCallback callback;
+  QueryAuditProof("ct.test", 123456, 999999, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsOk());
+  ASSERT_THAT(callback.proof(), NotNull());
+  EXPECT_THAT(callback.proof()->leaf_index, 123456);
+  // EXPECT_THAT(callback.proof()->tree_size, 999999);
+  EXPECT_THAT(callback.proof()->nodes, audit_proof);
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsThatLogDomainDoesNotExist) {
+  ExpectRequestAndErrorResponse("0.123456.999999.tree.ct.test.",
+                                net::dns_protocol::kRcodeNXDOMAIN);
+
+  MockAuditProofCallback callback;
+  QueryAuditProof("ct.test", 123456, 999999, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_NAME_NOT_RESOLVED));
+  EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsServerFailure) {
+  ExpectRequestAndErrorResponse("0.123456.999999.tree.ct.test.",
+                                net::dns_protocol::kRcodeSERVFAIL);
+
+  MockAuditProofCallback callback;
+  QueryAuditProof("ct.test", 123456, 999999, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_SERVER_FAILED));
+  EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsServerRefusal) {
+  ExpectRequestAndErrorResponse("0.123456.999999.tree.ct.test.",
+                                net::dns_protocol::kRcodeREFUSED);
+
+  MockAuditProofCallback callback;
+  QueryAuditProof("ct.test", 123456, 999999, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_SERVER_FAILED));
+  EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest,
+       QueryAuditProofReportsResponseMalformedIfNodeTooShort) {
+  // node is shorter than a SHA-256 hash (31 vs 32 bytes)
+  const std::vector<std::string> audit_proof(1, std::string(31, 'a'));
+
+  ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
+                                     audit_proof.begin(), audit_proof.end());
+
+  MockAuditProofCallback callback;
+  QueryAuditProof("ct.test", 123456, 999999, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+  EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsResponseMalformedIfNodeTooLong) {
+  // node is longer than a SHA-256 hash (33 vs 32 bytes)
+  const std::vector<std::string> audit_proof(1, std::string(33, 'a'));
+
+  ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
+                                     audit_proof.begin(), audit_proof.end());
+
+  MockAuditProofCallback callback;
+  QueryAuditProof("ct.test", 123456, 999999, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+  EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsResponseMalformedIfEmpty) {
+  const std::vector<std::string> audit_proof;
+
+  ExpectAuditProofRequestAndResponse("0.123456.999999.tree.ct.test.",
+                                     audit_proof.begin(), audit_proof.end());
+
+  MockAuditProofCallback callback;
+  QueryAuditProof("ct.test", 123456, 999999, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_MALFORMED_RESPONSE));
+  EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsInvalidArgIfLogDomainIsEmpty) {
+  MockAuditProofCallback callback;
+  QueryAuditProof("", 123456, 999999, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+  EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsInvalidArgIfLogDomainIsNull) {
+  MockAuditProofCallback callback;
+  QueryAuditProof(nullptr, 123456, 999999, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+  EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest,
+       QueryAuditProofReportsInvalidArgIfLeafIndexEqualToTreeSize) {
+  MockAuditProofCallback callback;
+  QueryAuditProof("ct.test", 123456, 123456, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+  EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest,
+       QueryAuditProofReportsInvalidArgIfLeafIndexGreaterThanTreeSize) {
+  MockAuditProofCallback callback;
+  QueryAuditProof("ct.test", 999999, 123456, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_INVALID_ARGUMENT));
+  EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsSocketError) {
+  ExpectRequestAndSocketError("0.123456.999999.tree.ct.test.",
+                              net::ERR_CONNECTION_REFUSED);
+
+  MockAuditProofCallback callback;
+  QueryAuditProof("ct.test", 123456, 999999, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_CONNECTION_REFUSED));
+  EXPECT_THAT(callback.proof(), IsNull());
+}
+
+TEST_P(LogDnsClientTest, QueryAuditProofReportsTimeout) {
+  ExpectRequestAndTimeout("0.123456.999999.tree.ct.test.");
+
+  MockAuditProofCallback callback;
+  QueryAuditProof("ct.test", 123456, 999999, &callback);
+  ASSERT_TRUE(callback.called());
+  EXPECT_THAT(callback.net_error(), IsError(net::ERR_DNS_TIMED_OUT));
+  EXPECT_THAT(callback.proof(), IsNull());
+}
+
+INSTANTIATE_TEST_CASE_P(ReadMode,
+                        LogDnsClientTest,
+                        ::testing::Values(net::IoMode::ASYNC,
+                                          net::IoMode::SYNCHRONOUS));
+
+}  // namespace
+}  // namespace certificate_transparency
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 1830d850..50759fe 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -116,6 +116,7 @@
     ],
     'certificate_transparency_unittest_sources': [
       'certificate_transparency/ct_policy_manager_unittest.cc',
+      'certificate_transparency/log_dns_client_unittest.cc',
       'certificate_transparency/log_proof_fetcher_unittest.cc',
       'certificate_transparency/single_tree_tracker_unittest.cc',
     ],
@@ -630,7 +631,6 @@
       'proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc',
       'proximity_auth/ble/bluetooth_low_energy_device_whitelist_unittest.cc',
       'proximity_auth/ble/bluetooth_low_energy_weave_packet_generator_unittest.cc',
-      'proximity_auth/ble/bluetooth_low_energy_weave_packet_receiver_unittest.cc',
       'proximity_auth/bluetooth_connection_finder_unittest.cc',
       'proximity_auth/bluetooth_connection_unittest.cc',
       'proximity_auth/bluetooth_throttler_impl_unittest.cc',
@@ -708,7 +708,6 @@
       'safe_browsing_db/v4_database_unittest.cc',
       'safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc',
       'safe_browsing_db/v4_protocol_manager_util_unittest.cc',
-      'safe_browsing_db/v4_store_unittest.cc',
       'safe_browsing_db/v4_update_protocol_manager_unittest.cc',
     ],
     'safe_json_unittest_sources': [
@@ -716,12 +715,14 @@
       'safe_json/testing_json_parser_unittest.cc',
     ],
     'scheduler_unittest_sources': [
+      'scheduler/base/queueing_time_estimator_unittest.cc',
       'scheduler/base/task_queue_manager_delegate_for_test.cc',
       'scheduler/base/task_queue_manager_delegate_for_test.h',
       'scheduler/base/task_queue_manager_unittest.cc',
       'scheduler/base/task_queue_selector_unittest.cc',
-      'scheduler/base/test_always_fail_time_source.cc',
-      'scheduler/base/test_always_fail_time_source.h',
+      'scheduler/base/test_count_uses_time_source.cc',
+      'scheduler/base/test_count_uses_time_source.h',
+      'scheduler/base/test_task_time_tracker.h',
       'scheduler/base/test_time_source.cc',
       'scheduler/base/test_time_source.h',
       'scheduler/base/time_domain_unittest.cc',
@@ -883,8 +884,6 @@
       'tracing/browser/trace_config_file_unittest.cc',
       'tracing/common/graphics_memory_dump_provider_android_unittest.cc',
       'tracing/common/process_metrics_memory_dump_provider_unittest.cc',
-      'tracing/core/trace_ring_buffer_unittest.cc',
-      'tracing/core/scattered_stream_writer_unittest.cc',
     ],
     'translate_unittest_sources': [
       'translate/core/browser/language_state_unittest.cc',
@@ -1881,6 +1880,7 @@
            'scheduler/base/task_queue_manager_delegate_for_test.cc',
            'scheduler/base/task_queue_manager_delegate_for_test.h',
            'scheduler/base/task_queue_manager_perftest.cc',
+           'scheduler/base/test_task_time_tracker.h',
            'visitedlink/test/visitedlink_perftest.cc',
          ],
          'conditions': [
diff --git a/components/content_settings/core/browser/host_content_settings_map.cc b/components/content_settings/core/browser/host_content_settings_map.cc
index 6b56ae6..3dbb4f5 100644
--- a/components/content_settings/core/browser/host_content_settings_map.cc
+++ b/components/content_settings/core/browser/host_content_settings_map.cc
@@ -497,6 +497,73 @@
   }
 }
 
+void HostContentSettingsMap::MigrateDomainScopedSettings() {
+  const ContentSettingsType kDomainScopedTypes[] = {
+      CONTENT_SETTINGS_TYPE_COOKIES,
+      CONTENT_SETTINGS_TYPE_IMAGES,
+      CONTENT_SETTINGS_TYPE_PLUGINS,
+      CONTENT_SETTINGS_TYPE_JAVASCRIPT,
+      CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
+      CONTENT_SETTINGS_TYPE_POPUPS};
+  for (const ContentSettingsType& type : kDomainScopedTypes) {
+    if (!content_settings::ContentSettingsRegistry::GetInstance()->Get(type))
+      continue;
+    ContentSettingsForOneType settings;
+    GetSettingsForOneType(type, std::string(), &settings);
+
+    for (const ContentSettingPatternSource& setting_entry : settings) {
+      // Migrate user preference settings only.
+      if (setting_entry.source != "preference")
+        continue;
+      // Migrate ALLOW settings only.
+      if (setting_entry.setting != CONTENT_SETTING_ALLOW)
+        continue;
+      // Skip default settings.
+      if (setting_entry.primary_pattern == ContentSettingsPattern::Wildcard())
+        continue;
+
+      if (setting_entry.secondary_pattern !=
+          ContentSettingsPattern::Wildcard()) {
+        NOTREACHED();
+        continue;
+      }
+
+      ContentSettingsPattern origin_pattern;
+      if (!ContentSettingsPattern::MigrateFromDomainToOrigin(
+              setting_entry.primary_pattern, &origin_pattern)) {
+        continue;
+      }
+
+      if (!origin_pattern.IsValid())
+        continue;
+
+      GURL origin(origin_pattern.ToString());
+      DCHECK(origin.is_valid());
+
+      // Ensure that the current resolved content setting for this origin is
+      // allowed. Otherwise we may be overriding some narrower setting which is
+      // set to block.
+      ContentSetting origin_setting =
+          GetContentSetting(origin, origin, type, std::string());
+
+      // Remove the domain scoped pattern. If |origin_setting| is not
+      // CONTENT_SETTING_ALLOW it implies there is some narrower pattern in
+      // effect, so it's still safe to remove the domain-scoped pattern.
+      SetContentSettingCustomScope(setting_entry.primary_pattern,
+                                   setting_entry.secondary_pattern, type,
+                                   std::string(), CONTENT_SETTING_DEFAULT);
+
+      // If the current resolved content setting is allowed it's safe to set the
+      // origin-scoped pattern.
+      if (origin_setting == CONTENT_SETTING_ALLOW)
+        SetContentSettingCustomScope(
+            ContentSettingsPattern::FromURLNoWildcard(origin),
+            ContentSettingsPattern::Wildcard(), type, std::string(),
+            CONTENT_SETTING_ALLOW);
+    }
+  }
+}
+
 void HostContentSettingsMap::RecordNumberOfExceptions() {
   for (const content_settings::WebsiteSettingsInfo* info :
        *content_settings::WebsiteSettingsRegistry::GetInstance()) {
diff --git a/components/content_settings/core/browser/host_content_settings_map.h b/components/content_settings/core/browser/host_content_settings_map.h
index ec33722e..9115c2836 100644
--- a/components/content_settings/core/browser/host_content_settings_map.h
+++ b/components/content_settings/core/browser/host_content_settings_map.h
@@ -280,6 +280,7 @@
 
  private:
   friend class base::RefCountedThreadSafe<HostContentSettingsMap>;
+  friend class HostContentSettingsMapTest_MigrateDomainScopedSettings_Test;
   friend class HostContentSettingsMapTest_MigrateKeygenSettings_Test;
 
   friend class content_settings::TestUtils;
@@ -311,6 +312,14 @@
   // leave in some code to remove old-format settings for a long time.
   void MigrateKeygenSettings();
 
+  // Migrate old domain scoped ALLOW settings to be origin scoped for
+  // ContentSettingsTypes which are domain scoped. Only narrow down ALLOW
+  // domain settings to origins so that this will not cause privacy/security
+  // issues.
+  // TODO(lshang): https://crbug.com/621398 Remove this when clients have
+  // migrated (~M56).
+  void MigrateDomainScopedSettings();
+
   // Collect UMA data about the number of exceptions.
   void RecordNumberOfExceptions();
 
diff --git a/components/content_settings/core/common/content_settings_pattern.cc b/components/content_settings/core/common/content_settings_pattern.cc
index 74a9ffa..d6dd272 100644
--- a/components/content_settings/core/common/content_settings_pattern.cc
+++ b/components/content_settings/core/common/content_settings_pattern.cc
@@ -439,6 +439,60 @@
 }
 
 // static
+bool ContentSettingsPattern::MigrateFromDomainToOrigin(
+    const ContentSettingsPattern& domain_pattern,
+    ContentSettingsPattern* origin_pattern) {
+  DCHECK(origin_pattern);
+
+  // Generated patterns with ::FromURL (which we want to migrate) must either
+  // have a scheme wildcard or be https.
+  if (domain_pattern.parts_.scheme != url::kHttpsScheme &&
+      !domain_pattern.parts_.is_scheme_wildcard) {
+    return false;
+  }
+
+  // Generated patterns using ::FromURL with the HTTPs scheme can not have a
+  // port wildcard.
+  if (domain_pattern.parts_.is_port_wildcard &&
+      domain_pattern.parts_.scheme == url::kHttpsScheme) {
+    return false;
+  }
+
+  // Patterns generated with ::FromURL will always have a domain wildcard. Those
+  // generated with ::FromURLNoWildcard don't.
+  if (!domain_pattern.parts_.has_domain_wildcard)
+    return false;
+
+  // Generated patterns with ::FromURL will always have a host.
+  if (domain_pattern.parts_.host.empty())
+    return false;
+
+  std::unique_ptr<ContentSettingsPattern::BuilderInterface> builder(
+      ContentSettingsPattern::CreateBuilder(false));
+
+  if (domain_pattern.parts_.is_scheme_wildcard)
+    builder->WithScheme(url::kHttpScheme);
+  else
+    builder->WithScheme(domain_pattern.parts_.scheme);
+
+  builder->WithHost(domain_pattern.parts_.host);
+
+  if (domain_pattern.parts_.is_port_wildcard) {
+    if (domain_pattern.parts_.scheme == url::kHttpsScheme) {
+      builder->WithPort(GetDefaultPort(url::kHttpsScheme));
+    } else {
+      builder->WithPort(GetDefaultPort(url::kHttpScheme));
+    }
+  } else {
+    builder->WithPort(domain_pattern.parts_.port);
+  }
+
+  *origin_pattern = builder->Build();
+
+  return true;
+}
+
+// static
 void ContentSettingsPattern::SetNonWildcardDomainNonPortScheme(
     const char* scheme) {
   DCHECK(scheme);
diff --git a/components/content_settings/core/common/content_settings_pattern.h b/components/content_settings/core/common/content_settings_pattern.h
index f85c648b..b5b8352 100644
--- a/components/content_settings/core/common/content_settings_pattern.h
+++ b/components/content_settings/core/common/content_settings_pattern.h
@@ -129,6 +129,7 @@
 
   // Returns a pattern that matches the scheme and host of this URL, as well as
   // all subdomains and ports.
+  // TODO(lshang): Remove this when crbug.com/604612 is done.
   static ContentSettingsPattern FromURL(const GURL& url);
 
   // Returns a pattern that matches exactly this URL.
@@ -145,6 +146,13 @@
   //   - [a:b:c:d:e:f:g:h] (matches an exact IPv6 ip)
   static ContentSettingsPattern FromString(const std::string& pattern_spec);
 
+  // Migrate domain scoped settings generated using FromURL() to be origin
+  // scoped. Return false if domain_pattern is not generated using FromURL().
+  // TODO(lshang): Remove this when migration is done. https://crbug.com/604612
+  static bool MigrateFromDomainToOrigin(
+      const ContentSettingsPattern& domain_pattern,
+      ContentSettingsPattern* origin_pattern);
+
   // Sets the scheme that doesn't support domain wildcard and port.
   // Needs to be called by the embedder before using ContentSettingsPattern.
   // |scheme| can't be NULL, and the pointed string must remain alive until the
diff --git a/components/content_settings/core/common/content_settings_pattern_unittest.cc b/components/content_settings/core/common/content_settings_pattern_unittest.cc
index 74e6019..38125c4 100644
--- a/components/content_settings/core/common/content_settings_pattern_unittest.cc
+++ b/components/content_settings/core/common/content_settings_pattern_unittest.cc
@@ -720,3 +720,92 @@
   EXPECT_STREQ("", Pattern("*\xC4\x87ira.com").ToString().c_str());
   EXPECT_STREQ("", Pattern("\xC4\x87ira.*").ToString().c_str());
 }
+
+TEST(ContentSettingsPatternTest, MigrateFromDomainToOrigin) {
+  ContentSettingsPattern origin_pattern;
+  // Http scheme patterns.
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("http://[*.]example.com"),
+      &origin_pattern));
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("http://[*.]example.com:80"),
+      &origin_pattern));
+
+  // Https patterns with port wildcard.
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("https://www.google.com"),
+      &origin_pattern));
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("https://[*.]google.com"),
+      &origin_pattern));
+
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("www.google.com"), &origin_pattern));
+
+  // Patterns with no domain wildcard.
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("*://www.google.com:8080"),
+      &origin_pattern));
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("www.example.com:8080"),
+      &origin_pattern));
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("www.google.com/*"), &origin_pattern));
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("google"), &origin_pattern));
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("https://www.google.com:443"),
+      &origin_pattern));
+
+  // Patterns with empty host.
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("*"), &origin_pattern));
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("[*.]"), &origin_pattern));
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("http://*"), &origin_pattern));
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("http://*:8080"), &origin_pattern));
+
+  // Other schemes and IP address patterns won't be migrated.
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("192.168.0.1"), &origin_pattern));
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("https://127.0.0.1"),
+      &origin_pattern));
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("http://[::1]"), &origin_pattern));
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("[::1]"), &origin_pattern));
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("file:///foo/bar.html"),
+      &origin_pattern));
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString(
+          "filesystem:http://www.google.com/temporary/"),
+      &origin_pattern));
+  EXPECT_FALSE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString(
+          "chrome-extension://peoadpeiejnhkmpaakpnompolbglelel/"),
+      &origin_pattern));
+
+  // These are pattern styles which might be generated using FromURL().
+  EXPECT_TRUE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("[*.]example.com"), &origin_pattern));
+  EXPECT_EQ("http://example.com:80", origin_pattern.ToString());
+
+  EXPECT_TRUE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("[*.]google.com:80"),
+      &origin_pattern));
+  EXPECT_EQ("http://google.com:80", origin_pattern.ToString());
+
+  EXPECT_TRUE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("[*.]example.com:123"),
+      &origin_pattern));
+  EXPECT_EQ("http://example.com:123", origin_pattern.ToString());
+
+  EXPECT_TRUE(ContentSettingsPattern::MigrateFromDomainToOrigin(
+      ContentSettingsPattern::FromString("https://[*.]google.com:443"),
+      &origin_pattern));
+  EXPECT_EQ("https://google.com:443", origin_pattern.ToString());
+}
\ No newline at end of file
diff --git a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
index f3638a2..17b5b7d 100644
--- a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
+++ b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
@@ -122,6 +122,7 @@
         private String mExperimentalOptions;
         private long mMockCertVerifier;
         private boolean mNetworkQualityEstimatorEnabled;
+        private String mCertVerifierData;
 
         /**
          * Default config enables SPDY, disables QUIC, SDCH and HTTP cache.
@@ -658,6 +659,22 @@
         }
 
         /**
+         * Initializes CachingCertVerifier's cache with certVerifierData which has
+         * the results of certificate verification.
+         * @param certVerifierData a serialized representation of certificate
+         *        verification results.
+         * @return the builder to facilitate chaining.
+         */
+        public Builder setCertVerifierData(String certVerifierData) {
+            mCertVerifierData = certVerifierData;
+            return this;
+        }
+
+        String certVerifierData() {
+            return mCertVerifierData;
+        }
+
+        /**
          * Returns {@link Context} for builder.
          *
          * @return {@link Context} for builder.
@@ -833,6 +850,19 @@
     public abstract void stopNetLog();
 
     /**
+     * Returns serialized representation of certificate verifier's cache
+     * which contains the list of hosts/certificates and the certificate
+     * verification results. May block until data is received from the network
+     * thread (will timeout after the specified timeout). In case of timeout, it
+     * returns the previous saved value.
+     *
+     * @param timeout in milliseconds. If timeout is 0, it will use default value.
+     * @return serialized representation of certificate verification results
+     *         data.
+     */
+    public abstract String getCertVerifierData(long timeout);
+
+    /**
      * Returns differences in metrics collected by Cronet since the last call to
      * {@link #getGlobalMetricsDeltas}.
      * <p>
diff --git a/components/cronet/android/api/src/org/chromium/net/JavaCronetEngine.java b/components/cronet/android/api/src/org/chromium/net/JavaCronetEngine.java
index e5b781d..9a94454 100644
--- a/components/cronet/android/api/src/org/chromium/net/JavaCronetEngine.java
+++ b/components/cronet/android/api/src/org/chromium/net/JavaCronetEngine.java
@@ -93,6 +93,11 @@
     public void stopNetLog() {}
 
     @Override
+    public String getCertVerifierData(long timeout) {
+        return "";
+    }
+
+    @Override
     public byte[] getGlobalMetricsDeltas() {
         return new byte[0];
     }
diff --git a/components/cronet/android/cronet_url_request_context_adapter.cc b/components/cronet/android/cronet_url_request_context_adapter.cc
index 118ce78d..91267ab 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.cc
+++ b/components/cronet/android/cronet_url_request_context_adapter.cc
@@ -14,6 +14,7 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
+#include "base/base64.h"
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -28,6 +29,8 @@
 #include "base/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "components/cronet/android/cert/cert_verifier_cache_serializer.h"
+#include "components/cronet/android/cert/proto/cert_verification.pb.h"
 #include "components/cronet/histogram_manager.h"
 #include "components/cronet/url_request_context_config.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -41,6 +44,7 @@
 #include "net/base/net_errors.h"
 #include "net/base/network_delegate_impl.h"
 #include "net/base/url_util.h"
+#include "net/cert/caching_cert_verifier.h"
 #include "net/cert/cert_verifier.h"
 #include "net/cookies/cookie_monster.h"
 #include "net/http/http_auth_handler_factory.h"
@@ -678,6 +682,19 @@
     }
   }
 
+  // If there is a cert_verifier, then populate its cache with
+  // |cert_verifier_data|.
+  if (!config->cert_verifier_data.empty() && context_->cert_verifier()) {
+    std::string data;
+    cronet_pb::CertVerificationCache cert_verification_cache;
+    if (base::Base64Decode(config->cert_verifier_data, &data) &&
+        cert_verification_cache.ParseFromString(data)) {
+      DeserializeCertVerifierCache(cert_verification_cache,
+                                   reinterpret_cast<net::CachingCertVerifier*>(
+                                       context_->cert_verifier()));
+    }
+  }
+
   // Iterate through PKP configuration for every host.
   for (const auto& pkp : config->pkp_list) {
     // Add the host pinning.
@@ -788,6 +805,33 @@
   StopNetLogHelper();
 }
 
+void CronetURLRequestContextAdapter::GetCertVerifierData(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& jcaller) {
+  PostTaskToNetworkThread(
+      FROM_HERE,
+      base::Bind(
+          &CronetURLRequestContextAdapter::GetCertVerifierDataOnNetworkThread,
+          base::Unretained(this)));
+}
+
+void CronetURLRequestContextAdapter::GetCertVerifierDataOnNetworkThread() {
+  DCHECK(GetNetworkTaskRunner()->BelongsToCurrentThread());
+  std::string encoded_data;
+  if (is_context_initialized_ && context_->cert_verifier()) {
+    std::string data;
+    cronet_pb::CertVerificationCache cert_cache =
+        SerializeCertVerifierCache(*reinterpret_cast<net::CachingCertVerifier*>(
+            context_->cert_verifier()));
+    cert_cache.SerializeToString(&data);
+    base::Base64Encode(data, &encoded_data);
+  }
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_CronetUrlRequestContext_onGetCertVerifierData(
+      env, jcronet_url_request_context_.obj(),
+      base::android::ConvertUTF8ToJavaString(env, encoded_data).obj());
+}
+
 base::Thread* CronetURLRequestContextAdapter::GetFileThread() {
   DCHECK(GetNetworkTaskRunner()->BelongsToCurrentThread());
   if (!file_thread_) {
@@ -845,7 +889,8 @@
     const JavaParamRef<jstring>& jexperimental_quic_connection_options,
     jlong jmock_cert_verifier,
     jboolean jenable_network_quality_estimator,
-    jboolean jbypass_public_key_pinning_for_local_trust_anchors) {
+    jboolean jbypass_public_key_pinning_for_local_trust_anchors,
+    const JavaParamRef<jstring>& jcert_verifier_data) {
   return reinterpret_cast<jlong>(new URLRequestContextConfig(
       jquic_enabled,
       ConvertNullableJavaStringToUTF8(env, jquic_default_user_agent_id),
@@ -865,7 +910,8 @@
       base::WrapUnique(
           reinterpret_cast<net::CertVerifier*>(jmock_cert_verifier)),
       jenable_network_quality_estimator,
-      jbypass_public_key_pinning_for_local_trust_anchors));
+      jbypass_public_key_pinning_for_local_trust_anchors,
+      ConvertNullableJavaStringToUTF8(env, jcert_verifier_data)));
 }
 
 // Add a QUIC hint to a URLRequestContextConfig.
diff --git a/components/cronet/android/cronet_url_request_context_adapter.h b/components/cronet/android/cronet_url_request_context_adapter.h
index 7b76431..95ee713 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.h
+++ b/components/cronet/android/cronet_url_request_context_adapter.h
@@ -87,6 +87,11 @@
   void StopNetLog(JNIEnv* env,
                   const base::android::JavaParamRef<jobject>& jcaller);
 
+  // Posts a task to Network thread to get serialized results of certificate
+  // verifications of |context_|'s |cert_verifier|.
+  void GetCertVerifierData(JNIEnv* env,
+                           const base::android::JavaParamRef<jobject>& jcaller);
+
   // Default net::LOAD flags used to create requests.
   int default_load_flags() const { return default_load_flags_; }
 
@@ -133,6 +138,10 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner() const;
 
+  // Serializes results of certificate verifications of |context_|'s
+  // |cert_verifier| on the Network thread.
+  void GetCertVerifierDataOnNetworkThread();
+
   // Gets the file thread. Create one if there is none.
   base::Thread* GetFileThread();
 
diff --git a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
index 3e4a3113..60ca98c 100644
--- a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
+++ b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
@@ -75,6 +75,14 @@
     private final ObserverList<RequestFinishedListener> mFinishedListenerList =
             new ObserverList<RequestFinishedListener>();
 
+    /**
+     * Synchronize access to mCertVerifierData.
+     */
+    private ConditionVariable mWaitGetCertVerifierDataComplete = new ConditionVariable();
+
+    /** Holds CertVerifier data. */
+    private String mCertVerifierData;
+
     @UsedByReflection("CronetEngine.java")
     public CronetUrlRequestContext(final CronetEngine.Builder builder) {
         CronetLibraryLoader.ensureInitialized(builder.getContext(), builder);
@@ -119,7 +127,8 @@
                 builder.dataReductionProxySecureProxyCheckUrl(), builder.cacheDisabled(),
                 builder.httpCacheMode(), builder.httpCacheMaxSize(), builder.experimentalOptions(),
                 builder.mockCertVerifier(), builder.networkQualityEstimatorEnabled(),
-                builder.publicKeyPinningBypassForLocalTrustAnchorsEnabled());
+                builder.publicKeyPinningBypassForLocalTrustAnchorsEnabled(),
+                builder.certVerifierData());
         for (Builder.QuicHint quicHint : builder.quicHints()) {
             nativeAddQuicHint(urlRequestContextConfig, quicHint.mHost, quicHint.mPort,
                     quicHint.mAlternatePort);
@@ -217,6 +226,22 @@
         }
     }
 
+    @Override
+    public String getCertVerifierData(long timeout) {
+        if (timeout < 0) {
+            throw new IllegalArgumentException("timeout must be a positive value");
+        } else if (timeout == 0) {
+            timeout = 100;
+        }
+        mWaitGetCertVerifierDataComplete.close();
+        synchronized (mLock) {
+            checkHaveAdapter();
+            nativeGetCertVerifierData(mUrlRequestContextAdapter);
+        }
+        mWaitGetCertVerifierDataComplete.block(timeout);
+        return mCertVerifierData;
+    }
+
     // This method is intentionally non-static to ensure Cronet native library
     // is loaded by class constructor.
     @Override
@@ -500,6 +525,13 @@
         }
     }
 
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private void onGetCertVerifierData(String certVerifierData) {
+        mCertVerifierData = certVerifierData;
+        mWaitGetCertVerifierDataComplete.open();
+    }
+
     void reportFinished(final CronetUrlRequest request) {
         if (!mNetworkQualityEstimatorEnabled) {
             return;
@@ -544,7 +576,7 @@
             String dataReductionProxySecureProxyCheckUrl, boolean disableCache, int httpCacheMode,
             long httpCacheMaxSize, String experimentalOptions, long mockCertVerifier,
             boolean enableNetworkQualityEstimator,
-            boolean bypassPublicKeyPinningForLocalTrustAnchors);
+            boolean bypassPublicKeyPinningForLocalTrustAnchors, String certVerifierData);
 
     private static native void nativeAddQuicHint(
             long urlRequestContextConfig, String host, int port, int alternatePort);
@@ -569,6 +601,9 @@
     private native void nativeStopNetLog(long nativePtr);
 
     @NativeClassQualifiedName("CronetURLRequestContextAdapter")
+    private native void nativeGetCertVerifierData(long nativePtr);
+
+    @NativeClassQualifiedName("CronetURLRequestContextAdapter")
     private native void nativeInitRequestContextOnMainThread(long nativePtr);
 
     @NativeClassQualifiedName("CronetURLRequestContextAdapter")
diff --git a/components/cronet/android/test/cronet_url_request_context_config_test.cc b/components/cronet/android/test/cronet_url_request_context_config_test.cc
index 5920aaf..2112077 100644
--- a/components/cronet/android/test/cronet_url_request_context_config_test.cc
+++ b/components/cronet/android/test/cronet_url_request_context_config_test.cc
@@ -37,6 +37,7 @@
   CHECK_NE(config->quic_user_agent_id.find("Cronet/" CRONET_VERSION),
            std::string::npos);
   CHECK_EQ(config->load_disable_cache, false);
+  CHECK_EQ(config->cert_verifier_data, "test_cert_verifier_data");
   CHECK_EQ(config->http_cache, URLRequestContextConfig::HttpCacheType::MEMORY);
   CHECK_EQ(config->http_cache_max_size, 54321);
   CHECK_EQ(config->data_reduction_proxy_key, "abcd");
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
index c323f87..b0a7a09 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
@@ -315,4 +315,40 @@
         assertTrue(NetError.ERR_QUIC_PROTOCOL_ERROR == callback.mError.getCronetInternalErrorCode()
                 || NetError.ERR_CONNECTION_REFUSED == callback.mError.getCronetInternalErrorCode());
     }
+
+    @SmallTest
+    @Feature({"Cronet"})
+    @OnlyRunNativeCronet
+    // Test that certificate verify results are serialized and deserialized correctly.
+    public void testSerializeDeserialize() throws Exception {
+        setUp(QuicBidirectionalStreams.ENABLED);
+        String path = "/simple.txt";
+        String quicURL = QuicTestServer.getServerURL() + path;
+        TestBidirectionalStreamCallback callback = new TestBidirectionalStreamCallback();
+        BidirectionalStream stream = new BidirectionalStream
+                                             .Builder(quicURL, callback, callback.getExecutor(),
+                                                     mTestFramework.mCronetEngine)
+                                             .setHttpMethod("GET")
+                                             .build();
+        stream.start();
+        callback.blockForDone();
+        assertTrue(stream.isDone());
+        assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+        assertEquals("This is a simple text file served by QUIC.\n", callback.mResponseAsString);
+        assertEquals("quic/1+spdy/3", callback.mResponseInfo.getNegotiatedProtocol());
+
+        String serialized_data = mTestFramework.mCronetEngine.getCertVerifierData(100);
+        assertFalse(serialized_data.isEmpty());
+
+        // Create a new builder and verify that the |serialized_data| is deserialized correctly.
+        CronetEngine.Builder builder = new CronetEngine.Builder(getContext());
+        builder.enableQUIC(true);
+        builder.setMockCertVerifierForTesting(QuicTestServer.createMockCertVerifier());
+        builder.setCertVerifierData(serialized_data);
+
+        CronetTestFramework testFramework =
+                startCronetTestFrameworkWithUrlAndCronetEngineBuilder(null, builder);
+        String deserialized_data = testFramework.mCronetEngine.getCertVerifierData(100);
+        assertEquals(deserialized_data, serialized_data);
+    }
 }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
index 2ce466f..ee00041 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
@@ -1159,6 +1159,31 @@
 
     @SmallTest
     @Feature({"Cronet"})
+    public void testEmptyGetCertVerifierData() {
+        CronetTestFramework testFramework = startCronetTestFrameworkAndSkipLibraryInit();
+
+        // Immediately make a request after initializing the engine.
+        CronetEngine cronetEngine = testFramework.initCronetEngine();
+        TestUrlRequestCallback callback = new TestUrlRequestCallback();
+        UrlRequest.Builder urlRequestBuilder =
+                new UrlRequest.Builder(mUrl, callback, callback.getExecutor(), cronetEngine);
+        urlRequestBuilder.build().start();
+        callback.blockForDone();
+        assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+
+        try {
+            cronetEngine.getCertVerifierData(-1);
+            fail("Should throw an exception");
+        } catch (Exception e) {
+            assertEquals("timeout must be a positive value", e.getMessage());
+        }
+        // Because mUrl is http, getCertVerifierData() will return empty data.
+        String data = cronetEngine.getCertVerifierData(100);
+        assertTrue(data.isEmpty());
+    }
+
+    @SmallTest
+    @Feature({"Cronet"})
     public void testInitEngineStartTwoRequests() throws Exception {
         CronetTestFramework testFramework = startCronetTestFrameworkAndSkipLibraryInit();
 
@@ -1260,6 +1285,7 @@
         builder.enableQUIC(true);
         builder.enableSDCH(true);
         builder.addQuicHint("example.com", 12, 34);
+        builder.setCertVerifierData("test_cert_verifier_data");
         builder.enableHttpCache(CronetEngine.Builder.HTTP_CACHE_IN_MEMORY, 54321);
         builder.enableDataReductionProxy("abcd");
         builder.setUserAgent("efgh");
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
index c47c96c..ec7d461 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
@@ -54,7 +54,6 @@
                                         .put("migrate_sessions_early", true);
         JSONObject experimentalOptions = new JSONObject().put("QUIC", quicParams);
         mBuilder.setExperimentalOptions(experimentalOptions.toString());
-
         mBuilder.setMockCertVerifierForTesting(QuicTestServer.createMockCertVerifier());
         mBuilder.setStoragePath(CronetTestFramework.getTestStorage(getContext()));
         mBuilder.enableHttpCache(CronetEngine.Builder.HTTP_CACHE_DISK_NO_HTTP, 1000 * 1024);
diff --git a/components/cronet/url_request_context_config.cc b/components/cronet/url_request_context_config.cc
index 3878536..fa080d2d 100644
--- a/components/cronet/url_request_context_config.cc
+++ b/components/cronet/url_request_context_config.cc
@@ -8,12 +8,16 @@
 
 #include "base/json/json_reader.h"
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
 #include "base/sequenced_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "base/values.h"
+#include "net/cert/caching_cert_verifier.h"
 #include "net/cert/cert_verifier.h"
+#include "net/cert/cert_verify_proc.h"
+#include "net/cert/multi_threaded_cert_verifier.h"
 #include "net/dns/host_resolver.h"
 #include "net/http/http_server_properties.h"
 #include "net/quic/quic_protocol.h"
@@ -251,7 +255,8 @@
     const std::string& data_reduction_secure_proxy_check_url,
     std::unique_ptr<net::CertVerifier> mock_cert_verifier,
     bool enable_network_quality_estimator,
-    bool bypass_public_key_pinning_for_local_trust_anchors)
+    bool bypass_public_key_pinning_for_local_trust_anchors,
+    const std::string& cert_verifier_data)
     : enable_quic(enable_quic),
       quic_user_agent_id(quic_user_agent_id),
       enable_spdy(enable_spdy),
@@ -270,7 +275,8 @@
       mock_cert_verifier(std::move(mock_cert_verifier)),
       enable_network_quality_estimator(enable_network_quality_estimator),
       bypass_public_key_pinning_for_local_trust_anchors(
-          bypass_public_key_pinning_for_local_trust_anchors) {}
+          bypass_public_key_pinning_for_local_trust_anchors),
+      cert_verifier_data(cert_verifier_data) {}
 
 URLRequestContextConfig::~URLRequestContextConfig() {}
 
@@ -304,8 +310,17 @@
   ParseAndSetExperimentalOptions(experimental_options, context_builder, net_log,
                                  file_task_runner);
 
-  if (mock_cert_verifier)
-    context_builder->SetCertVerifier(std::move(mock_cert_verifier));
+  std::unique_ptr<net::CertVerifier> cert_verifier;
+  if (mock_cert_verifier) {
+    // Because |context_builder| expects CachingCertVerifier, wrap
+    // |mock_cert_verifier| into a CachingCertVerifier.
+    cert_verifier = base::MakeUnique<net::CachingCertVerifier>(
+        std::move(mock_cert_verifier));
+  } else {
+    // net::CertVerifier::CreateDefault() returns a CachingCertVerifier.
+    cert_verifier = net::CertVerifier::CreateDefault();
+  }
+  context_builder->SetCertVerifier(std::move(cert_verifier));
   // TODO(mef): Use |config| to set cookies.
 }
 
diff --git a/components/cronet/url_request_context_config.h b/components/cronet/url_request_context_config.h
index 2a00cf1..5ede832 100644
--- a/components/cronet/url_request_context_config.h
+++ b/components/cronet/url_request_context_config.h
@@ -111,7 +111,9 @@
       // Enable network quality estimator.
       bool enable_network_quality_estimator,
       // Enable bypassing of public key pinning for local trust anchors
-      bool bypass_public_key_pinning_for_local_trust_anchors);
+      bool bypass_public_key_pinning_for_local_trust_anchors,
+      // Certificate verifier cache data.
+      const std::string& cert_verifier_data);
   ~URLRequestContextConfig();
 
   // Configure |context_builder| based on |this|.
@@ -161,6 +163,9 @@
   // Enable public key pinning bypass for local trust anchors.
   const bool bypass_public_key_pinning_for_local_trust_anchors;
 
+  // Data to populte CertVerifierCache.
+  const std::string cert_verifier_data;
+
   // App-provided list of servers that support QUIC.
   ScopedVector<QuicHint> quic_hints;
 
diff --git a/components/cronet/url_request_context_config_unittest.cc b/components/cronet/url_request_context_config_unittest.cc
index 56025cd..a0cef2a 100644
--- a/components/cronet/url_request_context_config_unittest.cc
+++ b/components/cronet/url_request_context_config_unittest.cc
@@ -61,7 +61,9 @@
       // Enable network quality estimator.
       false,
       // Enable Public Key Pinning bypass for local trust anchors.
-      true);
+      true,
+      // Certificate verifier cache data.
+      "");
 
   net::URLRequestContextBuilder builder;
   net::NetLog net_log;
@@ -142,7 +144,9 @@
       // Enable network quality estimator.
       false,
       // Enable Public Key Pinning bypass for local trust anchors.
-      true);
+      true,
+      // Certificate verifier cache data.
+      "");
 
   net::URLRequestContextBuilder builder;
   net::NetLog net_log;
diff --git a/components/data_reduction_proxy/core/browser/data_usage_store.cc b/components/data_reduction_proxy/core/browser/data_usage_store.cc
index 220231b..80f4ff2 100644
--- a/components/data_reduction_proxy/core/browser/data_usage_store.cc
+++ b/components/data_reduction_proxy/core/browser/data_usage_store.cc
@@ -56,7 +56,11 @@
   exploded.minute -= exploded.minute % kDataUsageBucketLengthInMinutes;
   exploded.second = 0;
   exploded.millisecond = 0;
-  return base::Time::FromUTCExploded(exploded);
+
+  base::Time out_time;
+  bool conversion_success = base::Time::FromUTCExploded(exploded, &out_time);
+  DCHECK(conversion_success);
+  return out_time;
 }
 
 }  // namespace
diff --git a/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc b/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc
index 8a4e640..6dc60c8 100644
--- a/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc
@@ -65,7 +65,8 @@
 
   void PopulateStore() {
     base::Time::Exploded exploded = TestExplodedTime();
-    base::Time current_time = base::Time::FromUTCExploded(exploded);
+    base::Time current_time;
+    EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &current_time));
 
     DataUsageBucket current_bucket;
     current_bucket.set_last_updated_timestamp(current_time.ToInternalValue());
@@ -144,12 +145,14 @@
   exploded.minute = 0;
   exploded.second = 0;
   exploded.millisecond = 0;
-  base::Time time1 = base::Time::FromUTCExploded(exploded);
+  base::Time time1;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time1));
 
   exploded.minute = 14;
   exploded.second = 59;
   exploded.millisecond = 999;
-  base::Time time2 = base::Time::FromUTCExploded(exploded);
+  base::Time time2;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time2));
 
   DataUsageBucket bucket;
   data_usage_store()->LoadCurrentDataUsageBucket(&bucket);
@@ -180,12 +183,14 @@
   exploded.minute = 0;
   exploded.second = 59;
   exploded.millisecond = 999;
-  base::Time time1 = base::Time::FromUTCExploded(exploded);
+  base::Time time1;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time1));
 
   exploded.minute = 15;
   exploded.second = 0;
   exploded.millisecond = 0;
-  base::Time time2 = base::Time::FromUTCExploded(exploded);
+  base::Time time2;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time2));
 
   DataUsageBucket bucket;
   data_usage_store()->LoadCurrentDataUsageBucket(&bucket);
@@ -308,25 +313,32 @@
 
 TEST_F(DataUsageStoreTest, BucketOverlapsInterval) {
   base::Time::Exploded exploded = TestExplodedTime();
-  base::Time time1 = base::Time::FromUTCExploded(exploded);
+  base::Time time1;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time1));
 
   exploded.minute = 16;
-  base::Time time16 = base::Time::FromUTCExploded(exploded);
+  base::Time time16;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time16));
 
   exploded.minute = 17;
-  base::Time time17 = base::Time::FromUTCExploded(exploded);
+  base::Time time17;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time17));
 
   exploded.minute = 18;
-  base::Time time18 = base::Time::FromUTCExploded(exploded);
+  base::Time time18;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time18));
 
   exploded.minute = 33;
-  base::Time time33 = base::Time::FromUTCExploded(exploded);
+  base::Time time33;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time33));
 
   exploded.minute = 34;
-  base::Time time34 = base::Time::FromUTCExploded(exploded);
+  base::Time time34;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time34));
 
   exploded.minute = 46;
-  base::Time time46 = base::Time::FromUTCExploded(exploded);
+  base::Time time46;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time46));
 
   ASSERT_FALSE(DataUsageStore::BucketOverlapsInterval(time1, time17, time33));
   ASSERT_TRUE(DataUsageStore::BucketOverlapsInterval(time16, time17, time33));
@@ -343,45 +355,53 @@
   DataUsageBucket current_bucket;
   data_usage_store()->LoadCurrentDataUsageBucket(&current_bucket);
 
+  base::Time out_time;
+
   exploded.minute = 0;
-  ASSERT_EQ(kTestCurrentBucketIndex,
-            ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
+  ASSERT_EQ(kTestCurrentBucketIndex, ComputeBucketIndex(out_time));
+
   exploded.minute = 14;
-  ASSERT_EQ(kTestCurrentBucketIndex,
-            ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
+  ASSERT_EQ(kTestCurrentBucketIndex, ComputeBucketIndex(out_time));
 
   exploded.minute = 15;
-  ASSERT_EQ(kTestCurrentBucketIndex + 1,
-            ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
+  ASSERT_EQ(kTestCurrentBucketIndex + 1, ComputeBucketIndex(out_time));
 
   exploded.hour = 11;
   exploded.minute = 59;
-  ASSERT_EQ(kTestCurrentBucketIndex - 1,
-            ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
+  ASSERT_EQ(kTestCurrentBucketIndex - 1, ComputeBucketIndex(out_time));
 
   exploded.minute = 0;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
   ASSERT_EQ(kTestCurrentBucketIndex - kBucketsInHour,
-            ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+            ComputeBucketIndex(out_time));
 
   exploded.hour = 1;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
   ASSERT_EQ(kTestCurrentBucketIndex - kBucketsInHour * 11,
-            ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+            ComputeBucketIndex(out_time));
 
   exploded.day_of_month = 1;
   exploded.hour = 12;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
   ASSERT_EQ(kTestCurrentBucketIndex - kBucketsInHour * 30 * 24,
-            ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+            ComputeBucketIndex(out_time));
 
   exploded.hour = 11;
   exploded.minute = 45;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
   ASSERT_EQ(kTestCurrentBucketIndex - kBucketsInHour * 30 * 24 - 1 +
                 static_cast<int>(kNumExpectedBuckets),
-            ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+            ComputeBucketIndex(out_time));
 
   exploded.minute = 30;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
   ASSERT_EQ(kTestCurrentBucketIndex - kBucketsInHour * 30 * 24 - 2 +
                 static_cast<int>(kNumExpectedBuckets),
-            ComputeBucketIndex(base::Time::FromUTCExploded(exploded)));
+            ComputeBucketIndex(out_time));
 }
 
 TEST_F(DataUsageStoreTest, DeleteBrowsingHistory) {
@@ -393,7 +413,8 @@
 
   base::Time::Exploded exploded = TestExplodedTime();
   exploded.minute = 0;
-  base::Time now = base::Time::FromUTCExploded(exploded);
+  base::Time now;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &now));
   base::Time fifteen_mins_from_now = now + base::TimeDelta::FromMinutes(15);
   // Deleting browsing from the future should be a no-op.
   data_usage_store()->DeleteBrowsingHistory(fifteen_mins_from_now,
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
index f821a88..5937da70 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
@@ -59,7 +59,7 @@
                             base::StringPiece action_prefix) {
   DCHECK(!action_prefix.empty());
   // A valid action does not include a trailing '='.
-  DCHECK(action_prefix[action_prefix.size() - 1] != kActionValueDelimiter);
+  DCHECK(action_prefix.back() != kActionValueDelimiter);
 
   return header_value.size() > action_prefix.size() + 1 &&
          header_value[action_prefix.size()] == kActionValueDelimiter &&
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
index c176f87..6742221 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
@@ -94,18 +94,21 @@
 }
 
 bool IsIncludedInLoFiEnabledFieldTrial() {
-  return FieldTrialList::FindFullName(GetLoFiFieldTrialName()).find(kEnabled) ==
-         0;
+  return !IsLoFiOnViaFlags() && !IsLoFiDisabledViaFlags() &&
+         FieldTrialList::FindFullName(GetLoFiFieldTrialName()).find(kEnabled) ==
+             0;
 }
 
 bool IsIncludedInLoFiControlFieldTrial() {
-  return FieldTrialList::FindFullName(GetLoFiFieldTrialName()).find(kControl) ==
-         0;
+  return !IsLoFiOnViaFlags() && !IsLoFiDisabledViaFlags() &&
+         FieldTrialList::FindFullName(GetLoFiFieldTrialName()).find(kControl) ==
+             0;
 }
 
 bool IsIncludedInLoFiPreviewFieldTrial() {
-  return FieldTrialList::FindFullName(GetLoFiFieldTrialName()).find(kPreview) ==
-         0;
+  return !IsLoFiOnViaFlags() && !IsLoFiDisabledViaFlags() &&
+         FieldTrialList::FindFullName(GetLoFiFieldTrialName()).find(kPreview) ==
+             0;
 }
 
 bool IsIncludedInServerExperimentsFieldTrial() {
diff --git a/components/devtools_discovery/devtools_discovery_manager.cc b/components/devtools_discovery/devtools_discovery_manager.cc
index aaa998c..3233085a 100644
--- a/components/devtools_discovery/devtools_discovery_manager.cc
+++ b/components/devtools_discovery/devtools_discovery_manager.cc
@@ -62,4 +62,31 @@
   return result;
 }
 
+std::unique_ptr<base::DictionaryValue>
+DevToolsDiscoveryManager::HandleNewTargetCommand(
+    base::DictionaryValue* command_dict) {
+  int id;
+  std::string method;
+  std::string initial_url;
+  const base::DictionaryValue* params_dict = nullptr;
+  if (command_dict->GetInteger("id", &id) &&
+      command_dict->GetString("method", &method) &&
+      method == "Browser.newPage" &&
+      command_dict->GetDictionary("params", &params_dict) &&
+      params_dict->GetString("initialUrl", &initial_url)) {
+    std::unique_ptr<devtools_discovery::DevToolsTargetDescriptor> descriptor =
+        CreateNew(GURL(initial_url));
+    if (!descriptor)
+      return nullptr;
+    std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
+    result->SetInteger("id", id);
+    std::unique_ptr<base::DictionaryValue> cmd_result(
+        new base::DictionaryValue());
+    cmd_result->SetString("pageId", descriptor->GetId());
+    result->Set("result", std::move(cmd_result));
+    return result;
+  }
+  return nullptr;
+}
+
 }  // namespace devtools_discovery
diff --git a/components/devtools_discovery/devtools_discovery_manager.h b/components/devtools_discovery/devtools_discovery_manager.h
index 75657d4..023e067 100644
--- a/components/devtools_discovery/devtools_discovery_manager.h
+++ b/components/devtools_discovery/devtools_discovery_manager.h
@@ -10,6 +10,7 @@
 
 #include "base/macros.h"
 #include "base/memory/singleton.h"
+#include "base/values.h"
 #include "components/devtools_discovery/devtools_target_descriptor.h"
 
 namespace devtools_discovery {
@@ -39,6 +40,10 @@
   DevToolsTargetDescriptor::List GetDescriptors();
   std::unique_ptr<DevToolsTargetDescriptor> CreateNew(const GURL& url);
 
+  // Handles Browser.newPage only.
+  std::unique_ptr<base::DictionaryValue> HandleNewTargetCommand(
+      base::DictionaryValue* command_dict);
+
  private:
   friend struct base::DefaultSingletonTraits<DevToolsDiscoveryManager>;
 
diff --git a/components/devtools_http_handler/devtools_http_handler.cc b/components/devtools_http_handler/devtools_http_handler.cc
index 38f32dc..48f5811 100644
--- a/components/devtools_http_handler/devtools_http_handler.cc
+++ b/components/devtools_http_handler/devtools_http_handler.cc
@@ -395,7 +395,7 @@
                                   const net::HttpServerRequestInfo& info) {
   server_->SetSendBufferSize(connection_id, kSendBufferSizeForDevTools);
 
-  if (info.path.find("/json") == 0) {
+  if (base::StartsWith(info.path, "/json", base::CompareCase::SENSITIVE)) {
     BrowserThread::PostTask(
         BrowserThread::UI,
         FROM_HERE,
@@ -406,7 +406,8 @@
     return;
   }
 
-  if (info.path.find(kThumbUrlPrefix) == 0) {
+  if (base::StartsWith(info.path, kThumbUrlPrefix,
+                       base::CompareCase::SENSITIVE)) {
     // Thumbnail request.
     const std::string target_id = info.path.substr(strlen(kThumbUrlPrefix));
     BrowserThread::PostTask(
@@ -430,7 +431,8 @@
     return;
   }
 
-  if (info.path.find("/devtools/") != 0) {
+  if (!base::StartsWith(info.path, "/devtools/",
+                        base::CompareCase::SENSITIVE)) {
     server_->Send404(connection_id);
     return;
   }
@@ -517,7 +519,7 @@
     return true;
   }
 
-  if (path.find("/") != 0) {
+  if (!base::StartsWith(path, "/", base::CompareCase::SENSITIVE)) {
     // Malformed command.
     return false;
   }
@@ -696,8 +698,8 @@
     return;
 
   std::string browser_prefix = "/devtools/browser";
-  size_t browser_pos = request.path.find(browser_prefix);
-  if (browser_pos == 0) {
+  if (base::StartsWith(request.path, browser_prefix,
+                       base::CompareCase::SENSITIVE)) {
     scoped_refptr<DevToolsAgentHost> browser_agent =
         DevToolsAgentHost::CreateForBrowser(
             thread_->task_runner(),
@@ -721,8 +723,8 @@
     return;
   }
 
-  size_t pos = request.path.find(kPageUrlPrefix);
-  if (pos != 0) {
+  if (!base::StartsWith(request.path, kPageUrlPrefix,
+                        base::CompareCase::SENSITIVE)) {
     Send404(connection_id);
     return;
   }
diff --git a/components/display_compositor/gl_helper_unittest.cc b/components/display_compositor/gl_helper_unittest.cc
index 44fe991..d456630 100644
--- a/components/display_compositor/gl_helper_unittest.cc
+++ b/components/display_compositor/gl_helper_unittest.cc
@@ -258,10 +258,8 @@
     }
 
     // Check the output size matches the destination of the last stage
-    EXPECT_EQ(scaler_stages[scaler_stages.size() - 1].dst_size.width(),
-              dst_size.width());
-    EXPECT_EQ(scaler_stages[scaler_stages.size() - 1].dst_size.height(),
-              dst_size.height());
+    EXPECT_EQ(scaler_stages.back().dst_size.width(), dst_size.width());
+    EXPECT_EQ(scaler_stages.back().dst_size.height(), dst_size.height());
 
     // Used to verify that up-scales are not attempted after some
     // other scale.
diff --git a/components/drive/file_system/touch_operation_unittest.cc b/components/drive/file_system/touch_operation_unittest.cc
index 8c15010a..49bbbe5 100644
--- a/components/drive/file_system/touch_operation_unittest.cc
+++ b/components/drive/file_system/touch_operation_unittest.cc
@@ -32,19 +32,22 @@
   };
 
   FileError error = FILE_ERROR_FAILED;
-  operation.TouchFile(
-      kTestPath,
-      base::Time::FromUTCExploded(kLastAccessTime),
-      base::Time::FromUTCExploded(kLastModifiedTime),
-      google_apis::test_util::CreateCopyResultCallback(&error));
+  base::Time last_access_time_utc;
+  base::Time last_modified_time_utc;
+  EXPECT_TRUE(
+      base::Time::FromUTCExploded(kLastAccessTime, &last_access_time_utc));
+  EXPECT_TRUE(
+      base::Time::FromUTCExploded(kLastModifiedTime, &last_modified_time_utc));
+  operation.TouchFile(kTestPath, last_access_time_utc, last_modified_time_utc,
+                      google_apis::test_util::CreateCopyResultCallback(&error));
   content::RunAllBlockingPoolTasksUntilIdle();
   EXPECT_EQ(FILE_ERROR_OK, error);
 
   ResourceEntry entry;
   EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kTestPath, &entry));
-  EXPECT_EQ(base::Time::FromUTCExploded(kLastAccessTime),
+  EXPECT_EQ(last_access_time_utc,
             base::Time::FromInternalValue(entry.file_info().last_accessed()));
-  EXPECT_EQ(base::Time::FromUTCExploded(kLastModifiedTime),
+  EXPECT_EQ(last_modified_time_utc,
             base::Time::FromInternalValue(entry.file_info().last_modified()));
   EXPECT_EQ(ResourceEntry::DIRTY, entry.metadata_edit_state());
 
diff --git a/components/drive/resource_entry_conversion_unittest.cc b/components/drive/resource_entry_conversion_unittest.cc
index ef1bd4f..5891d91671 100644
--- a/components/drive/resource_entry_conversion_unittest.cc
+++ b/components/drive/resource_entry_conversion_unittest.cc
@@ -26,7 +26,9 @@
   exploded.minute = 40;
   exploded.second = 47;
   exploded.millisecond = 330;
-  return base::Time::FromUTCExploded(exploded);
+  base::Time out_time;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
+  return out_time;
 }
 
 }  // namespace
diff --git a/components/drive/service/fake_drive_service_unittest.cc b/components/drive/service/fake_drive_service_unittest.cc
index bc6667a3..eae7f435 100644
--- a/components/drive/service/fake_drive_service_unittest.cc
+++ b/components/drive/service/fake_drive_service_unittest.cc
@@ -1066,11 +1066,10 @@
   const std::string kParentResourceId = "2_folder_resource_id";
   DriveApiErrorCode error = DRIVE_OTHER_ERROR;
   std::unique_ptr<FileResource> entry;
+  base::Time modified_date_utc;
+  EXPECT_TRUE(base::Time::FromUTCExploded(kModifiedDate, &modified_date_utc));
   fake_service_.CopyResource(
-      kResourceId,
-      kParentResourceId,
-      "new title",
-      base::Time::FromUTCExploded(kModifiedDate),
+      kResourceId, kParentResourceId, "new title", modified_date_utc,
       test_util::CreateCopyResultCallback(&error, &entry));
   base::RunLoop().RunUntilIdle();
 
@@ -1079,7 +1078,7 @@
   // The copied entry should have the new resource ID and the title.
   EXPECT_NE(kResourceId, entry->file_id());
   EXPECT_EQ("new title", entry->title());
-  EXPECT_EQ(base::Time::FromUTCExploded(kModifiedDate), entry->modified_date());
+  EXPECT_EQ(modified_date_utc, entry->modified_date());
   EXPECT_TRUE(HasParent(entry->file_id(), kParentResourceId));
   // Should be incremented as a new hosted document was created.
   EXPECT_EQ(old_largest_change_id + 1,
@@ -1163,11 +1162,14 @@
   const std::string kParentResourceId = "2_folder_resource_id";
   DriveApiErrorCode error = DRIVE_OTHER_ERROR;
   std::unique_ptr<FileResource> entry;
+  base::Time modified_date_utc;
+  base::Time viewed_date_utc;
+  EXPECT_TRUE(base::Time::FromUTCExploded(kModifiedDate, &modified_date_utc));
+  EXPECT_TRUE(base::Time::FromUTCExploded(kViewedDate, &viewed_date_utc));
+
   fake_service_.UpdateResource(
-      kResourceId, kParentResourceId, "new title",
-      base::Time::FromUTCExploded(kModifiedDate),
-      base::Time::FromUTCExploded(kViewedDate),
-      google_apis::drive::Properties(),
+      kResourceId, kParentResourceId, "new title", modified_date_utc,
+      viewed_date_utc, google_apis::drive::Properties(),
       test_util::CreateCopyResultCallback(&error, &entry));
   base::RunLoop().RunUntilIdle();
 
@@ -1176,10 +1178,8 @@
   // The updated entry should have the new title.
   EXPECT_EQ(kResourceId, entry->file_id());
   EXPECT_EQ("new title", entry->title());
-  EXPECT_EQ(base::Time::FromUTCExploded(kModifiedDate),
-            entry->modified_date());
-  EXPECT_EQ(base::Time::FromUTCExploded(kViewedDate),
-            entry->last_viewed_by_me_date());
+  EXPECT_EQ(modified_date_utc, entry->modified_date());
+  EXPECT_EQ(viewed_date_utc, entry->last_viewed_by_me_date());
   EXPECT_TRUE(HasParent(kResourceId, kParentResourceId));
   // Should be incremented as a new hosted document was created.
   EXPECT_EQ(old_largest_change_id + 1,
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc
index 9d01332..0e7e730a 100644
--- a/components/exo/wayland/server.cc
+++ b/components/exo/wayland/server.cc
@@ -37,8 +37,10 @@
 #include "base/macros.h"
 #include "base/memory/free_deleter.h"
 #include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "components/exo/buffer.h"
 #include "components/exo/display.h"
 #include "components/exo/keyboard.h"
@@ -87,6 +89,10 @@
 namespace wayland {
 namespace {
 
+// We don't send configure immediately after tablet mode switch
+// because layout can change due to orientation lock state or accelerometer.
+const int kConfigureDelayAfterLayoutSwitchMs = 300;
+
 // Default wayland socket name.
 const base::FilePath::CharType kSocketName[] = FILE_PATH_LITERAL("wayland-0");
 
@@ -1547,7 +1553,8 @@
                      wl_resource* remote_shell_resource)
       : display_(display),
         display_id_(display_id),
-        remote_shell_resource_(remote_shell_resource) {
+        remote_shell_resource_(remote_shell_resource),
+        weak_ptr_factory_(this) {
     ash::WmShell::Get()->AddShellObserver(this);
     ash::Shell* shell = ash::Shell::GetInstance();
     shell->activation_client()->AddObserver(this);
@@ -1585,9 +1592,19 @@
   void OnDisplayWorkAreaInsetsChanged() override { SendConfigure(); }
   void OnMaximizeModeStarted() override {
     SendLayoutModeChange(ZWP_REMOTE_SHELL_V1_LAYOUT_MODE_TABLET);
+    send_configure_after_layout_change_ = true;
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&WaylandRemoteShell::MaybeSendConfigure,
+                              weak_ptr_factory_.GetWeakPtr()),
+        base::TimeDelta::FromMilliseconds(kConfigureDelayAfterLayoutSwitchMs));
   }
   void OnMaximizeModeEnded() override {
     SendLayoutModeChange(ZWP_REMOTE_SHELL_V1_LAYOUT_MODE_WINDOWED);
+    send_configure_after_layout_change_ = true;
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&WaylandRemoteShell::MaybeSendConfigure,
+                              weak_ptr_factory_.GetWeakPtr()),
+        base::TimeDelta::FromMilliseconds(kConfigureDelayAfterLayoutSwitchMs));
   }
 
   // Overridden from aura::client::ActivationChangeObserver:
@@ -1599,7 +1616,13 @@
   }
 
  private:
+  void MaybeSendConfigure() {
+    if (send_configure_after_layout_change_)
+      SendConfigure();
+  }
+
   void SendConfigure() {
+    send_configure_after_layout_change_ = false;
     const display::Display& display =
         ash::Shell::GetInstance()->display_manager()->GetDisplayForId(
             display_id_);
@@ -1611,7 +1634,7 @@
     wl_client_flush(wl_resource_get_client(remote_shell_resource_));
   }
 
-  void SendLayoutModeChange(int mode) {
+  void SendLayoutModeChange(uint32_t mode) {
     if (wl_resource_get_version(remote_shell_resource_) < 8)
       return;
     zwp_remote_shell_v1_send_layout_mode_changed(remote_shell_resource_, mode);
@@ -1660,6 +1683,10 @@
   // The remote shell resource associated with observer.
   wl_resource* const remote_shell_resource_;
 
+  bool send_configure_after_layout_change_ = false;
+
+  base::WeakPtrFactory<WaylandRemoteShell> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(WaylandRemoteShell);
 };
 
diff --git a/components/filesystem/BUILD.gn b/components/filesystem/BUILD.gn
index c35762c2..67f6234 100644
--- a/components/filesystem/BUILD.gn
+++ b/components/filesystem/BUILD.gn
@@ -76,7 +76,7 @@
     "//mojo/common",
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
-    "//services/shell/public/cpp:shell_test_support",
+    "//services/shell/public/cpp:service_test_support",
     "//services/shell/public/cpp:sources",
     "//services/shell/public/cpp/test:run_all_shelltests",
   ]
diff --git a/components/filesystem/files_test_base.cc b/components/filesystem/files_test_base.cc
index c1a6d8b..b8a4d08 100644
--- a/components/filesystem/files_test_base.cc
+++ b/components/filesystem/files_test_base.cc
@@ -12,14 +12,15 @@
 
 namespace filesystem {
 
-FilesTestBase::FilesTestBase() : ShellTest("exe:filesystem_service_unittests") {
+FilesTestBase::FilesTestBase()
+    : ServiceTest("exe:filesystem_service_unittests") {
 }
 
 FilesTestBase::~FilesTestBase() {
 }
 
 void FilesTestBase::SetUp() {
-  ShellTest::SetUp();
+  ServiceTest::SetUp();
   connector()->ConnectToInterface("mojo:filesystem", &files_);
 }
 
diff --git a/components/filesystem/files_test_base.h b/components/filesystem/files_test_base.h
index fc594b0..8712a6c 100644
--- a/components/filesystem/files_test_base.h
+++ b/components/filesystem/files_test_base.h
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "components/filesystem/public/interfaces/file_system.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_test.h"
 
 namespace filesystem {
 
@@ -37,12 +37,12 @@
   return base::Bind(&DoCaptures<T1, T2, T3>, t1, t2, t3);
 }
 
-class FilesTestBase : public shell::test::ShellTest {
+class FilesTestBase : public shell::test::ServiceTest {
  public:
   FilesTestBase();
   ~FilesTestBase() override;
 
-  // Overridden from shell::test::ShellTest:
+  // Overridden from shell::test::ServiceTest:
   void SetUp() override;
 
  protected:
diff --git a/components/gcm_driver/crypto/gcm_encryption_provider.cc b/components/gcm_driver/crypto/gcm_encryption_provider.cc
index 9532d3b..fb3fd9ae 100644
--- a/components/gcm_driver/crypto/gcm_encryption_provider.cc
+++ b/components/gcm_driver/crypto/gcm_encryption_provider.cc
@@ -31,7 +31,7 @@
 
 std::string GCMEncryptionProvider::ToDecryptionResultDetailsString(
     DecryptionResult result) {
-  switch(result) {
+  switch (result) {
     case DECRYPTION_RESULT_UNENCRYPTED:
       return "Message was not encrypted";
     case DECRYPTION_RESULT_DECRYPTED:
diff --git a/components/history/core/browser/android/android_urls_sql_handler.cc b/components/history/core/browser/android/android_urls_sql_handler.cc
index e7552919..31d2299 100644
--- a/components/history/core/browser/android/android_urls_sql_handler.cc
+++ b/components/history/core/browser/android/android_urls_sql_handler.cc
@@ -51,14 +51,9 @@
 
 bool AndroidURLsSQLHandler::Delete(const TableIDRows& ids_set) {
   std::vector<URLID> ids;
-  for (TableIDRows::const_iterator id = ids_set.begin();
-       id != ids_set.end(); ++id)
-    ids.push_back(id->url_id);
-
-  if (!ids.size())
-    return true;
-
-  return android_urls_db_->DeleteAndroidURLRows(ids);
+  for (const auto& id : ids_set)
+    ids.push_back(id.url_id);
+  return ids.empty() || android_urls_db_->DeleteAndroidURLRows(ids);
 }
 
 }  // namespace history.
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc
index 42732d85..4ca3a34 100644
--- a/components/history/core/browser/history_backend.cc
+++ b/components/history/core/browser/history_backend.cc
@@ -102,7 +102,7 @@
     mv.redirects.push_back(mv.url);
   } else {
     mv.redirects = redirects;
-    if (mv.redirects[mv.redirects.size() - 1] != mv.url) {
+    if (mv.redirects.back() != mv.url) {
       // The last url must be the target url.
       mv.redirects.push_back(mv.url);
     }
diff --git a/components/history/core/browser/url_database.cc b/components/history/core/browser/url_database.cc
index 3b4cb27..5558457 100644
--- a/components/history/core/browser/url_database.cc
+++ b/components/history/core/browser/url_database.cc
@@ -528,8 +528,7 @@
   base::string16 lower_prefix = base::i18n::ToLower(prefix);
   // This magic gives us a prefix search.
   base::string16 next_prefix = lower_prefix;
-  next_prefix[next_prefix.size() - 1] =
-      next_prefix[next_prefix.size() - 1] + 1;
+  next_prefix.back() = next_prefix.back() + 1;
   statement.BindInt64(0, keyword_id);
   statement.BindString16(1, lower_prefix);
   statement.BindString16(2, next_prefix);
diff --git a/components/leveldb/BUILD.gn b/components/leveldb/BUILD.gn
index fb7068f9..012155f 100644
--- a/components/leveldb/BUILD.gn
+++ b/components/leveldb/BUILD.gn
@@ -70,7 +70,7 @@
     "//mojo/common",
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
-    "//services/shell/public/cpp:shell_test_support",
+    "//services/shell/public/cpp:service_test_support",
     "//services/shell/public/cpp:sources",
     "//services/shell/public/cpp/test:run_all_shelltests",
     "//third_party/leveldatabase",
diff --git a/components/leveldb/env_mojo.cc b/components/leveldb/env_mojo.cc
index 54681d0d..233a0cd 100644
--- a/components/leveldb/env_mojo.cc
+++ b/components/leveldb/env_mojo.cc
@@ -8,6 +8,7 @@
 
 #include <memory>
 
+#include "base/strings/string_util.h"
 #include "base/trace_event/trace_event.h"
 #include "third_party/leveldatabase/chromium_logger.h"
 #include "third_party/leveldatabase/src/include/leveldb/status.h"
@@ -137,10 +138,12 @@
         dir_(dir),
         thread_(thread) {
     base::FilePath path = base::FilePath::FromUTF8Unsafe(fname);
-    if (path.BaseName().AsUTF8Unsafe().find("MANIFEST") == 0)
+    if (base::StartsWith(path.BaseName().AsUTF8Unsafe(), "MANIFEST",
+                         base::CompareCase::SENSITIVE)) {
       file_type_ = kManifest;
-    else if (path.MatchesExtension(table_extension))
+    } else if (path.MatchesExtension(table_extension)) {
       file_type_ = kTable;
+    }
     parent_dir_ =
         base::FilePath::FromUTF8Unsafe(fname).DirName().AsUTF8Unsafe();
   }
diff --git a/components/leveldb/leveldb_service_unittest.cc b/components/leveldb/leveldb_service_unittest.cc
index 893ea6f..f6160c0 100644
--- a/components/leveldb/leveldb_service_unittest.cc
+++ b/components/leveldb/leveldb_service_unittest.cc
@@ -10,8 +10,8 @@
 #include "components/leveldb/public/interfaces/leveldb.mojom.h"
 #include "mojo/common/common_type_converters.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/shell/public/cpp/shell_connection.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_context.h"
+#include "services/shell/public/cpp/service_test.h"
 
 using filesystem::mojom::FileError;
 
@@ -35,15 +35,15 @@
   return base::Bind(&DoCaptures<T1, T2>, t1, t2);
 }
 
-class LevelDBServiceTest : public shell::test::ShellTest {
+class LevelDBServiceTest : public shell::test::ServiceTest {
  public:
-  LevelDBServiceTest() : ShellTest("exe:leveldb_service_unittests") {}
+  LevelDBServiceTest() : ServiceTest("exe:leveldb_service_unittests") {}
   ~LevelDBServiceTest() override {}
 
  protected:
   // Overridden from mojo::test::ApplicationTestBase:
   void SetUp() override {
-    ShellTest::SetUp();
+    ServiceTest::SetUp();
     connector()->ConnectToInterface("mojo:filesystem", &files_);
     connector()->ConnectToInterface("mojo:leveldb", &leveldb_);
   }
@@ -51,7 +51,7 @@
   void TearDown() override {
     leveldb_.reset();
     files_.reset();
-    ShellTest::TearDown();
+    ServiceTest::TearDown();
   }
 
   // Note: This has an out parameter rather than returning the |DirectoryPtr|,
diff --git a/components/leveldb/remote_iterator_unittest.cc b/components/leveldb/remote_iterator_unittest.cc
index bd61679..884915b 100644
--- a/components/leveldb/remote_iterator_unittest.cc
+++ b/components/leveldb/remote_iterator_unittest.cc
@@ -8,8 +8,8 @@
 #include "components/leveldb/public/cpp/remote_iterator.h"
 #include "components/leveldb/public/interfaces/leveldb.mojom.h"
 #include "mojo/common/common_type_converters.h"
-#include "services/shell/public/cpp/shell_connection.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_context.h"
+#include "services/shell/public/cpp/service_test.h"
 
 namespace leveldb {
 namespace {
@@ -22,15 +22,15 @@
   return base::Bind(&DoCapture<T1>, t1);
 }
 
-class RemoteIteratorTest : public shell::test::ShellTest {
+class RemoteIteratorTest : public shell::test::ServiceTest {
  public:
-  RemoteIteratorTest() : ShellTest("exe:leveldb_service_unittests") {}
+  RemoteIteratorTest() : ServiceTest("exe:leveldb_service_unittests") {}
   ~RemoteIteratorTest() override {}
 
  protected:
   // Overridden from mojo::test::ApplicationTestBase:
   void SetUp() override {
-    ShellTest::SetUp();
+    ServiceTest::SetUp();
     connector()->ConnectToInterface("mojo:leveldb", &leveldb_);
 
     mojom::DatabaseError error;
@@ -53,7 +53,7 @@
 
   void TearDown() override {
     leveldb_.reset();
-    ShellTest::TearDown();
+    ServiceTest::TearDown();
   }
 
   mojom::LevelDBServicePtr& leveldb() { return leveldb_; }
diff --git a/components/network_session_configurator/network_session_configurator.cc b/components/network_session_configurator/network_session_configurator.cc
index bca6885..f2f70aef 100644
--- a/components/network_session_configurator/network_session_configurator.cc
+++ b/components/network_session_configurator/network_session_configurator.cc
@@ -45,11 +45,6 @@
 const char kSpdyFieldTrialSpdy4GroupNamePrefix[] = "Spdy4Enabled";
 const char kSpdyFieldTrialParametrizedPrefix[] = "Parametrized";
 
-// Field trial for NPN.
-const char kNpnTrialName[] = "NPN";
-const char kNpnTrialEnabledGroupNamePrefix[] = "Enable";
-const char kNpnTrialDisabledGroupNamePrefix[] = "Disable";
-
 // Field trial for priority dependencies.
 const char kSpdyDependenciesFieldTrial[] = "SpdyEnableDependencies";
 const char kSpdyDependenciesFieldTrialEnable[] = "Enable";
@@ -140,16 +135,6 @@
   }
 }
 
-void ConfigureNPNParams(const base::CommandLine& command_line,
-                        base::StringPiece npn_trial_group,
-                        net::HttpNetworkSession::Params* params) {
-  if (npn_trial_group.starts_with(kNpnTrialEnabledGroupNamePrefix)) {
-    params->enable_npn = true;
-  } else if (npn_trial_group.starts_with(kNpnTrialDisabledGroupNamePrefix)) {
-    params->enable_npn = false;
-  }
-}
-
 void ConfigurePriorityDependencies(
     base::StringPiece priority_dependencies_trial_group,
     net::HttpNetworkSession::Params* params) {
@@ -548,10 +533,6 @@
       base::FieldTrialList::FindFullName(kTCPFastOpenFieldTrialName);
   ConfigureTCPFastOpenParams(tfo_trial_group, params);
 
-  std::string npn_trial_group =
-      base::FieldTrialList::FindFullName(kNpnTrialName);
-  ConfigureNPNParams(command_line, npn_trial_group, params);
-
   std::string priority_dependencies_trial_group =
       base::FieldTrialList::FindFullName(kSpdyDependenciesFieldTrial);
   ConfigurePriorityDependencies(priority_dependencies_trial_group, params);
diff --git a/components/network_session_configurator/network_session_configurator_unittest.cc b/components/network_session_configurator/network_session_configurator_unittest.cc
index df8a77c..604c0461 100644
--- a/components/network_session_configurator/network_session_configurator_unittest.cc
+++ b/components/network_session_configurator/network_session_configurator_unittest.cc
@@ -58,7 +58,6 @@
   EXPECT_TRUE(params_.enable_http2);
   EXPECT_FALSE(params_.enable_tcp_fast_open_for_ssl);
   EXPECT_TRUE(params_.enable_quic_alternative_service_with_different_host);
-  EXPECT_FALSE(params_.enable_npn);
   EXPECT_TRUE(params_.enable_priority_dependencies);
   EXPECT_FALSE(params_.enable_quic);
 }
@@ -145,22 +144,6 @@
   EXPECT_TRUE(params_.enable_http2);
 }
 
-TEST_F(NetworkSessionConfiguratorTest, NPNFieldTrialEnabled) {
-  base::FieldTrialList::CreateFieldTrial("NPN", "Enable-experiment");
-
-  ParseFieldTrials();
-
-  EXPECT_TRUE(params_.enable_npn);
-}
-
-TEST_F(NetworkSessionConfiguratorTest, NPNFieldTrialDisabled) {
-  base::FieldTrialList::CreateFieldTrial("NPN", "Disable-holdback");
-
-  ParseFieldTrials();
-
-  EXPECT_FALSE(params_.enable_npn);
-}
-
 TEST_F(NetworkSessionConfiguratorTest, PriorityDependenciesTrialEnabled) {
   base::FieldTrialList::CreateFieldTrial("SpdyEnableDependencies",
                                          "Enable-experiment");
diff --git a/components/ntp_snippets/ntp_snippets_service.cc b/components/ntp_snippets/ntp_snippets_service.cc
index 08f4203..4b18a58 100644
--- a/components/ntp_snippets/ntp_snippets_service.cc
+++ b/components/ntp_snippets/ntp_snippets_service.cc
@@ -139,7 +139,11 @@
   exploded.minute = 0;
   exploded.second = 0;
   exploded.millisecond = 0;
-  base::Time reschedule = base::Time::FromLocalExploded(exploded);
+  base::Time reschedule;
+  if (!base::Time::FromLocalExploded(exploded, &reschedule)) {
+    return GetRescheduleTime(now + base::TimeDelta::FromDays(1));
+  }
+
   if (next_day)
     reschedule += base::TimeDelta::FromDays(1);
 
diff --git a/components/ntp_snippets/ntp_snippets_service_unittest.cc b/components/ntp_snippets/ntp_snippets_service_unittest.cc
index 2b87e730..9ba767d 100644
--- a/components/ntp_snippets/ntp_snippets_service_unittest.cc
+++ b/components/ntp_snippets/ntp_snippets_service_unittest.cc
@@ -67,7 +67,9 @@
 const float kSnippetScore = 5.0;
 
 base::Time GetDefaultCreationTime() {
-  return base::Time::FromUTCExploded(kDefaultCreationTime);
+  base::Time out_time;
+  EXPECT_TRUE(base::Time::FromUTCExploded(kDefaultCreationTime, &out_time));
+  return out_time;
 }
 
 base::Time GetDefaultExpirationTime() {
diff --git a/components/offline_pages/offline_page_model_impl.cc b/components/offline_pages/offline_page_model_impl.cc
index 78cf6eb..8642ab13 100644
--- a/components/offline_pages/offline_page_model_impl.cc
+++ b/components/offline_pages/offline_page_model_impl.cc
@@ -740,8 +740,13 @@
   }
   InformSavePageDone(callback, result, offline_page.client_id,
                      offline_page.offline_id);
-  DeletePendingArchiver(archiver);
+  if (result == SavePageResult::SUCCESS) {
+    DeleteExistingPagesWithSameURL(offline_page);
+  } else {
+    PostClearStorageIfNeededTask();
+  }
 
+  DeletePendingArchiver(archiver);
   FOR_EACH_OBSERVER(Observer, observers_, OfflinePageModelChanged(this));
 }
 
@@ -808,30 +813,31 @@
   ReportSavePageResultHistogramAfterSave(client_id, result);
   archive_manager_->GetStorageStats(
       base::Bind(&ReportStorageHistogramsAfterSave));
-  // Remove existing pages generated by the same policy and with same url.
-  size_t pages_allowed =
-      policy_controller_->GetPolicy(client_id.name_space).pages_allowed_per_url;
-  if (result == SavePageResult::SUCCESS && pages_allowed != kUnlimitedPages) {
-    GetPagesByOnlineURL(
-        offline_pages_[offline_id].url,
-        base::Bind(&OfflinePageModelImpl::OnPagesFoundWithSameURL,
-                   weak_ptr_factory_.GetWeakPtr(), client_id, offline_id,
-                   pages_allowed));
-  } else {
-    PostClearStorageIfNeededTask();
-  }
   callback.Run(result, offline_id);
 }
 
+void OfflinePageModelImpl::DeleteExistingPagesWithSameURL(
+    const OfflinePageItem& offline_page) {
+  // Remove existing pages generated by the same policy and with same url.
+  size_t pages_allowed =
+      policy_controller_->GetPolicy(offline_page.client_id.name_space)
+          .pages_allowed_per_url;
+  if (pages_allowed == kUnlimitedPages)
+    return;
+  GetPagesByOnlineURL(
+      offline_page.url,
+      base::Bind(&OfflinePageModelImpl::OnPagesFoundWithSameURL,
+                 weak_ptr_factory_.GetWeakPtr(), offline_page, pages_allowed));
+}
+
 void OfflinePageModelImpl::OnPagesFoundWithSameURL(
-    const ClientId& client_id,
-    int64_t offline_id,
+    const OfflinePageItem& offline_page,
     size_t pages_allowed,
     const MultipleOfflinePageItemResult& items) {
   std::vector<OfflinePageItem> pages_to_delete;
   for (const auto& item : items) {
-    if (item.offline_id != offline_id &&
-        item.client_id.name_space == client_id.name_space) {
+    if (item.offline_id != offline_page.offline_id &&
+        item.client_id.name_space == offline_page.client_id.name_space) {
       pages_to_delete.push_back(item);
     }
   }
diff --git a/components/offline_pages/offline_page_model_impl.h b/components/offline_pages/offline_page_model_impl.h
index afda58c..1efb687 100644
--- a/components/offline_pages/offline_page_model_impl.h
+++ b/components/offline_pages/offline_page_model_impl.h
@@ -214,8 +214,8 @@
                                     bool success);
 
   // Callbacks for deleting pages with same URL when saving pages.
-  void OnPagesFoundWithSameURL(const ClientId& client_id,
-                               int64_t offline_id,
+  void DeleteExistingPagesWithSameURL(const OfflinePageItem& offline_page);
+  void OnPagesFoundWithSameURL(const OfflinePageItem& offline_page,
                                size_t pages_allowed,
                                const MultipleOfflinePageItemResult& items);
   void OnDeleteOldPagesWithSameURL(DeletePageResult result);
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index ae8f2c8c..cea5a58c 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -227,12 +227,26 @@
   std::string demotion_rule = OmniboxFieldTrial::GetValueForRuleInContext(
       kDemoteByTypeRule, current_page_classification);
   // If there is no demotion rule for this context, then use the default
-  // value for that context.  At the moment the default value is non-empty
-  // only for the fakebox-focus context.
-  if (demotion_rule.empty() &&
-      (current_page_classification ==
-       OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS))
-    demotion_rule = "1:61,2:61,3:61,4:61,16:61";
+  // value for that context.
+  if (demotion_rule.empty()) {
+    // This rule demotes URLs as strongly as possible without violating user
+    // expectations.  In particular, for URL-seeking inputs, if the user would
+    // likely expect a URL first (i.e., it would be inline autocompleted), then
+    // that URL will still score strongly enough to be first.  This is done
+    // using a demotion multipler of 0.61.  If a URL would get a score high
+    // enough to be inline autocompleted (1400+), even after demotion it will
+    // score above 850 ( 1400 * 0.61 > 850).  850 is the maximum score for
+    // queries when the input has been detected as URL-seeking.
+    constexpr char kDemoteURLs[] = "1:61,2:61,3:61,4:61,16:61";
+#if defined(OS_ANDROID)
+    if (current_page_classification == OmniboxEventProto::
+        SEARCH_RESULT_PAGE_NO_SEARCH_TERM_REPLACEMENT)
+      demotion_rule = kDemoteURLs;
+#endif
+    if (current_page_classification ==
+        OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS)
+      demotion_rule = kDemoteURLs;
+  }
 
   // The value of the DemoteByType rule is a comma-separated list of
   // {ResultType + ":" + Number} where ResultType is an AutocompleteMatchType::
diff --git a/components/os_crypt/os_crypt_posix.cc b/components/os_crypt/os_crypt_posix.cc
index 44f04b3..24a411e 100644
--- a/components/os_crypt/os_crypt_posix.cc
+++ b/components/os_crypt/os_crypt_posix.cc
@@ -9,6 +9,7 @@
 #include <memory>
 
 #include "base/logging.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "crypto/encryptor.h"
 #include "crypto/symmetric_key.h"
@@ -118,7 +119,8 @@
   // old data saved as clear text and we'll return it directly.
   // Credit card numbers are current legacy data, so false match with prefix
   // won't happen.
-  if (ciphertext.find(kObfuscationPrefix) != 0) {
+  if (!base::StartsWith(ciphertext, kObfuscationPrefix,
+                        base::CompareCase::SENSITIVE)) {
     *plaintext = ciphertext;
     return true;
   }
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index 9842dc2..1ffb69d 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -177,7 +177,11 @@
        form.signon_realm == "https://www.google.com/")) {
     static const base::Time::Exploded exploded_cutoff =
         { 2012, 1, 0, 1, 0, 0, 0, 0 };  // 00:00 Jan 1 2012
-    ignore_logins_cutoff = base::Time::FromUTCExploded(exploded_cutoff);
+    base::Time out_time;
+    bool conversion_success =
+        base::Time::FromUTCExploded(exploded_cutoff, &out_time);
+    DCHECK(conversion_success);
+    ignore_logins_cutoff = out_time;
   }
   std::unique_ptr<GetLoginsRequest> request(new GetLoginsRequest(consumer));
   request->set_ignore_logins_cutoff(ignore_logins_cutoff);
diff --git a/components/password_manager/core/browser/password_store_change.cc b/components/password_manager/core/browser/password_store_change.cc
index 950f55c..c5c82e08 100644
--- a/components/password_manager/core/browser/password_store_change.cc
+++ b/components/password_manager/core/browser/password_store_change.cc
@@ -9,7 +9,7 @@
 std::ostream& operator<<(std::ostream& os,
                          const PasswordStoreChange& password_store_change) {
   return os << "type: " << password_store_change.type()
-            << "password form: " << password_store_change.form();
+            << ", password form: " << password_store_change.form();
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_store_change.h b/components/password_manager/core/browser/password_store_change.h
index 90211ef..0d37f9d 100644
--- a/components/password_manager/core/browser/password_store_change.h
+++ b/components/password_manager/core/browser/password_store_change.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_STORE_CHANGE_H__
 #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_STORE_CHANGE_H__
 
+#include <ostream>
 #include <vector>
 
 #include "components/autofill/core/common/password_form.h"
diff --git a/components/password_manager/core/browser/password_store_default_unittest.cc b/components/password_manager/core/browser/password_store_default_unittest.cc
index 9648d2a..884adda 100644
--- a/components/password_manager/core/browser/password_store_default_unittest.cc
+++ b/components/password_manager/core/browser/password_store_default_unittest.cc
@@ -61,20 +61,18 @@
 };
 
 PasswordFormData CreateTestPasswordFormData() {
-  PasswordFormData data = {
-    PasswordForm::SCHEME_HTML,
-    "http://bar.example.com",
-    "http://bar.example.com/origin",
-    "http://bar.example.com/action",
-    L"submit_element",
-    L"username_element",
-    L"password_element",
-    L"username_value",
-    L"password_value",
-    true,
-    false,
-    1
-  };
+  PasswordFormData data = {PasswordForm::SCHEME_HTML,
+                           "http://bar.example.com",
+                           "http://bar.example.com/origin",
+                           "http://bar.example.com/action",
+                           L"submit_element",
+                           L"username_element",
+                           L"password_element",
+                           L"username_value",
+                           L"password_value",
+                           true,
+                           false,
+                           1};
   return data;
 }
 
@@ -168,16 +166,10 @@
 
   // Some non-ASCII password form data.
   static const PasswordFormData form_data[] = {
-    { PasswordForm::SCHEME_HTML,
-      "http://foo.example.com",
-      "http://foo.example.com/origin",
-      "http://foo.example.com/action",
-      L"มีสีสัน",
-      L"お元気ですか?",
-      L"盆栽",
-      L"أحب كرة",
-      L"£éä국수çà",
-      true, false, 1 },
+      {PasswordForm::SCHEME_HTML, "http://foo.example.com",
+       "http://foo.example.com/origin", "http://foo.example.com/action",
+       L"มีสีสัน", L"お元気ですか?", L"盆栽", L"أحب كرة", L"£éä국수çà", true,
+       false, 1},
   };
 
   // Build the expected forms vector and add the forms to the store.
@@ -212,7 +204,7 @@
   store->AddObserver(&observer);
 
   const PasswordStoreChange expected_add_changes[] = {
-    PasswordStoreChange(PasswordStoreChange::ADD, *form),
+      PasswordStoreChange(PasswordStoreChange::ADD, *form),
   };
 
   EXPECT_CALL(observer,
@@ -226,7 +218,7 @@
   form->password_value = base::ASCIIToUTF16("a different password");
 
   const PasswordStoreChange expected_update_changes[] = {
-    PasswordStoreChange(PasswordStoreChange::UPDATE, *form),
+      PasswordStoreChange(PasswordStoreChange::UPDATE, *form),
   };
 
   EXPECT_CALL(observer,
@@ -237,7 +229,7 @@
   base::RunLoop().RunUntilIdle();
 
   const PasswordStoreChange expected_delete_changes[] = {
-    PasswordStoreChange(PasswordStoreChange::REMOVE, *form),
+      PasswordStoreChange(PasswordStoreChange::REMOVE, *form),
   };
 
   EXPECT_CALL(observer,
diff --git a/components/password_manager/core/browser/password_store_unittest.cc b/components/password_manager/core/browser/password_store_unittest.cc
index c2b44a4..ac22a33 100644
--- a/components/password_manager/core/browser/password_store_unittest.cc
+++ b/components/password_manager/core/browser/password_store_unittest.cc
@@ -87,9 +87,7 @@
 
 class PasswordStoreTest : public testing::Test {
  protected:
-  void SetUp() override {
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-  }
+  void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
 
   void TearDown() override { ASSERT_TRUE(temp_dir_.Delete()); }
 
@@ -113,61 +111,34 @@
 
   const time_t cutoff = 1325376000;  // 00:00 Jan 1 2012 UTC
   static const PasswordFormData form_data[] = {
-    // A form on https://www.google.com/ older than the cutoff. Will be ignored.
-    { PasswordForm::SCHEME_HTML,
-      "https://www.google.com",
-      "https://www.google.com/origin",
-      "https://www.google.com/action",
-      L"submit_element",
-      L"username_element",
-      L"password_element",
-      L"username_value_1",
-      L"",
-      true, true, cutoff - 1 },
-    // A form on https://www.google.com/ older than the cutoff. Will be ignored.
-    { PasswordForm::SCHEME_HTML,
-      "https://www.google.com",
-      "https://www.google.com/origin",
-      "https://www.google.com/action",
-      L"submit_element",
-      L"username_element",
-      L"password_element",
-      L"username_value_2",
-      L"",
-      true, true, cutoff - 1 },
-    // A form on https://www.google.com/ newer than the cutoff.
-    { PasswordForm::SCHEME_HTML,
-      "https://www.google.com",
-      "https://www.google.com/origin",
-      "https://www.google.com/action",
-      L"submit_element",
-      L"username_element",
-      L"password_element",
-      L"username_value_3",
-      L"",
-      true, true, cutoff + 1 },
-    // A form on https://accounts.google.com/ older than the cutoff.
-    { PasswordForm::SCHEME_HTML,
-      "https://accounts.google.com",
-      "https://accounts.google.com/origin",
-      "https://accounts.google.com/action",
-      L"submit_element",
-      L"username_element",
-      L"password_element",
-      L"username_value",
-      L"",
-      true, true, cutoff - 1 },
-    // A form on http://bar.example.com/ older than the cutoff.
-    { PasswordForm::SCHEME_HTML,
-      "http://bar.example.com",
-      "http://bar.example.com/origin",
-      "http://bar.example.com/action",
-      L"submit_element",
-      L"username_element",
-      L"password_element",
-      L"username_value",
-      L"",
-      true, false, cutoff - 1 },
+      // A form on https://www.google.com/ older than the cutoff. Will be
+      // ignored.
+      {PasswordForm::SCHEME_HTML, "https://www.google.com",
+       "https://www.google.com/origin", "https://www.google.com/action",
+       L"submit_element", L"username_element", L"password_element",
+       L"username_value_1", L"", true, true, cutoff - 1},
+      // A form on https://www.google.com/ older than the cutoff. Will be
+      // ignored.
+      {PasswordForm::SCHEME_HTML, "https://www.google.com",
+       "https://www.google.com/origin", "https://www.google.com/action",
+       L"submit_element", L"username_element", L"password_element",
+       L"username_value_2", L"", true, true, cutoff - 1},
+      // A form on https://www.google.com/ newer than the cutoff.
+      {PasswordForm::SCHEME_HTML, "https://www.google.com",
+       "https://www.google.com/origin", "https://www.google.com/action",
+       L"submit_element", L"username_element", L"password_element",
+       L"username_value_3", L"", true, true, cutoff + 1},
+      // A form on https://accounts.google.com/ older than the cutoff.
+      {PasswordForm::SCHEME_HTML, "https://accounts.google.com",
+       "https://accounts.google.com/origin",
+       "https://accounts.google.com/action", L"submit_element",
+       L"username_element", L"password_element", L"username_value", L"", true,
+       true, cutoff - 1},
+      // A form on http://bar.example.com/ older than the cutoff.
+      {PasswordForm::SCHEME_HTML, "http://bar.example.com",
+       "http://bar.example.com/origin", "http://bar.example.com/action",
+       L"submit_element", L"username_element", L"password_element",
+       L"username_value", L"", true, false, cutoff - 1},
   };
 
   // Build the forms vector and add the forms to the store.
diff --git a/components/policy/BUILD.gn b/components/policy/BUILD.gn
index c2c7ea51..312d048 100644
--- a/components/policy/BUILD.gn
+++ b/components/policy/BUILD.gn
@@ -330,7 +330,6 @@
       ]
 
       args = [
-               "xcrun",
                "plutil",
                "-convert",
                "xml1",
diff --git a/components/policy/core/common/cloud/cloud_policy_constants.cc b/components/policy/core/common/cloud/cloud_policy_constants.cc
index be383dbf..46ecf6b 100644
--- a/components/policy/core/common/cloud/cloud_policy_constants.cc
+++ b/components/policy/core/common/cloud/cloud_policy_constants.cc
@@ -93,8 +93,6 @@
 const char kPolicyVerificationKeyHash[] = "1:356l7w";
 
 std::string GetPolicyVerificationKey() {
-  // Disable key verification by default until production servers generate
-  // the proper signatures.
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(switches::kDisablePolicyKeyVerification)) {
     return std::string();
diff --git a/components/printing/renderer/print_web_view_helper.cc b/components/printing/renderer/print_web_view_helper.cc
index 33fd48a..683bf39 100644
--- a/components/printing/renderer/print_web_view_helper.cc
+++ b/components/printing/renderer/print_web_view_helper.cc
@@ -32,6 +32,7 @@
 #include "printing/metafile_skia_wrapper.h"
 #include "printing/pdf_metafile_skia.h"
 #include "printing/units.h"
+#include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
 #include "third_party/WebKit/public/platform/WebSize.h"
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
@@ -751,7 +752,9 @@
 
   // When loading is done this will call didStopLoading() and that will do the
   // actual printing.
-  frame()->loadRequest(blink::WebURLRequest(GURL(url_str)));
+  blink::WebURLRequest request = blink::WebURLRequest(GURL(url_str));
+  request.setRequestorOrigin(blink::WebSecurityOrigin::createUnique());
+  frame()->loadRequest(request);
 }
 
 bool PrepareFrameAndViewForPrint::allowsBrokenNullLayerTreeView() const {
diff --git a/components/proximity_auth/remote_device_loader.cc b/components/proximity_auth/remote_device_loader.cc
index efb9fc9..7fe98c7 100644
--- a/components/proximity_auth/remote_device_loader.cc
+++ b/components/proximity_auth/remote_device_loader.cc
@@ -88,7 +88,7 @@
       user_id_, unlock_key.friendly_device_name(), unlock_key.public_key(),
       bluetooth_type, bluetooth_address, psk, std::string()));
 
-  if (!remaining_unlock_keys_.size())
+  if (remaining_unlock_keys_.empty())
     callback_.Run(remote_devices_);
 }
 
diff --git a/components/safe_browsing_db/util.cc b/components/safe_browsing_db/util.cc
index 3289aaae..74eb45e4 100644
--- a/components/safe_browsing_db/util.cc
+++ b/components/safe_browsing_db/util.cc
@@ -403,8 +403,7 @@
       // We may have /foo as path-prefix in the whitelist which should
       // also match with /foo/bar and /foo?bar.  Hence, for every path
       // that ends in '/' we also add the path without the slash.
-      if (include_whitelist_hashes && path.size() > 1 &&
-          path[path.size() - 1] == '/') {
+      if (include_whitelist_hashes && path.size() > 1 && path.back() == '/') {
         full_hashes->push_back(SBFullHashForString(
             host + path.substr(0, path.size() - 1)));
       }
diff --git a/components/safe_browsing_db/v4_store.cc b/components/safe_browsing_db/v4_store.cc
index 0920f2b..2ef5c03 100644
--- a/components/safe_browsing_db/v4_store.cc
+++ b/components/safe_browsing_db/v4_store.cc
@@ -67,8 +67,8 @@
   std::string state_base64;
   base::Base64Encode(state_, &state_base64);
 
-  return base::StringPrintf("path: %s; state: %s", store_path_.value().c_str(),
-                            state_base64.c_str());
+  return base::StringPrintf("path: %" PRIsFP "; state: %s",
+                            store_path_.value().c_str(), state_base64.c_str());
 }
 
 bool V4Store::Reset() {
diff --git a/components/scheduler/BUILD.gn b/components/scheduler/BUILD.gn
index 35138e7..236b9a436 100644
--- a/components/scheduler/BUILD.gn
+++ b/components/scheduler/BUILD.gn
@@ -13,6 +13,8 @@
     "base/lazy_now.h",
     "base/pollable_thread_safe_flag.cc",
     "base/pollable_thread_safe_flag.h",
+    "base/queueing_time_estimator.cc",
+    "base/queueing_time_estimator.h",
     "base/real_time_domain.cc",
     "base/real_time_domain.h",
     "base/task_queue.h",
@@ -23,6 +25,7 @@
     "base/task_queue_manager_delegate.h",
     "base/task_queue_selector.cc",
     "base/task_queue_selector.h",
+    "base/task_time_tracker.h",
     "base/time_domain.cc",
     "base/time_domain.h",
     "base/virtual_time_domain.cc",
@@ -119,12 +122,14 @@
   testonly = true
 
   sources = [
+    "base/queueing_time_estimator_unittest.cc",
     "base/task_queue_manager_delegate_for_test.cc",
     "base/task_queue_manager_delegate_for_test.h",
     "base/task_queue_manager_unittest.cc",
     "base/task_queue_selector_unittest.cc",
-    "base/test_always_fail_time_source.cc",
-    "base/test_always_fail_time_source.h",
+    "base/test_count_uses_time_source.cc",
+    "base/test_count_uses_time_source.h",
+    "base/test_task_time_tracker.h",
     "base/test_time_source.cc",
     "base/test_time_source.h",
     "base/time_domain_unittest.cc",
diff --git a/components/scheduler/base/queueing_time_estimator.cc b/components/scheduler/base/queueing_time_estimator.cc
new file mode 100644
index 0000000..1402380
--- /dev/null
+++ b/components/scheduler/base/queueing_time_estimator.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 "components/scheduler/base/queueing_time_estimator.h"
+
+#include "base/time/default_tick_clock.h"
+
+namespace scheduler {
+
+namespace {
+
+// This method computes the expected queueing time of a randomly distributed
+// task R within a window containing a single task T. Let T' be the time range
+// for which T overlaps the window. We first compute the probability that R will
+// start within T'. We then compute the expected queueing duration if R does
+// start within this range. Since the start time of R is uniformly distributed
+// within the window, this is equal to the average of the queueing times if R
+// started at the beginning or end of T'. The expected queueing time of T is the
+// probability that R will start within T', multiplied by the expected queueing
+// duration if R does fall in this range.
+base::TimeDelta ExpectedQueueingTimeFromTask(base::TimeTicks task_start,
+                                             base::TimeTicks task_end,
+                                             base::TimeTicks window_start,
+                                             base::TimeTicks window_end) {
+  DCHECK(task_start <= task_end);
+  DCHECK(task_start <= window_end);
+  DCHECK(window_start < window_end);
+  DCHECK(task_end >= window_start);
+  base::TimeTicks task_in_window_start_time =
+      std::max(task_start, window_start);
+  base::TimeTicks task_in_window_end_time =
+      std::min(task_end, window_end);
+  DCHECK(task_in_window_end_time <= task_in_window_end_time);
+
+  double probability_of_this_task =
+      static_cast<double>((task_in_window_end_time - task_in_window_start_time)
+                              .InMicroseconds()) /
+      (window_end - window_start).InMicroseconds();
+
+  base::TimeDelta expected_queueing_duration_within_task =
+      ((task_end - task_in_window_start_time) +
+       (task_end - task_in_window_end_time)) /
+      2;
+
+  return base::TimeDelta::FromMillisecondsD(
+      probability_of_this_task *
+      expected_queueing_duration_within_task.InMillisecondsF());
+}
+
+}  // namespace
+
+QueueingTimeEstimator::QueueingTimeEstimator(
+    QueueingTimeEstimator::Client* client,
+    base::TimeDelta window_duration)
+    : client_(client),
+      window_duration_(window_duration),
+      window_start_time_() {}
+
+void QueueingTimeEstimator::OnToplevelTaskCompleted(
+    base::TimeTicks task_start_time,
+    base::TimeTicks task_end_time) {
+  if (window_start_time_.is_null())
+    window_start_time_ = task_start_time;
+
+  while (TimePastWindowEnd(task_end_time)) {
+    if (!TimePastWindowEnd(task_start_time)) {
+      // Include the current task in this window.
+      current_expected_queueing_time_ += ExpectedQueueingTimeFromTask(
+          task_start_time, task_end_time, window_start_time_,
+          window_start_time_ + window_duration_);
+    }
+    client_->OnQueueingTimeForWindowEstimated(current_expected_queueing_time_);
+    window_start_time_ += window_duration_;
+    current_expected_queueing_time_ = base::TimeDelta();
+  }
+
+  current_expected_queueing_time_ += ExpectedQueueingTimeFromTask(
+      task_start_time, task_end_time, window_start_time_,
+      window_start_time_ + window_duration_);
+}
+
+bool QueueingTimeEstimator::TimePastWindowEnd(base::TimeTicks time) {
+  return time > window_start_time_ + window_duration_;
+}
+
+}  // namespace scheduler
diff --git a/components/scheduler/base/queueing_time_estimator.h b/components/scheduler/base/queueing_time_estimator.h
new file mode 100644
index 0000000..2d302ea
--- /dev/null
+++ b/components/scheduler/base/queueing_time_estimator.h
@@ -0,0 +1,53 @@
+// 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 COMPONENTS_SCHEDULER_RENDERER_QUEUEING_TIME_ESTIMATOR_H_
+#define COMPONENTS_SCHEDULER_RENDERER_QUEUEING_TIME_ESTIMATOR_H_
+
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/time/time.h"
+#include "components/scheduler/scheduler_export.h"
+
+namespace base {
+class TickClock;
+}
+
+namespace scheduler {
+
+// Records the expected queueing time for a high priority task occurring
+// randomly during each interval of length |window_duration|.
+class SCHEDULER_EXPORT QueueingTimeEstimator {
+ public:
+  class SCHEDULER_EXPORT Client {
+   public:
+    virtual void OnQueueingTimeForWindowEstimated(
+        base::TimeDelta queueing_time) = 0;
+    Client() {}
+    virtual ~Client() {}
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Client);
+  };
+
+  QueueingTimeEstimator(Client* client,
+                        base::TimeDelta window_duration);
+
+  void OnToplevelTaskCompleted(base::TimeTicks task_start_time,
+                               base::TimeTicks task_end_time);
+
+ private:
+  bool TimePastWindowEnd(base::TimeTicks task_end_time);
+  Client* client_;  // NOT OWNED.
+
+  base::TimeDelta current_expected_queueing_time_;
+  base::TimeDelta window_duration_;
+  base::TimeTicks window_start_time_;
+
+  DISALLOW_COPY_AND_ASSIGN(QueueingTimeEstimator);
+};
+
+}  // namespace scheduler
+
+#endif  // COMPONENTS_SCHEDULER_RENDERER_QUEUEING_TIME_ESTIMATOR_H_
diff --git a/components/scheduler/base/queueing_time_estimator_unittest.cc b/components/scheduler/base/queueing_time_estimator_unittest.cc
new file mode 100644
index 0000000..c9df20b29
--- /dev/null
+++ b/components/scheduler/base/queueing_time_estimator_unittest.cc
@@ -0,0 +1,94 @@
+// 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 "components/scheduler/base/queueing_time_estimator.h"
+#include "components/scheduler/base/test_time_source.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace scheduler {
+
+using QueueingTimeEstimatorTest = testing::Test;
+
+class TestQueueingTimeEstimatorClient
+    : public QueueingTimeEstimator::Client {
+ public:
+  void OnQueueingTimeForWindowEstimated(
+      base::TimeDelta queueing_time) override {
+    expected_queueing_times_.push_back(queueing_time);
+  }
+  const std::vector<base::TimeDelta>& expected_queueing_times() {
+    return expected_queueing_times_;
+  }
+
+ private:
+  std::vector<base::TimeDelta> expected_queueing_times_;
+};
+
+class QueueingTimeEstimatorForTest : public QueueingTimeEstimator {
+ public:
+  QueueingTimeEstimatorForTest(TestQueueingTimeEstimatorClient* client,
+                               base::TimeDelta window_duration)
+      : QueueingTimeEstimator(client, window_duration) {}
+};
+
+// Three tasks of one second each, all within a 5 second window. Expected
+// queueing time is the probability of falling into one of these tasks (3/5),
+// multiplied by the expected queueing time within a task (0.5 seconds). Thus we
+// expect a queueing time of 0.3 seconds.
+TEST_F(QueueingTimeEstimatorTest, AllTasksWithinWindow) {
+  base::TimeTicks time;
+  TestQueueingTimeEstimatorClient client;
+  QueueingTimeEstimatorForTest estimator(&client,
+                                         base::TimeDelta::FromSeconds(5));
+  for (int i = 0; i < 3; ++i) {
+    estimator.OnToplevelTaskCompleted(
+        time, time + base::TimeDelta::FromMilliseconds(1000));
+    time += base::TimeDelta::FromMilliseconds(1500);
+  }
+
+  // Flush the data by adding a task in the next window.
+  time += base::TimeDelta::FromMilliseconds(5000);
+  estimator.OnToplevelTaskCompleted(
+      time, time + base::TimeDelta::FromMilliseconds(500));
+
+  EXPECT_THAT(client.expected_queueing_times(),
+              testing::ElementsAre(base::TimeDelta::FromMilliseconds(300)));
+}
+
+// One 20 second long task, starting 3 seconds into the first window.
+// Window 1: Probability of being within task = 2/5. Expected delay within task:
+// avg(20, 18). Total expected queueing time = 7.6s.
+// Window 2: Probability of being within task = 1. Expected delay within task:
+// avg(18, 13). Total expected queueing time = 15.5s.
+// Window 5: Probability of being within task = 3/5. Expected delay within task:
+// avg(3, 0). Total expected queueing time = 0.9s.
+TEST_F(QueueingTimeEstimatorTest, MultiWindowTask) {
+  TestQueueingTimeEstimatorClient client;
+  QueueingTimeEstimatorForTest estimator(&client,
+                                         base::TimeDelta::FromSeconds(5));
+  base::TimeTicks time;
+  time += base::TimeDelta::FromMilliseconds(5000);
+  estimator.OnToplevelTaskCompleted(time, time);
+
+  time += base::TimeDelta::FromMilliseconds(3000);
+
+  estimator.OnToplevelTaskCompleted(
+      time, time + base::TimeDelta::FromMilliseconds(20000));
+
+  // Flush the data by adding a task in the next window.
+  time += base::TimeDelta::FromMilliseconds(25000);
+
+  estimator.OnToplevelTaskCompleted(
+      time, time + base::TimeDelta::FromMilliseconds(500));
+
+  EXPECT_THAT(client.expected_queueing_times(),
+              testing::ElementsAre(base::TimeDelta::FromMilliseconds(7600),
+                                   base::TimeDelta::FromMilliseconds(15500),
+                                   base::TimeDelta::FromMilliseconds(10500),
+                                   base::TimeDelta::FromMilliseconds(5500),
+                                   base::TimeDelta::FromMilliseconds(900)));
+}
+
+}  // namespace scheduler
diff --git a/components/scheduler/base/task_queue_impl.cc b/components/scheduler/base/task_queue_impl.cc
index c3f1d8a..c8ce1e9 100644
--- a/components/scheduler/base/task_queue_impl.cc
+++ b/components/scheduler/base/task_queue_impl.cc
@@ -219,32 +219,32 @@
 }
 
 void TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread(
-    const Task& pending_task,
+    Task pending_task,
     base::TimeTicks now) {
   main_thread_only().task_queue_manager->DidQueueTask(pending_task);
 
   // Schedule a later call to MoveReadyDelayedTasksToDelayedWorkQueue.
-  main_thread_only().delayed_incoming_queue.push(pending_task);
+  base::TimeTicks delayed_run_time = pending_task.delayed_run_time;
+  main_thread_only().delayed_incoming_queue.push(std::move(pending_task));
   main_thread_only().time_domain->ScheduleDelayedWork(
-      this, pending_task.delayed_run_time, now);
+      this, delayed_run_time, now);
   TraceQueueSize(false);
 }
 
-void TaskQueueImpl::PushOntoDelayedIncomingQueueLocked(
-    const Task& pending_task) {
+void TaskQueueImpl::PushOntoDelayedIncomingQueueLocked(Task pending_task) {
   any_thread().task_queue_manager->DidQueueTask(pending_task);
 
   int thread_hop_task_sequence_number =
       any_thread().task_queue_manager->GetNextSequenceNumber();
   PushOntoImmediateIncomingQueueLocked(Task(
       FROM_HERE,
-      base::Bind(&TaskQueueImpl::ScheduleDelayedWorkTask, this, pending_task),
+      base::Bind(&TaskQueueImpl::ScheduleDelayedWorkTask, this,
+                 base::Passed(&pending_task)),
       base::TimeTicks(), thread_hop_task_sequence_number, false,
       thread_hop_task_sequence_number));
 }
 
-void TaskQueueImpl::PushOntoImmediateIncomingQueueLocked(
-    const Task& pending_task) {
+void TaskQueueImpl::PushOntoImmediateIncomingQueueLocked(Task pending_task) {
   if (any_thread().immediate_incoming_queue.empty())
     any_thread().time_domain->RegisterAsUpdatableTaskQueue(this);
   if (any_thread().pump_policy == PumpPolicy::AUTO &&
@@ -252,15 +252,16 @@
     any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE);
   }
   any_thread().task_queue_manager->DidQueueTask(pending_task);
-  any_thread().immediate_incoming_queue.push(pending_task);
+  any_thread().immediate_incoming_queue.push(std::move(pending_task));
   TraceQueueSize(true);
 }
 
-void TaskQueueImpl::ScheduleDelayedWorkTask(const Task& pending_task) {
+void TaskQueueImpl::ScheduleDelayedWorkTask(Task pending_task) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
-  main_thread_only().delayed_incoming_queue.push(pending_task);
+  base::TimeTicks delayed_run_time = pending_task.delayed_run_time;
+  main_thread_only().delayed_incoming_queue.push(std::move(pending_task));
   main_thread_only().time_domain->ScheduleDelayedWork(
-      this, pending_task.delayed_run_time,
+      this, delayed_run_time,
       main_thread_only().time_domain->Now());
 }
 
@@ -667,21 +668,32 @@
 // static
 void TaskQueueImpl::QueueAsValueInto(const std::queue<Task>& queue,
                                      base::trace_event::TracedValue* state) {
-  std::queue<Task> queue_copy(queue);
-  while (!queue_copy.empty()) {
-    TaskAsValueInto(queue_copy.front(), state);
-    queue_copy.pop();
+  // Remove const to search |queue| in the destructive manner. Restore the
+  // content from |visited| later.
+  std::queue<Task>* mutable_queue = const_cast<std::queue<Task>*>(&queue);
+  std::queue<Task> visited;
+  while (!mutable_queue->empty()) {
+    TaskAsValueInto(mutable_queue->front(), state);
+    visited.push(std::move(mutable_queue->front()));
+    mutable_queue->pop();
   }
+  *mutable_queue = std::move(visited);
 }
 
 // static
 void TaskQueueImpl::QueueAsValueInto(const std::priority_queue<Task>& queue,
                                      base::trace_event::TracedValue* state) {
-  std::priority_queue<Task> queue_copy(queue);
-  while (!queue_copy.empty()) {
-    TaskAsValueInto(queue_copy.top(), state);
-    queue_copy.pop();
+  // Remove const to search |queue| in the destructive manner. Restore the
+  // content from |visited| later.
+  std::priority_queue<Task>* mutable_queue =
+      const_cast<std::priority_queue<Task>*>(&queue);
+  std::priority_queue<Task> visited;
+  while (!mutable_queue->empty()) {
+    TaskAsValueInto(mutable_queue->top(), state);
+    visited.push(std::move(const_cast<Task&>(mutable_queue->top())));
+    mutable_queue->pop();
   }
+  *mutable_queue = std::move(visited);
 }
 
 // static
diff --git a/components/scheduler/base/task_queue_impl.h b/components/scheduler/base/task_queue_impl.h
index 69fd02e..3508c623 100644
--- a/components/scheduler/base/task_queue_impl.h
+++ b/components/scheduler/base/task_queue_impl.h
@@ -220,14 +220,14 @@
 
   // Push the task onto the |delayed_incoming_queue|. Lock-free main thread
   // only fast path.
-  void PushOntoDelayedIncomingQueueFromMainThread(const Task& pending_task,
+  void PushOntoDelayedIncomingQueueFromMainThread(Task pending_task,
                                                   base::TimeTicks now);
 
   // Push the task onto the |delayed_incoming_queue|.  Slow path from other
   // threads.
-  void PushOntoDelayedIncomingQueueLocked(const Task& pending_task);
+  void PushOntoDelayedIncomingQueueLocked(Task pending_task);
 
-  void ScheduleDelayedWorkTask(const Task& pending_task);
+  void ScheduleDelayedWorkTask(Task pending_task);
 
   // Enqueues any delayed tasks which should be run now on the
   // |delayed_work_queue|.  Must be called from the main thread.
@@ -257,7 +257,7 @@
   // Push the task onto the |immediate_incoming_queue| and for auto pumped
   // queues it calls MaybePostDoWorkOnMainRunner if the Incoming queue was
   // empty.
-  void PushOntoImmediateIncomingQueueLocked(const Task& pending_task);
+  void PushOntoImmediateIncomingQueueLocked(Task pending_task);
 
   void TraceQueueSize(bool is_locked) const;
   static void QueueAsValueInto(const std::queue<Task>& queue,
diff --git a/components/scheduler/base/task_queue_manager.cc b/components/scheduler/base/task_queue_manager.cc
index 36f08de..9b1c1a6 100644
--- a/components/scheduler/base/task_queue_manager.cc
+++ b/components/scheduler/base/task_queue_manager.cc
@@ -14,6 +14,7 @@
 #include "components/scheduler/base/task_queue_impl.h"
 #include "components/scheduler/base/task_queue_manager_delegate.h"
 #include "components/scheduler/base/task_queue_selector.h"
+#include "components/scheduler/base/task_time_tracker.h"
 #include "components/scheduler/base/work_queue.h"
 #include "components/scheduler/base/work_queue_sets.h"
 
@@ -44,6 +45,7 @@
       task_was_run_on_quiescence_monitored_queue_(false),
       work_batch_size_(1),
       task_count_(0),
+      task_time_tracker_(nullptr),
       tracing_category_(tracing_category),
       disabled_by_default_tracing_category_(
           disabled_by_default_tracing_category),
@@ -128,12 +130,17 @@
 
 void TaskQueueManager::UpdateWorkQueues(
     bool should_trigger_wakeup,
-    const internal::TaskQueueImpl::Task* previous_task) {
+    const internal::TaskQueueImpl::Task* previous_task,
+    LazyNow lazy_now) {
   TRACE_EVENT0(disabled_by_default_tracing_category_,
                "TaskQueueManager::UpdateWorkQueues");
 
   for (TimeDomain* time_domain : time_domains_) {
-    time_domain->UpdateWorkQueues(should_trigger_wakeup, previous_task);
+    LazyNow lazy_now_in_domain = time_domain == real_time_domain_.get()
+                                     ? lazy_now
+                                     : time_domain->CreateLazyNow();
+    time_domain->UpdateWorkQueues(should_trigger_wakeup, previous_task,
+                                  lazy_now_in_domain);
   }
 }
 
@@ -187,11 +194,18 @@
   if (!delegate_->IsNested())
     queues_to_delete_.clear();
 
+  LazyNow lazy_now(real_time_domain()->CreateLazyNow());
+  base::TimeTicks task_start_time;
+
+  if (!delegate_->IsNested() && task_time_tracker_)
+    task_start_time = lazy_now.Now();
+
   // Pass false and nullptr to UpdateWorkQueues here to prevent waking up a
   // pump-after-wakeup queue.
-  UpdateWorkQueues(false, nullptr);
+  UpdateWorkQueues(false, nullptr, lazy_now);
 
   internal::TaskQueueImpl::Task previous_task;
+
   for (int i = 0; i < work_batch_size_; i++) {
     internal::WorkQueue* work_queue;
     if (!SelectWorkQueueToService(&work_queue)) {
@@ -200,6 +214,7 @@
 
     bool should_trigger_wakeup = work_queue->task_queue()->wakeup_policy() ==
                                  TaskQueue::WakeupPolicy::CAN_WAKE_OTHER_QUEUES;
+
     switch (ProcessTaskFromWorkQueue(work_queue, &previous_task)) {
       case ProcessTaskResult::DEFERRED:
         // If a task was deferred, try again with another task. Note that this
@@ -211,9 +226,18 @@
       case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED:
         return;  // The TaskQueueManager got deleted, we must bail out.
     }
+
+    lazy_now = real_time_domain()->CreateLazyNow();
+    if (!delegate_->IsNested() && task_time_tracker_) {
+      // Only report top level task durations.
+      base::TimeTicks task_end_time = lazy_now.Now();
+      task_time_tracker_->ReportTaskTime(task_start_time, task_end_time);
+      task_start_time = task_end_time;
+    }
+
     work_queue = nullptr; // The queue may have been unregistered.
 
-    UpdateWorkQueues(should_trigger_wakeup, &previous_task);
+    UpdateWorkQueues(should_trigger_wakeup, &previous_task, lazy_now);
 
     // Only run a single task per batch in nested run loops so that we can
     // properly exit the nested loop when someone calls RunLoop::Quit().
@@ -304,7 +328,7 @@
   }
 
   pending_task.task.Reset();
-  *out_previous_task = pending_task;
+  *out_previous_task = std::move(pending_task);
   return ProcessTaskResult::EXECUTED;
 }
 
diff --git a/components/scheduler/base/task_queue_manager.h b/components/scheduler/base/task_queue_manager.h
index 1e9eef4..bb938ad 100644
--- a/components/scheduler/base/task_queue_manager.h
+++ b/components/scheduler/base/task_queue_manager.h
@@ -38,6 +38,7 @@
 class RealTimeDomain;
 class TimeDomain;
 class TaskQueueManagerDelegate;
+class TaskTimeTracker;
 
 // The task queue manager provides N task queues and a selector interface for
 // choosing which task queue to service next. Each task queue consists of two
@@ -82,6 +83,13 @@
   // tasks posted to the main loop. The batch size is 1 by default.
   void SetWorkBatchSize(int work_batch_size);
 
+  // When given a non-null TaskTimeTracker, the TaskQueueManager calls its
+  // ReportTaskTime method for every top level task. The task_time_tracker must
+  // outlive this object, or be removed via SetTaskTimeTracker(nullptr).
+  void SetTaskTimeTracker(TaskTimeTracker* task_time_tracker) {
+    task_time_tracker_ = task_time_tracker;
+  }
+
   // These functions can only be called on the same thread that the task queue
   // manager executes its tasks on.
   void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer);
@@ -167,7 +175,8 @@
   // run and |should_trigger_wakeup|. Call with an empty |previous_task| if no
   // task was just run.
   void UpdateWorkQueues(bool should_trigger_wakeup,
-                        const internal::TaskQueueImpl::Task* previous_task);
+                        const internal::TaskQueueImpl::Task* previous_task,
+                        LazyNow lazy_now);
 
   // Chooses the next work queue to service. Returns true if |out_queue|
   // indicates the queue from which the next task should be run, false to
@@ -226,7 +235,7 @@
 
   bool task_was_run_on_quiescence_monitored_queue_;
 
-  // To reduce locking overhead we track pending calls to DoWork seperatly for
+  // To reduce locking overhead we track pending calls to DoWork separately for
   // the main thread and other threads.
   std::set<base::TimeTicks> main_thread_pending_wakeups_;
 
@@ -239,6 +248,8 @@
 
   base::ObserverList<base::MessageLoop::TaskObserver> task_observers_;
 
+  TaskTimeTracker* task_time_tracker_;  // NOT OWNED
+
   const char* tracing_category_;
   const char* disabled_by_default_tracing_category_;
   const char* disabled_by_default_verbose_tracing_category_;
diff --git a/components/scheduler/base/task_queue_manager_perftest.cc b/components/scheduler/base/task_queue_manager_perftest.cc
index a81fea32..c62ba467 100644
--- a/components/scheduler/base/task_queue_manager_perftest.cc
+++ b/components/scheduler/base/task_queue_manager_perftest.cc
@@ -13,6 +13,7 @@
 #include "components/scheduler/base/task_queue_impl.h"
 #include "components/scheduler/base/task_queue_manager_delegate_for_test.h"
 #include "components/scheduler/base/task_queue_selector.h"
+#include "components/scheduler/base/test_task_time_tracker.h"
 #include "components/scheduler/base/work_queue_sets.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/perf/perf_test.h"
@@ -41,6 +42,7 @@
             message_loop_->task_runner(),
             base::WrapUnique(new base::DefaultTickClock())),
         "fake.category", "fake.category", "fake.category.debug"));
+    manager_->SetTaskTimeTracker(&test_task_time_tracker_);
     for (size_t i = 0; i < num_queues; i++)
       queues_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test")));
   }
@@ -111,6 +113,9 @@
   std::unique_ptr<TaskQueueManager> manager_;
   std::unique_ptr<base::MessageLoop> message_loop_;
   std::vector<scoped_refptr<base::SingleThreadTaskRunner>> queues_;
+  // TODO(alexclarke): parameterize so we can measure with and without a
+  // TaskTimeTracker.
+  TestTaskTimeTracker test_task_time_tracker_;
 };
 
 TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_OneQueue) {
diff --git a/components/scheduler/base/task_queue_manager_unittest.cc b/components/scheduler/base/task_queue_manager_unittest.cc
index 39baad3..89493b12 100644
--- a/components/scheduler/base/task_queue_manager_unittest.cc
+++ b/components/scheduler/base/task_queue_manager_unittest.cc
@@ -23,7 +23,8 @@
 #include "components/scheduler/base/task_queue_impl.h"
 #include "components/scheduler/base/task_queue_manager_delegate_for_test.h"
 #include "components/scheduler/base/task_queue_selector.h"
-#include "components/scheduler/base/test_always_fail_time_source.h"
+#include "components/scheduler/base/test_count_uses_time_source.h"
+#include "components/scheduler/base/test_task_time_tracker.h"
 #include "components/scheduler/base/test_time_source.h"
 #include "components/scheduler/base/virtual_time_domain.h"
 #include "components/scheduler/base/work_queue.h"
@@ -59,6 +60,7 @@
 
 class TaskQueueManagerTest : public testing::Test {
  public:
+  TaskQueueManagerTest() {}
   void DeleteTaskQueueManager() { manager_.reset(); }
 
  protected:
@@ -69,9 +71,11 @@
     main_task_runner_ = TaskQueueManagerDelegateForTest::Create(
         test_task_runner_.get(),
         base::WrapUnique(new TestTimeSource(now_src_.get())));
-    manager_ = base::WrapUnique(
-        new TaskQueueManager(main_task_runner_, "test.scheduler",
-                             "test.scheduler", "test.scheduler.debug"));
+
+    manager_ = base::WrapUnique(new TaskQueueManager(
+        main_task_runner_, "test.scheduler", "test.scheduler",
+        "test.scheduler.debug"));
+    manager_->SetTaskTimeTracker(&test_task_time_tracker_);
 
     for (size_t i = 0; i < num_queues; i++)
       runners_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test_queue")));
@@ -87,10 +91,13 @@
   void InitializeWithRealMessageLoop(size_t num_queues) {
     now_src_.reset(new base::SimpleTestTickClock());
     message_loop_.reset(new base::MessageLoop());
+    // A null clock triggers some assertions.
+    now_src_->Advance(base::TimeDelta::FromMicroseconds(1000));
     manager_ = base::WrapUnique(new TaskQueueManager(
         MessageLoopTaskRunner::Create(
             base::WrapUnique(new TestTimeSource(now_src_.get()))),
         "test.scheduler", "test.scheduler", "test.scheduler.debug"));
+    manager_->SetTaskTimeTracker(&test_task_time_tracker_);
 
     for (size_t i = 0; i < num_queues; i++)
       runners_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test_queue")));
@@ -102,6 +109,7 @@
   scoped_refptr<cc::OrderedSimpleTaskRunner> test_task_runner_;
   std::unique_ptr<TaskQueueManager> manager_;
   std::vector<scoped_refptr<internal::TaskQueueImpl>> runners_;
+  TestTaskTimeTracker test_task_time_tracker_;
 };
 
 void PostFromNestedRunloop(base::MessageLoop* message_loop,
@@ -120,12 +128,20 @@
 
 void NopTask() {}
 
-TEST_F(TaskQueueManagerTest, NowNotCalledWhenThereAreNoDelayedTasks) {
+TEST_F(TaskQueueManagerTest,
+       NowCalledMinimumNumberOfTimesToComputeTaskDurations) {
   message_loop_.reset(new base::MessageLoop());
+  // This memory is managed by the TaskQueueManager, but we need to hold a
+  // pointer to this object to read out how many times Now was called.
+  TestCountUsesTimeSource* test_count_uses_time_source =
+      new TestCountUsesTimeSource();
+
   manager_ = base::WrapUnique(new TaskQueueManager(
       MessageLoopTaskRunner::Create(
-          base::WrapUnique(new TestAlwaysFailTimeSource())),
+          base::WrapUnique(test_count_uses_time_source)),
       "test.scheduler", "test.scheduler", "test.scheduler.debug"));
+  manager_->SetWorkBatchSize(6);
+  manager_->SetTaskTimeTracker(&test_task_time_tracker_);
 
   for (size_t i = 0; i < 3; i++)
     runners_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test_queue")));
@@ -138,6 +154,44 @@
   runners_[2]->PostTask(FROM_HERE, base::Bind(&NopTask));
 
   message_loop_->RunUntilIdle();
+  // We need to call Now for the beginning of the first task, and then the end
+  // of every task after. We reuse the end time of one task for the start time
+  // of the next task. In this case, there were 6 tasks, so we expect 7 calls to
+  // Now.
+  EXPECT_EQ(7, test_count_uses_time_source->now_calls_count());
+}
+
+TEST_F(TaskQueueManagerTest,
+       NowNotCalledForNestedTasks) {
+  message_loop_.reset(new base::MessageLoop());
+  // This memory is managed by the TaskQueueManager, but we need to hold a
+  // pointer to this object to read out how many times Now was called.
+  TestCountUsesTimeSource* test_count_uses_time_source =
+      new TestCountUsesTimeSource();
+
+  manager_ = base::WrapUnique(new TaskQueueManager(
+      MessageLoopTaskRunner::Create(
+          base::WrapUnique(test_count_uses_time_source)),
+      "test.scheduler", "test.scheduler", "test.scheduler.debug"));
+  manager_->SetTaskTimeTracker(&test_task_time_tracker_);
+
+  runners_.push_back(manager_->NewTaskQueue(TaskQueue::Spec("test_queue")));
+
+  std::vector<std::pair<base::Closure, bool>> tasks_to_post_from_nested_loop;
+  for (int i = 0; i <= 6; ++i) {
+    tasks_to_post_from_nested_loop.push_back(
+        std::make_pair(base::Bind(&NopTask), true));
+  }
+
+  runners_[0]->PostTask(
+      FROM_HERE, base::Bind(&PostFromNestedRunloop, message_loop_.get(),
+                            base::RetainedRef(runners_[0]),
+                            base::Unretained(&tasks_to_post_from_nested_loop)));
+
+  message_loop_->RunUntilIdle();
+  // We need to call Now twice, to measure the start and end of the outermost
+  // task. We shouldn't call it for any of the nested tasks.
+  EXPECT_EQ(2, test_count_uses_time_source->now_calls_count());
 }
 
 void NullTask() {}
diff --git a/components/scheduler/base/task_time_tracker.h b/components/scheduler/base/task_time_tracker.h
new file mode 100644
index 0000000..8546229
--- /dev/null
+++ b/components/scheduler/base/task_time_tracker.h
@@ -0,0 +1,26 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_SCHEDULER_BASE_TASK_TIME_TRACKER_H_
+#define CONTENT_RENDERER_SCHEDULER_BASE_TASK_TIME_TRACKER_H_
+
+#include "base/time/time.h"
+#include "components/scheduler/scheduler_export.h"
+
+namespace scheduler {
+
+class SCHEDULER_EXPORT TaskTimeTracker {
+ public:
+  TaskTimeTracker() {}
+  virtual ~TaskTimeTracker() {}
+
+  virtual void ReportTaskTime(base::TimeTicks startTime,
+                              base::TimeTicks endTime) = 0;
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TaskTimeTracker);
+};
+
+} // namespace scheduler
+
+#endif // CONTENT_RENDERER_SCHEDULER_BASE_TASK_TIME_TRACKER_H_
diff --git a/components/scheduler/base/test_always_fail_time_source.cc b/components/scheduler/base/test_always_fail_time_source.cc
deleted file mode 100644
index 25429845..0000000
--- a/components/scheduler/base/test_always_fail_time_source.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/scheduler/base/test_always_fail_time_source.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace scheduler {
-
-TestAlwaysFailTimeSource::TestAlwaysFailTimeSource() {
-}
-
-TestAlwaysFailTimeSource::~TestAlwaysFailTimeSource() {
-}
-
-base::TimeTicks TestAlwaysFailTimeSource::NowTicks() {
-  ADD_FAILURE() << "NowTicks() was called!";
-  return base::TimeTicks();
-}
-
-}  // namespace scheduler
diff --git a/components/scheduler/base/test_always_fail_time_source.h b/components/scheduler/base/test_always_fail_time_source.h
deleted file mode 100644
index ec6e73d..0000000
--- a/components/scheduler/base/test_always_fail_time_source.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SCHEDULER_BASE_TEST_ALWAYS_FAIL_TIME_SOURCE_H_
-#define COMPONENTS_SCHEDULER_BASE_TEST_ALWAYS_FAIL_TIME_SOURCE_H_
-
-#include "base/macros.h"
-#include "base/time/tick_clock.h"
-
-namespace scheduler {
-
-class TestAlwaysFailTimeSource : public base::TickClock {
- public:
-  explicit TestAlwaysFailTimeSource();
-  ~TestAlwaysFailTimeSource() override;
-
-  base::TimeTicks NowTicks() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestAlwaysFailTimeSource);
-};
-
-}  // namespace scheduler
-
-#endif  // COMPONENTS_SCHEDULER_BASE_TEST_ALWAYS_FAIL_TIME_SOURCE_H_
diff --git a/components/scheduler/base/test_count_uses_time_source.cc b/components/scheduler/base/test_count_uses_time_source.cc
new file mode 100644
index 0000000..4175d1aa2
--- /dev/null
+++ b/components/scheduler/base/test_count_uses_time_source.cc
@@ -0,0 +1,21 @@
+// 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 "components/scheduler/base/test_count_uses_time_source.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace scheduler {
+
+TestCountUsesTimeSource::TestCountUsesTimeSource() : now_calls_count_(0) {}
+
+TestCountUsesTimeSource::~TestCountUsesTimeSource() {
+}
+
+base::TimeTicks TestCountUsesTimeSource::NowTicks() {
+  now_calls_count_++;
+  // Don't return 0, as it triggers some assertions.
+  return base::TimeTicks() + base::TimeDelta::FromSeconds(1);
+}
+
+}  // namespace scheduler
diff --git a/components/scheduler/base/test_count_uses_time_source.h b/components/scheduler/base/test_count_uses_time_source.h
new file mode 100644
index 0000000..92dbc19
--- /dev/null
+++ b/components/scheduler/base/test_count_uses_time_source.h
@@ -0,0 +1,29 @@
+// 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.
+
+#ifndef COMPONENTS_SCHEDULER_BASE_TEST_COUNT_USES_TIME_SOURCE_H_
+#define COMPONENTS_SCHEDULER_BASE_TEST_COUNT_USES_TIME_SOURCE_H_
+
+#include "base/macros.h"
+#include "base/time/tick_clock.h"
+
+namespace scheduler {
+
+class TestCountUsesTimeSource : public base::TickClock {
+ public:
+  explicit TestCountUsesTimeSource();
+  ~TestCountUsesTimeSource() override;
+
+  base::TimeTicks NowTicks() override;
+  int now_calls_count() { return now_calls_count_; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestCountUsesTimeSource);
+
+  int now_calls_count_;
+};
+
+}  // namespace scheduler
+
+#endif  // COMPONENTS_SCHEDULER_BASE_TEST_COUNT_USES_TIME_SOURCE_H_
diff --git a/components/scheduler/base/test_task_time_tracker.h b/components/scheduler/base/test_task_time_tracker.h
new file mode 100644
index 0000000..7703e8f
--- /dev/null
+++ b/components/scheduler/base/test_task_time_tracker.h
@@ -0,0 +1,21 @@
+// 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_RENDERER_SCHEDULER_BASE_TEST_TASK_TIME_TRACKER_H_
+#define CONTENT_RENDERER_SCHEDULER_BASE_TEST_TASK_TIME_TRACKER_H_
+
+#include "base/time/time.h"
+#include "components/scheduler/base/task_time_tracker.h"
+
+namespace scheduler {
+
+class TestTaskTimeTracker : public TaskTimeTracker {
+ public:
+  void ReportTaskTime(base::TimeTicks startTime,
+                      base::TimeTicks endTime) override {}
+};
+
+} // namespace scheduler
+
+#endif // CONTENT_RENDERER_SCHEDULER_BASE_TEST_TASK_TIME_TRACKER_H_
diff --git a/components/scheduler/base/time_domain.cc b/components/scheduler/base/time_domain.cc
index 61851c53..510ad796 100644
--- a/components/scheduler/base/time_domain.cc
+++ b/components/scheduler/base/time_domain.cc
@@ -110,9 +110,9 @@
 
 void TimeDomain::UpdateWorkQueues(
     bool should_trigger_wakeup,
-    const internal::TaskQueueImpl::Task* previous_task) {
+    const internal::TaskQueueImpl::Task* previous_task,
+    LazyNow lazy_now) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
-  LazyNow lazy_now(CreateLazyNow());
 
   // Move any ready delayed tasks into the Incoming queues.
   WakeupReadyDelayedQueues(&lazy_now, should_trigger_wakeup, previous_task);
diff --git a/components/scheduler/base/time_domain.h b/components/scheduler/base/time_domain.h
index 3938891..3b8db03e 100644
--- a/components/scheduler/base/time_domain.h
+++ b/components/scheduler/base/time_domain.h
@@ -104,7 +104,8 @@
 
   // Updates active queues associated with this TimeDomain.
   void UpdateWorkQueues(bool should_trigger_wakeup,
-                        const internal::TaskQueueImpl::Task* previous_task);
+                        const internal::TaskQueueImpl::Task* previous_task,
+                        LazyNow lazy_now);
 
   // Called by the TaskQueueManager when the TimeDomain is registered.
   virtual void OnRegisterWithTaskQueueManager(
diff --git a/components/scheduler/base/time_domain_unittest.cc b/components/scheduler/base/time_domain_unittest.cc
index 7f422883..1d9fdcd 100644
--- a/components/scheduler/base/time_domain_unittest.cc
+++ b/components/scheduler/base/time_domain_unittest.cc
@@ -164,12 +164,14 @@
   ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time));
   EXPECT_EQ(delayed_runtime, next_run_time);
 
-  time_domain_->UpdateWorkQueues(false, nullptr);
+  LazyNow lazy_now = time_domain_->CreateLazyNow();
+  time_domain_->UpdateWorkQueues(false, nullptr, lazy_now);
   ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time));
   EXPECT_EQ(delayed_runtime, next_run_time);
 
   time_domain_->SetNow(delayed_runtime);
-  time_domain_->UpdateWorkQueues(false, nullptr);
+  lazy_now = time_domain_->CreateLazyNow();
+  time_domain_->UpdateWorkQueues(false, nullptr, lazy_now);
   ASSERT_FALSE(time_domain_->NextScheduledRunTime(&next_run_time));
 }
 
diff --git a/components/scheduler/base/work_queue.cc b/components/scheduler/base/work_queue.cc
index 313baa9..ec770cb 100644
--- a/components/scheduler/base/work_queue.cc
+++ b/components/scheduler/base/work_queue.cc
@@ -16,11 +16,17 @@
       name_(name) {}
 
 void WorkQueue::AsValueInto(base::trace_event::TracedValue* state) const {
-  std::queue<TaskQueueImpl::Task> queue_copy(work_queue_);
-  while (!queue_copy.empty()) {
-    TaskQueueImpl::TaskAsValueInto(queue_copy.front(), state);
-    queue_copy.pop();
+  // Remove const to search |work_queue_| in the destructive manner. Restore the
+  // content from |visited| later.
+  std::queue<TaskQueueImpl::Task>* mutable_queue =
+      const_cast<std::queue<TaskQueueImpl::Task>*>(&work_queue_);
+  std::queue<TaskQueueImpl::Task> visited;
+  while (!mutable_queue->empty()) {
+    TaskQueueImpl::TaskAsValueInto(mutable_queue->front(), state);
+    visited.push(std::move(mutable_queue->front()));
+    mutable_queue->pop();
   }
+  *mutable_queue = std::move(visited);
 }
 
 WorkQueue::~WorkQueue() {
@@ -41,17 +47,17 @@
   return true;
 }
 
-void WorkQueue::Push(const TaskQueueImpl::Task& task) {
+void WorkQueue::Push(TaskQueueImpl::Task task) {
   bool was_empty = work_queue_.empty();
-  work_queue_.push(task);
+  work_queue_.push(std::move(task));
   if (was_empty && work_queue_sets_)
     work_queue_sets_->OnPushQueue(this);
 }
 
-void WorkQueue::PushAndSetEnqueueOrder(const TaskQueueImpl::Task& task,
+void WorkQueue::PushAndSetEnqueueOrder(TaskQueueImpl::Task task,
                                        EnqueueOrder enqueue_order) {
   bool was_empty = work_queue_.empty();
-  work_queue_.push(task);
+  work_queue_.push(std::move(task));
   work_queue_.back().set_enqueue_order(enqueue_order);
 
   if (was_empty && work_queue_sets_)
diff --git a/components/scheduler/base/work_queue.h b/components/scheduler/base/work_queue.h
index 9ff919d7..c97c34c6 100644
--- a/components/scheduler/base/work_queue.h
+++ b/components/scheduler/base/work_queue.h
@@ -49,11 +49,11 @@
 
   // Pushes the task onto the |work_queue_| and informs the WorkQueueSets if
   // the head changed.
-  void Push(const TaskQueueImpl::Task& task);
+  void Push(TaskQueueImpl::Task task);
 
   // Pushes the task onto the |work_queue_|, sets the |enqueue_order| and
   // informs the WorkQueueSets if the head changed.
-  void PushAndSetEnqueueOrder(const TaskQueueImpl::Task& task,
+  void PushAndSetEnqueueOrder(TaskQueueImpl::Task task,
                               EnqueueOrder enqueue_order);
 
   // Swap the |work_queue_| with |incoming_queue| and informs the
@@ -88,6 +88,8 @@
   TaskQueueImpl* task_queue_;       // NOT OWNED.
   size_t work_queue_set_index_;
   const char* name_;
+
+  DISALLOW_COPY_AND_ASSIGN(WorkQueue);
 };
 
 }  // namespace internal
diff --git a/components/scheduler/child/scheduler_helper.cc b/components/scheduler/child/scheduler_helper.cc
index 43944359..57cbbc38 100644
--- a/components/scheduler/child/scheduler_helper.cc
+++ b/components/scheduler/child/scheduler_helper.cc
@@ -32,8 +32,8 @@
               .SetPumpPolicy(TaskQueue::PumpPolicy::AFTER_WAKEUP)
               .SetWakeupPolicy(TaskQueue::WakeupPolicy::DONT_WAKE_OTHER_QUEUES)
               .SetShouldNotifyObservers(false))),
-      default_task_runner_(NewTaskQueue(TaskQueue::Spec("default_tq")
-                                            .SetShouldMonitorQuiescence(true))),
+      default_task_runner_(NewTaskQueue(
+          TaskQueue::Spec("default_tq").SetShouldMonitorQuiescence(true))),
       observer_(nullptr),
       tracing_category_(tracing_category),
       disabled_by_default_tracing_category_(
diff --git a/components/scheduler/child/scheduler_helper.h b/components/scheduler/child/scheduler_helper.h
index 0348a6808..c19f023 100644
--- a/components/scheduler/child/scheduler_helper.h
+++ b/components/scheduler/child/scheduler_helper.h
@@ -22,7 +22,8 @@
 class SchedulerTqmDelegate;
 
 // Common scheduler functionality for default tasks.
-class SCHEDULER_EXPORT SchedulerHelper : public TaskQueueManager::Observer {
+class SCHEDULER_EXPORT SchedulerHelper
+    : public TaskQueueManager::Observer {
  public:
   // Category strings must have application lifetime (statics or
   // literals). They may not include " chars.
@@ -57,6 +58,11 @@
   void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer);
   void RemoveTaskObserver(base::MessageLoop::TaskObserver* task_observer);
 
+  void SetTaskTimeTracker(TaskTimeTracker* task_time_tracker) {
+    if (task_queue_manager_)
+      task_queue_manager_->SetTaskTimeTracker(task_time_tracker);
+  }
+
   // Shuts down the scheduler by dropping any remaining pending work in the work
   // queues. After this call any work posted to the task runners will be
   // silently dropped.
diff --git a/components/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc b/components/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc
index 578c8f7f..3ce01a71 100644
--- a/components/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc
+++ b/components/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/test/simple_test_tick_clock.h"
 #include "cc/test/ordered_simple_task_runner.h"
 #include "components/scheduler/base/task_queue_manager.h"
+#include "components/scheduler/base/test_task_time_tracker.h"
 #include "components/scheduler/base/test_time_source.h"
 #include "components/scheduler/child/scheduler_tqm_delegate_for_test.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -29,9 +30,11 @@
         new cc::OrderedSimpleTaskRunner(clock_.get(), false));
     main_task_runner_ = SchedulerTqmDelegateForTest::Create(
         mock_task_runner_, base::WrapUnique(new TestTimeSource(clock_.get())));
-    manager_ = base::WrapUnique(
-        new TaskQueueManager(main_task_runner_, "test.scheduler",
-                             "test.scheduler", "test.scheduler.debug"));
+
+    manager_ = base::WrapUnique(new TaskQueueManager(
+        main_task_runner_, "test.scheduler", "test.scheduler",
+        "test.scheduler.debug"));
+    manager_->SetTaskTimeTracker(&test_task_time_tracker_);
     task_runner_ =
         manager_->NewTaskQueue(TaskQueue::Spec("test_task_queue"));
     initial_time_= clock_->NowTicks();
@@ -54,6 +57,7 @@
   std::unique_ptr<TaskQueueManager> manager_;
   scoped_refptr<TaskQueue> task_runner_;
   std::unique_ptr<AutoAdvancingVirtualTimeDomain> auto_advancing_time_domain_;
+  TestTaskTimeTracker test_task_time_tracker_;
 };
 
 namespace {
diff --git a/components/scheduler/renderer/idle_time_estimator_unittest.cc b/components/scheduler/renderer/idle_time_estimator_unittest.cc
index c50ad83..d7d67a8 100644
--- a/components/scheduler/renderer/idle_time_estimator_unittest.cc
+++ b/components/scheduler/renderer/idle_time_estimator_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/test/simple_test_tick_clock.h"
 #include "cc/test/ordered_simple_task_runner.h"
 #include "components/scheduler/base/task_queue_manager.h"
+#include "components/scheduler/base/test_task_time_tracker.h"
 #include "components/scheduler/base/test_time_source.h"
 #include "components/scheduler/child/scheduler_tqm_delegate_for_test.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -42,10 +43,10 @@
     mock_task_runner_ = make_scoped_refptr(
         new cc::OrderedSimpleTaskRunner(clock_.get(), false));
     main_task_runner_ = SchedulerTqmDelegateForTest::Create(
-        mock_task_runner_, base::WrapUnique(new TestTimeSource(clock_.get())));
-    manager_ = base::WrapUnique(
-        new TaskQueueManager(main_task_runner_, "test.scheduler",
-                             "test.scheduler", "test.scheduler.debug"));
+        mock_task_runner_, base::MakeUnique<TestTimeSource>(clock_.get()));
+    manager_ = base::MakeUnique<TaskQueueManager>(
+        main_task_runner_, "test.scheduler", "test.scheduler",
+        "test.scheduler.debug");
     compositor_task_runner_ =
         manager_->NewTaskQueue(TaskQueue::Spec("compositor_tq"));
     estimator_.reset(new IdleTimeEstimatorForTest(
@@ -92,6 +93,7 @@
   scoped_refptr<TaskQueue> compositor_task_runner_;
   std::unique_ptr<IdleTimeEstimatorForTest> estimator_;
   const base::TimeDelta frame_length_;
+  TestTaskTimeTracker test_task_time_tracker_;
 };
 
 TEST_F(IdleTimeEstimatorTest, InitialTimeEstimateWithNoData) {
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.cc b/components/scheduler/renderer/renderer_scheduler_impl.cc
index c02624ef..209e563 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/components/scheduler/renderer/renderer_scheduler_impl.cc
@@ -8,6 +8,7 @@
 #include "base/debug/stack_trace.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "cc/output/begin_frame_args.h"
@@ -22,7 +23,7 @@
 namespace {
 // The run time of loading tasks is strongly bimodal.  The vast majority are
 // very cheap, but there are usually a handful of very expensive tasks (e.g ~1
-// second on a mobile device) so we take a very pesimistic view when estimating
+// second on a mobile device) so we take a very pessimistic view when estimating
 // the cost of loading tasks.
 const int kLoadingTaskEstimationSampleCount = 1000;
 const double kLoadingTaskEstimationPercentile = 99;
@@ -49,14 +50,14 @@
                    base::TimeDelta()),
       render_widget_scheduler_signals_(this),
       control_task_runner_(helper_.ControlTaskRunner()),
-      compositor_task_runner_(
-          helper_.NewTaskQueue(TaskQueue::Spec("compositor_tq")
-                                   .SetShouldMonitorQuiescence(true))),
+      compositor_task_runner_(helper_.NewTaskQueue(
+          TaskQueue::Spec("compositor_tq").SetShouldMonitorQuiescence(true))),
       delayed_update_policy_runner_(
           base::Bind(&RendererSchedulerImpl::UpdatePolicy,
                      base::Unretained(this)),
           helper_.ControlTaskRunner()),
-      main_thread_only_(compositor_task_runner_,
+      main_thread_only_(this,
+                        compositor_task_runner_,
                         helper_.scheduler_tqm_delegate().get()),
       policy_may_need_update_(&any_thread_lock_),
       weak_factory_(this) {
@@ -78,6 +79,7 @@
       this);
 
   helper_.SetObserver(this);
+  helper_.SetTaskTimeTracker(this);
 }
 
 RendererSchedulerImpl::~RendererSchedulerImpl() {
@@ -101,6 +103,7 @@
 }
 
 RendererSchedulerImpl::MainThreadOnly::MainThreadOnly(
+    RendererSchedulerImpl* renderer_scheduler_impl,
     const scoped_refptr<TaskQueue>& compositor_task_runner,
     base::TickClock* time_source)
     : loading_task_cost_estimator(time_source,
@@ -109,6 +112,8 @@
       timer_task_cost_estimator(time_source,
                                 kTimerTaskEstimationSampleCount,
                                 kTimerTaskEstimationPercentile),
+      queueing_time_estimator(renderer_scheduler_impl,
+                              base::TimeDelta::FromSeconds(1)),
       idle_time_estimator(compositor_task_runner,
                           time_source,
                           kShortIdlePeriodDurationSampleCount,
@@ -1383,6 +1388,21 @@
   }
 }
 
+void RendererSchedulerImpl::ReportTaskTime(base::TimeTicks start_time,
+                                           base::TimeTicks end_time) {
+  MainThreadOnly().queueing_time_estimator.OnToplevelTaskCompleted(start_time,
+                                                                   end_time);
+}
+
+void RendererSchedulerImpl::OnQueueingTimeForWindowEstimated(
+    base::TimeDelta queueing_time) {
+  UMA_HISTOGRAM_TIMES("RendererScheduler.ExpectedTaskQueueingDuration",
+                      queueing_time);
+  TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
+                 "estimated_queueing_time_for_window",
+                 queueing_time.InMillisecondsF());
+}
+
 // static
 const char* RendererSchedulerImpl::UseCaseToString(UseCase use_case) {
   switch (use_case) {
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.h b/components/scheduler/renderer/renderer_scheduler_impl.h
index 0f9d623b..e35ee15a 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl.h
+++ b/components/scheduler/renderer/renderer_scheduler_impl.h
@@ -9,6 +9,8 @@
 #include "base/macros.h"
 #include "base/synchronization/lock.h"
 #include "components/scheduler/base/pollable_thread_safe_flag.h"
+#include "components/scheduler/base/queueing_time_estimator.h"
+#include "components/scheduler/base/task_time_tracker.h"
 #include "components/scheduler/child/idle_helper.h"
 #include "components/scheduler/child/scheduler_helper.h"
 #include "components/scheduler/renderer/deadline_task_runner.h"
@@ -36,7 +38,9 @@
     : public RendererScheduler,
       public IdleHelper::Delegate,
       public SchedulerHelper::Observer,
-      public RenderWidgetSignals::Observer {
+      public RenderWidgetSignals::Observer,
+      public TaskTimeTracker,
+      public QueueingTimeEstimator::Client {
  public:
   // Keep RendererScheduler::UseCaseToString in sync with this enum.
   enum class UseCase {
@@ -126,6 +130,13 @@
   void OnTriedToExecuteBlockedTask(const TaskQueue& queue,
                                    const base::PendingTask& task) override;
 
+  // TaskTimeTracker implementation:
+  void ReportTaskTime(base::TimeTicks start_time,
+                      base::TimeTicks end_time) override;
+
+  // QueueingTimeEstimator::Client implementation:
+  void OnQueueingTimeForWindowEstimated(base::TimeDelta queueing_time) override;
+
   // Returns a task runner where tasks run at the highest possible priority.
   scoped_refptr<TaskQueue> ControlTaskRunner();
 
@@ -352,12 +363,14 @@
   // (the accessors) for the following data members.
 
   struct MainThreadOnly {
-    MainThreadOnly(const scoped_refptr<TaskQueue>& compositor_task_runner,
+    MainThreadOnly(RendererSchedulerImpl* renderer_scheduler_impl,
+                   const scoped_refptr<TaskQueue>& compositor_task_runner,
                    base::TickClock* time_source);
     ~MainThreadOnly();
 
     TaskCostEstimator loading_task_cost_estimator;
     TaskCostEstimator timer_task_cost_estimator;
+    QueueingTimeEstimator queueing_time_estimator;
     IdleTimeEstimator idle_time_estimator;
     UseCase current_use_case;
     Policy current_policy;
diff --git a/components/scheduler/renderer/web_frame_scheduler_impl.cc b/components/scheduler/renderer/web_frame_scheduler_impl.cc
index 495a1db3..44cdf203 100644
--- a/components/scheduler/renderer/web_frame_scheduler_impl.cc
+++ b/components/scheduler/renderer/web_frame_scheduler_impl.cc
@@ -108,14 +108,14 @@
   return parent_web_view_scheduler_;
 }
 
-void WebFrameSchedulerImpl::incrementPendingResourceLoadCount() {
+void WebFrameSchedulerImpl::didStartLoading(unsigned long identifier) {
   if (parent_web_view_scheduler_)
-    parent_web_view_scheduler_->incrementPendingResourceLoadCount();
+    parent_web_view_scheduler_->DidStartLoading(identifier);
 }
 
-void WebFrameSchedulerImpl::decrementPendingResourceLoadCount() {
+void WebFrameSchedulerImpl::didStopLoading(unsigned long identifier) {
   if (parent_web_view_scheduler_)
-    parent_web_view_scheduler_->decrementPendingResourceLoadCount();
+    parent_web_view_scheduler_->DidStopLoading(identifier);
 }
 
 void WebFrameSchedulerImpl::setPageVisible(bool page_visible) {
diff --git a/components/scheduler/renderer/web_frame_scheduler_impl.h b/components/scheduler/renderer/web_frame_scheduler_impl.h
index 0500ba3..367340d6 100644
--- a/components/scheduler/renderer/web_frame_scheduler_impl.h
+++ b/components/scheduler/renderer/web_frame_scheduler_impl.h
@@ -44,8 +44,8 @@
   blink::WebTaskRunner* timerTaskRunner() override;
   blink::WebTaskRunner* unthrottledTaskRunner() override;
   blink::WebViewScheduler* webViewScheduler() override;
-  void incrementPendingResourceLoadCount() override;
-  void decrementPendingResourceLoadCount() override;
+  void didStartLoading(unsigned long identifier) override;
+  void didStopLoading(unsigned long identifier) override;
 
   void OnVirtualTimeDomainChanged();
 
diff --git a/components/scheduler/renderer/web_view_scheduler_impl.cc b/components/scheduler/renderer/web_view_scheduler_impl.cc
index 48f565c..da4e80b3 100644
--- a/components/scheduler/renderer/web_view_scheduler_impl.cc
+++ b/components/scheduler/renderer/web_view_scheduler_impl.cc
@@ -24,7 +24,6 @@
     : virtual_time_pump_policy_(TaskQueue::PumpPolicy::AUTO),
       web_view_(web_view),
       renderer_scheduler_(renderer_scheduler),
-      pending_resource_load_count_(0),
       virtual_time_policy_(VirtualTimePolicy::ADVANCE),
       page_visible_(true),
       disable_background_timer_throttling_(disable_background_timer_throttling),
@@ -118,28 +117,27 @@
   return allow_virtual_time_to_advance_;
 }
 
-void WebViewSchedulerImpl::incrementPendingResourceLoadCount() {
-  pending_resource_load_count_++;
+void WebViewSchedulerImpl::DidStartLoading(unsigned long identifier) {
+  pending_loads_.insert(identifier);
 
   if (virtual_time_policy_ !=
       VirtualTimePolicy::PAUSE_IF_NETWORK_FETCHES_PENDING) {
     return;
   }
 
-  if (pending_resource_load_count_ == 1)
+  if (pending_loads_.size() == 1u)
     setAllowVirtualTimeToAdvance(false);
 }
 
-void WebViewSchedulerImpl::decrementPendingResourceLoadCount() {
-  pending_resource_load_count_--;
-  DCHECK_GE(pending_resource_load_count_, 0);
+void WebViewSchedulerImpl::DidStopLoading(unsigned long identifier) {
+  pending_loads_.erase(identifier);
 
   if (virtual_time_policy_ !=
       VirtualTimePolicy::PAUSE_IF_NETWORK_FETCHES_PENDING) {
       return;
   }
 
-  if (pending_resource_load_count_ == 0)
+  if (pending_loads_.size() == 0)
       setAllowVirtualTimeToAdvance(true);
 }
 
@@ -156,7 +154,7 @@
       break;
 
     case VirtualTimePolicy::PAUSE_IF_NETWORK_FETCHES_PENDING:
-      setAllowVirtualTimeToAdvance(pending_resource_load_count_ == 0);
+      setAllowVirtualTimeToAdvance(pending_loads_.size() == 0);
       break;
   }
 }
diff --git a/components/scheduler/renderer/web_view_scheduler_impl.h b/components/scheduler/renderer/web_view_scheduler_impl.h
index 233c1dc2..019696c8 100644
--- a/components/scheduler/renderer/web_view_scheduler_impl.h
+++ b/components/scheduler/renderer/web_view_scheduler_impl.h
@@ -53,8 +53,8 @@
   std::unique_ptr<WebFrameSchedulerImpl> createWebFrameSchedulerImpl(
       base::trace_event::BlameContext* blame_context);
 
-  void incrementPendingResourceLoadCount();
-  void decrementPendingResourceLoadCount();
+  void DidStartLoading(unsigned long identifier);
+  void DidStopLoading(unsigned long identifier);
 
  private:
   friend class WebFrameSchedulerImpl;
@@ -68,11 +68,11 @@
   void setAllowVirtualTimeToAdvance(bool allow_virtual_time_to_advance);
 
   std::set<WebFrameSchedulerImpl*> frame_schedulers_;
+  std::set<unsigned long> pending_loads_;
   std::unique_ptr<AutoAdvancingVirtualTimeDomain> virtual_time_domain_;
   TaskQueue::PumpPolicy virtual_time_pump_policy_;
   blink::WebView* web_view_;
   RendererSchedulerImpl* renderer_scheduler_;
-  int pending_resource_load_count_;
   VirtualTimePolicy virtual_time_policy_;
   bool page_visible_;
   bool disable_background_timer_throttling_;
diff --git a/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc b/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc
index 5a3d5475..49bed4d 100644
--- a/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc
+++ b/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc
@@ -508,22 +508,45 @@
       VirtualTimePolicy::PAUSE_IF_NETWORK_FETCHES_PENDING);
   EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance());
 
-  web_view_scheduler_->incrementPendingResourceLoadCount();
+  web_view_scheduler_->DidStartLoading(1u);
   EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance());
 
-  web_view_scheduler_->incrementPendingResourceLoadCount();
+  web_view_scheduler_->DidStartLoading(2u);
   EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance());
 
-  web_view_scheduler_->decrementPendingResourceLoadCount();
+  web_view_scheduler_->DidStopLoading(2u);
   EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance());
 
-  web_view_scheduler_->incrementPendingResourceLoadCount();
+  web_view_scheduler_->DidStartLoading(3u);
   EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance());
 
-  web_view_scheduler_->decrementPendingResourceLoadCount();
+  web_view_scheduler_->DidStopLoading(1u);
   EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance());
 
-  web_view_scheduler_->decrementPendingResourceLoadCount();
+  web_view_scheduler_->DidStopLoading(3u);
+  EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance());
+}
+
+TEST_F(WebViewSchedulerImplTest, RedundantDidStopLoadingCallsAreHarmless) {
+  web_view_scheduler_->setVirtualTimePolicy(
+      VirtualTimePolicy::PAUSE_IF_NETWORK_FETCHES_PENDING);
+
+  web_view_scheduler_->DidStartLoading(1u);
+  EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance());
+
+  web_view_scheduler_->DidStopLoading(1u);
+  EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance());
+
+  web_view_scheduler_->DidStopLoading(1u);
+  EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance());
+
+  web_view_scheduler_->DidStopLoading(1u);
+  EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance());
+
+  web_view_scheduler_->DidStartLoading(2u);
+  EXPECT_FALSE(web_view_scheduler_->virtualTimeAllowedToAdvance());
+
+  web_view_scheduler_->DidStopLoading(2u);
   EXPECT_TRUE(web_view_scheduler_->virtualTimeAllowedToAdvance());
 }
 
diff --git a/components/scheduler/scheduler.gypi b/components/scheduler/scheduler.gypi
index dbcfefd..4bc63988 100644
--- a/components/scheduler/scheduler.gypi
+++ b/components/scheduler/scheduler.gypi
@@ -15,6 +15,8 @@
       'base/cancelable_closure_holder.h',
       'base/lazy_now.cc',
       'base/lazy_now.h',
+      'base/queueing_time_estimator.cc',
+      'base/queueing_time_estimator.h',
       'base/real_time_domain.cc',
       'base/real_time_domain.h',
       'base/task_queue.h',
@@ -25,6 +27,7 @@
       'base/task_queue_manager_delegate.h',
       'base/task_queue_selector.cc',
       'base/task_queue_selector.h',
+      'base/task_time_tracker.h',
       'base/time_domain.cc',
       'base/time_domain.h',
       'base/work_queue.cc',
diff --git a/components/sessions/core/tab_restore_service_helper.cc b/components/sessions/core/tab_restore_service_helper.cc
index f89946f2..73a4c72 100644
--- a/components/sessions/core/tab_restore_service_helper.cc
+++ b/components/sessions/core/tab_restore_service_helper.cc
@@ -138,22 +138,21 @@
     LiveTabContext* context) {
   if (entries_.empty())
     return std::vector<LiveTab*>();
-
   return RestoreEntryById(context, entries_.front()->id, UNKNOWN);
 }
 
 TabRestoreService::Tab* TabRestoreServiceHelper::RemoveTabEntryById(
     SessionID::id_type id) {
-  Entries::iterator i = GetEntryIteratorById(id);
-  if (i == entries_.end())
-    return NULL;
+  Entries::iterator it = GetEntryIteratorById(id);
+  if (it == entries_.end())
+    return nullptr;
 
-  Entry* entry = *i;
+  Entry* entry = *it;
   if (entry->type != TabRestoreService::TAB)
-    return NULL;
+    return nullptr;
 
   Tab* tab = static_cast<Tab*>(entry);
-  entries_.erase(i);
+  entries_.erase(it);
   return tab;
 }
 
@@ -162,9 +161,10 @@
     SessionID::id_type id,
     WindowOpenDisposition disposition) {
   Entries::iterator entry_iterator = GetEntryIteratorById(id);
-  if (entry_iterator == entries_.end())
+  if (entry_iterator == entries_.end()) {
     // Don't hoark here, we allow an invalid id.
     return std::vector<LiveTab*>();
+  }
 
   if (observer_)
     observer_->OnRestoreEntryById(id, entry_iterator);
@@ -186,7 +186,7 @@
   std::vector<LiveTab*> live_tabs;
   if (entry->type == TabRestoreService::TAB) {
     Tab* tab = static_cast<Tab*>(entry);
-    LiveTab* restored_tab = NULL;
+    LiveTab* restored_tab = nullptr;
     context = RestoreTab(*tab, context, disposition, &restored_tab);
     live_tabs.push_back(restored_tab);
     context->ShowBrowserWindow();
@@ -225,28 +225,27 @@
       for (std::vector<Tab>::iterator tab_i = window->tabs.begin();
            tab_i != window->tabs.end(); ++tab_i) {
         const Tab& tab = *tab_i;
-        if (tab.id == id) {
-          LiveTab* restored_tab = NULL;
-          context = RestoreTab(tab, context, disposition, &restored_tab);
-          live_tabs.push_back(restored_tab);
-          window->tabs.erase(tab_i);
-          // If restoring the tab leaves the window with nothing else, delete it
-          // as well.
-          if (!window->tabs.size()) {
-            entries_.erase(entry_iterator);
-            delete entry;
-          } else {
-            // Update the browser ID of the rest of the tabs in the window so if
-            // any one is restored, it goes into the same window as the tab
-            // being restored now.
-            UpdateTabBrowserIDs(tab.browser_id, context->GetSessionID().id());
-            for (std::vector<Tab>::iterator tab_j = window->tabs.begin();
-                 tab_j != window->tabs.end(); ++tab_j) {
-              (*tab_j).browser_id = context->GetSessionID().id();
-            }
-          }
-          break;
+        if (tab.id != id)
+          continue;
+
+        LiveTab* restored_tab = nullptr;
+        context = RestoreTab(tab, context, disposition, &restored_tab);
+        live_tabs.push_back(restored_tab);
+        window->tabs.erase(tab_i);
+        // If restoring the tab leaves the window with nothing else, delete it
+        // as well.
+        if (window->tabs.empty()) {
+          entries_.erase(entry_iterator);
+          delete entry;
+        } else {
+          // Update the browser ID of the rest of the tabs in the window so if
+          // any one is restored, it goes into the same window as the tab
+          // being restored now.
+          UpdateTabBrowserIDs(tab.browser_id, context->GetSessionID().id());
+          for (Tab& tab_j : window->tabs)
+            tab_j.browser_id = context->GetSessionID().id();
         }
+        break;
       }
     }
     context->ShowBrowserWindow();
diff --git a/components/signin.gypi b/components/signin.gypi
index 049ab5a4..1a00eb8 100644
--- a/components/signin.gypi
+++ b/components/signin.gypi
@@ -256,8 +256,6 @@
           ],
           'sources': [
             # Note: file list duplicated in GN build.
-            'signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.h',
-            'signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.mm',
             'signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.h',
             'signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.mm',
           ],
diff --git a/components/signin/ios/browser/BUILD.gn b/components/signin/ios/browser/BUILD.gn
index 9d1572b3..c0a9f35 100644
--- a/components/signin/ios/browser/BUILD.gn
+++ b/components/signin/ios/browser/BUILD.gn
@@ -35,8 +35,6 @@
 source_set("test_support") {
   testonly = true
   sources = [
-    "fake_profile_oauth2_token_service_ios_delegate.h",
-    "fake_profile_oauth2_token_service_ios_delegate.mm",
     "fake_profile_oauth2_token_service_ios_provider.h",
     "fake_profile_oauth2_token_service_ios_provider.mm",
   ]
diff --git a/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.h b/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.h
deleted file mode 100644
index ed5c5a15..0000000
--- a/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SIGNIN_IOS_BROWSER_FAKE_PROFILE_OAUTH2_TOKEN_SERVICE_IOS_DELEGATE_H_
-#define COMPONENTS_SIGNIN_IOS_BROWSER_FAKE_PROFILE_OAUTH2_TOKEN_SERVICE_IOS_DELEGATE_H_
-
-#include "base/macros.h"
-#include "base/threading/thread_checker.h"
-#include "components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h"
-
-class FakeProfileOAuth2TokenServiceIOSDelegate
-    : public ProfileOAuth2TokenServiceIOSDelegate {
- public:
-  FakeProfileOAuth2TokenServiceIOSDelegate(
-      SigninClient* client,
-      std::unique_ptr<ProfileOAuth2TokenServiceIOSProvider> provider,
-      AccountTrackerService* account_tracker_service,
-      SigninErrorController* signin_error_controller);
-  ~FakeProfileOAuth2TokenServiceIOSDelegate() override;
-
-  OAuth2AccessTokenFetcher* CreateAccessTokenFetcher(
-      const std::string& account_id,
-      net::URLRequestContextGetter* getter,
-      OAuth2AccessTokenConsumer* consumer) override;
-
-  bool RefreshTokenIsAvailable(const std::string& account_id) const override;
-  bool RefreshTokenHasError(const std::string& account_id) const override;
-  void UpdateAuthError(const std::string& account_id,
-                       const GoogleServiceAuthError& error) override;
-
-  std::vector<std::string> GetAccounts() override;
-  void RevokeAllCredentials() override;
-
-  void LoadCredentials(const std::string& primary_account_id) override;
-
-  void UpdateCredentials(const std::string& account_id,
-                         const std::string& refresh_token) override;
-  void RevokeCredentials(const std::string& account_id) override;
-  void AddOrUpdateAccount(const std::string& account_id) override;
-  void RemoveAccount(const std::string& account_id) override;
-
- private:
-  void IssueRefreshTokenForUser(const std::string& account_id,
-                                const std::string& token);
-  std::string GetRefreshToken(const std::string& account_id) const;
-
-  // Calls to this class are expected to be made from the browser UI thread.
-  // The purpose of this checker is to detect access to
-  // ProfileOAuth2TokenService from multiple threads in upstream code.
-  base::ThreadChecker thread_checker_;
-
-  // Maps account ids to their refresh token strings.
-  std::map<std::string, std::string> refresh_tokens_;
-  // Maps account ids to their auth errors.
-  std::map<std::string, GoogleServiceAuthError> auth_errors_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeProfileOAuth2TokenServiceIOSDelegate);
-};
-
-#endif  // COMPONENTS_SIGNIN_IOS_BROWSER_FAKE_PROFILE_OAUTH2_TOKEN_SERVICE_IOS_DELEGATE_H_
diff --git a/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.mm b/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.mm
deleted file mode 100644
index 51421524..0000000
--- a/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.mm
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.h"
-
-#include "components/signin/ios/browser/profile_oauth2_token_service_ios_provider.h"
-#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
-
-FakeProfileOAuth2TokenServiceIOSDelegate::
-    FakeProfileOAuth2TokenServiceIOSDelegate(
-        SigninClient* client,
-        std::unique_ptr<ProfileOAuth2TokenServiceIOSProvider> provider,
-        AccountTrackerService* account_tracker_service,
-        SigninErrorController* signin_error_controller)
-    : ProfileOAuth2TokenServiceIOSDelegate(client,
-                                           std::move(provider),
-                                           account_tracker_service,
-                                           signin_error_controller) {}
-
-FakeProfileOAuth2TokenServiceIOSDelegate::
-    ~FakeProfileOAuth2TokenServiceIOSDelegate() {}
-
-OAuth2AccessTokenFetcher*
-FakeProfileOAuth2TokenServiceIOSDelegate::CreateAccessTokenFetcher(
-    const std::string& account_id,
-    net::URLRequestContextGetter* getter,
-    OAuth2AccessTokenConsumer* consumer) {
-  std::map<std::string, std::string>::const_iterator it =
-      refresh_tokens_.find(account_id);
-  DCHECK(it != refresh_tokens_.end());
-  std::string refresh_token(it->second);
-  return new OAuth2AccessTokenFetcherImpl(consumer, getter, refresh_token);
-}
-
-bool FakeProfileOAuth2TokenServiceIOSDelegate::RefreshTokenIsAvailable(
-    const std::string& account_id) const {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  return !GetRefreshToken(account_id).empty();
-}
-
-bool FakeProfileOAuth2TokenServiceIOSDelegate::RefreshTokenHasError(
-    const std::string& account_id) const {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  auto it = auth_errors_.find(account_id);
-  return it != auth_errors_.end() && IsError(it->second);
-}
-
-void FakeProfileOAuth2TokenServiceIOSDelegate::UpdateAuthError(
-    const std::string& account_id,
-    const GoogleServiceAuthError& error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  auth_errors_.erase(account_id);
-  auth_errors_.emplace(account_id, error);
-}
-
-std::string FakeProfileOAuth2TokenServiceIOSDelegate::GetRefreshToken(
-    const std::string& account_id) const {
-  std::map<std::string, std::string>::const_iterator it =
-      refresh_tokens_.find(account_id);
-  if (it != refresh_tokens_.end())
-    return it->second;
-  return std::string();
-}
-
-std::vector<std::string>
-FakeProfileOAuth2TokenServiceIOSDelegate::GetAccounts() {
-  std::vector<std::string> account_ids;
-  for (std::map<std::string, std::string>::const_iterator iter =
-           refresh_tokens_.begin();
-       iter != refresh_tokens_.end(); ++iter) {
-    account_ids.push_back(iter->first);
-  }
-  return account_ids;
-}
-
-void FakeProfileOAuth2TokenServiceIOSDelegate::RevokeAllCredentials() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  std::vector<std::string> account_ids = GetAccounts();
-  for (std::vector<std::string>::const_iterator it = account_ids.begin();
-       it != account_ids.end(); it++) {
-    RevokeCredentials(*it);
-  }
-}
-
-void FakeProfileOAuth2TokenServiceIOSDelegate::LoadCredentials(
-    const std::string& primary_account_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  FireRefreshTokensLoaded();
-}
-
-void FakeProfileOAuth2TokenServiceIOSDelegate::UpdateCredentials(
-    const std::string& account_id,
-    const std::string& refresh_token) {
-  IssueRefreshTokenForUser(account_id, refresh_token);
-}
-
-void FakeProfileOAuth2TokenServiceIOSDelegate::AddOrUpdateAccount(
-    const std::string& account_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  UpdateCredentials(account_id, "fake_refresh_token");
-}
-
-void FakeProfileOAuth2TokenServiceIOSDelegate::RemoveAccount(
-    const std::string& account_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!account_id.empty());
-
-  IssueRefreshTokenForUser(account_id, "");
-}
-
-void FakeProfileOAuth2TokenServiceIOSDelegate::IssueRefreshTokenForUser(
-    const std::string& account_id,
-    const std::string& token) {
-  ScopedBatchChange batch(this);
-  if (token.empty()) {
-    refresh_tokens_.erase(account_id);
-    auth_errors_.erase(account_id);
-    FireRefreshTokenRevoked(account_id);
-  } else {
-    refresh_tokens_[account_id] = token;
-    auth_errors_.emplace(account_id,
-                         GoogleServiceAuthError(GoogleServiceAuthError::NONE));
-    FireRefreshTokenAvailable(account_id);
-  }
-}
-
-void FakeProfileOAuth2TokenServiceIOSDelegate::RevokeCredentials(
-    const std::string& account_id) {
-  IssueRefreshTokenForUser(account_id, std::string());
-}
diff --git a/components/sync_sessions/favicon_cache_unittest.cc b/components/sync_sessions/favicon_cache_unittest.cc
index 0eb2092..b2aac8cae 100644
--- a/components/sync_sessions/favicon_cache_unittest.cc
+++ b/components/sync_sessions/favicon_cache_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "sync/api/attachments/attachment_id.h"
@@ -244,7 +245,7 @@
   std::string tag = syncer::SyncDataLocal(change.sync_data()).GetTag();
   const std::string kPrefix = "http://bla.com/";
   const std::string kSuffix = ".ico";
-  if (tag.find(kPrefix) != 0)
+  if (!base::StartsWith(tag, kPrefix, base::CompareCase::SENSITIVE))
     return -1;
   std::string temp = tag.substr(kPrefix.length());
   if (temp.rfind(kSuffix) <= 0)
diff --git a/components/sync_sessions/synced_session_tracker.cc b/components/sync_sessions/synced_session_tracker.cc
index abff52e7..527c5a3 100644
--- a/components/sync_sessions/synced_session_tracker.cc
+++ b/components/sync_sessions/synced_session_tracker.cc
@@ -215,39 +215,36 @@
 
 bool SyncedSessionTracker::DeleteOldSessionWindowIfNecessary(
     const SessionWindowWrapper& window_wrapper) {
-  if (!window_wrapper.owned) {
-    DVLOG(1) << "Deleting closed window "
-             << window_wrapper.window_ptr->window_id.id();
-    // Clear the tabs first, since we don't want the destructor to destroy
-    // them. Their deletion will be handled by DeleteOldSessionTabIfNecessary.
-    window_wrapper.window_ptr->tabs.clear();
-    delete window_wrapper.window_ptr;
-    return true;
-  }
-  return false;
+  if (window_wrapper.owned)
+    return false;
+
+  DVLOG(1) << "Deleting closed window "
+           << window_wrapper.window_ptr->window_id.id();
+  // Clear the tabs first, since we don't want the destructor to destroy
+  // them. Their deletion will be handled by DeleteOldSessionTabIfNecessary.
+  window_wrapper.window_ptr->tabs.clear();
+  delete window_wrapper.window_ptr;
+  return true;
 }
 
 bool SyncedSessionTracker::DeleteOldSessionTabIfNecessary(
     const SessionTabWrapper& tab_wrapper) {
-  if (!tab_wrapper.owned) {
-    if (VLOG_IS_ON(1)) {
-      sessions::SessionTab* tab_ptr = tab_wrapper.tab_ptr;
-      std::string title;
-      if (tab_ptr->navigations.size() > 0) {
-        title =
-            " (" +
-            base::UTF16ToUTF8(
-                tab_ptr->navigations[tab_ptr->navigations.size() - 1].title()) +
-            ")";
-      }
-      DVLOG(1) << "Deleting closed tab " << tab_ptr->tab_id.id() << title
-               << " from window " << tab_ptr->window_id.id();
+  if (tab_wrapper.owned)
+    return false;
+
+  if (VLOG_IS_ON(1)) {
+    sessions::SessionTab* tab_ptr = tab_wrapper.tab_ptr;
+    std::string title;
+    if (!tab_ptr->navigations.empty()) {
+      title =
+          " (" + base::UTF16ToUTF8(tab_ptr->navigations.back().title()) + ")";
     }
-    unmapped_tabs_.erase(tab_wrapper.tab_ptr);
-    delete tab_wrapper.tab_ptr;
-    return true;
+    DVLOG(1) << "Deleting closed tab " << tab_ptr->tab_id.id() << title
+             << " from window " << tab_ptr->window_id.id();
   }
-  return false;
+  unmapped_tabs_.erase(tab_wrapper.tab_ptr);
+  delete tab_wrapper.tab_ptr;
+  return true;
 }
 
 void SyncedSessionTracker::CleanupSession(const std::string& session_tag) {
@@ -400,15 +397,12 @@
       std::string title;
       if (tab_ptr->navigations.size() > 0) {
         title =
-            " (" +
-            base::UTF16ToUTF8(
-                tab_ptr->navigations[tab_ptr->navigations.size() - 1].title()) +
-            ")";
+            " (" + base::UTF16ToUTF8(tab_ptr->navigations.back().title()) + ")";
       }
       DVLOG(1) << "Getting "
                << (session_tag == local_session_tag_ ? "local session"
                                                      : session_tag)
-               << "'s seen tab " << tab_id << " at " << tab_ptr << title;
+               << "'s seen tab " << tab_id << " at " << tab_ptr << " " << title;
     }
   } else {
     tab_ptr = new sessions::SessionTab();
diff --git a/components/url_matcher/url_matcher.cc b/components/url_matcher/url_matcher.cc
index 91cd15b..b4a9d21 100644
--- a/components/url_matcher/url_matcher.cc
+++ b/components/url_matcher/url_matcher.cc
@@ -513,30 +513,26 @@
   PatternSingletons::const_iterator iter =
       pattern_singletons->find(&search_pattern);
 
-  if (iter != pattern_singletons->end()) {
+  if (iter != pattern_singletons->end())
     return URLMatcherCondition(criterion, *iter);
-  } else {
-    StringPattern* new_pattern =
-        new StringPattern(pattern, id_counter_++);
-    pattern_singletons->insert(new_pattern);
-    return URLMatcherCondition(criterion, new_pattern);
-  }
+
+  StringPattern* new_pattern = new StringPattern(pattern, id_counter_++);
+  pattern_singletons->insert(new_pattern);
+  return URLMatcherCondition(criterion, new_pattern);
 }
 
 std::string URLMatcherConditionFactory::CanonicalizeHostSuffix(
     const std::string& suffix) const {
-  if (!suffix.empty() && suffix[suffix.size() - 1] == '.')
-    return suffix;
-  else
-    return suffix + ".";
+  if (suffix.empty())
+    return ".";
+  return suffix.back() == '.' ? suffix : suffix + ".";
 }
 
 std::string URLMatcherConditionFactory::CanonicalizeHostPrefix(
     const std::string& prefix) const {
-  if (!prefix.empty() && prefix[0] == '.')
-    return prefix;
-  else
-    return "." + prefix;
+  if (prefix.empty())
+    return ".";
+  return prefix[0] == '.' ? prefix : "." + prefix;
 }
 
 std::string URLMatcherConditionFactory::CanonicalizeHostname(
diff --git a/components/variations/variations_seed_store.cc b/components/variations/variations_seed_store.cc
index 65b1efd..8067651 100644
--- a/components/variations/variations_seed_store.cc
+++ b/components/variations/variations_seed_store.cc
@@ -112,7 +112,10 @@
   exploded.second = 0;
   exploded.millisecond = 0;
 
-  return base::Time::FromUTCExploded(exploded);
+  base::Time out_time;
+  bool conversion_success = base::Time::FromUTCExploded(exploded, &out_time);
+  DCHECK(conversion_success);
+  return out_time;
 }
 
 VariationsSeedDateChangeState GetSeedDateChangeState(
diff --git a/components/webcrypto/algorithms/ecdh_unittest.cc b/components/webcrypto/algorithms/ecdh_unittest.cc
index 5faccbd..387b16a 100644
--- a/components/webcrypto/algorithms/ecdh_unittest.cc
+++ b/components/webcrypto/algorithms/ecdh_unittest.cc
@@ -219,7 +219,7 @@
             ExportKey(blink::WebCryptoKeyFormatRaw, derived_key, &raw_key));
   EXPECT_EQ(3u, raw_key.size());
   // The last 7 bits of the key should be zero.
-  EXPECT_EQ(0, raw_key[raw_key.size() - 1] & 0x1f);
+  EXPECT_EQ(0, raw_key.back() & 0x1f);
 }
 
 // Derive an HMAC key with no specified length (just the hash of SHA-256).
diff --git a/components/webcrypto/algorithms/util.cc b/components/webcrypto/algorithms/util.cc
index 4a3b747..f8eb6ae 100644
--- a/components/webcrypto/algorithms/util.cc
+++ b/components/webcrypto/algorithms/util.cc
@@ -47,7 +47,7 @@
 
   // Zero any "unused bits" in the final byte.
   if (remainder_bits)
-    (*bytes)[bytes->size() - 1] &= ~((0xFF) >> remainder_bits);
+    bytes->back() &= ~((0xFF) >> remainder_bits);
 }
 
 Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages,
diff --git a/content/browser/android/java/java_bridge_thread.cc b/content/browser/android/java/java_bridge_thread.cc
index 6c69bc0..4c8b24ed 100644
--- a/content/browser/android/java/java_bridge_thread.cc
+++ b/content/browser/android/java/java_bridge_thread.cc
@@ -6,6 +6,7 @@
 
 #include "base/lazy_instance.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/task_runner_util.h"
 #include "build/build_config.h"
 
@@ -33,8 +34,10 @@
 
 // static
 bool JavaBridgeThread::CurrentlyOn() {
-  return base::MessageLoop::current() ==
-         g_background_thread.Get().message_loop();
+  return g_background_thread.Get()
+      .message_loop()
+      ->task_runner()
+      ->BelongsToCurrentThread();
 }
 
 // static
diff --git a/content/browser/appcache/appcache_request_handler_unittest.cc b/content/browser/appcache/appcache_request_handler_unittest.cc
index ffb58da60..f90f48e 100644
--- a/content/browser/appcache/appcache_request_handler_unittest.cc
+++ b/content/browser/appcache/appcache_request_handler_unittest.cc
@@ -195,7 +195,7 @@
   }
 
   void SetUpTest() {
-    DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
+    DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
     mock_service_.reset(new MockAppCacheService);
     mock_service_->set_request_context(&empty_context_);
     mock_policy_.reset(new MockAppCachePolicy);
@@ -212,7 +212,7 @@
   }
 
   void TearDownTest() {
-    DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
+    DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
     job_ = NULL;
     handler_.reset();
     request_.reset();
@@ -227,7 +227,7 @@
   void TestFinished() {
     // We unwind the stack prior to finishing up to let stack
     // based objects get deleted.
-    DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
+    DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&AppCacheRequestHandlerTest::TestFinishedUnwound,
                               base::Unretained(this)));
@@ -243,7 +243,7 @@
   }
 
   void ScheduleNextTask() {
-    DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
+    DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
     if (task_stack_.empty()) {
       TestFinished();
       return;
diff --git a/content/browser/appcache/appcache_response_unittest.cc b/content/browser/appcache/appcache_response_unittest.cc
index 9c279d3..8e633c1f 100644
--- a/content/browser/appcache/appcache_response_unittest.cc
+++ b/content/browser/appcache/appcache_response_unittest.cc
@@ -91,7 +91,7 @@
   }
 
   void SetUpTest() {
-    DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
+    DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
     DCHECK(task_stack_.empty());
     storage_delegate_.reset(new MockStorageDelegate(this));
     service_.reset(new MockAppCacheService());
@@ -107,7 +107,7 @@
   }
 
   void TearDownTest() {
-    DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
+    DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
     while (!task_stack_.empty())
       task_stack_.pop();
 
@@ -124,7 +124,7 @@
   void TestFinished() {
     // We unwind the stack prior to finishing up to let stack
     // based objects get deleted.
-    DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
+    DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&AppCacheResponseTest::TestFinishedUnwound,
                               base::Unretained(this)));
@@ -144,7 +144,7 @@
   }
 
   void ScheduleNextTask() {
-    DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
+    DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
     if (task_stack_.empty()) {
       TestFinished();
       return;
diff --git a/content/browser/appcache/appcache_storage_impl_unittest.cc b/content/browser/appcache/appcache_storage_impl_unittest.cc
index 85725b4..a59be1c7 100644
--- a/content/browser/appcache/appcache_storage_impl_unittest.cc
+++ b/content/browser/appcache/appcache_storage_impl_unittest.cc
@@ -410,7 +410,7 @@
   }
 
   void SetUpTest() {
-    DCHECK(base::MessageLoop::current() == io_thread->message_loop());
+    DCHECK(io_thread->task_runner()->BelongsToCurrentThread());
     service_.reset(new AppCacheServiceImpl(NULL));
     service_->Initialize(base::FilePath(), db_thread->task_runner(), NULL);
     mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
@@ -419,7 +419,7 @@
   }
 
   void TearDownTest() {
-    DCHECK(base::MessageLoop::current() == io_thread->message_loop());
+    DCHECK(io_thread->task_runner()->BelongsToCurrentThread());
     storage()->CancelDelegateCallbacks(delegate());
     group_ = NULL;
     cache_ = NULL;
@@ -433,7 +433,7 @@
   void TestFinished() {
     // We unwind the stack prior to finishing up to let stack
     // based objects get deleted.
-    DCHECK(base::MessageLoop::current() == io_thread->message_loop());
+    DCHECK(io_thread->task_runner()->BelongsToCurrentThread());
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&AppCacheStorageImplTest::TestFinishedUnwound,
                               base::Unretained(this)));
@@ -449,7 +449,7 @@
   }
 
   void ScheduleNextTask() {
-    DCHECK(base::MessageLoop::current() == io_thread->message_loop());
+    DCHECK(io_thread->task_runner()->BelongsToCurrentThread());
     if (task_stack_.empty()) {
       return;
     }
diff --git a/content/browser/appcache/appcache_url_request_job_unittest.cc b/content/browser/appcache/appcache_url_request_job_unittest.cc
index dbce38dd..8cde90b1 100644
--- a/content/browser/appcache/appcache_url_request_job_unittest.cc
+++ b/content/browser/appcache/appcache_url_request_job_unittest.cc
@@ -248,7 +248,7 @@
   }
 
   void SetUpTest() {
-    DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
+    DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
     DCHECK(task_stack_.empty());
 
     storage_delegate_.reset(new MockStorageDelegate(this));
@@ -268,7 +268,7 @@
   }
 
   void TearDownTest() {
-    DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
+    DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
     request_.reset();
 
     while (!task_stack_.empty())
@@ -292,7 +292,7 @@
   void TestFinished() {
     // We unwind the stack prior to finishing up to let stack
     // based objects get deleted.
-    DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
+    DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&AppCacheURLRequestJobTest::TestFinishedUnwound,
                               base::Unretained(this)));
@@ -312,7 +312,7 @@
   }
 
   void ScheduleNextTask() {
-    DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
+    DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
     if (task_stack_.empty()) {
       TestFinished();
       return;
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index d5faefd0..94ee2c3 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -192,11 +192,6 @@
 #include "gpu/vulkan/vulkan_implementation.h"
 #endif
 
-#if defined(MOJO_SHELL_CLIENT) && defined(USE_AURA)
-#include "services/ui/common/gpu_service.h"  // nogncheck
-#endif
-
-
 // One of the linux specific headers defines this as a macro.
 #ifdef DestroyAll
 #undef DestroyAll
@@ -1162,28 +1157,27 @@
 
   // Bring up Mojo IPC and shell as early as possible.
 
-  // Disallow mojo sync call in the browser process.
-  bool sync_call_allowed = false;
-  MojoResult result = mojo::edk::SetProperty(
-      MOJO_PROPERTY_TYPE_SYNC_CALL_ALLOWED, &sync_call_allowed);
-  DCHECK_EQ(MOJO_RESULT_OK, result);
+  if (!parsed_command_line_.HasSwitch(switches::kSingleProcess)) {
+    // Disallow mojo sync calls in the browser process. Note that we allow sync
+    // calls in single-process mode since renderer IPCs are made from a browser
+    // thread.
+    bool sync_call_allowed = false;
+    MojoResult result = mojo::edk::SetProperty(
+        MOJO_PROPERTY_TYPE_SYNC_CALL_ALLOWED, &sync_call_allowed);
+    DCHECK_EQ(MOJO_RESULT_OK, result);
+  }
 
   mojo_ipc_support_.reset(new mojo::edk::ScopedIPCSupport(
       BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO)
           ->task_runner()));
 
   mojo_shell_context_.reset(new MojoShellContext);
-  if (shell::ShellIsRemote()) {
 #if defined(MOJO_SHELL_CLIENT) && defined(USE_AURA)
-    // TODO(rockot): Remove the blocking wait for init.
-    // http://crbug.com/594852.
-    auto connection = MojoShellConnection::GetForProcess();
-    if (connection) {
-      WaitForMojoShellInitialize();
-      ui::GpuService::Initialize(connection->GetConnector());
-    }
+  // TODO(rockot): Remove the blocking wait for init.
+  // http://crbug.com/594852.
+  if (shell::ShellIsRemote() && MojoShellConnection::GetForProcess())
+    WaitForMojoShellInitialize();
 #endif
-  }
 
 #if defined(OS_MACOSX)
   mojo::edk::SetMachPortProvider(MachBroker::GetInstance());
diff --git a/content/browser/compositor/surface_utils.cc b/content/browser/compositor/surface_utils.cc
index e0e491627..4cbd80dfa 100644
--- a/content/browser/compositor/surface_utils.cc
+++ b/content/browser/compositor/surface_utils.cc
@@ -76,7 +76,7 @@
   if (!bitmap->tryAllocPixels(SkImageInfo::Make(
           dst_size_in_pixel.width(), dst_size_in_pixel.height(), color_type,
           kOpaque_SkAlphaType))) {
-    scoped_callback_runner.Reset(base::Bind(
+    scoped_callback_runner.ReplaceClosure(base::Bind(
         callback, SkBitmap(), content::READBACK_BITMAP_ALLOCATION_FAILURE));
     return;
   }
diff --git a/content/browser/device_sensors/data_fetcher_shared_memory_base_unittest.cc b/content/browser/device_sensors/data_fetcher_shared_memory_base_unittest.cc
index 581f10c7..11adcda 100644
--- a/content/browser/device_sensors/data_fetcher_shared_memory_base_unittest.cc
+++ b/content/browser/device_sensors/data_fetcher_shared_memory_base_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/process/process_handle.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
 #include "content/common/device_sensors/device_light_hardware_buffer.h"
@@ -273,7 +274,8 @@
   ~FakePollingDataFetcher() override {}
 
   bool Start(ConsumerType consumer_type, void* buffer) override {
-    EXPECT_TRUE(base::MessageLoop::current() == GetPollingMessageLoop());
+    EXPECT_TRUE(
+        GetPollingMessageLoop()->task_runner()->BelongsToCurrentThread());
 
     Init(consumer_type, buffer);
     switch (consumer_type) {
@@ -296,7 +298,8 @@
   }
 
   bool Stop(ConsumerType consumer_type) override {
-    EXPECT_TRUE(base::MessageLoop::current() == GetPollingMessageLoop());
+    EXPECT_TRUE(
+        GetPollingMessageLoop()->task_runner()->BelongsToCurrentThread());
 
     switch (consumer_type) {
       case CONSUMER_TYPE_MOTION:
@@ -318,7 +321,8 @@
   }
 
   void Fetch(unsigned consumer_bitmask) override {
-    EXPECT_TRUE(base::MessageLoop::current() == GetPollingMessageLoop());
+    EXPECT_TRUE(
+        GetPollingMessageLoop()->task_runner()->BelongsToCurrentThread());
     EXPECT_TRUE(consumer_bitmask & CONSUMER_TYPE_ORIENTATION ||
                 consumer_bitmask & CONSUMER_TYPE_ORIENTATION_ABSOLUTE ||
                 consumer_bitmask & CONSUMER_TYPE_MOTION ||
@@ -346,7 +350,8 @@
   ~FakeZeroDelayPollingDataFetcher() override {}
 
   bool Start(ConsumerType consumer_type, void* buffer) override {
-    EXPECT_TRUE(base::MessageLoop::current() == GetPollingMessageLoop());
+    EXPECT_TRUE(
+        GetPollingMessageLoop()->task_runner()->BelongsToCurrentThread());
 
     Init(consumer_type, buffer);
     switch (consumer_type) {
@@ -369,7 +374,8 @@
   }
 
   bool Stop(ConsumerType consumer_type) override {
-    EXPECT_TRUE(base::MessageLoop::current() == GetPollingMessageLoop());
+    EXPECT_TRUE(
+        GetPollingMessageLoop()->task_runner()->BelongsToCurrentThread());
 
     switch (consumer_type) {
       case CONSUMER_TYPE_MOTION:
diff --git a/content/browser/device_sensors/data_fetcher_shared_memory_mac.cc b/content/browser/device_sensors/data_fetcher_shared_memory_mac.cc
index 1af22c3..b3334ad 100644
--- a/content/browser/device_sensors/data_fetcher_shared_memory_mac.cc
+++ b/content/browser/device_sensors/data_fetcher_shared_memory_mac.cc
@@ -8,6 +8,7 @@
 
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
 #include "content/browser/device_sensors/ambient_light_mac.h"
 #include "third_party/sudden_motion_sensor/sudden_motion_sensor_mac.h"
 
@@ -141,7 +142,7 @@
 }
 
 void DataFetcherSharedMemory::Fetch(unsigned consumer_bitmask) {
-  DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
+  DCHECK(GetPollingMessageLoop()->task_runner()->BelongsToCurrentThread());
   DCHECK(consumer_bitmask & CONSUMER_TYPE_ORIENTATION ||
          consumer_bitmask & CONSUMER_TYPE_MOTION ||
          consumer_bitmask & CONSUMER_TYPE_LIGHT);
@@ -159,7 +160,7 @@
 }
 
 bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
-  DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
+  DCHECK(GetPollingMessageLoop()->task_runner()->BelongsToCurrentThread());
   DCHECK(buffer);
 
   switch (consumer_type) {
@@ -235,7 +236,7 @@
 }
 
 bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) {
-  DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
+  DCHECK(GetPollingMessageLoop()->task_runner()->BelongsToCurrentThread());
 
   switch (consumer_type) {
     case CONSUMER_TYPE_MOTION:
diff --git a/content/browser/devtools/BUILD.gn b/content/browser/devtools/BUILD.gn
index da789a4a..68d4bd1 100644
--- a/content/browser/devtools/BUILD.gn
+++ b/content/browser/devtools/BUILD.gn
@@ -43,10 +43,8 @@
            "devtools_protocol_handler_generator.py"
 
   blink_protocol = "$root_gen_dir/blink/core/inspector/protocol.json"
-  browser_protocol = "browser_protocol.json"
   inputs = [
     blink_protocol,
-    browser_protocol,
   ]
 
   outputs = [
diff --git a/content/browser/devtools/browser_protocol.json b/content/browser/devtools/browser_protocol.json
deleted file mode 100644
index 1152ca7..0000000
--- a/content/browser/devtools/browser_protocol.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
-    "version": { "major": "1", "minor": "0" },
-    "domains": [{
-        "domain": "SystemInfo",
-        "description": "The SystemInfo domain defines methods and events for querying low-level system information.",
-        "hidden": true,
-        "types": [
-            {
-                "id": "GPUDevice",
-                "type": "object",
-                "properties": [
-                    { "name": "vendorId", "type": "number", "description": "PCI ID of the GPU vendor, if available; 0 otherwise." },
-                    { "name": "deviceId", "type": "number", "description": "PCI ID of the GPU device, if available; 0 otherwise." },
-                    { "name": "vendorString", "type": "string", "description": "String description of the GPU vendor, if the PCI ID is not available." },
-                    { "name": "deviceString", "type": "string", "description": "String description of the GPU device, if the PCI ID is not available." }
-                ],
-                "description": "Describes a single graphics processor (GPU)."
-            },
-            {
-                "id": "GPUInfo",
-                "type": "object",
-                "properties": [
-                    { "name": "devices", "type": "array", "items": { "$ref": "GPUDevice" }, "description": "The graphics devices on the system. Element 0 is the primary GPU." },
-                    { "name": "auxAttributes", "type": "object", "optional": "true", "description": "An optional dictionary of additional GPU related attributes." },
-                    { "name": "featureStatus", "type": "object", "optional": "true", "description": "An optional dictionary of graphics features and their status." },
-                    { "name": "driverBugWorkarounds", "type": "array", "items": { "type": "string" }, "description": "An optional array of GPU driver bug workarounds." }
-                ],
-                "description": "Provides information about the GPU(s) on the system."
-            }
-        ],
-        "commands": [
-            {
-                "name": "getInfo",
-                "async": true,
-                "description": "Returns information about the system.",
-                "returns": [
-                    { "name": "gpu", "$ref": "GPUInfo", "description": "Information about the GPUs on the system." },
-                    { "name": "modelName", "type": "string", "description": "A platform-dependent description of the model of the machine. On Mac OS, this is, for example, 'MacBookPro'. Will be the empty string if not supported." },
-                    { "name": "modelVersion", "type": "string", "description": "A platform-dependent description of the version of the machine. On Mac OS, this is, for example, '10.1'. Will be the empty string if not supported." }
-                ],
-                "handlers": ["browser"]
-            }
-        ]
-    },
-    {
-        "domain": "Tethering",
-        "description": "The Tethering domain defines methods and events for browser port binding.",
-        "hidden": true,
-        "commands": [
-            {
-                "name": "bind",
-                "async": true,
-                "description": "Request browser port binding.",
-                "parameters": [
-                    { "name": "port", "type": "integer", "description": "Port number to bind." }
-                ],
-                "handlers": ["browser"]
-            },
-            {
-                "name": "unbind",
-                "async": true,
-                "description": "Request browser port unbinding.",
-                "parameters": [
-                    { "name": "port", "type": "integer", "description": "Port number to unbind." }
-                ],
-                "handlers": ["browser"]
-            }
-        ],
-        "events": [
-            {
-                "name": "accepted",
-                "description": "Informs that port was successfully bound and got a specified connection id.",
-                "parameters": [
-                    {"name": "port", "type": "integer", "description": "Port number that was successfully bound." },
-                    {"name": "connectionId", "type": "string", "description": "Connection id to be used." }
-                ],
-                "handlers": ["browser"]
-            }
-        ]
-    }]
-}
diff --git a/content/browser/devtools/devtools.gyp b/content/browser/devtools/devtools.gyp
index 33c99b1e..fc1a8a41 100644
--- a/content/browser/devtools/devtools.gyp
+++ b/content/browser/devtools/devtools.gyp
@@ -15,14 +15,12 @@
           'action_name': 'devtools_protocol_handler',
           'variables': {
             'blink_protocol': '<(SHARED_INTERMEDIATE_DIR)/blink/core/inspector/protocol.json',
-            'browser_protocol': 'browser_protocol.json',
             'generator': 'protocol/devtools_protocol_handler_generator.py',
             'output_cc': '<(SHARED_INTERMEDIATE_DIR)/content/browser/devtools/protocol/devtools_protocol_dispatcher.cc',
             'output_h': '<(SHARED_INTERMEDIATE_DIR)/content/browser/devtools/protocol/devtools_protocol_dispatcher.h',
           },
           'inputs': [
             '<(blink_protocol)',
-            '<(browser_protocol)',
             '<(generator)',
           ],
           'outputs': [
@@ -33,11 +31,10 @@
             'python',
             '<(generator)',
             '<(blink_protocol)',
-            '<(browser_protocol)',
             '<(output_cc)',
             '<(output_h)',
           ],
-          'message': 'Generating DevTools protocol browser-side handlers from <(blink_protocol) and <(browser_protocol)'
+          'message': 'Generating DevTools protocol browser-side handlers from <(blink_protocol)'
         },
       ],
       'direct_dependent_settings': {
diff --git a/content/browser/devtools/protocol/browser_handler.cc b/content/browser/devtools/protocol/browser_handler.cc
index ac575f6..83fd95f 100644
--- a/content/browser/devtools/protocol/browser_handler.cc
+++ b/content/browser/devtools/protocol/browser_handler.cc
@@ -43,6 +43,39 @@
   }
 }
 
+Response BrowserHandler::CreateBrowserContext(std::string* out_context_id) {
+  // For layering reasons this needs to be handled by
+  // DevToolsManagerDelegate::HandleCommand.
+  return Response::ServerError("Not supported");
+}
+
+Response BrowserHandler::DisposeBrowserContext(const std::string& context_id,
+                                               bool* out_success) {
+  // For layering reasons this needs to be handled by
+  // DevToolsManagerDelegate::HandleCommand.
+  return Response::ServerError("Not supported");
+}
+
+Response BrowserHandler::CreateTarget(const std::string& initial_url,
+                                      const int* width,
+                                      const int* height,
+                                      const std::string* context_id,
+                                      std::string* out_target_id) {
+  // For layering reasons this needs to be handled by
+  // DevToolsManagerDelegate::HandleCommand.
+  return Response::ServerError("Not supported");
+}
+
+Response BrowserHandler::CloseTarget(const std::string& target_id,
+                                     bool* out_success) {
+  scoped_refptr<DevToolsAgentHost> agent_host =
+      DevToolsAgentHost::GetForId(target_id);
+  if (!agent_host)
+    return Response::ServerError("No target with given id found");
+  *out_success = agent_host->Close();
+  return Response::OK();
+}
+
 Response BrowserHandler::GetTargets(TargetInfos* infos) {
   DevToolsAgentHost::List agents = DevToolsAgentHost::GetOrCreateAll();
   for (DevToolsAgentHost::List::iterator it = agents.begin();
diff --git a/content/browser/devtools/protocol/browser_handler.h b/content/browser/devtools/protocol/browser_handler.h
index d4135bc1..3cf34de7 100644
--- a/content/browser/devtools/protocol/browser_handler.h
+++ b/content/browser/devtools/protocol/browser_handler.h
@@ -33,6 +33,16 @@
   void SetClient(std::unique_ptr<Client> client);
 
   using TargetInfos = std::vector<scoped_refptr<devtools::browser::TargetInfo>>;
+
+  Response CreateBrowserContext(std::string* out_context_id);
+  Response DisposeBrowserContext(const std::string& context_id,
+                                 bool* out_success);
+  Response CreateTarget(const std::string& initial_url,
+                        const int* width,
+                        const int* height,
+                        const std::string* context_id,
+                        std::string* out_targetId);
+  Response CloseTarget(const std::string& targetId, bool* out_success);
   Response GetTargets(TargetInfos* infos);
   Response Attach(const std::string& targetId);
   Response Detach(const std::string& targetId);
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index 1e554763..e6e8357 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -587,4 +587,14 @@
   dialog_manager.Handle();
 }
 
+IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, BrowserNewPage) {
+  NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
+  Attach();
+  EXPECT_EQ(1u, shell()->windows().size());
+  std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue());
+  params->SetString("initialUrl", "about:blank");
+  SendCommand("Browser.newPage", std::move(params), true);
+  EXPECT_EQ(2u, shell()->windows().size());
+}
+
 }  // namespace content
diff --git a/content/browser/devtools/protocol/devtools_protocol_handler_generator.py b/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
index f9cb63ce..1697708f 100755
--- a/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
+++ b/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
@@ -8,9 +8,8 @@
 import json
 
 blink_protocol_path = sys.argv[1]
-browser_protocol_path = sys.argv[2]
-output_cc_path = sys.argv[3]
-output_h_path = sys.argv[4]
+output_cc_path = sys.argv[2]
+output_h_path = sys.argv[3]
 
 header = """\
 // Copyright 2014 The Chromium Authors. All rights reserved.
@@ -21,7 +20,6 @@
 // Generated by
 //  content/public/browser/devtools_protocol_handler_generator.py from
 //  gen/blink/core/inspector/protocol.json and
-//  content/browser/devtools/browser_protocol.json
 """
 
 template_h = string.Template(header + """\
@@ -454,7 +452,6 @@
 
 types = {}
 blink_protocol = json.loads(open(blink_protocol_path, "r").read())
-browser_protocol = json.loads(open(browser_protocol_path, "r").read())
 type_decls = []
 type_impls = []
 handler_methods = []
@@ -462,7 +459,7 @@
 domain_maps = []
 redirects = {}
 
-all_domains = blink_protocol["domains"] + browser_protocol["domains"]
+all_domains = blink_protocol["domains"]
 
 for json_domain in all_domains:
   if "types" in json_domain:
diff --git a/content/browser/devtools/protocol/security_handler.cc b/content/browser/devtools/protocol/security_handler.cc
index 913602e..4a2bce8 100644
--- a/content/browser/devtools/protocol/security_handler.cc
+++ b/content/browser/devtools/protocol/security_handler.cc
@@ -105,6 +105,8 @@
   AddExplanations(kSecurityStateSecure,
                   security_style_explanations.secure_explanations,
                   &explanations);
+  AddExplanations(kSecurityStateInfo,
+                  security_style_explanations.info_explanations, &explanations);
 
   scoped_refptr<MixedContentStatus> mixed_content_status =
       MixedContentStatus::Create()
diff --git a/content/browser/dom_storage/session_storage_database.cc b/content/browser/dom_storage/session_storage_database.cc
index 3a9457121..f3ac14d 100644
--- a/content/browser/dom_storage/session_storage_database.cc
+++ b/content/browser/dom_storage/session_storage_database.cc
@@ -298,7 +298,8 @@
   std::string current_namespace_id;
   for (it->Next(); it->Valid(); it->Next()) {
     std::string key = it->key().ToString();
-    if (key.find(namespace_prefix) != 0) {
+    if (!base::StartsWith(key, namespace_prefix,
+                          base::CompareCase::SENSITIVE)) {
       // Iterated past the "namespace-" keys.
       break;
     }
@@ -497,7 +498,8 @@
   // Skip the dummy entry "namespace-<namespaceid>-" and iterate the origins.
   for (it->Next(); it->Valid(); it->Next()) {
     std::string key = it->key().ToString();
-    if (key.find(namespace_start_key) != 0) {
+    if (!base::StartsWith(key, namespace_start_key,
+                          base::CompareCase::SENSITIVE)) {
       // Iterated past the origins for this namespace.
       break;
     }
@@ -549,7 +551,7 @@
   if (!it->Valid())
     return true;
   std::string key = it->key().ToString();
-  if (key.find(namespace_start_key) != 0)
+  if (!base::StartsWith(key, namespace_start_key, base::CompareCase::SENSITIVE))
     batch->Delete(namespace_start_key);
   return true;
 }
@@ -608,7 +610,7 @@
   // Skip the dummy entry "map-<mapid>-".
   for (it->Next(); it->Valid(); it->Next()) {
     std::string key = it->key().ToString();
-    if (key.find(map_start_key) != 0) {
+    if (!base::StartsWith(key, map_start_key, base::CompareCase::SENSITIVE)) {
       // Iterated past the keys in this map.
       break;
     }
diff --git a/content/browser/dom_storage/session_storage_database_unittest.cc b/content/browser/dom_storage/session_storage_database_unittest.cc
index 9440e0d..bc6a5fdd 100644
--- a/content/browser/dom_storage/session_storage_database_unittest.cc
+++ b/content/browser/dom_storage/session_storage_database_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/common/dom_storage/dom_storage_types.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -113,7 +114,7 @@
 bool SessionStorageDatabaseTest::IsNamespaceKey(const std::string& key,
                                                 std::string* namespace_id) {
   std::string namespace_prefix = SessionStorageDatabase::NamespacePrefix();
-  if (key.find(namespace_prefix) != 0)
+  if (!base::StartsWith(key, namespace_prefix, base::CompareCase::SENSITIVE))
     return false;
   if (key == namespace_prefix)
     return false;
@@ -134,7 +135,7 @@
     const std::string& key,
     std::string* namespace_id) {
   std::string namespace_prefix = SessionStorageDatabase::NamespacePrefix();
-  if (key.find(namespace_prefix) != 0)
+  if (!base::StartsWith(key, namespace_prefix, base::CompareCase::SENSITIVE))
     return false;
   size_t second_dash = key.find('-', namespace_prefix.length());
   if (second_dash == std::string::npos || second_dash == key.length() - 1)
@@ -152,7 +153,7 @@
 bool SessionStorageDatabaseTest::IsMapRefCountKey(const std::string& key,
                                                   int64_t* map_id) {
   std::string map_prefix = "map-";
-  if (key.find(map_prefix) != 0)
+  if (!base::StartsWith(key, map_prefix, base::CompareCase::SENSITIVE))
     return false;
   size_t second_dash = key.find('-', map_prefix.length());
   if (second_dash != key.length() - 1)
@@ -169,7 +170,7 @@
 bool SessionStorageDatabaseTest::IsMapValueKey(const std::string& key,
                                                int64_t* map_id) {
   std::string map_prefix = "map-";
-  if (key.find(map_prefix) != 0)
+  if (!base::StartsWith(key, map_prefix, base::CompareCase::SENSITIVE))
     return false;
   size_t second_dash = key.find('-', map_prefix.length());
   if (second_dash == std::string::npos || second_dash == key.length() - 1)
diff --git a/content/browser/download/drag_download_file.cc b/content/browser/download/drag_download_file.cc
index cd68969..94725a67 100644
--- a/content/browser/download/drag_download_file.cc
+++ b/content/browser/download/drag_download_file.cc
@@ -11,6 +11,7 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "content/browser/download/download_stats.h"
 #include "content/browser/web_contents/web_contents_impl.h"
@@ -37,13 +38,14 @@
 // anyway.
 class DragDownloadFile::DragDownloadFileUI : public DownloadItem::Observer {
  public:
-  DragDownloadFileUI(const GURL& url,
-                     const Referrer& referrer,
-                     const std::string& referrer_encoding,
-                     WebContents* web_contents,
-                     base::MessageLoop* on_completed_loop,
-                     const OnCompleted& on_completed)
-      : on_completed_loop_(on_completed_loop),
+  DragDownloadFileUI(
+      const GURL& url,
+      const Referrer& referrer,
+      const std::string& referrer_encoding,
+      WebContents* web_contents,
+      scoped_refptr<base::SingleThreadTaskRunner> on_completed_task_runner,
+      const OnCompleted& on_completed)
+      : on_completed_task_runner_(on_completed_task_runner),
         on_completed_(on_completed),
         url_(url),
         referrer_(referrer),
@@ -51,7 +53,7 @@
         web_contents_(web_contents),
         download_item_(NULL),
         weak_ptr_factory_(this) {
-    DCHECK(on_completed_loop_);
+    DCHECK(on_completed_task_runner_);
     DCHECK(!on_completed_.is_null());
     DCHECK(web_contents_);
     // May be called on any thread.
@@ -102,8 +104,8 @@
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
     if (!item || item->GetState() != DownloadItem::IN_PROGRESS) {
       DCHECK(!item || item->GetLastReason() != DOWNLOAD_INTERRUPT_REASON_NONE);
-      on_completed_loop_->task_runner()->PostTask(
-          FROM_HERE, base::Bind(on_completed_, false));
+      on_completed_task_runner_->PostTask(FROM_HERE,
+                                          base::Bind(on_completed_, false));
       return;
     }
     DCHECK_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
@@ -120,7 +122,7 @@
         state == DownloadItem::CANCELLED ||
         state == DownloadItem::INTERRUPTED) {
       if (!on_completed_.is_null()) {
-        on_completed_loop_->task_runner()->PostTask(
+        on_completed_task_runner_->PostTask(
             FROM_HERE,
             base::Bind(on_completed_, state == DownloadItem::COMPLETE));
         on_completed_.Reset();
@@ -137,7 +139,7 @@
     if (!on_completed_.is_null()) {
       const bool is_complete =
           download_item_->GetState() == DownloadItem::COMPLETE;
-      on_completed_loop_->task_runner()->PostTask(
+      on_completed_task_runner_->PostTask(
           FROM_HERE, base::Bind(on_completed_, is_complete));
       on_completed_.Reset();
     }
@@ -145,7 +147,7 @@
     download_item_ = NULL;
   }
 
-  base::MessageLoop* on_completed_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> const on_completed_task_runner_;
   OnCompleted on_completed_;
   GURL url_;
   Referrer referrer_;
@@ -167,16 +169,12 @@
                                    WebContents* web_contents)
     : file_path_(file_path),
       file_(std::move(file)),
-      drag_message_loop_(base::MessageLoop::current()),
+      drag_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       state_(INITIALIZED),
       drag_ui_(NULL),
       weak_ptr_factory_(this) {
   drag_ui_ = new DragDownloadFileUI(
-      url,
-      referrer,
-      referrer_encoding,
-      web_contents,
-      drag_message_loop_,
+      url, referrer, referrer_encoding, web_contents, drag_task_runner_,
       base::Bind(&DragDownloadFile::DownloadCompleted,
                  weak_ptr_factory_.GetWeakPtr()));
   DCHECK(!file_path_.empty());
@@ -244,7 +242,7 @@
 
 void DragDownloadFile::CheckThread() {
 #if defined(OS_WIN)
-  DCHECK(drag_message_loop_ == base::MessageLoop::current());
+  DCHECK(drag_task_runner_->BelongsToCurrentThread());
 #else
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 #endif
diff --git a/content/browser/download/drag_download_file.h b/content/browser/download/drag_download_file.h
index f6c12f6a..4e2a8216 100644
--- a/content/browser/download/drag_download_file.h
+++ b/content/browser/download/drag_download_file.h
@@ -11,8 +11,10 @@
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "content/browser/download/download_file.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/download_item.h"
@@ -59,7 +61,7 @@
 
   base::FilePath file_path_;
   base::File file_;
-  base::MessageLoop* drag_message_loop_;
+  const scoped_refptr<base::SingleThreadTaskRunner> drag_task_runner_;
   State state_;
   scoped_refptr<ui::DownloadFileObserver> observer_;
   base::RunLoop nested_loop_;
diff --git a/content/browser/frame_host/navigator_impl_unittest.cc b/content/browser/frame_host/navigator_impl_unittest.cc
index d869f06a..6b8bc12 100644
--- a/content/browser/frame_host/navigator_impl_unittest.cc
+++ b/content/browser/frame_host/navigator_impl_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <stdint.h>
 
+#include "base/feature_list.h"
 #include "base/macros.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
@@ -21,6 +22,7 @@
 #include "content/common/site_isolation_policy.h"
 #include "content/public/browser/navigation_data.h"
 #include "content/public/browser/stream_handle.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/common/url_utils.h"
 #include "content/public/test/mock_render_process_host.h"
@@ -832,8 +834,15 @@
   // A NavigationRequest should have been generated.
   NavigationRequest* main_request = node->navigation_request();
   ASSERT_TRUE(main_request != NULL);
-  EXPECT_EQ(FrameMsg_Navigate_Type::RELOAD,
-            main_request->common_params().navigation_type);
+  // TODO(toyoshim): Modify following checks once the feature is enabled.
+  if (base::FeatureList::IsEnabled(
+          features::kNonValidatingReloadOnNormalReload)) {
+    EXPECT_EQ(FrameMsg_Navigate_Type::RELOAD_MAIN_RESOURCE,
+              main_request->common_params().navigation_type);
+  } else {
+    EXPECT_EQ(FrameMsg_Navigate_Type::RELOAD,
+              main_request->common_params().navigation_type);
+  }
   main_test_rfh()->PrepareForCommit();
   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
 
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.cc b/content/browser/frame_host/render_widget_host_view_child_frame.cc
index e3a0361..cfea857 100644
--- a/content/browser/frame_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/frame_host/render_widget_host_view_child_frame.cc
@@ -297,10 +297,6 @@
     const gfx::Range& range) {
 }
 
-void RenderWidgetHostViewChildFrame::SelectionBoundsChanged(
-    const ViewHostMsg_SelectionBounds_Params& params) {
-}
-
 void RenderWidgetHostViewChildFrame::LockCompositingSurface() {
   NOTIMPLEMENTED();
 }
@@ -352,6 +348,7 @@
                                                   cc::SurfaceDrawStatus drawn) {
   cc::CompositorFrameAck ack;
   DCHECK_GT(ack_pending_count_, 0U);
+
   if (!surface_returned_resources_.empty())
     ack.resources.swap(surface_returned_resources_);
   if (host_) {
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.h b/content/browser/frame_host/render_widget_host_view_child_frame.h
index 67f11be..a569b9c 100644
--- a/content/browser/frame_host/render_widget_host_view_child_frame.h
+++ b/content/browser/frame_host/render_widget_host_view_child_frame.h
@@ -106,8 +106,6 @@
   void SelectionChanged(const base::string16& text,
                         size_t offset,
                         const gfx::Range& range) override;
-  void SelectionBoundsChanged(
-      const ViewHostMsg_SelectionBounds_Params& params) override;
   void CopyFromCompositingSurface(
       const gfx::Rect& src_subrect,
       const gfx::Size& dst_size,
diff --git a/content/browser/geolocation/geolocation_provider_impl.cc b/content/browser/geolocation/geolocation_provider_impl.cc
index df8fd63..2343fa7d 100644
--- a/content/browser/geolocation/geolocation_provider_impl.cc
+++ b/content/browser/geolocation/geolocation_provider_impl.cc
@@ -94,7 +94,7 @@
 }
 
 bool GeolocationProviderImpl::OnGeolocationThread() const {
-  return base::MessageLoop::current() == message_loop();
+  return task_runner()->BelongsToCurrentThread();
 }
 
 void GeolocationProviderImpl::OnClientsChanged() {
diff --git a/content/browser/geolocation/geolocation_provider_impl_unittest.cc b/content/browser/geolocation/geolocation_provider_impl_unittest.cc
index d9b30b8..62506f9 100644
--- a/content/browser/geolocation/geolocation_provider_impl_unittest.cc
+++ b/content/browser/geolocation/geolocation_provider_impl_unittest.cc
@@ -157,7 +157,7 @@
 }
 
 void GeolocationProviderTest::GetProvidersStarted(bool* started) {
-  DCHECK(base::MessageLoop::current() == provider_->message_loop());
+  DCHECK(provider_->task_runner()->BelongsToCurrentThread());
   *started = provider_->mock_arbitrator()->providers_started();
 }
 
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index 0d45e84..8263e0f6 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -190,10 +190,6 @@
 }
 
 bool IsPartialRasterEnabled() {
-  // Zero copy currently doesn't take advantage of partial raster.
-  if (IsZeroCopyUploadEnabled())
-    return false;
-
   const auto& command_line = *base::CommandLine::ForCurrentProcess();
   return !command_line.HasSwitch(switches::kDisablePartialRaster);
 }
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 9cb3b2a..dc270709 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -552,9 +552,8 @@
 
   TRACE_EVENT_INSTANT0("gpu", "LaunchGpuProcess", TRACE_EVENT_SCOPE_THREAD);
 
-  const std::string mojo_channel_token =
-      process_->GetHost()->CreateChannelMojo(child_token_);
-  if (mojo_channel_token.empty())
+  std::string channel_id = process_->GetHost()->CreateChannel();
+  if (channel_id.empty())
     return false;
 
   DCHECK(!mojo_child_connection_);
@@ -570,8 +569,8 @@
     DCHECK(g_gpu_main_thread_factory);
     in_process_gpu_thread_.reset(g_gpu_main_thread_factory(
         InProcessChildThreadParams(
-            std::string(), base::ThreadTaskRunnerHandle::Get(),
-            mojo_channel_token, mojo_child_connection_->service_token()),
+            channel_id, base::ThreadTaskRunnerHandle::Get(), std::string(),
+            mojo_child_connection_->service_token()),
         gpu_preferences));
     base::Thread::Options options;
 #if defined(OS_WIN)
@@ -584,7 +583,7 @@
     in_process_gpu_thread_->StartWithOptions(options);
 
     OnProcessLaunched();  // Fake a callback that the process is ready.
-  } else if (!LaunchGpuProcess(mojo_channel_token, &gpu_preferences)) {
+  } else if (!LaunchGpuProcess(channel_id, &gpu_preferences)) {
     return false;
   }
 
@@ -957,7 +956,7 @@
   Send(new GpuMsg_Finalize());
 }
 
-bool GpuProcessHost::LaunchGpuProcess(const std::string& mojo_channel_token,
+bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id,
                                       gpu::GpuPreferences* gpu_preferences) {
   if (!(gpu_enabled_ &&
       GpuDataManagerImpl::GetInstance()->ShouldUseSwiftShader()) &&
@@ -993,7 +992,7 @@
   base::CommandLine* cmd_line = new base::CommandLine(exe_path);
 #endif
   cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kGpuProcess);
-  cmd_line->AppendSwitchASCII(switches::kMojoChannelToken, mojo_channel_token);
+  cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
   cmd_line->AppendSwitchASCII(switches::kMojoApplicationChannelToken,
                               mojo_child_connection_->service_token());
   BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(cmd_line);
diff --git a/content/browser/iframe_zoom_browsertest.cc b/content/browser/iframe_zoom_browsertest.cc
index b74135c..80ba2665 100644
--- a/content/browser/iframe_zoom_browsertest.cc
+++ b/content/browser/iframe_zoom_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include <vector>
 
+#include "base/strings/string_util.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
@@ -121,7 +122,7 @@
   }
 
   void Check(const std::string& status_msg) {
-    if (status_msg.find(msg_label) != 0)
+    if (!base::StartsWith(status_msg, msg_label, base::CompareCase::SENSITIVE))
       return;
 
     double inner_width = std::stod(status_msg.substr(msg_label.length() + 1));
diff --git a/content/browser/indexed_db/indexed_db_class_factory.cc b/content/browser/indexed_db/indexed_db_class_factory.cc
index 71c30fd..3189b2d 100644
--- a/content/browser/indexed_db/indexed_db_class_factory.cc
+++ b/content/browser/indexed_db/indexed_db_class_factory.cc
@@ -37,12 +37,11 @@
 
 IndexedDBTransaction* IndexedDBClassFactory::CreateIndexedDBTransaction(
     int64_t id,
-    scoped_refptr<IndexedDBDatabaseCallbacks> callbacks,
+    base::WeakPtr<IndexedDBConnection> connection,
     const std::set<int64_t>& scope,
     blink::WebIDBTransactionMode mode,
-    IndexedDBDatabase* db,
     IndexedDBBackingStore::Transaction* backing_store_transaction) {
-  return new IndexedDBTransaction(id, callbacks, scope, mode, db,
+  return new IndexedDBTransaction(id, std::move(connection), scope, mode,
                                   backing_store_transaction);
 }
 
diff --git a/content/browser/indexed_db/indexed_db_class_factory.h b/content/browser/indexed_db/indexed_db_class_factory.h
index 2f8521032..fb4f1d7e 100644
--- a/content/browser/indexed_db/indexed_db_class_factory.h
+++ b/content/browser/indexed_db/indexed_db_class_factory.h
@@ -23,6 +23,7 @@
 namespace content {
 
 class IndexedDBBackingStore;
+class IndexedDBConnection;
 class IndexedDBDatabaseCallbacks;
 class IndexedDBFactory;
 class IndexedDBTransaction;
@@ -48,10 +49,9 @@
 
   virtual IndexedDBTransaction* CreateIndexedDBTransaction(
       int64_t id,
-      scoped_refptr<IndexedDBDatabaseCallbacks> callbacks,
+      base::WeakPtr<IndexedDBConnection> connection,
       const std::set<int64_t>& scope,
       blink::WebIDBTransactionMode mode,
-      IndexedDBDatabase* db,
       IndexedDBBackingStore::Transaction* backing_store_transaction);
 
   virtual LevelDBIteratorImpl* CreateIteratorImpl(
diff --git a/content/browser/indexed_db/indexed_db_connection.cc b/content/browser/indexed_db/indexed_db_connection.cc
index f7133a6..c2c7ebd 100644
--- a/content/browser/indexed_db/indexed_db_connection.cc
+++ b/content/browser/indexed_db/indexed_db_connection.cc
@@ -4,6 +4,9 @@
 
 #include "content/browser/indexed_db/indexed_db_connection.h"
 
+#include "base/logging.h"
+#include "base/stl_util.h"
+
 namespace content {
 
 IndexedDBConnection::IndexedDBConnection(
@@ -21,6 +24,7 @@
   if (this_obj) {
     database_ = nullptr;
     callbacks_ = nullptr;
+    active_observers_.clear();
   }
 }
 
@@ -35,6 +39,7 @@
   if (this_obj) {
     database_ = nullptr;
     callbacks_ = nullptr;
+    active_observers_.clear();
   }
   callbacks->OnForcedClose();
 }
@@ -49,4 +54,31 @@
   return database_.get() != NULL;
 }
 
+// The observers begin listening to changes only once they are activated.
+void IndexedDBConnection::ActivatePendingObservers(
+    std::vector<std::unique_ptr<IndexedDBObserver>> pending_observers) {
+  for (auto& observer : pending_observers) {
+    active_observers_.push_back(std::move(observer));
+  }
+  pending_observers.clear();
+}
+
+void IndexedDBConnection::RemoveObservers(
+    const std::vector<int32_t>& observer_ids_to_remove) {
+  std::vector<int32_t> pending_observer_ids;
+  for (int32_t id_to_remove : observer_ids_to_remove) {
+    const auto& it = std::find_if(
+        active_observers_.begin(), active_observers_.end(),
+        [&id_to_remove](const std::unique_ptr<IndexedDBObserver>& o) {
+          return o->id() == id_to_remove;
+        });
+    if (it != active_observers_.end())
+      active_observers_.erase(it);
+    else
+      pending_observer_ids.push_back(id_to_remove);
+  }
+  if (!pending_observer_ids.empty())
+    database_->RemovePendingObservers(this, pending_observer_ids);
+}
+
 }  // namespace content
diff --git a/content/browser/indexed_db/indexed_db_connection.h b/content/browser/indexed_db/indexed_db_connection.h
index 4d828e5..3c305f3 100644
--- a/content/browser/indexed_db/indexed_db_connection.h
+++ b/content/browser/indexed_db/indexed_db_connection.h
@@ -10,9 +10,9 @@
 #include "base/memory/weak_ptr.h"
 #include "content/browser/indexed_db/indexed_db_database.h"
 #include "content/browser/indexed_db/indexed_db_database_callbacks.h"
+#include "content/browser/indexed_db/indexed_db_observer.h"
 
 namespace content {
-class IndexedDBCallbacks;
 class IndexedDBDatabaseError;
 
 class CONTENT_EXPORT IndexedDBConnection {
@@ -28,8 +28,22 @@
 
   void VersionChangeIgnored();
 
+  virtual void ActivatePendingObservers(
+      std::vector<std::unique_ptr<IndexedDBObserver>> pending_observers);
+  // Removes observer listed in |remove_observer_ids| from active_observer of
+  // connection or pending_observer of transactions associated with this
+  // connection.
+  virtual void RemoveObservers(const std::vector<int32_t>& remove_observer_ids);
+
   IndexedDBDatabase* database() const { return database_.get(); }
   IndexedDBDatabaseCallbacks* callbacks() const { return callbacks_.get(); }
+  const std::vector<std::unique_ptr<IndexedDBObserver>>& active_observers()
+      const {
+    return active_observers_;
+  }
+  base::WeakPtr<IndexedDBConnection> GetWeakPtr() {
+    return weak_factory_.GetWeakPtr();
+  }
 
  private:
   // NULL in some unit tests, and after the connection is closed.
@@ -38,7 +52,7 @@
   // The callbacks_ member is cleared when the connection is closed.
   // May be NULL in unit tests.
   scoped_refptr<IndexedDBDatabaseCallbacks> callbacks_;
-
+  std::vector<std::unique_ptr<IndexedDBObserver>> active_observers_;
   base::WeakPtrFactory<IndexedDBConnection> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(IndexedDBConnection);
diff --git a/content/browser/indexed_db/indexed_db_database.cc b/content/browser/indexed_db/indexed_db_database.cc
index 6d104a5..a73ba29 100644
--- a/content/browser/indexed_db/indexed_db_database.cc
+++ b/content/browser/indexed_db/indexed_db_database.cc
@@ -541,6 +541,26 @@
     transaction->Abort(error);
 }
 
+void IndexedDBDatabase::AddPendingObserver(int64_t transaction_id,
+                                           int32_t observer_id) {
+  IndexedDBTransaction* transaction = GetTransaction(transaction_id);
+  if (!transaction)
+    return;
+  transaction->AddPendingObserver(observer_id);
+}
+
+void IndexedDBDatabase::RemovePendingObservers(
+    IndexedDBConnection* connection,
+    const std::vector<int32_t>& pending_observer_ids) {
+  TransactionMap::iterator it;
+  for (it = transactions_.begin(); it != transactions_.end(); it++) {
+    // Avoid call to RemovePendingObservers for transactions on other
+    // connections.
+    if (it->second->connection() == connection)
+      it->second->RemovePendingObservers(pending_observer_ids);
+  }
+}
+
 void IndexedDBDatabase::GetAll(int64_t transaction_id,
                                int64_t object_store_id,
                                int64_t index_id,
@@ -1665,9 +1685,9 @@
   // The transaction will add itself to this database's coordinator, which
   // manages the lifetime of the object.
   TransactionCreated(IndexedDBClassFactory::Get()->CreateIndexedDBTransaction(
-      transaction_id, connection->callbacks(),
+      transaction_id, connection->GetWeakPtr(),
       std::set<int64_t>(object_store_ids.begin(), object_store_ids.end()), mode,
-      this, new IndexedDBBackingStore::Transaction(backing_store_.get())));
+      new IndexedDBBackingStore::Transaction(backing_store_.get())));
 }
 
 void IndexedDBDatabase::TransactionCreated(IndexedDBTransaction* transaction) {
@@ -1905,7 +1925,7 @@
   {
     TransactionMap transactions(transactions_);
     for (const auto& it : transactions) {
-      if (it.second->connection() == connection->callbacks())
+      if (it.second->callbacks() == connection->callbacks())
         it.second->Abort(
             IndexedDBDatabaseError(blink::WebIDBDatabaseExceptionUnknownError,
                                    "Connection is closing."));
diff --git a/content/browser/indexed_db/indexed_db_database.h b/content/browser/indexed_db/indexed_db_database.h
index bcbdb53..527b516 100644
--- a/content/browser/indexed_db/indexed_db_database.h
+++ b/content/browser/indexed_db/indexed_db_database.h
@@ -125,6 +125,10 @@
   // Called by transactions to report failure committing to the backing store.
   void TransactionCommitFailed(const leveldb::Status& status);
 
+  void AddPendingObserver(int64_t transaction_id, int32_t observer_id);
+  void RemovePendingObservers(IndexedDBConnection* connection,
+                              const std::vector<int32_t>& pending_observer_ids);
+
   void Get(int64_t transaction_id,
            int64_t object_store_id,
            int64_t index_id,
diff --git a/content/browser/indexed_db/indexed_db_database_unittest.cc b/content/browser/indexed_db/indexed_db_database_unittest.cc
index f01c413e1..1ade60316 100644
--- a/content/browser/indexed_db/indexed_db_database_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_database_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/auto_reset.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
@@ -238,9 +239,11 @@
         IndexedDBDatabaseMetadata::DEFAULT_VERSION));
     EXPECT_EQ(IndexedDBDatabaseMetadata::NO_VERSION, db_->metadata().version);
 
+    connection_ = base::WrapUnique(new IndexedDBConnection(db_, callbacks_));
     transaction_ = IndexedDBClassFactory::Get()->CreateIndexedDBTransaction(
-        transaction_id, callbacks_, std::set<int64_t>() /*scope*/,
-        blink::WebIDBTransactionModeVersionChange, db_.get(),
+        transaction_id, connection_->GetWeakPtr(),
+        std::set<int64_t>() /*scope*/,
+        blink::WebIDBTransactionModeVersionChange,
         new IndexedDBFakeBackingStore::FakeTransaction(commit_success_));
     db_->TransactionCreated(transaction_.get());
 
@@ -258,6 +261,7 @@
   scoped_refptr<MockIndexedDBCallbacks> request_;
   scoped_refptr<MockIndexedDBDatabaseCallbacks> callbacks_;
   scoped_refptr<IndexedDBTransaction> transaction_;
+  std::unique_ptr<IndexedDBConnection> connection_;
 
   leveldb::Status commit_success_;
 
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host.cc b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
index 96cad054..aac0dd93 100644
--- a/content/browser/indexed_db/indexed_db_dispatcher_host.cc
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
@@ -520,6 +520,8 @@
     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseVersionChangeIgnored,
                         OnVersionChangeIgnored)
     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed, OnDestroyed)
+    IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseObserve, OnObserve)
+    IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseUnobserve, OnUnobserve)
     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGet, OnGet)
     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGetAll, OnGetAll)
     IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabasePut, OnPutWrapper)
@@ -629,6 +631,31 @@
   parent_->DestroyObject(&map_, ipc_object_id);
 }
 
+void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnObserve(
+    int32_t ipc_database_id,
+    int64_t transaction_id,
+    int32_t observer_id) {
+  DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
+  IndexedDBConnection* connection =
+      parent_->GetOrTerminateProcess(&map_, ipc_database_id);
+  if (!connection || !connection->IsConnected())
+    return;
+  connection->database()->AddPendingObserver(
+      parent_->HostTransactionId(transaction_id), observer_id);
+}
+
+void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnUnobserve(
+    int32_t ipc_database_id,
+    const std::vector<int32_t>& observer_ids_to_remove) {
+  DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
+  DCHECK(!observer_ids_to_remove.empty());
+  IndexedDBConnection* connection =
+      parent_->GetOrTerminateProcess(&map_, ipc_database_id);
+  if (!connection || !connection->IsConnected())
+    return;
+  connection->RemoveObservers(observer_ids_to_remove);
+}
+
 void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet(
     const IndexedDBHostMsg_DatabaseGet_Params& params) {
   DCHECK(parent_->context()->TaskRunner()->RunsTasksOnCurrentThread());
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host.h b/content/browser/indexed_db/indexed_db_dispatcher_host.h
index ba7a65f..524c68e 100644
--- a/content/browser/indexed_db/indexed_db_dispatcher_host.h
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host.h
@@ -174,6 +174,12 @@
     void OnVersionChangeIgnored(int32_t ipc_database_id);
     void OnDestroyed(int32_t ipc_database_id);
 
+    void OnObserve(int32_t ipc_database_id,
+                   int64_t transaction_id,
+                   int32_t observer_id);
+    void OnUnobserve(int32_t ipc_database_id,
+                     const std::vector<int32_t>& observer_ids_to_remove);
+
     void OnGet(const IndexedDBHostMsg_DatabaseGet_Params& params);
     void OnGetAll(const IndexedDBHostMsg_DatabaseGetAll_Params& params);
     // OnPutWrapper starts on the IO thread so that it can grab BlobDataHandles
diff --git a/content/browser/indexed_db/indexed_db_observer.cc b/content/browser/indexed_db/indexed_db_observer.cc
new file mode 100644
index 0000000..56d53eb
--- /dev/null
+++ b/content/browser/indexed_db/indexed_db_observer.cc
@@ -0,0 +1,14 @@
+// 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 "content/browser/indexed_db/indexed_db_observer.h"
+
+namespace content {
+
+IndexedDBObserver::IndexedDBObserver(int32_t observer_id)
+    : observer_id_(observer_id) {}
+
+IndexedDBObserver::~IndexedDBObserver() {}
+
+}  // namespace content
diff --git a/content/browser/indexed_db/indexed_db_observer.h b/content/browser/indexed_db/indexed_db_observer.h
new file mode 100644
index 0000000..f7bd959
--- /dev/null
+++ b/content/browser/indexed_db/indexed_db_observer.h
@@ -0,0 +1,31 @@
+// 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_INDEXED_DB_INDEXED_DB_OBSERVER_H_
+#define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_OBSERVER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class CONTENT_EXPORT IndexedDBObserver {
+ public:
+  IndexedDBObserver(int32_t observer_id);
+  ~IndexedDBObserver();
+
+  int32_t id() const { return observer_id_; }
+
+ private:
+  int32_t observer_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(IndexedDBObserver);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_OBSERVER_H_
diff --git a/content/browser/indexed_db/indexed_db_transaction.cc b/content/browser/indexed_db/indexed_db_transaction.cc
index 768cf1d..5de620d 100644
--- a/content/browser/indexed_db/indexed_db_transaction.cc
+++ b/content/browser/indexed_db/indexed_db_transaction.cc
@@ -7,13 +7,16 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/browser/indexed_db/indexed_db_backing_store.h"
 #include "content/browser/indexed_db/indexed_db_cursor.h"
 #include "content/browser/indexed_db/indexed_db_database.h"
 #include "content/browser/indexed_db/indexed_db_database_callbacks.h"
+#include "content/browser/indexed_db/indexed_db_observer.h"
 #include "content/browser/indexed_db/indexed_db_tracing.h"
 #include "content/browser/indexed_db/indexed_db_transaction_coordinator.h"
 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h"
@@ -66,10 +69,9 @@
 
 IndexedDBTransaction::IndexedDBTransaction(
     int64_t id,
-    scoped_refptr<IndexedDBDatabaseCallbacks> callbacks,
+    base::WeakPtr<IndexedDBConnection> connection,
     const std::set<int64_t>& object_store_ids,
     blink::WebIDBTransactionMode mode,
-    IndexedDBDatabase* database,
     IndexedDBBackingStore::Transaction* backing_store_transaction)
     : id_(id),
       object_store_ids_(object_store_ids),
@@ -77,12 +79,14 @@
       used_(false),
       state_(CREATED),
       commit_pending_(false),
-      callbacks_(callbacks),
-      database_(database),
+      connection_(std::move(connection)),
       transaction_(backing_store_transaction),
       backing_store_transaction_begun_(false),
       should_process_queue_(false),
       pending_preemptive_events_(0) {
+  callbacks_ = connection_->callbacks();
+  database_ = connection_->database();
+
   database_->transaction_coordinator().DidCreateTransaction(this);
 
   diagnostics_.tasks_scheduled = 0;
@@ -98,6 +102,7 @@
   DCHECK_EQ(pending_preemptive_events_, 0);
   DCHECK(task_queue_.empty());
   DCHECK(abort_task_stack_.empty());
+  DCHECK(pending_observers_.empty());
 }
 
 void IndexedDBTransaction::ScheduleTask(blink::WebIDBTaskType type,
@@ -191,6 +196,8 @@
   database_->TransactionFinished(this, false);
 
   database_ = NULL;
+  connection_ = nullptr;
+  pending_observers_.clear();
 }
 
 bool IndexedDBTransaction::IsTaskQueueEmpty() const {
@@ -339,6 +346,9 @@
   database_->transaction_coordinator().DidFinishTransaction(this);
 
   if (committed) {
+    // TODO (palakj) : Send Observations to observers
+    if (!pending_observers_.empty() && connection_)
+      connection_->ActivatePendingObservers(std::move(pending_observers_));
     abort_task_stack_.clear();
     {
       IDB_TRACE1(
@@ -445,4 +455,20 @@
   open_cursors_.clear();
 }
 
+void IndexedDBTransaction::AddPendingObserver(int32_t observer_id) {
+  pending_observers_.push_back(
+      base::WrapUnique(new IndexedDBObserver(observer_id)));
+}
+
+void IndexedDBTransaction::RemovePendingObservers(
+    const std::vector<int32_t>& pending_observer_ids) {
+  const auto& it = std::remove_if(
+      pending_observers_.begin(), pending_observers_.end(),
+      [&pending_observer_ids](const std::unique_ptr<IndexedDBObserver>& o) {
+        return ContainsValue(pending_observer_ids, o->id());
+      });
+  if (it != pending_observers_.end())
+    pending_observers_.erase(it, pending_observers_.end());
+}
+
 }  // namespace content
diff --git a/content/browser/indexed_db/indexed_db_transaction.h b/content/browser/indexed_db/indexed_db_transaction.h
index ae1863b..e889d438 100644
--- a/content/browser/indexed_db/indexed_db_transaction.h
+++ b/content/browser/indexed_db/indexed_db_transaction.h
@@ -18,6 +18,7 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "content/browser/indexed_db/indexed_db_backing_store.h"
+#include "content/browser/indexed_db/indexed_db_connection.h"
 #include "content/browser/indexed_db/indexed_db_database.h"
 #include "content/browser/indexed_db/indexed_db_database_error.h"
 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h"
@@ -27,6 +28,7 @@
 class BlobWriteCallbackImpl;
 class IndexedDBCursor;
 class IndexedDBDatabaseCallbacks;
+class IndexedDBObserver;
 
 class CONTENT_EXPORT IndexedDBTransaction
     : public NON_EXPORTED_BASE(base::RefCounted<IndexedDBTransaction>) {
@@ -63,13 +65,18 @@
     pending_preemptive_events_--;
     DCHECK_GE(pending_preemptive_events_, 0);
   }
+  void AddPendingObserver(int32_t observer_id);
+  // Delete pending observers with ID's listed in |pending_observer_ids|.
+  void RemovePendingObservers(const std::vector<int32_t>& pending_observer_ids);
+
   IndexedDBBackingStore::Transaction* BackingStoreTransaction() {
     return transaction_.get();
   }
   int64_t id() const { return id_; }
 
   IndexedDBDatabase* database() const { return database_.get(); }
-  IndexedDBDatabaseCallbacks* connection() const { return callbacks_.get(); }
+  IndexedDBDatabaseCallbacks* callbacks() const { return callbacks_.get(); }
+  IndexedDBConnection* connection() const { return connection_.get(); }
 
   State state() const { return state_; }
   bool IsTimeoutTimerRunning() const { return timeout_timer_.IsRunning(); }
@@ -88,10 +95,9 @@
   // IndexedDBClassFactory.
   IndexedDBTransaction(
       int64_t id,
-      scoped_refptr<IndexedDBDatabaseCallbacks> callbacks,
+      base::WeakPtr<IndexedDBConnection> connection,
       const std::set<int64_t>& object_store_ids,
       blink::WebIDBTransactionMode mode,
-      IndexedDBDatabase* db,
       IndexedDBBackingStore::Transaction* backing_store_transaction);
   virtual ~IndexedDBTransaction();
 
@@ -111,6 +117,7 @@
   FRIEND_TEST_ALL_PREFIXES(IndexedDBTransactionTestMode,
                            ScheduleNormalTask);
   FRIEND_TEST_ALL_PREFIXES(IndexedDBTransactionTest, Timeout);
+  FRIEND_TEST_ALL_PREFIXES(IndexedDBTransactionTest, IndexedDBObserver);
 
   void RunTasksIfStarted();
 
@@ -130,9 +137,13 @@
   bool used_;
   State state_;
   bool commit_pending_;
+  base::WeakPtr<IndexedDBConnection> connection_;
   scoped_refptr<IndexedDBDatabaseCallbacks> callbacks_;
   scoped_refptr<IndexedDBDatabase> database_;
 
+  // Observers in pending queue do not listen to changes until activated.
+  std::vector<std::unique_ptr<IndexedDBObserver>> pending_observers_;
+
   class TaskQueue {
    public:
     TaskQueue();
diff --git a/content/browser/indexed_db/indexed_db_transaction_unittest.cc b/content/browser/indexed_db/indexed_db_transaction_unittest.cc
index 632b1ee..935aa167 100644
--- a/content/browser/indexed_db/indexed_db_transaction_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_transaction_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "content/browser/indexed_db/indexed_db_connection.h"
 #include "content/browser/indexed_db/indexed_db_fake_backing_store.h"
 #include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h"
 #include "content/browser/indexed_db/mock_indexed_db_factory.h"
@@ -86,12 +87,11 @@
   const int64_t id = 0;
   const std::set<int64_t> scope;
   const leveldb::Status commit_success = leveldb::Status::OK();
+  std::unique_ptr<IndexedDBConnection> connection(
+      new IndexedDBConnection(db_, new MockIndexedDBDatabaseCallbacks()));
   scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction(
-      id,
-      new MockIndexedDBDatabaseCallbacks(),
-      scope,
+      id, connection->GetWeakPtr(), scope,
       blink::WebIDBTransactionModeReadWrite,
-      db_.get(),
       new IndexedDBFakeBackingStore::FakeTransaction(commit_success));
   db_->TransactionCreated(transaction.get());
 
@@ -130,12 +130,10 @@
   const int64_t id = 0;
   const std::set<int64_t> scope;
   const leveldb::Status commit_success = leveldb::Status::OK();
+  std::unique_ptr<IndexedDBConnection> connection(
+      new IndexedDBConnection(db_, new MockIndexedDBDatabaseCallbacks()));
   scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction(
-      id,
-      new MockIndexedDBDatabaseCallbacks(),
-      scope,
-      blink::WebIDBTransactionModeReadOnly,
-      db_.get(),
+      id, connection->GetWeakPtr(), scope, blink::WebIDBTransactionModeReadOnly,
       new IndexedDBFakeBackingStore::FakeTransaction(commit_success));
   db_->TransactionCreated(transaction.get());
 
@@ -162,12 +160,10 @@
   const int64_t id = 0;
   const std::set<int64_t> scope;
   const leveldb::Status commit_success = leveldb::Status::OK();
+  std::unique_ptr<IndexedDBConnection> connection(
+      new IndexedDBConnection(db_, new MockIndexedDBDatabaseCallbacks()));
   scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction(
-      id,
-      new MockIndexedDBDatabaseCallbacks(),
-      scope,
-      GetParam(),
-      db_.get(),
+      id, connection->GetWeakPtr(), scope, GetParam(),
       new IndexedDBFakeBackingStore::FakeTransaction(commit_success));
 
   EXPECT_FALSE(transaction->HasPendingTasks());
@@ -224,12 +220,11 @@
   const int64_t id = 0;
   const std::set<int64_t> scope;
   const leveldb::Status commit_failure = leveldb::Status::Corruption("Ouch.");
+  std::unique_ptr<IndexedDBConnection> connection(
+      new IndexedDBConnection(db_, new MockIndexedDBDatabaseCallbacks()));
   scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction(
-      id,
-      new MockIndexedDBDatabaseCallbacks(),
-      scope,
+      id, connection->GetWeakPtr(), scope,
       blink::WebIDBTransactionModeVersionChange,
-      db_.get(),
       new IndexedDBFakeBackingStore::FakeTransaction(commit_failure));
 
   EXPECT_FALSE(transaction->HasPendingTasks());
@@ -285,12 +280,10 @@
   const int64_t id = 0;
   const std::set<int64_t> scope;
   const leveldb::Status commit_failure = leveldb::Status::Corruption("Ouch.");
+  std::unique_ptr<IndexedDBConnection> connection(
+      new IndexedDBConnection(db_, new MockIndexedDBDatabaseCallbacks()));
   scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction(
-      id,
-      new MockIndexedDBDatabaseCallbacks(),
-      scope,
-      GetParam(),
-      db_.get(),
+      id, connection->GetWeakPtr(), scope, GetParam(),
       new IndexedDBFakeBackingStore::FakeTransaction(commit_failure));
   db_->TransactionCreated(transaction.get());
 
@@ -315,12 +308,10 @@
   const int64_t id = 0;
   const std::set<int64_t> scope;
   const leveldb::Status commit_success = leveldb::Status::OK();
+  std::unique_ptr<IndexedDBConnection> connection(
+      new IndexedDBConnection(db_, new MockIndexedDBDatabaseCallbacks()));
   scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction(
-      id,
-      new MockIndexedDBDatabaseCallbacks(),
-      scope,
-      GetParam(),
-      db_.get(),
+      id, connection->GetWeakPtr(), scope, GetParam(),
       new IndexedDBFakeBackingStore::FakeTransaction(commit_success));
   db_->TransactionCreated(transaction.get());
 
@@ -362,6 +353,49 @@
             transaction->diagnostics().tasks_scheduled);
 }
 
+TEST_F(IndexedDBTransactionTest, IndexedDBObserver) {
+  const int64_t id = 0;
+  const std::set<int64_t> scope;
+  const leveldb::Status commit_success = leveldb::Status::OK();
+  std::unique_ptr<IndexedDBConnection> connection(
+      new IndexedDBConnection(db_, new MockIndexedDBDatabaseCallbacks()));
+  scoped_refptr<IndexedDBTransaction> transaction = new IndexedDBTransaction(
+      id, connection->GetWeakPtr(), scope,
+      blink::WebIDBTransactionModeReadWrite,
+      new IndexedDBFakeBackingStore::FakeTransaction(commit_success));
+  db_->TransactionCreated(transaction.get());
+
+  EXPECT_EQ(0UL, transaction->pending_observers_.size());
+  EXPECT_EQ(0UL, connection->active_observers().size());
+
+  // Add observers to pending observer list.
+  const int32_t observer_id1 = 1, observer_id2 = 2;
+  transaction->AddPendingObserver(observer_id1);
+  transaction->AddPendingObserver(observer_id2);
+  EXPECT_EQ(2UL, transaction->pending_observers_.size());
+  EXPECT_EQ(0UL, connection->active_observers().size());
+
+  // Before commit, observer would be in pending list of transaction.
+  std::vector<int32_t> observer_to_remove1 = {observer_id1};
+  connection->RemoveObservers(observer_to_remove1);
+  EXPECT_EQ(1UL, transaction->pending_observers_.size());
+  EXPECT_EQ(0UL, connection->active_observers().size());
+
+  // After commit, observer moved to connection's active observer.
+  transaction->Commit();
+  EXPECT_EQ(0UL, transaction->pending_observers_.size());
+  EXPECT_EQ(1UL, connection->active_observers().size());
+
+  // Observer does not exist, so no change to active_observers.
+  connection->RemoveObservers(observer_to_remove1);
+  EXPECT_EQ(1UL, connection->active_observers().size());
+
+  // Observer removed from connection's active observer.
+  std::vector<int32_t> observer_to_remove2 = {observer_id2};
+  connection->RemoveObservers(observer_to_remove2);
+  EXPECT_EQ(0UL, connection->active_observers().size());
+}
+
 static const blink::WebIDBTransactionMode kTestModes[] = {
     blink::WebIDBTransactionModeReadOnly, blink::WebIDBTransactionModeReadWrite,
     blink::WebIDBTransactionModeVersionChange};
diff --git a/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc b/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc
index 51edd56..ec3ef6d 100644
--- a/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc
+++ b/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.cc
@@ -64,16 +64,14 @@
  public:
   IndexedDBTestTransaction(
       int64_t id,
-      scoped_refptr<IndexedDBDatabaseCallbacks> callbacks,
+      base::WeakPtr<IndexedDBConnection> connection,
       const std::set<int64_t>& scope,
       blink::WebIDBTransactionMode mode,
-      IndexedDBDatabase* db,
       IndexedDBBackingStore::Transaction* backing_store_transaction)
       : IndexedDBTransaction(id,
-                             callbacks,
+                             std::move(connection),
                              scope,
                              mode,
-                             db,
                              backing_store_transaction) {}
 
  protected:
@@ -267,12 +265,11 @@
 IndexedDBTransaction*
 MockBrowserTestIndexedDBClassFactory::CreateIndexedDBTransaction(
     int64_t id,
-    scoped_refptr<IndexedDBDatabaseCallbacks> callbacks,
+    base::WeakPtr<IndexedDBConnection> connection,
     const std::set<int64_t>& scope,
     blink::WebIDBTransactionMode mode,
-    IndexedDBDatabase* db,
     IndexedDBBackingStore::Transaction* backing_store_transaction) {
-  return new IndexedDBTestTransaction(id, callbacks, scope, mode, db,
+  return new IndexedDBTestTransaction(id, std::move(connection), scope, mode,
                                       backing_store_transaction);
 }
 
diff --git a/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h b/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h
index 8011e72..2f91516 100644
--- a/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h
+++ b/content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h
@@ -18,6 +18,7 @@
 
 namespace content {
 
+class IndexedDBConnection;
 class LevelDBTransaction;
 class LevelDBDatabase;
 
@@ -47,10 +48,9 @@
       const IndexedDBDatabase::Identifier& unique_identifier) override;
   IndexedDBTransaction* CreateIndexedDBTransaction(
       int64_t id,
-      scoped_refptr<IndexedDBDatabaseCallbacks> callbacks,
+      base::WeakPtr<IndexedDBConnection> connection,
       const std::set<int64_t>& scope,
       blink::WebIDBTransactionMode mode,
-      IndexedDBDatabase* db,
       IndexedDBBackingStore::Transaction* backing_store_transaction) override;
   LevelDBTransaction* CreateLevelDBTransaction(LevelDBDatabase* db) override;
   LevelDBIteratorImpl* CreateIteratorImpl(
diff --git a/content/browser/loader/reload_cache_control_browsertest.cc b/content/browser/loader/reload_cache_control_browsertest.cc
index 3858676..2ab56cad 100644
--- a/content/browser/loader/reload_cache_control_browsertest.cc
+++ b/content/browser/loader/reload_cache_control_browsertest.cc
@@ -43,6 +43,18 @@
   ~ReloadCacheControlBrowserTest() override = default;
 
   void SetUpOnMainThread() override {
+    // TODO(toyoshim): Tests in this file depend on current reload behavior,
+    // and should be modified when we enable the new reload behavior.
+    base::FeatureList::ClearInstanceForTesting();
+    std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+    feature_list->InitializeFromCommandLine(
+        std::string(), features::kNonValidatingReloadOnNormalReload.name);
+    base::FeatureList::SetInstance(std::move(feature_list));
+
+    SetUpTestServerOnMainThread();
+  }
+
+  void SetUpTestServerOnMainThread() {
     // ContentBrowserTest creates embedded_test_server instance with
     // a registered HandleFileRequest for "content/test/data".
     // Because the handler is registered as the first handler, MonitorHandler
@@ -83,7 +95,7 @@
         features::kNonValidatingReloadOnNormalReload.name, std::string());
     base::FeatureList::SetInstance(std::move(feature_list));
 
-    ReloadCacheControlBrowserTest::SetUpOnMainThread();
+    SetUpTestServerOnMainThread();
   }
 
   DISALLOW_COPY_AND_ASSIGN(ReloadCacheControlWithAnExperimentBrowserTest);
diff --git a/content/browser/media/android/browser_media_session_manager.cc b/content/browser/media/android/browser_media_session_manager.cc
index a7e5fd5b..80d3173a 100644
--- a/content/browser/media/android/browser_media_session_manager.cc
+++ b/content/browser/media/android/browser_media_session_manager.cc
@@ -4,6 +4,9 @@
 
 #include "content/browser/media/android/browser_media_session_manager.h"
 
+#include "content/browser/media/session/media_session.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/media/media_metadata_sanitizer.h"
 #include "content/common/media/media_session_messages_android.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
@@ -30,15 +33,7 @@
     const MediaMetadata& insecure_metadata) {
   // When receiving a MediaMetadata, the browser process can't trust that it is
   // coming from a known and secure source. It must be processed accordingly.
-  MediaMetadata metadata;
-  metadata.title =
-      insecure_metadata.title.substr(0, MediaMetadata::kMaxIPCStringLength);
-  metadata.artist =
-      insecure_metadata.artist.substr(0, MediaMetadata::kMaxIPCStringLength);
-  metadata.album =
-      insecure_metadata.album.substr(0, MediaMetadata::kMaxIPCStringLength);
-
-  if (metadata != insecure_metadata) {
+  if (!MediaMetadataSanitizer::CheckSanity(insecure_metadata)) {
     render_frame_host_->GetProcess()->ShutdownForBadMessage();
     return;
   }
diff --git a/content/browser/media/android/browser_media_session_manager.h b/content/browser/media/android/browser_media_session_manager.h
index b936ba0..cd92bdc 100644
--- a/content/browser/media/android/browser_media_session_manager.h
+++ b/content/browser/media/android/browser_media_session_manager.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_MEDIA_ANDROID_BROWSER_MEDIA_SESSION_MANAGER_H_
 
 #include "base/macros.h"
+#include "content/common/content_export.h"
 
 namespace IPC {
 class Message;
@@ -16,14 +17,14 @@
 class RenderFrameHost;
 struct MediaMetadata;
 
-class BrowserMediaSessionManager {
+class CONTENT_EXPORT BrowserMediaSessionManager {
  public:
-  BrowserMediaSessionManager(RenderFrameHost* render_frame_host);
+  explicit BrowserMediaSessionManager(RenderFrameHost* render_frame_host);
 
   // Message handlers.
-  void OnActivate(int session_id, int request_id);
-  void OnDeactivate(int session_id, int request_id);
-  void OnSetMetadata(int session_id, const MediaMetadata& metadata);
+  virtual void OnActivate(int session_id, int request_id);
+  virtual void OnDeactivate(int session_id, int request_id);
+  virtual void OnSetMetadata(int session_id, const MediaMetadata& metadata);
 
   int GetRoutingID() const;
 
diff --git a/content/browser/media/android/browser_media_session_manager_browsertest.cc b/content/browser/media/android/browser_media_session_manager_browsertest.cc
new file mode 100644
index 0000000..f98d73f
--- /dev/null
+++ b/content/browser/media/android/browser_media_session_manager_browsertest.cc
@@ -0,0 +1,209 @@
+// 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 "content/browser/media/android/browser_media_session_manager.h"
+
+#include <iostream>
+#include <sstream>
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/media/android/media_web_contents_observer_android.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::InvokeWithoutArgs;
+using ::testing::Ne;
+
+namespace content {
+
+namespace {
+
+// Helper function for build test javascripts.
+std::string BuildSetMetadataScript(const MediaMetadata& metadata) {
+  std::ostringstream generated_script;
+
+  generated_script << "var audio = document.createElement(\'audio\');"
+     << "audio.session = new MediaSession();"
+     << "audio.session.metadata = new MediaMetadata({"
+     << "title: \"" << metadata.title << "\", "
+     << "artist: \"" << metadata.artist << "\", "
+     << "album: \"" << metadata.album << "\", "
+     << "artwork: [";
+
+  std::string artwork_separator = "";
+  for (const auto& artwork : metadata.artwork) {
+    generated_script << artwork_separator << "{"
+       << "src: \"" << artwork.src.spec() << "\", "
+       << "type: \"" << artwork.type.string() << "\", "
+       << "sizes: \"";
+    for (const auto& size : artwork.sizes) {
+      generated_script << size.width() << "x" << size.height() << " ";
+    }
+    generated_script << "\"}";
+    artwork_separator = ", ";
+  }
+  generated_script << "]});";
+
+  return generated_script.str();
+}
+
+}  // anonymous namespace
+
+// Helper function to be pretty-print error messages by GMock.
+void PrintTo(const MediaMetadata& metadata, std::ostream* os) {
+  *os << "{ title=" << metadata.title << ", ";
+  *os << "artist=" << metadata.artist << ", ";
+  *os << "album=" << metadata.album << ", ";
+  *os << "artwork=[";
+  for (const auto& artwork : metadata.artwork) {
+    *os << "{ src=" << artwork.src.spec() << ", ";
+    *os << "type=" << artwork.type.string() << ", ";
+    *os << "sizes=[";
+    for (const auto& size : artwork.sizes) {
+      *os <<  size.width() << "x" << size.height() << " ";
+    }
+    *os << "]}";
+  }
+  *os << "]}";
+}
+
+class MockBrowserMediaSessionManager : public BrowserMediaSessionManager {
+ public:
+  explicit MockBrowserMediaSessionManager(RenderFrameHost* render_frame_host)
+      : BrowserMediaSessionManager(render_frame_host) {}
+
+  MOCK_METHOD2(OnActiveate, void(int session_id, int request_id));
+  MOCK_METHOD2(OnDeactiveate, void(int session_id, int request_id));
+  MOCK_METHOD2(OnSetMetadata, void(int session_id,
+                                   const MediaMetadata& metadata));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockBrowserMediaSessionManager);
+};
+
+class BrowserMediaSessionManagerBrowserTest : public ContentBrowserTest {
+ public:
+  BrowserMediaSessionManagerBrowserTest() = default;
+  ~BrowserMediaSessionManagerBrowserTest() override = default;
+
+ protected:
+  void SetUpOnMainThread() override {
+    ContentBrowserTest::SetUpOnMainThread();
+    web_contents_ = shell()->web_contents();
+
+    std::unique_ptr<MockBrowserMediaSessionManager> manager(
+        new MockBrowserMediaSessionManager(web_contents_->GetMainFrame()));
+    browser_media_session_manager_ = manager.get();
+    MediaWebContentsObserverAndroid::FromWebContents(web_contents_)
+        ->SetMediaSessionManagerForTest(
+            web_contents_->GetMainFrame(), std::move(manager));
+
+    shell()->LoadURL(GURL("about:blank"));
+
+    ON_CALL(*browser_media_session_manager_, OnSetMetadata(_, _))
+        .WillByDefault(InvokeWithoutArgs([&]{
+              message_loop_runner_->Quit();
+            }));
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    command_line->AppendSwitchASCII(
+        switches::kEnableBlinkFeatures, "MediaSession");
+  }
+
+  WebContents* web_contents_;
+  MockBrowserMediaSessionManager* browser_media_session_manager_;
+  scoped_refptr<MessageLoopRunner> message_loop_runner_;
+};
+
+IN_PROC_BROWSER_TEST_F(BrowserMediaSessionManagerBrowserTest,
+                       TestMetadataPropagated) {
+  MediaMetadata expected;
+  expected.title = base::ASCIIToUTF16("title1");
+  expected.artist = base::ASCIIToUTF16("artist1");
+  expected.album = base::ASCIIToUTF16("album1");
+  MediaMetadata::Artwork artwork;
+  artwork.src = GURL("http://foo.com/bar.png");
+  artwork.type = base::NullableString16(base::ASCIIToUTF16("image/png"), false);
+  artwork.sizes.push_back(gfx::Size(128, 128));
+  expected.artwork.push_back(artwork);
+
+  message_loop_runner_ = new MessageLoopRunner();
+  EXPECT_CALL(*browser_media_session_manager_, OnSetMetadata(_, expected))
+      .Times(1);
+  ASSERT_TRUE(ExecuteScript(web_contents_->GetMainFrame(),
+                            BuildSetMetadataScript(expected)));
+  message_loop_runner_->Run();
+}
+
+IN_PROC_BROWSER_TEST_F(BrowserMediaSessionManagerBrowserTest,
+                       TestSetMetadataTwice) {
+  // Make expectations ordered.
+  InSequence s;
+
+  MediaMetadata dont_care_metadata;
+
+  MediaMetadata expected;
+  expected.title = base::ASCIIToUTF16("title2");
+  expected.artist = base::ASCIIToUTF16("artist2");
+  expected.album = base::ASCIIToUTF16("album2");
+  MediaMetadata::Artwork artwork;
+  artwork.src = GURL("http://foo.com/bar.jpg");
+  artwork.type = base::NullableString16(
+      base::ASCIIToUTF16("image/jpeg"), false);
+  artwork.sizes.push_back(gfx::Size(256, 256));
+  expected.artwork.push_back(artwork);
+
+  // Set metadata for the first time.
+  message_loop_runner_ = new MessageLoopRunner();
+  EXPECT_CALL(*browser_media_session_manager_,
+              OnSetMetadata(_, dont_care_metadata))
+      .Times(1);
+  ASSERT_TRUE(ExecuteScript(web_contents_->GetMainFrame(),
+                            BuildSetMetadataScript(dont_care_metadata)));
+  message_loop_runner_->Run();
+
+  // Set metadata for the second time.
+  message_loop_runner_ = new MessageLoopRunner();
+  EXPECT_CALL(*browser_media_session_manager_, OnSetMetadata(_, expected))
+      .Times(1);
+  ASSERT_TRUE(ExecuteScript(web_contents_->GetMainFrame(),
+                            BuildSetMetadataScript(expected)));
+  message_loop_runner_->Run();
+}
+
+IN_PROC_BROWSER_TEST_F(BrowserMediaSessionManagerBrowserTest,
+                       TestFileArtworkRemoved) {
+  // Make expectations ordered.
+  InSequence s;
+
+  MediaMetadata dirty_metadata;
+  MediaMetadata::Artwork file_artwork;
+  file_artwork.src = GURL("file:///foo/bar.jpg");
+  file_artwork.type = base::NullableString16(
+      base::ASCIIToUTF16("image/jpeg"), false);
+  dirty_metadata.artwork.push_back(file_artwork);
+
+  MediaMetadata expected;
+
+  // Set metadata for the first time.
+  message_loop_runner_ = new MessageLoopRunner();
+  EXPECT_CALL(*browser_media_session_manager_, OnSetMetadata(_, expected))
+      .Times(1);
+  ASSERT_TRUE(ExecuteScript(web_contents_->GetMainFrame(),
+                            BuildSetMetadataScript(dirty_metadata)));
+  message_loop_runner_->Run();
+}
+
+}  // namespace content
diff --git a/content/browser/media/android/media_web_contents_observer_android.cc b/content/browser/media/android/media_web_contents_observer_android.cc
index 5a6c451f..3912563 100644
--- a/content/browser/media/android/media_web_contents_observer_android.cc
+++ b/content/browser/media/android/media_web_contents_observer_android.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/media/android/media_web_contents_observer_android.h"
 
+#include <utility>
+
 #include "base/memory/ptr_util.h"
 #include "content/browser/media/android/browser_media_player_manager.h"
 #include "content/browser/media/android/browser_media_session_manager.h"
@@ -80,6 +82,12 @@
   return manager;
 }
 
+void MediaWebContentsObserverAndroid::SetMediaSessionManagerForTest(
+    RenderFrameHost* render_frame_host,
+    std::unique_ptr<BrowserMediaSessionManager> manager) {
+  media_session_managers_.set(render_frame_host, std::move(manager));
+}
+
 void MediaWebContentsObserverAndroid::SuspendAllMediaPlayers() {
   web_contents()->ForEachFrame(
       base::Bind(&SuspendAllMediaPlayersInRenderFrame));
diff --git a/content/browser/media/android/media_web_contents_observer_android.h b/content/browser/media/android/media_web_contents_observer_android.h
index 0f3a2a9..2531fe0 100644
--- a/content/browser/media/android/media_web_contents_observer_android.h
+++ b/content/browser/media/android/media_web_contents_observer_android.h
@@ -42,6 +42,12 @@
   BrowserSurfaceViewManager* GetSurfaceViewManager(
       RenderFrameHost* render_frame_host);
 
+  // Sets or overrides the BrowserMediaSessionManager for the given
+  // |render_frame_host|.
+  void SetMediaSessionManagerForTest(
+      RenderFrameHost* render_frame_host,
+      std::unique_ptr<BrowserMediaSessionManager> manager);
+
   // Called by the WebContents when a tab has been closed but may still be
   // available for "undo" -- indicates that all media players (even audio only
   // players typically allowed background audio) bound to this WebContents must
diff --git a/content/browser/media/session/media_session.cc b/content/browser/media/session/media_session.cc
index 5c63545..33fa652 100644
--- a/content/browser/media/session/media_session.cc
+++ b/content/browser/media/session/media_session.cc
@@ -58,6 +58,14 @@
   DCHECK(audio_focus_state_ == State::INACTIVE);
 }
 
+void MediaSession::SetMetadata(const MediaMetadata& metadata) {
+  metadata_ = metadata;
+  // TODO(zqzhang): On Android, the metadata is sent though JNI everytime the
+  // media session play/pause state changes. Need to find a way to seprate the
+  // state change and Metadata update. See https://crbug.com/621855.
+  static_cast<WebContentsImpl*>(web_contents())->OnMediaSessionStateChanged();
+}
+
 bool MediaSession::AddPlayer(MediaSessionObserver* observer,
                              int player_id,
                              Type type) {
diff --git a/content/browser/media/session/media_session.h b/content/browser/media/session/media_session.h
index 3c0cf159..9e961f4 100644
--- a/content/browser/media/session/media_session.h
+++ b/content/browser/media/session/media_session.h
@@ -62,9 +62,7 @@
 
   ~MediaSession() override;
 
-  void setMetadata(const MediaMetadata& metadata) {
-    metadata_ = metadata;
-  }
+  void SetMetadata(const MediaMetadata& metadata);
   const MediaMetadata& metadata() const { return metadata_; }
 
   // Adds the given player to the current media session. Returns whether the
diff --git a/content/browser/media/webrtc/webrtc_eventlog_host.cc b/content/browser/media/webrtc/webrtc_eventlog_host.cc
new file mode 100644
index 0000000..279ed48
--- /dev/null
+++ b/content/browser/media/webrtc/webrtc_eventlog_host.cc
@@ -0,0 +1,157 @@
+// 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 "content/browser/media/webrtc/webrtc_eventlog_host.h"
+
+#include <algorithm>
+#include <string>
+
+#include "base/files/file_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "content/browser/media/webrtc/webrtc_internals.h"
+#include "content/common/media/peer_connection_tracker_messages.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+
+#if defined(OS_WIN)
+#define IntToStringType base::IntToString16
+#else
+#define IntToStringType base::IntToString
+#endif
+
+namespace content {
+
+int WebRTCEventLogHost::number_active_log_files_ = 0;
+
+namespace {
+
+// In addition to the limit to the number of files given below, the size of the
+// files is also capped, see content/renderer/media/peer_connection_tracker.cc.
+#if defined(OS_ANDROID)
+const int kMaxNumberLogFiles = 3;
+#else
+const int kMaxNumberLogFiles = 5;
+#endif
+
+// Appends the IDs to the RTC event log file name.
+base::FilePath GetWebRtcEventLogPath(const base::FilePath& base_file,
+                                     int render_process_id,
+                                     int connection_id) {
+  return base_file.AddExtension(IntToStringType(render_process_id))
+      .AddExtension(IntToStringType(connection_id));
+}
+
+// Opens a logfile to pass on to the renderer.
+IPC::PlatformFileForTransit CreateFileForProcess(
+    const base::FilePath& base_path,
+    int render_process_id,
+    int connection_id) {
+  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::FilePath file_path =
+      GetWebRtcEventLogPath(base_path, render_process_id, connection_id);
+  base::File event_log_file(
+      file_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+  if (!event_log_file.IsValid()) {
+    PLOG(ERROR) << "Could not open WebRTC event log file, error="
+                << event_log_file.error_details();
+    return IPC::InvalidPlatformFileForTransit();
+  }
+  return IPC::TakePlatformFileForTransit(std::move(event_log_file));
+}
+
+}  // namespace
+
+WebRTCEventLogHost::WebRTCEventLogHost(int render_process_id)
+    : render_process_id_(render_process_id),
+      rtc_event_logging_enabled_(false),
+      weak_ptr_factory_(this) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  auto webrtc_internals = WebRTCInternals::GetInstance();
+  if (webrtc_internals->IsEventLogRecordingsEnabled())
+    StartWebRTCEventLog(webrtc_internals->GetEventLogFilePath());
+}
+
+WebRTCEventLogHost::~WebRTCEventLogHost() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
+
+void WebRTCEventLogHost::PeerConnectionAdded(int peer_connection_local_id) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(std::find(active_peer_connection_local_ids_.begin(),
+                   active_peer_connection_local_ids_.end(),
+                   peer_connection_local_id) ==
+         active_peer_connection_local_ids_.end());
+  active_peer_connection_local_ids_.push_back(peer_connection_local_id);
+  if (rtc_event_logging_enabled_ &&
+      number_active_log_files_ < kMaxNumberLogFiles) {
+    StartEventLogForPeerConnection(peer_connection_local_id);
+  }
+}
+
+void WebRTCEventLogHost::PeerConnectionRemoved(int peer_connection_local_id) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  const auto found = std::find(active_peer_connection_local_ids_.begin(),
+                               active_peer_connection_local_ids_.end(),
+                               peer_connection_local_id);
+  DCHECK(found != active_peer_connection_local_ids_.end());
+  active_peer_connection_local_ids_.erase(found);
+}
+
+bool WebRTCEventLogHost::StartWebRTCEventLog(const base::FilePath& file_path) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (rtc_event_logging_enabled_)
+    return false;
+  rtc_event_logging_enabled_ = true;
+  base_file_path_ = file_path;
+  for (int local_id : active_peer_connection_local_ids_)
+    StartEventLogForPeerConnection(local_id);
+  return true;
+}
+
+bool WebRTCEventLogHost::StopWebRTCEventLog() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (!rtc_event_logging_enabled_)
+    return false;
+  number_active_log_files_ = 0;
+  rtc_event_logging_enabled_ = false;
+  RenderProcessHost* host = RenderProcessHost::FromID(render_process_id_);
+  if (host) {
+    for (int local_id : active_peer_connection_local_ids_)
+      host->Send(new PeerConnectionTracker_StopEventLog(local_id));
+  }
+  return true;
+}
+
+bool WebRTCEventLogHost::StartEventLogForPeerConnection(
+    int peer_connection_local_id) {
+  if (number_active_log_files_ < kMaxNumberLogFiles) {
+    ++number_active_log_files_;
+    BrowserThread::PostTaskAndReplyWithResult(
+        BrowserThread::FILE, FROM_HERE,
+        base::Bind(&CreateFileForProcess, base_file_path_, render_process_id_,
+                   peer_connection_local_id),
+        base::Bind(&WebRTCEventLogHost::SendEventLogFileToRenderer,
+                   weak_ptr_factory_.GetWeakPtr(), peer_connection_local_id));
+  }
+  return true;
+}
+
+void WebRTCEventLogHost::SendEventLogFileToRenderer(
+    int peer_connection_local_id,
+    IPC::PlatformFileForTransit file_for_transit) {
+  if (file_for_transit == IPC::InvalidPlatformFileForTransit()) {
+    --number_active_log_files_;
+    return;
+  }
+  RenderProcessHost* rph = RenderProcessHost::FromID(render_process_id_);
+  if (rph) {
+    rph->Send(new PeerConnectionTracker_StartEventLog(peer_connection_local_id,
+                                                      file_for_transit));
+  } else {
+    --number_active_log_files_;
+    IPC::PlatformFileForTransitToFile(file_for_transit).Close();
+  }
+}
+
+}  // namespace content
diff --git a/content/browser/media/webrtc/webrtc_eventlog_host.h b/content/browser/media/webrtc/webrtc_eventlog_host.h
new file mode 100644
index 0000000..8c3377a
--- /dev/null
+++ b/content/browser/media/webrtc/webrtc_eventlog_host.h
@@ -0,0 +1,75 @@
+// 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_MEDIA_WEBRTC_WEBRTC_EVENTLOG_HOST_H_
+#define CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_EVENTLOG_HOST_H_
+
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/memory/weak_ptr.h"
+#include "content/common/content_export.h"
+#include "ipc/ipc_platform_file.h"
+
+namespace content {
+
+// This class is used to enable and disable WebRTC event logs on each of the
+// PeerConnections in the render process. This class and all its members should
+// only be accessed from the Browser UI thread.
+class CONTENT_EXPORT WebRTCEventLogHost {
+ public:
+  explicit WebRTCEventLogHost(int render_process_id);
+  ~WebRTCEventLogHost();
+
+  // Starts an RTC event log for all current and future PeerConnections on the
+  // render process. A base file_path can be supplied, which will be extended to
+  // include several identifiers to ensure uniqueness. If a recording was
+  // already in progress, this call will return false and have no other effect.
+  bool StartWebRTCEventLog(const base::FilePath& file_path);
+
+  // Stops recording an RTC event log for each PeerConnection on the render
+  // process. If no recording was in progress, this call will return false.
+  bool StopWebRTCEventLog();
+
+  // This function should be used to notify the WebRTCEventLogHost object that a
+  // PeerConnection was created in the corresponding render process.
+  void PeerConnectionAdded(int peer_connection_local_id);
+
+  // This function should be used to notify the WebRTCEventLogHost object that a
+  // PeerConnection was removed in the corresponding render process.
+  void PeerConnectionRemoved(int peer_connection_local_id);
+
+ private:
+  // Actually start the eventlog for a single PeerConnection using the path
+  // stored in base_file_path_.
+  bool StartEventLogForPeerConnection(int peer_connection_local_id);
+
+  // Send the platform file to the render process using an IPC message.
+  void SendEventLogFileToRenderer(int peer_connection_local_id,
+                                  IPC::PlatformFileForTransit file_for_transit);
+
+  // The render process ID that this object is associated with.
+  const int render_process_id_;
+
+  // In case new PeerConnections are created during logging, the path is needed
+  // to enable logging for them.
+  base::FilePath base_file_path_;
+
+  // The local identifiers of all the currently active PeerConnections.
+  std::vector<int> active_peer_connection_local_ids_;
+
+  // Number of active log files that have been opened.
+  static int number_active_log_files_;
+
+  // Track if the RTC event log is currently active.
+  bool rtc_event_logging_enabled_;
+
+  base::WeakPtrFactory<WebRTCEventLogHost> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebRTCEventLogHost);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_EVENTLOG_HOST_H_
diff --git a/content/browser/media/webrtc/webrtc_eventlog_host_unittest.cc b/content/browser/media/webrtc/webrtc_eventlog_host_unittest.cc
new file mode 100644
index 0000000..c8d73a09
--- /dev/null
+++ b/content/browser/media/webrtc/webrtc_eventlog_host_unittest.cc
@@ -0,0 +1,268 @@
+// 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 "content/browser/media/webrtc/webrtc_eventlog_host.h"
+
+#include <tuple>
+
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/common/media/peer_connection_tracker_messages.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/test/mock_render_process_host.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#define IntToStringType base::IntToString16
+#else
+#define IntToStringType base::IntToString
+#endif
+
+namespace content {
+
+namespace {
+
+// Get the expected Rtc eventlog file name. The name will be
+// <temporary path>.<render process id>.<peer connection local id>
+base::FilePath GetExpectedEventLogFileName(const base::FilePath& base_file,
+                                           int render_process_id,
+                                           int peer_connection_local_id) {
+  return base_file.AddExtension(IntToStringType(render_process_id))
+      .AddExtension(IntToStringType(peer_connection_local_id));
+}
+
+}  // namespace
+
+class WebRtcEventlogHostTest : public testing::Test {
+ public:
+  WebRtcEventlogHostTest()
+      : mock_render_process_host_(static_cast<MockRenderProcessHost*>(
+            mock_render_process_factory_.CreateRenderProcessHost(
+                &test_browser_context_,
+                nullptr))),
+        render_id_(mock_render_process_host_->GetID()),
+        event_log_host_(render_id_) {}
+  TestBrowserThreadBundle thread_bundle_;
+  MockRenderProcessHostFactory mock_render_process_factory_;
+  TestBrowserContext test_browser_context_;
+  std::unique_ptr<MockRenderProcessHost> mock_render_process_host_;
+  const int render_id_;
+  WebRTCEventLogHost event_log_host_;
+  base::FilePath base_file_;
+
+  void StartLogging() {
+    ASSERT_TRUE(base::CreateTemporaryFile(&base_file_));
+    EXPECT_TRUE(base::DeleteFile(base_file_, false));
+    EXPECT_FALSE(base::PathExists(base_file_));
+    EXPECT_TRUE(event_log_host_.StartWebRTCEventLog(base_file_));
+    base::RunLoop().RunUntilIdle();
+  }
+
+  void StopLogging() {
+    EXPECT_TRUE(event_log_host_.StopWebRTCEventLog());
+    base::RunLoop().RunUntilIdle();
+  }
+
+  void ValidateStartIPCMessageAndCloseFile(const IPC::Message* msg,
+                                           const int peer_connection_id) {
+    ASSERT_TRUE(msg);
+    std::tuple<int, IPC::PlatformFileForTransit> start_params;
+    PeerConnectionTracker_StartEventLog::Read(msg, &start_params);
+    EXPECT_EQ(peer_connection_id, std::get<0>(start_params));
+    ASSERT_NE(IPC::InvalidPlatformFileForTransit(), std::get<1>(start_params));
+    IPC::PlatformFileForTransitToFile(std::get<1>(start_params)).Close();
+  }
+
+  void ValidateStopIPCMessage(const IPC::Message* msg,
+                              const int peer_connection_id) {
+    ASSERT_TRUE(msg);
+    std::tuple<int> stop_params;
+    PeerConnectionTracker_StopEventLog::Read(msg, &stop_params);
+    EXPECT_EQ(peer_connection_id, std::get<0>(stop_params));
+  }
+};
+
+// This test calls StartWebRTCEventLog() and StopWebRTCEventLog() without having
+// added any PeerConnections. It is expected that no IPC messages will be sent.
+TEST_F(WebRtcEventlogHostTest, NoPeerConnectionTest) {
+  mock_render_process_host_->sink().ClearMessages();
+
+  // Start logging and check that no IPC messages were sent.
+  StartLogging();
+  EXPECT_EQ(size_t(0), mock_render_process_host_->sink().message_count());
+
+  // Stop logging and check that no IPC messages were sent.
+  StopLogging();
+  EXPECT_EQ(size_t(0), mock_render_process_host_->sink().message_count());
+}
+
+// This test calls StartWebRTCEventLog() and StopWebRTCEventLog() after adding a
+// single PeerConnection. It is expected that one IPC message will be sent for
+// each of the Start and Stop calls, and that a logfile is created.
+TEST_F(WebRtcEventlogHostTest, OnePeerConnectionTest) {
+  const int kTestPeerConnectionId = 123;
+  mock_render_process_host_->sink().ClearMessages();
+
+  // Add a PeerConnection and start logging.
+  event_log_host_.PeerConnectionAdded(kTestPeerConnectionId);
+  StartLogging();
+
+  // Check that the correct IPC message was sent.
+  EXPECT_EQ(size_t(1), mock_render_process_host_->sink().message_count());
+  const IPC::Message* start_msg =
+      mock_render_process_host_->sink().GetMessageAt(0);
+  ValidateStartIPCMessageAndCloseFile(start_msg, kTestPeerConnectionId);
+
+  // Stop logging.
+  mock_render_process_host_->sink().ClearMessages();
+  StopLogging();
+
+  // Check that the correct IPC message was sent.
+  EXPECT_EQ(size_t(1), mock_render_process_host_->sink().message_count());
+  const IPC::Message* stop_msg =
+      mock_render_process_host_->sink().GetMessageAt(0);
+  ValidateStopIPCMessage(stop_msg, kTestPeerConnectionId);
+
+  // Clean up the logfile.
+  base::FilePath expected_file = GetExpectedEventLogFileName(
+      base_file_, render_id_, kTestPeerConnectionId);
+  ASSERT_TRUE(base::PathExists(expected_file));
+  EXPECT_TRUE(base::DeleteFile(expected_file, false));
+}
+
+// This test calls StartWebRTCEventLog() and StopWebRTCEventLog() after adding
+// two PeerConnections. It is expected that two IPC messages will be sent for
+// each of the Start and Stop calls, and that a file is created for both
+// PeerConnections.
+TEST_F(WebRtcEventlogHostTest, TwoPeerConnectionsTest) {
+  const int kTestPeerConnectionId1 = 123;
+  const int kTestPeerConnectionId2 = 321;
+  mock_render_process_host_->sink().ClearMessages();
+
+  // Add two PeerConnections and start logging.
+  event_log_host_.PeerConnectionAdded(kTestPeerConnectionId1);
+  event_log_host_.PeerConnectionAdded(kTestPeerConnectionId2);
+  StartLogging();
+
+  // Check that the correct IPC messages were sent.
+  EXPECT_EQ(size_t(2), mock_render_process_host_->sink().message_count());
+  const IPC::Message* start_msg1 =
+      mock_render_process_host_->sink().GetMessageAt(0);
+  ValidateStartIPCMessageAndCloseFile(start_msg1, kTestPeerConnectionId1);
+  const IPC::Message* start_msg2 =
+      mock_render_process_host_->sink().GetMessageAt(1);
+  ValidateStartIPCMessageAndCloseFile(start_msg2, kTestPeerConnectionId2);
+
+  // Stop logging.
+  mock_render_process_host_->sink().ClearMessages();
+  StopLogging();
+
+  // Check that the correct IPC messages were sent.
+  EXPECT_EQ(size_t(2), mock_render_process_host_->sink().message_count());
+  const IPC::Message* stop_msg1 =
+      mock_render_process_host_->sink().GetMessageAt(0);
+  ValidateStopIPCMessage(stop_msg1, kTestPeerConnectionId1);
+  const IPC::Message* stop_msg2 =
+      mock_render_process_host_->sink().GetMessageAt(1);
+  ValidateStopIPCMessage(stop_msg2, kTestPeerConnectionId2);
+
+  // Clean up the logfiles.
+  base::FilePath expected_file1 = GetExpectedEventLogFileName(
+      base_file_, render_id_, kTestPeerConnectionId1);
+  base::FilePath expected_file2 = GetExpectedEventLogFileName(
+      base_file_, render_id_, kTestPeerConnectionId2);
+  ASSERT_TRUE(base::PathExists(expected_file1));
+  EXPECT_TRUE(base::DeleteFile(expected_file1, false));
+  ASSERT_TRUE(base::PathExists(expected_file2));
+  EXPECT_TRUE(base::DeleteFile(expected_file2, false));
+}
+
+// This test calls StartWebRTCEventLog() and StopWebRTCEventLog() after adding
+// more PeerConnections than the maximum allowed. It is expected that only the
+// maximum allowed number of IPC messages and log files will be opened, but we
+// expect the number of stop IPC messages to be equal to the actual number of
+// PeerConnections.
+TEST_F(WebRtcEventlogHostTest, ExceedMaxPeerConnectionsTest) {
+#if defined(OS_ANDROID)
+  const int kMaxNumberLogFiles = 3;
+#else
+  const int kMaxNumberLogFiles = 5;
+#endif
+  const int kNumberOfPeerConnections = kMaxNumberLogFiles + 1;
+  mock_render_process_host_->sink().ClearMessages();
+
+  // Add the maximum number + 1 PeerConnections and start logging.
+  for (int i = 0; i < kNumberOfPeerConnections; ++i)
+    event_log_host_.PeerConnectionAdded(i);
+  StartLogging();
+
+  // Check that the correct IPC messages were sent.
+  ASSERT_EQ(size_t(kMaxNumberLogFiles),
+            mock_render_process_host_->sink().message_count());
+  for (int i = 0; i < kMaxNumberLogFiles; ++i) {
+    const IPC::Message* start_msg =
+        mock_render_process_host_->sink().GetMessageAt(i);
+    ValidateStartIPCMessageAndCloseFile(start_msg, i);
+  }
+
+  // Stop logging.
+  mock_render_process_host_->sink().ClearMessages();
+  StopLogging();
+
+  // Check that the correct IPC messages were sent.
+  ASSERT_EQ(size_t(kNumberOfPeerConnections),
+            mock_render_process_host_->sink().message_count());
+  for (int i = 0; i < kNumberOfPeerConnections; ++i) {
+    const IPC::Message* stop_msg =
+        mock_render_process_host_->sink().GetMessageAt(i);
+    ValidateStopIPCMessage(stop_msg, i);
+  }
+
+  // Clean up the logfiles.
+  for (int i = 0; i < kMaxNumberLogFiles; ++i) {
+    base::FilePath expected_file =
+        GetExpectedEventLogFileName(base_file_, render_id_, i);
+    ASSERT_TRUE(base::PathExists(expected_file));
+    EXPECT_TRUE(base::DeleteFile(expected_file, false));
+  }
+
+  // Check that not too many files were created.
+  for (int i = kMaxNumberLogFiles; i < kNumberOfPeerConnections; ++i) {
+    base::FilePath expected_file =
+        GetExpectedEventLogFileName(base_file_, render_id_, i);
+    EXPECT_FALSE(base::PathExists(expected_file));
+  }
+}
+
+// This test calls StartWebRTCEventLog() and StopWebRTCEventLog() after first
+// adding and then removing a single PeerConnection. It is expected that no IPC
+// message will be sent.
+TEST_F(WebRtcEventlogHostTest, AddRemovePeerConnectionTest) {
+  const int kTestPeerConnectionId = 123;
+  mock_render_process_host_->sink().ClearMessages();
+
+  // Add and immediately remove a PeerConnection.
+  event_log_host_.PeerConnectionAdded(kTestPeerConnectionId);
+  event_log_host_.PeerConnectionRemoved(kTestPeerConnectionId);
+
+  // Start logging and check that no IPC messages were sent.
+  StartLogging();
+  EXPECT_EQ(size_t(0), mock_render_process_host_->sink().message_count());
+
+  // Stop logging and check that no IPC messages were sent.
+  StopLogging();
+  EXPECT_EQ(size_t(0), mock_render_process_host_->sink().message_count());
+
+  // Check that no logfile was created.
+  base::FilePath expected_file = GetExpectedEventLogFileName(
+      base_file_, render_id_, kTestPeerConnectionId);
+  ASSERT_FALSE(base::PathExists(expected_file));
+}
+
+}  // namespace content
diff --git a/content/browser/media/webrtc/webrtc_internals.cc b/content/browser/media/webrtc/webrtc_internals.cc
index 1a1d57f1..070dfb3 100644
--- a/content/browser/media/webrtc/webrtc_internals.cc
+++ b/content/browser/media/webrtc/webrtc_internals.cc
@@ -9,12 +9,19 @@
 #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/renderer_host/render_process_host_impl.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/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 #include "device/power_save_blocker/power_save_blocker.h"
+#include "ipc/ipc_platform_file.h"
+
+#if defined(OS_WIN)
+#define IntToStringType base::IntToString16
+#else
+#define IntToStringType base::IntToString
+#endif
 
 using base::ProcessId;
 using std::string;
@@ -252,10 +259,13 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   observers_.RemoveObserver(observer);
 
-  // Disables audio debug recordings if it is enabled and the last
+  // Disables event log and audio debug recordings if enabled and the last
   // webrtc-internals page is going away.
-  if (audio_debug_recordings_ && !observers_.might_have_observers())
-    DisableAudioDebugRecordings();
+  if (!observers_.might_have_observers()) {
+    if (audio_debug_recordings_)
+      DisableAudioDebugRecordings();
+    DisableEventLogRecordings();
+  }
 }
 
 void WebRTCInternals::UpdateObserver(WebRTCInternalsUIObserver* observer) {
@@ -318,37 +328,34 @@
   return audio_debug_recordings_file_path_;
 }
 
-void WebRTCInternals::SetEventLogRecordings(
-    bool enable,
+void WebRTCInternals::EnableEventLogRecordings(
     content::WebContents* web_contents) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 #if defined(ENABLE_WEBRTC)
-  if (enable) {
 #if defined(OS_ANDROID)
-    EnableEventLogRecordingsOnAllRenderProcessHosts();
+  EnableEventLogRecordingsOnAllRenderProcessHosts();
 #else
-    DCHECK(web_contents);
-    DCHECK(!select_file_dialog_);
-    selecting_event_log_ = true;
-    select_file_dialog_ = ui::SelectFileDialog::Create(this, nullptr);
-    select_file_dialog_->SelectFile(
-        ui::SelectFileDialog::SELECT_SAVEAS_FILE, base::string16(),
-        event_log_recordings_file_path_, nullptr, 0, FILE_PATH_LITERAL(""),
-        web_contents->GetTopLevelNativeWindow(), nullptr);
+  DCHECK(web_contents);
+  DCHECK(!select_file_dialog_);
+  selecting_event_log_ = true;
+  select_file_dialog_ = ui::SelectFileDialog::Create(this, nullptr);
+  select_file_dialog_->SelectFile(
+      ui::SelectFileDialog::SELECT_SAVEAS_FILE, base::string16(),
+      event_log_recordings_file_path_, nullptr, 0, FILE_PATH_LITERAL(""),
+      web_contents->GetTopLevelNativeWindow(), nullptr);
 #endif
-  } else {
-    event_log_recordings_ = false;
-    // Tear down the dialog since the user has unchecked the audio debug
-    // recordings box.
-    select_file_dialog_ = nullptr;
-    DCHECK(select_file_dialog_->HasOneRef());
+#endif
+}
 
-    for (RenderProcessHost::iterator i(
-             content::RenderProcessHost::AllHostsIterator());
-         !i.IsAtEnd(); i.Advance()) {
-      i.GetCurrentValue()->DisableEventLogRecordings();
-    }
-  }
+void WebRTCInternals::DisableEventLogRecordings() {
+#if defined(ENABLE_WEBRTC)
+  event_log_recordings_ = false;
+  // Tear down the dialog since the user has unchecked the event log checkbox.
+  select_file_dialog_ = nullptr;
+  for (RenderProcessHost::iterator i(
+           content::RenderProcessHost::AllHostsIterator());
+       !i.IsAtEnd(); i.Advance())
+    i.GetCurrentValue()->StopWebRTCEventLog();
 #endif
 }
 
@@ -357,7 +364,7 @@
   return event_log_recordings_;
 }
 
-const base::FilePath& WebRTCInternals::GetEventLogRecordingsFilePath() const {
+const base::FilePath& WebRTCInternals::GetEventLogFilePath() const {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return event_log_recordings_file_path_;
 }
@@ -483,10 +490,8 @@
   event_log_recordings_ = true;
   for (RenderProcessHost::iterator i(
            content::RenderProcessHost::AllHostsIterator());
-       !i.IsAtEnd(); i.Advance()) {
-    i.GetCurrentValue()->EnableEventLogRecordings(
-        event_log_recordings_file_path_);
-  }
+       !i.IsAtEnd(); i.Advance())
+    i.GetCurrentValue()->StartWebRTCEventLog(event_log_recordings_file_path_);
 }
 #endif
 
diff --git a/content/browser/media/webrtc/webrtc_internals.h b/content/browser/media/webrtc/webrtc_internals.h
index ddcb671..35a1d89 100644
--- a/content/browser/media/webrtc/webrtc_internals.h
+++ b/content/browser/media/webrtc/webrtc_internals.h
@@ -102,10 +102,11 @@
   const base::FilePath& GetAudioDebugRecordingsFilePath() const;
 
   // Enables or disables diagnostic event log.
-  void SetEventLogRecordings(bool enable, content::WebContents* web_contents);
+  void EnableEventLogRecordings(content::WebContents* web_contents);
+  void DisableEventLogRecordings();
 
   bool IsEventLogRecordingsEnabled() const;
-  const base::FilePath& GetEventLogRecordingsFilePath() const;
+  const base::FilePath& GetEventLogFilePath() const;
 
  protected:
   // Constructor/Destructor are protected to allow tests to derive from the
diff --git a/content/browser/media/webrtc/webrtc_internals_message_handler.cc b/content/browser/media/webrtc/webrtc_internals_message_handler.cc
index eaaea95a..ea74c5b 100644
--- a/content/browser/media/webrtc/webrtc_internals_message_handler.cc
+++ b/content/browser/media/webrtc/webrtc_internals_message_handler.cc
@@ -94,8 +94,12 @@
 void WebRTCInternalsMessageHandler::OnSetEventLogRecordingsEnabled(
     bool enable,
     const base::ListValue* /* unused_list */) {
-  WebRTCInternals::GetInstance()->SetEventLogRecordings(
-      enable, enable ? web_ui()->GetWebContents() : nullptr);
+  if (enable) {
+    WebRTCInternals::GetInstance()->EnableEventLogRecordings(
+        web_ui()->GetWebContents());
+  } else {
+    WebRTCInternals::GetInstance()->DisableEventLogRecordings();
+  }
 }
 
 void WebRTCInternalsMessageHandler::OnDOMLoadDone(
diff --git a/content/browser/mojo/mojo_shell_context.cc b/content/browser/mojo/mojo_shell_context.cc
index 7f4177f..a7148d1 100644
--- a/content/browser/mojo/mojo_shell_context.cc
+++ b/content/browser/mojo/mojo_shell_context.cc
@@ -267,11 +267,10 @@
     mojo::edk::SetParentPipeHandleFromCommandLine();
     request = shell::GetServiceRequestFromCommandLine();
   } else {
-    service_manager_.reset(
-        new shell::ServiceManager(std::move(native_runner_factory),
-                                  catalog_->TakeService()));
-    request = service_manager_->StartEmbedderService(
-        kBrowserMojoApplicationName);
+    service_manager_.reset(new shell::ServiceManager(
+        std::move(native_runner_factory), catalog_->TakeService()));
+    request =
+        service_manager_->StartEmbedderService(kBrowserMojoApplicationName);
   }
   MojoShellConnection::SetForProcess(
       MojoShellConnection::Create(std::move(request)));
diff --git a/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc b/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc
index b7f0a6c..6d572ab 100644
--- a/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc
+++ b/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.cc
@@ -15,6 +15,7 @@
 #include "base/callback_helpers.h"
 #include "base/i18n/case_conversion.h"
 #include "base/logging.h"
+#include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
@@ -42,11 +43,40 @@
   FONT_LOADER_TYPE_MAX_VALUE
 };
 
+// This enum is used to define the buckets for an enumerated UMA histogram.
+// Hence,
+//   (a) existing enumerated constants should never be deleted or reordered, and
+//   (b) new constants should only be appended at the end of the enumeration.
+enum MessageFilterError {
+  LAST_RESORT_FONT_GET_FONT_FAILED = 0,
+  LAST_RESORT_FONT_ADD_FILES_FAILED = 1,
+  LAST_RESORT_FONT_GET_FAMILY_FAILED = 2,
+  ERROR_NO_COLLECTION = 3,
+  MAP_CHARACTERS_NO_FAMILY = 4,
+
+  MESSAGE_FILTER_ERROR_MAX_VALUE
+};
+
 void LogLoaderType(DirectWriteFontLoaderType loader_type) {
   UMA_HISTOGRAM_ENUMERATION("DirectWrite.Fonts.Proxy.LoaderType", loader_type,
                             FONT_LOADER_TYPE_MAX_VALUE);
 }
 
+void LogLastResortFontCount(size_t count) {
+  UMA_HISTOGRAM_COUNTS_100("DirectWrite.Fonts.Proxy.LastResortFontCount",
+                           count);
+}
+
+void LogLastResortFontFileCount(size_t count) {
+  UMA_HISTOGRAM_COUNTS_100("DirectWrite.Fonts.Proxy.LastResortFontFileCount",
+                           count);
+}
+
+void LogMessageFilterError(MessageFilterError error) {
+  UMA_HISTOGRAM_ENUMERATION("DirectWrite.Fonts.Proxy.MessageFilterError", error,
+                            MESSAGE_FILTER_ERROR_MAX_VALUE);
+}
+
 const wchar_t* kFontsToIgnore[] = {
     // "Gill Sans Ultra Bold" turns into an Ultra Bold weight "Gill Sans" in
     // DirectWrite, but most users don't have any other weights. The regular
@@ -75,6 +105,11 @@
   return base::i18n::FoldCase(font_path_chars.data());
 }
 
+// These are the fonts that Blink tries to load in getLastResortFallbackFont,
+// and will crash if none can be loaded.
+const wchar_t* kLastResortFontNames[] = {L"Sans", L"Arial", L"MS UI Gothic",
+                                         L"Microsoft Sans Serif"};
+
 }  // namespace
 
 DWriteFontProxyMessageFilter::DWriteFontProxyMessageFilter()
@@ -203,6 +238,8 @@
   mswr::ComPtr<IDWriteFontFamily> family;
   HRESULT hr = collection_->GetFontFamily(family_index, &family);
   if (FAILED(hr)) {
+    if (IsLastResortFallbackFont(family_index))
+      LogMessageFilterError(LAST_RESORT_FONT_GET_FAMILY_FAILED);
     return;
   }
 
@@ -216,13 +253,19 @@
     mswr::ComPtr<IDWriteFont> font;
     hr = family->GetFont(font_index, &font);
     if (FAILED(hr)) {
+      if (IsLastResortFallbackFont(family_index))
+        LogMessageFilterError(LAST_RESORT_FONT_GET_FONT_FAILED);
       return;
     }
 
-    AddFilesForFont(&path_set, font.Get());
+    if (!AddFilesForFont(&path_set, font.Get())) {
+      if (IsLastResortFallbackFont(family_index))
+        LogMessageFilterError(LAST_RESORT_FONT_ADD_FILES_FAILED);
+    }
   }
 
   file_paths->assign(path_set.begin(), path_set.end());
+  LogLastResortFontFileCount(file_paths->size());
 }
 
 void DWriteFontProxyMessageFilter::OnMapCharacters(
@@ -318,8 +361,7 @@
     return;
   }
   // Could not find a matching family
-  // TODO(kulshin): log UMA that we matched a font, but could not locate the
-  // family
+  LogMessageFilterError(MAP_CHARACTERS_NO_FAMILY);
   DCHECK_EQ(result->family_index, UINT32_MAX);
   DCHECK_GT(result->mapped_length, 0u);
 }
@@ -344,6 +386,23 @@
 
   HRESULT hr = factory->GetSystemFontCollection(&collection_);
   DCHECK(SUCCEEDED(hr));
+
+  if (!collection_) {
+    LogMessageFilterError(ERROR_NO_COLLECTION);
+    return;
+  }
+
+  // Temp code to help track down crbug.com/561873
+  for (size_t font = 0; font < arraysize(kLastResortFontNames); font++) {
+    uint32_t font_index = 0;
+    BOOL exists = FALSE;
+    if (SUCCEEDED(collection_->FindFamilyName(kLastResortFontNames[font],
+                                              &font_index, &exists)) &&
+        exists && font_index != UINT32_MAX) {
+      last_resort_fonts_.push_back(font_index);
+    }
+  }
+  LogLastResortFontCount(last_resort_fonts_.size());
 }
 
 bool DWriteFontProxyMessageFilter::AddFilesForFont(
@@ -471,4 +530,14 @@
   return true;
 }
 
+bool DWriteFontProxyMessageFilter::IsLastResortFallbackFont(
+    uint32_t font_index) {
+  for (auto iter = last_resort_fonts_.begin(); iter != last_resort_fonts_.end();
+       ++iter) {
+    if (*iter == font_index)
+      return true;
+  }
+  return false;
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.h b/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.h
index c105f4d0..7539ff16 100644
--- a/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.h
+++ b/content/browser/renderer_host/dwrite_font_proxy_message_filter_win.h
@@ -62,6 +62,8 @@
                     IDWriteLocalFontFileLoader* local_loader,
                     IDWriteFontFile* font_file);
 
+  bool IsLastResortFallbackFont(uint32_t font_index);
+
  private:
   bool direct_write_initialized_ = false;
   Microsoft::WRL::ComPtr<IDWriteFontCollection> collection_;
@@ -69,6 +71,9 @@
   Microsoft::WRL::ComPtr<IDWriteFontFallback> font_fallback_;
   base::string16 windows_fonts_path_;
 
+  // Temp code to help track down crbug.com/561873
+  std::vector<uint32_t> last_resort_fonts_;
+
   DISALLOW_COPY_AND_ASSIGN(DWriteFontProxyMessageFilter);
 };
 
diff --git a/content/browser/renderer_host/media/peer_connection_tracker_host.cc b/content/browser/renderer_host/media/peer_connection_tracker_host.cc
index 12f6edc..9fceb42 100644
--- a/content/browser/renderer_host/media/peer_connection_tracker_host.cc
+++ b/content/browser/renderer_host/media/peer_connection_tracker_host.cc
@@ -4,15 +4,20 @@
 #include "content/browser/renderer_host/media/peer_connection_tracker_host.h"
 
 #include "base/power_monitor/power_monitor.h"
+#include "content/browser/media/webrtc/webrtc_eventlog_host.h"
 #include "content/browser/media/webrtc/webrtc_internals.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/common/media/peer_connection_tracker_messages.h"
-#include "content/public/browser/render_process_host.h"
 
 namespace content {
 
-PeerConnectionTrackerHost::PeerConnectionTrackerHost(int render_process_id)
+PeerConnectionTrackerHost::PeerConnectionTrackerHost(
+    int render_process_id,
+    WebRTCEventLogHost* event_log_host)
     : BrowserMessageFilter(PeerConnectionTrackerMsgStart),
-      render_process_id_(render_process_id) {
+      render_process_id_(render_process_id),
+      event_log_host_(event_log_host) {
+  DCHECK(event_log_host);
 }
 
 bool PeerConnectionTrackerHost::OnMessageReceived(const IPC::Message& message) {
@@ -71,10 +76,12 @@
       info.url,
       info.rtc_configuration,
       info.constraints);
+  event_log_host_->PeerConnectionAdded(info.lid);
 }
 
 void PeerConnectionTrackerHost::OnRemovePeerConnection(int lid) {
   WebRTCInternals::GetInstance()->OnRemovePeerConnection(peer_pid(), lid);
+  event_log_host_->PeerConnectionRemoved(lid);
 }
 
 void PeerConnectionTrackerHost::OnUpdatePeerConnection(
diff --git a/content/browser/renderer_host/media/peer_connection_tracker_host.h b/content/browser/renderer_host/media/peer_connection_tracker_host.h
index 53a9630..53926f8 100644
--- a/content/browser/renderer_host/media/peer_connection_tracker_host.h
+++ b/content/browser/renderer_host/media/peer_connection_tracker_host.h
@@ -19,6 +19,8 @@
 
 namespace content {
 
+class WebRTCEventLogHost;
+
 // This class is the host for PeerConnectionTracker in the browser process
 // managed by RenderProcessHostImpl. It receives PeerConnection events from
 // PeerConnectionTracker as IPC messages that it forwards to WebRTCInternals.
@@ -26,7 +28,8 @@
 class PeerConnectionTrackerHost : public BrowserMessageFilter,
                                   public base::PowerObserver {
  public:
-  explicit PeerConnectionTrackerHost(int render_process_id);
+  PeerConnectionTrackerHost(int render_process_id,
+                            WebRTCEventLogHost* event_log_host);
 
   // content::BrowserMessageFilter override.
   bool OnMessageReceived(const IPC::Message& message) override;
@@ -57,6 +60,8 @@
 
   int render_process_id_;
 
+  WebRTCEventLogHost* const event_log_host_;
+
   DISALLOW_COPY_AND_ASSIGN(PeerConnectionTrackerHost);
 };
 
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index b20943e..77e6b662 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -248,8 +248,6 @@
 #ifdef ENABLE_WEBRTC
 const base::FilePath::CharType kAecDumpFileNameAddition[] =
     FILE_PATH_LITERAL("aec_dump");
-const base::FilePath::CharType kEventLogFileNameAddition[] =
-    FILE_PATH_LITERAL("event_log");
 #endif
 
 void CacheShaderInfo(int32_t id, base::FilePath path) {
@@ -553,6 +551,9 @@
       delayed_cleanup_needed_(false),
       within_process_died_observer_(false),
       power_monitor_broadcaster_(this),
+#if defined(ENABLE_WEBRTC)
+      webrtc_eventlog_host_(id_),
+#endif
       worker_ref_count_(0),
       max_worker_count_(0),
       permission_service_context_(new PermissionServiceContext(this)),
@@ -932,7 +933,8 @@
       blob_storage_context.get()));
 
 #if defined(ENABLE_WEBRTC)
-  peer_connection_tracker_host_ = new PeerConnectionTrackerHost(GetID());
+  peer_connection_tracker_host_ =
+      new PeerConnectionTrackerHost(GetID(), &webrtc_eventlog_host_);
   AddFilter(peer_connection_tracker_host_.get());
   AddFilter(new MediaStreamDispatcherHost(
       GetID(), browser_context->GetResourceContext()->GetMediaDeviceIDSalt(),
@@ -1408,6 +1410,7 @@
     switches::kDisableMediaSuspend,
     switches::kDisableNotifications,
     switches::kDisableOverlayScrollbar,
+    switches::kDisablePepper3DImageChromium,
     switches::kDisablePermissionsAPI,
     switches::kDisablePresentationAPI,
     switches::kDisablePinch,
@@ -1757,12 +1760,8 @@
 #if defined(ENABLE_WEBRTC)
       IPC_MESSAGE_HANDLER(AecDumpMsg_RegisterAecDumpConsumer,
                           OnRegisterAecDumpConsumer)
-      IPC_MESSAGE_HANDLER(WebRTCEventLogMsg_RegisterEventLogConsumer,
-                          OnRegisterEventLogConsumer)
       IPC_MESSAGE_HANDLER(AecDumpMsg_UnregisterAecDumpConsumer,
                           OnUnregisterAecDumpConsumer)
-      IPC_MESSAGE_HANDLER(WebRTCEventLogMsg_UnregisterEventLogConsumer,
-                          OnUnregisterEventLogConsumer)
 #endif
     // Adding single handlers for your service here is fine, but once your
     // service needs more than one handler, please extract them into a new
@@ -2021,26 +2020,13 @@
   }
 }
 
-void RenderProcessHostImpl::EnableEventLogRecordings(
-    const base::FilePath& file) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  // Enable Event log for each registered consumer.
-  base::FilePath file_with_extensions = GetEventLogFilePathWithExtensions(file);
-  for (int id : aec_dump_consumers_)
-    EnableEventLogForId(file_with_extensions, id);
+bool RenderProcessHostImpl::StartWebRTCEventLog(
+    const base::FilePath& file_path) {
+  return webrtc_eventlog_host_.StartWebRTCEventLog(file_path);
 }
 
-void RenderProcessHostImpl::DisableEventLogRecordings() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  // Posting on the FILE thread and then replying back on the UI thread is only
-  // for avoiding races between enable and disable. Nothing is done on the FILE
-  // thread.
-  BrowserThread::PostTaskAndReply(
-      BrowserThread::FILE, FROM_HERE, base::Bind(&base::DoNothing),
-      base::Bind(&RenderProcessHostImpl::SendDisableEventLogToRenderer,
-                 weak_factory_.GetWeakPtr()));
+bool RenderProcessHostImpl::StopWebRTCEventLog() {
+  return webrtc_eventlog_host_.StopWebRTCEventLog();
 }
 
 void RenderProcessHostImpl::SetWebRtcLogMessageCallback(
@@ -2682,13 +2668,6 @@
                  weak_factory_.GetWeakPtr(), id));
 }
 
-void RenderProcessHostImpl::OnRegisterEventLogConsumer(int id) {
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&RenderProcessHostImpl::RegisterEventLogConsumerOnUIThread,
-                 weak_factory_.GetWeakPtr(), id));
-}
-
 void RenderProcessHostImpl::OnUnregisterAecDumpConsumer(int id) {
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
@@ -2696,13 +2675,6 @@
                  weak_factory_.GetWeakPtr(), id));
 }
 
-void RenderProcessHostImpl::OnUnregisterEventLogConsumer(int id) {
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&RenderProcessHostImpl::UnregisterEventLogConsumerOnUIThread,
-                 weak_factory_.GetWeakPtr(), id));
-}
-
 void RenderProcessHostImpl::RegisterAecDumpConsumerOnUIThread(int id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   aec_dump_consumers_.push_back(id);
@@ -2714,17 +2686,6 @@
   }
 }
 
-void RenderProcessHostImpl::RegisterEventLogConsumerOnUIThread(int id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  aec_dump_consumers_.push_back(id);
-
-  if (WebRTCInternals::GetInstance()->IsEventLogRecordingsEnabled()) {
-    base::FilePath file_with_extensions = GetEventLogFilePathWithExtensions(
-        WebRTCInternals::GetInstance()->GetEventLogRecordingsFilePath());
-    EnableEventLogForId(file_with_extensions, id);
-  }
-}
-
 void RenderProcessHostImpl::UnregisterAecDumpConsumerOnUIThread(int id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   for (std::vector<int>::iterator it = aec_dump_consumers_.begin();
@@ -2736,17 +2697,6 @@
   }
 }
 
-void RenderProcessHostImpl::UnregisterEventLogConsumerOnUIThread(int id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  for (std::vector<int>::iterator it = aec_dump_consumers_.begin();
-       it != aec_dump_consumers_.end(); ++it) {
-    if (*it == id) {
-      aec_dump_consumers_.erase(it);
-      break;
-    }
-  }
-}
-
 void RenderProcessHostImpl::EnableAecDumpForId(const base::FilePath& file,
                                                int id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -2757,16 +2707,6 @@
                  weak_factory_.GetWeakPtr(), id));
 }
 
-void RenderProcessHostImpl::EnableEventLogForId(const base::FilePath& file,
-                                                int id) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  BrowserThread::PostTaskAndReplyWithResult(
-      BrowserThread::FILE, FROM_HERE,
-      base::Bind(&CreateFileForProcess, file.AddExtension(IntToStringType(id))),
-      base::Bind(&RenderProcessHostImpl::SendEventLogFileToRenderer,
-                 weak_factory_.GetWeakPtr(), id));
-}
-
 void RenderProcessHostImpl::SendAecDumpFileToRenderer(
     int id,
     IPC::PlatformFileForTransit file_for_transit) {
@@ -2775,33 +2715,15 @@
   Send(new AecDumpMsg_EnableAecDump(id, file_for_transit));
 }
 
-void RenderProcessHostImpl::SendEventLogFileToRenderer(
-    int id,
-    IPC::PlatformFileForTransit file_for_transit) {
-  if (file_for_transit == IPC::InvalidPlatformFileForTransit())
-    return;
-  Send(new WebRTCEventLogMsg_EnableEventLog(id, file_for_transit));
-}
-
 void RenderProcessHostImpl::SendDisableAecDumpToRenderer() {
   Send(new AecDumpMsg_DisableAecDump());
 }
 
-void RenderProcessHostImpl::SendDisableEventLogToRenderer() {
-  Send(new WebRTCEventLogMsg_DisableEventLog());
-}
-
 base::FilePath RenderProcessHostImpl::GetAecDumpFilePathWithExtensions(
     const base::FilePath& file) {
   return file.AddExtension(IntToStringType(base::GetProcId(GetHandle())))
       .AddExtension(kAecDumpFileNameAddition);
 }
-
-base::FilePath RenderProcessHostImpl::GetEventLogFilePathWithExtensions(
-    const base::FilePath& file) {
-  return file.AddExtension(IntToStringType(base::GetProcId(GetHandle())))
-      .AddExtension(kEventLogFileNameAddition);
-}
 #endif  // defined(ENABLE_WEBRTC)
 
 void RenderProcessHostImpl::GetAudioOutputControllers(
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 72f2995..18b9386 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -23,6 +23,7 @@
 #include "content/browser/bluetooth/bluetooth_adapter_factory_wrapper.h"
 #include "content/browser/child_process_launcher.h"
 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
+#include "content/browser/media/webrtc/webrtc_eventlog_host.h"
 #include "content/browser/power_monitor_message_broadcaster.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/render_process_host.h"
@@ -143,8 +144,8 @@
 #if defined(ENABLE_WEBRTC)
   void EnableAudioDebugRecordings(const base::FilePath& file) override;
   void DisableAudioDebugRecordings() override;
-  void EnableEventLogRecordings(const base::FilePath& file) override;
-  void DisableEventLogRecordings() override;
+  bool StartWebRTCEventLog(const base::FilePath& file_path) override;
+  bool StopWebRTCEventLog() override;
   void SetWebRtcLogMessageCallback(
       base::Callback<void(const std::string&)> callback) override;
   void ClearWebRtcLogMessageCallback() override;
@@ -343,24 +344,15 @@
 
 #if defined(ENABLE_WEBRTC)
   void OnRegisterAecDumpConsumer(int id);
-  void OnRegisterEventLogConsumer(int id);
   void OnUnregisterAecDumpConsumer(int id);
-  void OnUnregisterEventLogConsumer(int id);
   void RegisterAecDumpConsumerOnUIThread(int id);
-  void RegisterEventLogConsumerOnUIThread(int id);
   void UnregisterAecDumpConsumerOnUIThread(int id);
-  void UnregisterEventLogConsumerOnUIThread(int id);
   void EnableAecDumpForId(const base::FilePath& file, int id);
-  void EnableEventLogForId(const base::FilePath& file, int id);
   // Sends |file_for_transit| to the render process.
   void SendAecDumpFileToRenderer(int id,
                                  IPC::PlatformFileForTransit file_for_transit);
-  void SendEventLogFileToRenderer(int id,
-                                  IPC::PlatformFileForTransit file_for_transit);
   void SendDisableAecDumpToRenderer();
-  void SendDisableEventLogToRenderer();
   base::FilePath GetAecDumpFilePathWithExtensions(const base::FilePath& file);
-  base::FilePath GetEventLogFilePathWithExtensions(const base::FilePath& file);
 #endif
 
   static void OnMojoError(
@@ -488,6 +480,8 @@
   std::vector<int> aec_dump_consumers_;
 
   WebRtcStopRtpDumpCallback stop_rtp_dump_callback_;
+
+  WebRTCEventLogHost webrtc_eventlog_host_;
 #endif
 
   int worker_ref_count_;
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index 46129fb..55216b1c 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -1908,7 +1908,7 @@
                                                 output_size_in_pixel.height(),
                                                 color_type,
                                                 kOpaque_SkAlphaType))) {
-    scoped_callback_runner.Reset(
+    scoped_callback_runner.ReplaceClosure(
         base::Bind(callback, SkBitmap(), READBACK_BITMAP_ALLOCATION_FAILURE));
     return;
   }
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index b2bd30b0..7940896 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -1041,46 +1041,6 @@
   return delegated_frame_host_->GetRequestedRendererSize();
 }
 
-void RenderWidgetHostViewAura::SelectionBoundsChanged(
-    const ViewHostMsg_SelectionBounds_Params& params) {
-  gfx::SelectionBound anchor_bound, focus_bound;
-  anchor_bound.SetEdge(gfx::PointF(params.anchor_rect.origin()),
-                       gfx::PointF(params.anchor_rect.bottom_left()));
-  focus_bound.SetEdge(gfx::PointF(params.focus_rect.origin()),
-                      gfx::PointF(params.focus_rect.bottom_left()));
-
-  if (params.anchor_rect == params.focus_rect) {
-    anchor_bound.set_type(gfx::SelectionBound::CENTER);
-    focus_bound.set_type(gfx::SelectionBound::CENTER);
-  } else {
-    // Whether text is LTR at the anchor handle.
-    bool anchor_LTR = params.anchor_dir == blink::WebTextDirectionLeftToRight;
-    // Whether text is LTR at the focus handle.
-    bool focus_LTR = params.focus_dir == blink::WebTextDirectionLeftToRight;
-
-    if ((params.is_anchor_first && anchor_LTR) ||
-        (!params.is_anchor_first && !anchor_LTR)) {
-      anchor_bound.set_type(gfx::SelectionBound::LEFT);
-    } else {
-      anchor_bound.set_type(gfx::SelectionBound::RIGHT);
-    }
-    if ((params.is_anchor_first && focus_LTR) ||
-        (!params.is_anchor_first && !focus_LTR)) {
-      focus_bound.set_type(gfx::SelectionBound::RIGHT);
-    } else {
-      focus_bound.set_type(gfx::SelectionBound::LEFT);
-    }
-  }
-
-  if (anchor_bound == selection_anchor_ && focus_bound == selection_focus_)
-    return;
-
-  selection_anchor_ = anchor_bound;
-  selection_focus_ = focus_bound;
-  if (GetInputMethod())
-    GetInputMethod()->OnCaretBoundsChanged(this);
-}
-
 void RenderWidgetHostViewAura::CopyFromCompositingSurface(
     const gfx::Rect& src_subrect,
     const gfx::Size& dst_size,
@@ -1564,8 +1524,9 @@
 }
 
 gfx::Rect RenderWidgetHostViewAura::GetCaretBounds() const {
-  return ConvertRectToScreen(
-      gfx::RectBetweenSelectionBounds(selection_anchor_, selection_focus_));
+  if (!text_input_manager_ || !text_input_manager_->GetActiveWidget())
+    return gfx::Rect();
+  return ConvertRectToScreen(text_input_manager_->GetSelectionBoundsRect());
 }
 
 bool RenderWidgetHostViewAura::GetCompositionCharacterBounds(
@@ -3031,6 +2992,13 @@
   has_composition_text_ = false;
 }
 
+void RenderWidgetHostViewAura::OnSelectionBoundsChanged(
+    TextInputManager* text_input_manager,
+    RenderWidgetHostViewBase* updated_view) {
+  if (GetInputMethod())
+    GetInputMethod()->OnCaretBoundsChanged(this);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // RenderWidgetHostViewBase, public:
 
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 0be92468..b71e90c 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -153,8 +153,6 @@
                         size_t offset,
                         const gfx::Range& range) override;
   gfx::Size GetRequestedRendererSize() const override;
-  void SelectionBoundsChanged(
-      const ViewHostMsg_SelectionBounds_Params& params) override;
   void CopyFromCompositingSurface(
       const gfx::Rect& src_subrect,
       const gfx::Size& dst_size,
@@ -349,7 +347,7 @@
   const ui::MotionEventAura& pointer_state() const { return pointer_state_; }
 
  private:
-  friend class InputMethodResultAuraTest;
+  friend class InputMethodAuraTestBase;
   friend class RenderWidgetHostViewAuraCopyRequestTest;
   friend class TestInputMethodObserver;
   FRIEND_TEST_ALL_PREFIXES(InputMethodResultAuraTest,
@@ -475,6 +473,9 @@
                                     bool did_update_state) override;
   void OnImeCancelComposition(TextInputManager* text_input_manager,
                               RenderWidgetHostViewBase* updated_view) override;
+  void OnSelectionBoundsChanged(
+      TextInputManager* text_input_manager,
+      RenderWidgetHostViewBase* updated_view) override;
 
   // cc::BeginFrameObserver implementation.
   void OnBeginFrame(const cc::BeginFrameArgs& args) override;
@@ -585,10 +586,6 @@
   // object.
   ui::MotionEventAura pointer_state_;
 
-  // Bounds for the selection.
-  gfx::SelectionBound selection_anchor_;
-  gfx::SelectionBound selection_focus_;
-
   // The current composition character bounds.
   std::vector<gfx::Rect> composition_character_bounds_;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 8b213136..30defc8 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -87,6 +87,8 @@
 #include "ui/events/keycodes/dom/dom_code.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
 #include "ui/events/test/event_generator.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/selection_bound.h"
 #include "ui/wm/core/default_activation_client.h"
 #include "ui/wm/core/default_screen_position_client.h"
 #include "ui/wm/core/window_util.h"
@@ -4031,19 +4033,13 @@
 // ----------------------------------------------------------------------------
 // TextInputManager and IME-Related Tests
 
-// A group of tests which verify that the IME method results are routed to the
-// right RenderWidget in the OOPIF structure.
+// The test class for OOPIF IME related unit tests in RenderWidgetHostViewAura.
 // In each test, 3 views are created where one is in process with main frame and
-// the other two are in distinct processes (this makes a total of 4 RWHVs). Then
-// each test will verify the correctness of routing for one of the IME result
-// methods. The method is called on ui::TextInputClient (i.e., RWHV for the tab
-// in aura) and then the test verifies that the IPC is routed to the
-// RenderWidget corresponding to the active view (i.e., the RenderWidget
-// with focused <input>).
-class InputMethodResultAuraTest : public RenderWidgetHostViewAuraTest {
+// the other two are in distinct processes (this makes a total of 4 RWHVs).
+class InputMethodAuraTestBase : public RenderWidgetHostViewAuraTest {
  public:
-  InputMethodResultAuraTest() {}
-  ~InputMethodResultAuraTest() override {}
+  InputMethodAuraTestBase() {}
+  ~InputMethodAuraTestBase() override {}
 
   void SetUp() override {
     RenderWidgetHostViewAuraTest::SetUp();
@@ -4087,14 +4083,6 @@
   }
 
  protected:
-  const IPC::Message* RunAndReturnIPCSent(const base::Closure closure,
-                                          MockRenderProcessHost* process,
-                                          int32_t message_id) {
-    process->sink().ClearMessages();
-    closure.Run();
-    return process->sink().GetFirstMessageMatching(message_id);
-  }
-
   MockRenderWidgetHostDelegate* render_widget_host_delegate() const {
     return delegates_.back().get();
   }
@@ -4157,6 +4145,31 @@
   MockRenderProcessHost* third_process_host_;
   TestRenderWidgetHostView* view_for_third_process_;
 
+  DISALLOW_COPY_AND_ASSIGN(InputMethodAuraTestBase);
+};
+
+// A group of tests which verify that the IME method results are routed to the
+// right RenderWidget when there are multiple RenderWidgetHostViews on tab. Each
+// test will verify the correctness of routing for one of the IME result
+// methods. The method is called on ui::TextInputClient (i.e., RWHV for the tab
+// in aura) and then the test verifies that the IPC is routed to the
+// RenderWidget corresponding to the active view (i.e., the RenderWidget
+// with focused <input>).
+class InputMethodResultAuraTest : public InputMethodAuraTestBase {
+ public:
+  InputMethodResultAuraTest() {}
+  ~InputMethodResultAuraTest() override {}
+
+ protected:
+  const IPC::Message* RunAndReturnIPCSent(const base::Closure closure,
+                                          MockRenderProcessHost* process,
+                                          int32_t message_id) {
+    process->sink().ClearMessages();
+    closure.Run();
+    return process->sink().GetFirstMessageMatching(message_id);
+  }
+
+ private:
   DISALLOW_COPY_AND_ASSIGN(InputMethodResultAuraTest);
 };
 
@@ -4217,9 +4230,9 @@
   }
 }
 
-// This test makes a specific child frame's view active and then forces the
-// tab's view end the current IME composition session by sending out an IME
-// IPC to confirm composition. The test then verifies that the message is sent
+// This test makes a specific view active and then forces the tab's view end the
+// current IME composition session by sending out an IME IPC to confirm
+// composition. The test then verifies that the message is sent
 //  to the active widget's process.
 TEST_F(InputMethodResultAuraTest, FinishImeCompositionSession) {
   base::Closure ime_finish_session_call =
@@ -4234,4 +4247,57 @@
   }
 }
 
+// A class of tests which verify the correctness of some tracked IME related
+// state at the browser side, e.g., caret bounds.
+class InputMethodStateAuraTest : public InputMethodAuraTestBase {
+ public:
+  InputMethodStateAuraTest() {}
+  ~InputMethodStateAuraTest() override {}
+
+ protected:
+  gfx::SelectionBound GetSelectionBoundFromRect(const gfx::Rect& rect) {
+    gfx::SelectionBound bound;
+    bound.SetEdge(gfx::PointF(rect.origin()), gfx::PointF(rect.bottom_left()));
+    return bound;
+  }
+
+  gfx::Rect TransformRectToViewsRootCoordSpace(const gfx::Rect rect,
+                                               RenderWidgetHostView* view) {
+    return gfx::Rect(view->TransformPointToRootCoordSpace(rect.origin()),
+                     rect.size());
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(InputMethodStateAuraTest);
+};
+
+// This test activates the views on the tab according to a predefined order and
+// for each tab, simulates a selection bounds changed call. Then it verifies
+// that the caret bounds reported by the TextInputClient match those reported
+// for the active view.
+TEST_F(InputMethodStateAuraTest, GetCaretBounds) {
+  ViewHostMsg_SelectionBounds_Params params;
+  params.is_anchor_first = true;
+  params.anchor_dir = blink::WebTextDirectionLeftToRight;
+  params.focus_dir = blink::WebTextDirectionLeftToRight;
+  params.anchor_rect = gfx::Rect(0, 0, 10, 10);
+  for (auto index : active_view_sequence_) {
+    ActivateViewForTextInputManager(views_[index], ui::TEXT_INPUT_TYPE_TEXT);
+    params.focus_rect = gfx::Rect(10 + index, 10 + index, 10, 10);
+    views_[index]->SelectionBoundsChanged(params);
+
+    // Calculate the bounds.
+    gfx::SelectionBound anchor_bound = GetSelectionBoundFromRect(
+        TransformRectToViewsRootCoordSpace(params.anchor_rect, views_[index]));
+    gfx::SelectionBound focus_bound = GetSelectionBoundFromRect(
+        TransformRectToViewsRootCoordSpace(params.focus_rect, views_[index]));
+    anchor_bound.set_type(gfx::SelectionBound::LEFT);
+    focus_bound.set_type(gfx::SelectionBound::RIGHT);
+    gfx::Rect measured_rect =
+        gfx::RectBetweenSelectionBounds(anchor_bound, focus_bound);
+
+    EXPECT_EQ(measured_rect, text_input_client()->GetCaretBounds());
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc
index 0b34ce0..41724ea 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.cc
+++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -102,6 +102,12 @@
   return 0.f;
 }
 
+void RenderWidgetHostViewBase::SelectionBoundsChanged(
+    const ViewHostMsg_SelectionBounds_Params& params) {
+  if (GetTextInputManager())
+    GetTextInputManager()->SelectionBoundsChanged(this, params);
+}
+
 void RenderWidgetHostViewBase::SelectionChanged(const base::string16& text,
                                                 size_t offset,
                                                 const gfx::Range& range) {
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h
index f6a25c17c..756a7d8 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -251,18 +251,27 @@
                                                cc::SurfaceId original_surface,
                                                gfx::Point* transformed_point);
 
+  //----------------------------------------------------------------------------
+  // The following methods are related to IME.
+  // TODO(ekaramad): Most of the IME methods should not stay virtual after IME
+  // is implemented for OOPIF. After fixing IME, mark the corresponding methods
+  // non-virtual (https://crbug.com/578168).
+
   // Updates the state of the input method attached to the view.
-  // TODO(ekaramad): This method will not stay virtual. It will be moved up top
-  // with the other non-virtual methods after TextInputState tracking is fixed
-  // on all platforms (https://crbug.com/578168).
   virtual void TextInputStateChanged(const TextInputState& text_input_state);
 
   // Cancel the ongoing composition of the input method attached to the view.
-  // TODO(ekaramad): This method will not stay virtual. It will be moved up top
-  // with the other non-virtual methods after IME is fixed on all platforms.
-  // (https://crbug.com/578168).
   virtual void ImeCancelComposition();
 
+  // Notifies the view that the renderer selection bounds has changed.
+  // Selection bounds are described as a focus bound which is the current
+  // position of caret on the screen, as well as the anchor bound which is the
+  // starting position of the selection. The coordinates are with respect to
+  // RenderWidget's window's origin. Focus and anchor bound are represented as
+  // gfx::Rect.
+  virtual void SelectionBoundsChanged(
+      const ViewHostMsg_SelectionBounds_Params& params);
+
   //----------------------------------------------------------------------------
   // The following static methods are implemented by each platform.
 
@@ -299,13 +308,6 @@
   // the page has changed.
   virtual void SetTooltipText(const base::string16& tooltip_text) = 0;
 
-  // Notifies the View that the renderer selection bounds has changed.
-  // |start_rect| and |end_rect| are the bounds end of the selection in the
-  // coordinate system of the render view. |start_direction| and |end_direction|
-  // indicates the direction at which the selection was made on touch devices.
-  virtual void SelectionBoundsChanged(
-      const ViewHostMsg_SelectionBounds_Params& params) = 0;
-
   // Copies the contents of the compositing surface, providing a new SkBitmap
   // result via an asynchronously-run |callback|. |src_subrect| is specified in
   // layer space coordinates for the current platform (e.g., DIP for Aura/Mac,
diff --git a/content/browser/renderer_host/text_input_manager.cc b/content/browser/renderer_host/text_input_manager.cc
index 903c471b..3029d93 100644
--- a/content/browser/renderer_host/text_input_manager.cc
+++ b/content/browser/renderer_host/text_input_manager.cc
@@ -6,6 +6,7 @@
 
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
+#include "content/common/view_messages.h"
 
 namespace content {
 
@@ -54,6 +55,15 @@
                         : nullptr;
 }
 
+gfx::Rect TextInputManager::GetSelectionBoundsRect() {
+  if (!active_view_)
+    return gfx::Rect();
+
+  return gfx::RectBetweenSelectionBounds(
+      selection_region_map_[active_view_].anchor,
+      selection_region_map_[active_view_].focus);
+}
+
 void TextInputManager::UpdateTextInputState(
     RenderWidgetHostViewBase* view,
     const TextInputState& text_input_state) {
@@ -84,6 +94,60 @@
                     OnImeCancelComposition(this, view));
 }
 
+void TextInputManager::SelectionBoundsChanged(
+    RenderWidgetHostViewBase* view,
+    const ViewHostMsg_SelectionBounds_Params& params) {
+  DCHECK(IsRegistered(view));
+
+// TODO(ekaramad): Implement the logic for other platforms (crbug.com/578168).
+#if defined(USE_AURA)
+  gfx::SelectionBound anchor_bound, focus_bound;
+  // Converting the points to the |view|'s root coordinate space (for child
+  // frame views).
+  anchor_bound.SetEdge(gfx::PointF(view->TransformPointToRootCoordSpace(
+                           params.anchor_rect.origin())),
+                       gfx::PointF(view->TransformPointToRootCoordSpace(
+                           params.anchor_rect.bottom_left())));
+  focus_bound.SetEdge(gfx::PointF(view->TransformPointToRootCoordSpace(
+                          params.focus_rect.origin())),
+                      gfx::PointF(view->TransformPointToRootCoordSpace(
+                          params.focus_rect.bottom_left())));
+
+  if (params.anchor_rect == params.focus_rect) {
+    anchor_bound.set_type(gfx::SelectionBound::CENTER);
+    focus_bound.set_type(gfx::SelectionBound::CENTER);
+  } else {
+    // Whether text is LTR at the anchor handle.
+    bool anchor_LTR = params.anchor_dir == blink::WebTextDirectionLeftToRight;
+    // Whether text is LTR at the focus handle.
+    bool focus_LTR = params.focus_dir == blink::WebTextDirectionLeftToRight;
+
+    if ((params.is_anchor_first && anchor_LTR) ||
+        (!params.is_anchor_first && !anchor_LTR)) {
+      anchor_bound.set_type(gfx::SelectionBound::LEFT);
+    } else {
+      anchor_bound.set_type(gfx::SelectionBound::RIGHT);
+    }
+    if ((params.is_anchor_first && focus_LTR) ||
+        (!params.is_anchor_first && !focus_LTR)) {
+      focus_bound.set_type(gfx::SelectionBound::RIGHT);
+    } else {
+      focus_bound.set_type(gfx::SelectionBound::LEFT);
+    }
+  }
+
+  if (anchor_bound == selection_region_map_[view].anchor &&
+      focus_bound == selection_region_map_[view].focus)
+    return;
+
+  selection_region_map_[view].anchor = anchor_bound;
+  selection_region_map_[view].focus = focus_bound;
+
+  FOR_EACH_OBSERVER(Observer, observer_list_,
+                    OnSelectionBoundsChanged(this, view));
+#endif
+}
+
 void TextInputManager::Register(RenderWidgetHostViewBase* view) {
   DCHECK(!IsRegistered(view));
 
@@ -131,4 +195,9 @@
       OnUpdateTextInputStateCalled(this, updated_view, did_update_state));
 }
 
+TextInputManager::SelectionRegion::SelectionRegion() {}
+
+TextInputManager::SelectionRegion::SelectionRegion(
+    const SelectionRegion& other) = default;
+
 }  // namespace content
\ No newline at end of file
diff --git a/content/browser/renderer_host/text_input_manager.h b/content/browser/renderer_host/text_input_manager.h
index 2bb4c16d..f240a1b 100644
--- a/content/browser/renderer_host/text_input_manager.h
+++ b/content/browser/renderer_host/text_input_manager.h
@@ -6,13 +6,17 @@
 #define CONTENT_BROWSER_RENDERER_HOST_TEXT_INPUT_MANAGER_H__
 
 #include <unordered_map>
+#include <utility>
 
 #include "base/observer_list.h"
 #include "content/common/content_export.h"
 #include "content/common/text_input_state.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/selection_bound.h"
+
+struct ViewHostMsg_SelectionBounds_Params;
 
 namespace content {
-
 class RenderWidgetHostImpl;
 class RenderWidgetHostView;
 class RenderWidgetHostViewBase;
@@ -41,6 +45,10 @@
     virtual void OnImeCancelComposition(
         TextInputManager* text_input_manager,
         RenderWidgetHostViewBase* updated_view) {}
+    // Called when the selection bounds for the |updated_view| has changed.
+    virtual void OnSelectionBoundsChanged(
+        TextInputManager* text_input_manager,
+        RenderWidgetHostViewBase* updated_view) {}
   };
 
   TextInputManager();
@@ -59,6 +67,9 @@
   // dangling if the TextInputManager or |active_view_| might go away.
   const TextInputState* GetTextInputState();
 
+  // Returns the rect between selection bounds for the |active_view_|.
+  gfx::Rect GetSelectionBoundsRect();
+
   // ---------------------------------------------------------------------------
   // The following methods are called by RWHVs on the tab to update their IME-
   // related state.
@@ -71,6 +82,12 @@
   // the widget corresponding to |view|.
   void ImeCancelComposition(RenderWidgetHostViewBase* view);
 
+  // Updates the selection bounds for the |view|. In Aura, selection bounds are
+  // used to provide the InputMethod with the position of the caret, e.g., in
+  // setting the position of the ui::ImeWindow.
+  void SelectionBoundsChanged(RenderWidgetHostViewBase* view,
+                              const ViewHostMsg_SelectionBounds_Params& params);
+
   // Registers the given |view| for tracking its TextInputState. This is called
   // by any view which has updates in its TextInputState (whether tab's RWHV or
   // that of a child frame). The |view| must unregister itself before being
@@ -100,6 +117,23 @@
       RenderWidgetHostViewBase* view);
 
  private:
+  // Text selection bounds.
+  struct SelectionRegion {
+    SelectionRegion();
+    SelectionRegion(const SelectionRegion& other);
+
+    // The begining of the selection region.
+    gfx::SelectionBound anchor;
+    // The end of the selection region (caret position).
+    gfx::SelectionBound focus;
+  };
+
+  // This class is used to create maps which hold specific IME state for a
+  // view.
+  template <class Value>
+  class ViewMap : public std::unordered_map<RenderWidgetHostViewBase*, Value> {
+  };
+
   void NotifyObserversAboutInputStateUpdate(RenderWidgetHostViewBase* view,
                                             bool did_update_state);
 
@@ -108,8 +142,10 @@
   // cannot have a |TextInputState.type| of ui::TEXT_INPUT_TYPE_NONE.
   RenderWidgetHostViewBase* active_view_;
 
-  std::unordered_map<RenderWidgetHostViewBase*, TextInputState>
-      text_input_state_map_;
+  ViewMap<TextInputState> text_input_state_map_;
+
+  // Text selection bounds information for registered views.
+  ViewMap<SelectionRegion> selection_region_map_;
 
   base::ObserverList<Observer> observer_list_;
 
diff --git a/content/browser/resources/media/dump_creator.js b/content/browser/resources/media/dump_creator.js
index c8f53df..29f053f 100644
--- a/content/browser/resources/media/dump_creator.js
+++ b/content/browser/resources/media/dump_creator.js
@@ -33,12 +33,12 @@
         '</button></a></div>' +
         '<p><label><input type=checkbox>' +
         'Enable diagnostic audio recordings</label></p>' +
-        '<p class=audio-recordings-info>A diagnostic audio recording is used' +
-        ' for analyzing audio problems. It consists of two files and contains' +
-        ' the audio played out from the speaker and recorded from the' +
-        ' microphone and is saved to the local disk. Checking this box will' +
-        ' enable the recording for ongoing WebRTC calls and for future WebRTC' +
-        ' calls. When the box is unchecked or this page is closed, all' +
+        '<p class=audio-diagnostic-dumps-info>A diagnostic audio recording is' +
+        ' used for analyzing audio problems. It consists of two files and' +
+        ' contains the audio played out from the speaker and recorded from' +
+        ' the microphone and is saved to the local disk. Checking this box' +
+        ' will enable the recording for ongoing WebRTC calls and for future' +
+        ' WebRTC calls. When the box is unchecked or this page is closed, all' +
         ' ongoing recordings will be stopped and this recording' +
         ' functionality will be disabled for future WebRTC calls. Recordings' +
         ' in multiple tabs are supported as well as multiple recordings in' +
@@ -48,26 +48,37 @@
         '.aec_dump.&lt;recording ID&gt;</div>' +
         '<div>&lt;base filename&gt;.&lt;render process ID&gt;' +
         '.source_input.&lt;stream ID&gt;.wav</div></p>' +
-        '<p class=audio-recordings-info>If recordings are disabled and then' +
-        ' enabled using the same base filename, the microphone recording file' +
-        ' will be overwritten, and the AEC dump file will be appended to and' +
-        ' may become invalid. It is recommended to choose a new base filename' +
-        ' each time or move the produced files before enabling again.</p>' +
+        '<p class=audio-diagnostic-dumps-info>If recordings are disabled and' +
+        ' then enabled using the same base filename, the microphone recording' +
+        ' file will be overwritten, and the AEC dump file will be appended to' +
+        ' and may become invalid. It is recommended to choose a new base' +
+        ' filename each time or move the produced files before enabling' +
+        ' again.</p>' +
         '<p><label><input type=checkbox>' +
         'Enable diagnostic packet and event recording</label></p>' +
-        '<p class=audio-recordings-info>A diagnostic packet and event' +
+        '<p class=audio-diagnostic-dumps-info>A diagnostic packet and event' +
         ' recording can be used for analyzing various issues related to' +
         ' thread starvation, jitter buffers or bandwidth estimation. Two' +
         ' types of data are logged. First, incoming and outgoing RTP headers' +
         ' and RTCP packets are logged. These do not include any audio or' +
         ' video information, nor any other types of personally identifiable' +
         ' information (so no IP addresses or URLs). Checking this box will' +
-        ' enable the recording for currently ongoing WebRTC calls. When' +
-        ' the box is unchecked or this page is closed, all active recordings' +
-        ' will be stopped. Recording in multiple tabs or multiple recordings' +
-        ' in the same tab is currently not supported. When enabling, a' +
-        ' filename for the recording can be selected. If an existing file is' +
-        ' selected, it will be overwritten. </p>';
+        ' enable the recording for ongoing WebRTC calls and for future' +
+        ' WebRTC calls. When the box is unchecked or this page is closed,' +
+        ' all ongoing recordings will be stopped and this recording' +
+        ' functionality will be disabled for future WebRTC calls. Recording' +
+        ' in multiple tabs or multiple recordings in the same tab will cause' +
+        ' multiple log files to be created. When enabling, a filename for the' +
+        ' recording can be entered. The entered filename is used as a' +
+        ' base, to which the following suffixes will be appended.</p>' +
+        ' <p>&lt;base filename&gt;.&lt;render process ID&gt;' +
+        '.&lt;recording ID&gt;</p>' +
+        '<p class=audio-diagnostic-dumps-info>If a file with the same name' +
+        ' already exists, it will be overwritten. No more than 5 logfiles ' +
+        ' will be created, and each of them is limited to 60MB of storage. ' +
+        ' On Android these limits are 3 files of at most 10MB each. ' +
+        ' When the limit is reached, the checkbox must be unchecked and ' +
+        ' rechecked to resume logging.</p>';
     content.getElementsByTagName('a')[0].addEventListener(
         'click', this.onDownloadData_.bind(this));
     content.getElementsByTagName('input')[0].addEventListener(
diff --git a/content/browser/resources/media/webrtc_internals.css b/content/browser/resources/media/webrtc_internals.css
index 54eec7e..cf6f31a 100644
--- a/content/browser/resources/media/webrtc_internals.css
+++ b/content/browser/resources/media/webrtc_internals.css
@@ -118,6 +118,6 @@
   margin: 5px 0 5px 0;
 }
 
-.audio-recordings-info {
+.audio-diagnostic-dumps-info {
   max-width: 60em;
 }
diff --git a/content/browser/service_worker/service_worker_registration_status.cc b/content/browser/service_worker/service_worker_registration_status.cc
index 46ff019b..e404eadd 100644
--- a/content/browser/service_worker/service_worker_registration_status.cc
+++ b/content/browser/service_worker/service_worker_registration_status.cc
@@ -31,7 +31,6 @@
     case SERVICE_WORKER_ERROR_START_WORKER_FAILED:
     case SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED:
     case SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND:
-    case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
     case SERVICE_WORKER_ERROR_REDUNDANT:
     case SERVICE_WORKER_ERROR_DISALLOWED:
       *error_type = WebServiceWorkerError::ErrorTypeInstall;
@@ -45,6 +44,10 @@
       *error_type = WebServiceWorkerError::ErrorTypeNetwork;
       return;
 
+    case SERVICE_WORKER_ERROR_SCRIPT_EVALUATE_FAILED:
+      *error_type = WebServiceWorkerError::ErrorTypeScriptEvaluateFailed;
+      return;
+
     case SERVICE_WORKER_ERROR_SECURITY:
       *error_type = WebServiceWorkerError::ErrorTypeSecurity;
       return;
diff --git a/content/browser/service_worker/service_worker_url_request_job.cc b/content/browser/service_worker/service_worker_url_request_job.cc
index a81f6968..326e3ef 100644
--- a/content/browser/service_worker/service_worker_url_request_job.cc
+++ b/content/browser/service_worker/service_worker_url_request_job.cc
@@ -250,10 +250,29 @@
 
 void ServiceWorkerURLRequestJob::FallbackToNetwork() {
   DCHECK_EQ(NOT_DETERMINED, response_type_);
+  // TODO(shimazu): Remove the condition of FOREIGN_FETCH after figuring out
+  // what to do about CORS preflight and fallbacks for foreign fetch events.
+  // http://crbug.com/604084
+  DCHECK(!IsFallbackToRendererNeeded() ||
+         (fetch_type_ == ServiceWorkerFetchType::FOREIGN_FETCH));
   response_type_ = FALLBACK_TO_NETWORK;
   MaybeStartRequest();
 }
 
+void ServiceWorkerURLRequestJob::FallbackToNetworkOrRenderer() {
+  DCHECK_EQ(NOT_DETERMINED, response_type_);
+  // TODO(shimazu): Remove the condition of FOREIGN_FETCH after figuring out
+  // what to do about CORS preflight and fallbacks for foreign fetch events.
+  // http://crbug.com/604084
+  DCHECK_NE(ServiceWorkerFetchType::FOREIGN_FETCH, fetch_type_);
+  if (IsFallbackToRendererNeeded()) {
+    response_type_ = FALLBACK_TO_RENDERER;
+  } else {
+    response_type_ = FALLBACK_TO_NETWORK;
+  }
+  MaybeStartRequest();
+}
+
 void ServiceWorkerURLRequestJob::ForwardToServiceWorker() {
   DCHECK_EQ(NOT_DETERMINED, response_type_);
   response_type_ = FORWARD_TO_SERVICE_WORKER;
@@ -499,10 +518,11 @@
       return;
 
     case FALLBACK_TO_NETWORK:
-      // Restart the request to create a new job. Our request handler will
-      // return nullptr, and the default job (which will hit network) should be
-      // created.
-      NotifyRestartRequired();
+      FinalizeFallbackToNetwork();
+      return;
+
+    case FALLBACK_TO_RENDERER:
+      FinalizeFallbackToRenderer();
       return;
 
     case FORWARD_TO_SERVICE_WORKER:
@@ -698,8 +718,7 @@
     if (IsMainResourceLoad()) {
       // Using the service worker failed, so fallback to network.
       delegate_->MainResourceLoadFailed();
-      response_type_ = FALLBACK_TO_NETWORK;
-      NotifyRestartRequired();
+      FinalizeFallbackToNetwork();
     } else {
       DeliverErrorResponse();
     }
@@ -708,30 +727,11 @@
 
   if (fetch_result == SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK) {
     ServiceWorkerMetrics::RecordFallbackedRequestMode(request_mode_);
-    // When the request_mode is |CORS| or |CORS-with-forced-preflight| and the
-    // origin of the request URL is different from the security origin of the
-    // document, we can't simply fallback to the network in the browser process.
-    // It is because the CORS preflight logic is implemented in the renderer. So
-    // we returns a fall_back_required response to the renderer.
-    if ((request_mode_ == FETCH_REQUEST_MODE_CORS ||
-         request_mode_ == FETCH_REQUEST_MODE_CORS_WITH_FORCED_PREFLIGHT) &&
-        !request()->initiator().IsSameOriginWith(
-            url::Origin(request()->url()))) {
-      // TODO(mek): http://crbug.com/604084 Figure out what to do about CORS
-      // preflight and fallbacks for foreign fetch events.
-      fall_back_required_ =
-          fetch_type_ != ServiceWorkerFetchType::FOREIGN_FETCH;
-      RecordResult(ServiceWorkerMetrics::REQUEST_JOB_FALLBACK_FOR_CORS);
-      CreateResponseHeader(
-          400, "Service Worker Fallback Required", ServiceWorkerHeaderMap());
-      CommitResponseHeader();
-      return;
+    if (IsFallbackToRendererNeeded()) {
+      FinalizeFallbackToRenderer();
+    } else {
+      FinalizeFallbackToNetwork();
     }
-    // Change the response type and restart the request to fallback to
-    // the network.
-    RecordResult(ServiceWorkerMetrics::REQUEST_JOB_FALLBACK_RESPONSE);
-    response_type_ = FALLBACK_TO_NETWORK;
-    NotifyRestartRequired();
     return;
   }
 
@@ -866,6 +866,43 @@
   CommitResponseHeader();
 }
 
+void ServiceWorkerURLRequestJob::FinalizeFallbackToNetwork() {
+  // Restart this request to create a new job. The default job (which will hit
+  // network) will be created in the next time because our request handler will
+  // return nullptr after restarting and this means our interceptor does not
+  // intercept.
+  if (ShouldRecordResult())
+    RecordResult(ServiceWorkerMetrics::REQUEST_JOB_FALLBACK_RESPONSE);
+  response_type_ = FALLBACK_TO_NETWORK;
+  NotifyRestartRequired();
+  return;
+}
+
+void ServiceWorkerURLRequestJob::FinalizeFallbackToRenderer() {
+  // TODO(mek): http://crbug.com/604084 Figure out what to do about CORS
+  // preflight and fallbacks for foreign fetch events.
+  fall_back_required_ = fetch_type_ != ServiceWorkerFetchType::FOREIGN_FETCH;
+  if (ShouldRecordResult())
+    RecordResult(ServiceWorkerMetrics::REQUEST_JOB_FALLBACK_FOR_CORS);
+  CreateResponseHeader(400, "Service Worker Fallback Required",
+                       ServiceWorkerHeaderMap());
+  response_type_ = FALLBACK_TO_RENDERER;
+  CommitResponseHeader();
+}
+
+bool ServiceWorkerURLRequestJob::IsFallbackToRendererNeeded() const {
+  // When the request_mode is |CORS| or |CORS-with-forced-preflight| and the
+  // origin of the request URL is different from the security origin of the
+  // document, we can't simply fallback to the network in the browser process.
+  // It is because the CORS preflight logic is implemented in the renderer. So
+  // we return a fall_back_required response to the renderer.
+  return !IsMainResourceLoad() &&
+         (request_mode_ == FETCH_REQUEST_MODE_CORS ||
+          request_mode_ == FETCH_REQUEST_MODE_CORS_WITH_FORCED_PREFLIGHT) &&
+         !request()->initiator().IsSameOriginWith(
+             url::Origin(request()->url()));
+}
+
 void ServiceWorkerURLRequestJob::SetResponseBodyType(ResponseBodyType type) {
   DCHECK_EQ(response_body_type_, UNKNOWN);
   DCHECK_NE(type, UNKNOWN);
@@ -941,7 +978,8 @@
 }
 
 void ServiceWorkerURLRequestJob::OnStartCompleted() const {
-  if (response_type_ != FORWARD_TO_SERVICE_WORKER) {
+  if (response_type_ != FORWARD_TO_SERVICE_WORKER &&
+      response_type_ != FALLBACK_TO_RENDERER) {
     ServiceWorkerResponseInfo::ForRequest(request_, true)
         ->OnStartCompleted(
             false /* was_fetched_via_service_worker */,
diff --git a/content/browser/service_worker/service_worker_url_request_job.h b/content/browser/service_worker/service_worker_url_request_job.h
index 029871bed..f77ff43 100644
--- a/content/browser/service_worker/service_worker_url_request_job.h
+++ b/content/browser/service_worker/service_worker_url_request_job.h
@@ -103,7 +103,16 @@
   ~ServiceWorkerURLRequestJob() override;
 
   // Sets the response type.
+  // When an in-flight request possibly needs CORS check, use
+  // FallbackToNetworkOrRenderer. This method will decide whether the request
+  // can directly go to the network or should fallback to a renderer to send
+  // CORS preflight. You can use FallbackToNetwork only when, like main resource
+  // or foreign fetch cases, it's apparent that the request should go to the
+  // network directly.
+  // TODO(shimazu): Update the comment when what should we do at foreign fetch
+  // fallback is determined: crbug.com/604084
   void FallbackToNetwork();
+  void FallbackToNetworkOrRenderer();
   void ForwardToServiceWorker();
 
   bool ShouldFallbackToNetwork() const {
@@ -156,6 +165,7 @@
   enum ResponseType {
     NOT_DETERMINED,
     FALLBACK_TO_NETWORK,
+    FALLBACK_TO_RENDERER,  // Use this when falling back with CORS check
     FORWARD_TO_SERVICE_WORKER,
   };
 
@@ -199,6 +209,19 @@
   // Creates and commits a response header indicating error.
   void DeliverErrorResponse();
 
+  // Restarts this job to fallback to network.
+  // This can be called after StartRequest.
+  void FinalizeFallbackToNetwork();
+
+  // Sends back a response with fall_back_required set as true to trigger
+  // subsequent network requests with CORS checking.
+  // This can be called after StartRequest.
+  void FinalizeFallbackToRenderer();
+
+  // True if need to send back a response with fall_back_required set as true to
+  // trigger subsequent network requests with CORS checking.
+  bool IsFallbackToRendererNeeded() const;
+
   // For UMA.
   void SetResponseBodyType(ResponseBodyType type);
   bool ShouldRecordResult();
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index 0833357..1c769daa 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -1167,4 +1167,62 @@
   EXPECT_EQ(web_ui_url, entry->GetURL());
 }
 
+namespace {
+
+class DownloadImageObserver {
+ public:
+  MOCK_METHOD5(OnFinishDownloadImage, void(
+      int id,
+      int status_code,
+      const GURL& image_url,
+      const std::vector<SkBitmap>& bitmap,
+      const std::vector<gfx::Size>& sizes));
+  ~DownloadImageObserver() = default;
+};
+
+void DownloadImageTestInternal(Shell* shell,
+                               const GURL &image_url,
+                               int expected_http_status) {
+  using ::testing::_;
+  using ::testing::InvokeWithoutArgs;
+
+  // Set up everything.
+  DownloadImageObserver download_image_observer;
+  scoped_refptr<MessageLoopRunner> loop_runner =
+      new MessageLoopRunner();
+
+  // Set up expectation and stub.
+  EXPECT_CALL(download_image_observer,
+              OnFinishDownloadImage(_, expected_http_status, _, _, _));
+  ON_CALL(download_image_observer, OnFinishDownloadImage(_, _, _, _, _))
+      .WillByDefault(
+          InvokeWithoutArgs(loop_runner.get(), &MessageLoopRunner::Quit));
+
+  shell->LoadURL(GURL("about:blank"));
+  shell->web_contents()->DownloadImage(
+      image_url, false, 1024, false,
+      base::Bind(&DownloadImageObserver::OnFinishDownloadImage,
+                 base::Unretained(&download_image_observer)));
+
+  // Wait for response.
+  loop_runner->Run();
+}
+
+}  // anonymous namespace
+
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+                       DownloadImage_HttpImage) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  const GURL kImageUrl =
+      embedded_test_server()->GetURL("/image.jpg");
+  DownloadImageTestInternal(shell(), kImageUrl, 200);
+}
+
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+                       DownloadImage_Deny_FileImage) {
+  const GURL kImageUrl =
+      GetTestUrl("", "image.jpg");
+  DownloadImageTestInternal(shell(), kImageUrl, 0);
+}
+
 }  // namespace content
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc
index 77d2c5f..8c326e0c 100644
--- a/content/browser/web_contents/web_contents_view_android.cc
+++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -198,7 +198,7 @@
 }
 
 void WebContentsViewAndroid::UpdateDragCursor(blink::WebDragOperation op) {
-  NOTIMPLEMENTED();
+  // Intentional no-op because Android does not have cursor.
 }
 
 void WebContentsViewAndroid::OnDragEntered(
diff --git a/content/browser/webui/shared_resources_data_source.cc b/content/browser/webui/shared_resources_data_source.cc
index 7e5baf3..d715569 100644
--- a/content/browser/webui/shared_resources_data_source.cc
+++ b/content/browser/webui/shared_resources_data_source.cc
@@ -160,8 +160,10 @@
   // back.
   std::string allowed_origin_prefix = kChromeUIScheme;
   allowed_origin_prefix += "://";
-  if (origin.find(allowed_origin_prefix) != 0)
+  if (!base::StartsWith(origin, allowed_origin_prefix,
+                        base::CompareCase::SENSITIVE)) {
     return "null";
+  }
   return origin;
 }
 
diff --git a/content/child/child_process.cc b/content/child/child_process.cc
index 8411653a..9805c06 100644
--- a/content/child/child_process.cc
+++ b/content/child/child_process.cc
@@ -10,6 +10,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/statistics_recorder.h"
 #include "base/process/process_handle.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread.h"
@@ -87,13 +88,13 @@
 
 void ChildProcess::AddRefProcess() {
   DCHECK(!main_thread_.get() ||  // null in unittests.
-         base::MessageLoop::current() == main_thread_->message_loop());
+         main_thread_->message_loop()->task_runner()->BelongsToCurrentThread());
   ref_count_++;
 }
 
 void ChildProcess::ReleaseProcess() {
   DCHECK(!main_thread_.get() ||  // null in unittests.
-         base::MessageLoop::current() == main_thread_->message_loop());
+         main_thread_->message_loop()->task_runner()->BelongsToCurrentThread());
   DCHECK(ref_count_);
   if (--ref_count_)
     return;
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc
index f5290ff..3bac8ae 100644
--- a/content/child/child_thread_impl.cc
+++ b/content/child/child_thread_impl.cc
@@ -565,7 +565,7 @@
 }
 
 bool ChildThreadImpl::Send(IPC::Message* msg) {
-  DCHECK(base::MessageLoop::current() == message_loop());
+  DCHECK(message_loop_->task_runner()->BelongsToCurrentThread());
   if (!channel_) {
     delete msg;
     return false;
@@ -617,13 +617,13 @@
 }
 
 IPC::MessageRouter* ChildThreadImpl::GetRouter() {
-  DCHECK(base::MessageLoop::current() == message_loop());
+  DCHECK(message_loop_->task_runner()->BelongsToCurrentThread());
   return &router_;
 }
 
 std::unique_ptr<base::SharedMemory> ChildThreadImpl::AllocateSharedMemory(
     size_t buf_size) {
-  DCHECK(base::MessageLoop::current() == message_loop());
+  DCHECK(message_loop_->task_runner()->BelongsToCurrentThread());
   return AllocateSharedMemory(buf_size, this, nullptr);
 }
 
diff --git a/content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc b/content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc
index d91cf32..887f9974 100644
--- a/content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc
+++ b/content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc
@@ -40,6 +40,21 @@
   LOAD_FAMILY_MAX_VALUE
 };
 
+// This enum is used to define the buckets for an enumerated UMA histogram.
+// Hence,
+//   (a) existing enumerated constants should never be deleted or reordered, and
+//   (b) new constants should only be appended at the end of the enumeration.
+enum FontProxyError {
+  FIND_FAMILY_SEND_FAILED = 0,
+  GET_FAMILY_COUNT_SEND_FAILED = 1,
+  COLLECTION_KEY_INVALID = 2,
+  FAMILY_INDEX_OUT_OF_RANGE = 3,
+  GET_FONT_FILES_SEND_FAILED = 4,
+  MAPPED_FILE_FAILED = 5,
+
+  FONT_PROXY_ERROR_MAX_VALUE
+};
+
 const char kFontKeyName[] = "font_key_name";
 
 void LogLoadFamilyResult(DirectWriteLoadFamilyResult result) {
@@ -47,6 +62,15 @@
                             LOAD_FAMILY_MAX_VALUE);
 }
 
+void LogFamilyCount(uint32_t count) {
+  UMA_HISTOGRAM_COUNTS_1000("DirectWrite.Fonts.Proxy.FamilyCount", count);
+}
+
+void LogFontProxyError(FontProxyError error) {
+  UMA_HISTOGRAM_ENUMERATION("DirectWrite.Fonts.Proxy.FontProxyError", error,
+                            FONT_PROXY_ERROR_MAX_VALUE);
+}
+
 }  // namespace
 
 DWriteFontCollectionProxy::DWriteFontCollectionProxy() = default;
@@ -73,6 +97,7 @@
 
   if (!GetSender()->Send(
           new DWriteFontProxyMsg_FindFamily(name, &family_index))) {
+    LogFontProxyError(FIND_FAMILY_SEND_FAILED);
     return E_FAIL;
   }
 
@@ -117,8 +142,11 @@
   uint32_t family_count = 0;
   if (!GetSender()->Send(
           new DWriteFontProxyMsg_GetFamilyCount(&family_count))) {
+    LogFontProxyError(GET_FAMILY_COUNT_SEND_FAILED);
     return 0;
   }
+
+  LogFamilyCount(family_count);
   family_count_ = family_count;
   return family_count;
 }
@@ -146,6 +174,7 @@
     UINT32 collection_key_size,
     IDWriteFontFileEnumerator** font_file_enumerator) {
   if (!collection_key || collection_key_size != sizeof(uint32_t)) {
+    LogFontProxyError(COLLECTION_KEY_INVALID);
     return E_INVALIDARG;
   }
 
@@ -155,6 +184,7 @@
       reinterpret_cast<const uint32_t*>(collection_key);
 
   if (*family_index >= GetFontFamilyCount()) {
+    LogFontProxyError(FAMILY_INDEX_OUT_OF_RANGE);
     return E_INVALIDARG;
   }
 
@@ -164,6 +194,7 @@
   std::vector<base::string16> file_names;
   if (!GetSender()->Send(
           new DWriteFontProxyMsg_GetFontFiles(*family_index, &file_names))) {
+    LogFontProxyError(GET_FONT_FILES_SEND_FAILED);
     return E_FAIL;
   }
 
@@ -552,8 +583,10 @@
 HRESULT FontFileStream::RuntimeClassInitialize(
     const base::string16& file_name) {
   data_.Initialize(base::FilePath(file_name));
-  if (!data_.IsValid())
+  if (!data_.IsValid()) {
+    LogFontProxyError(MAPPED_FILE_FAILED);
     return E_FAIL;
+  }
   return S_OK;
 }
 
diff --git a/content/child/indexed_db/indexed_db_dispatcher.cc b/content/child/indexed_db/indexed_db_dispatcher.cc
index aa40cca..7d6196c6 100644
--- a/content/child/indexed_db/indexed_db_dispatcher.cc
+++ b/content/child/indexed_db/indexed_db_dispatcher.cc
@@ -30,6 +30,7 @@
 using blink::WebIDBDatabaseError;
 using blink::WebIDBKey;
 using blink::WebIDBMetadata;
+using blink::WebIDBObserver;
 using blink::WebIDBValue;
 using blink::WebString;
 using blink::WebVector;
@@ -167,6 +168,32 @@
   return thread_safe_sender_->Send(msg);
 }
 
+int32_t IndexedDBDispatcher::AddIDBObserver(
+    int32_t ipc_database_id,
+    int64_t transaction_id,
+    std::unique_ptr<WebIDBObserver> observer) {
+  int32_t observer_id = observers_.Add(observer.release());
+  Send(new IndexedDBHostMsg_DatabaseObserve(ipc_database_id, transaction_id,
+                                            observer_id));
+  return observer_id;
+}
+
+void IndexedDBDispatcher::RemoveIDBObserversFromDatabase(
+    int32_t ipc_database_id,
+    const std::vector<int32_t>& observer_ids_to_remove) {
+  for (int32_t id_to_remove : observer_ids_to_remove) {
+    observers_.Remove(id_to_remove);
+  }
+  Send(new IndexedDBHostMsg_DatabaseUnobserve(ipc_database_id,
+                                              observer_ids_to_remove));
+}
+
+void IndexedDBDispatcher::RemoveIDBObservers(
+    const std::set<int32_t>& observer_ids_to_remove) {
+  for (int32_t id : observer_ids_to_remove)
+    observers_.Remove(id);
+}
+
 void IndexedDBDispatcher::RequestIDBCursorAdvance(
     unsigned long count,
     WebIDBCallbacks* callbacks_ptr,
diff --git a/content/child/indexed_db/indexed_db_dispatcher.h b/content/child/indexed_db/indexed_db_dispatcher.h
index 9e5068d..bb1d3b6 100644
--- a/content/child/indexed_db/indexed_db_dispatcher.h
+++ b/content/child/indexed_db/indexed_db_dispatcher.h
@@ -24,6 +24,7 @@
 #include "third_party/WebKit/public/platform/WebBlobInfo.h"
 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBCallbacks.h"
 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseCallbacks.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBObserver.h"
 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h"
 #include "url/origin.h"
 
@@ -74,6 +75,21 @@
   // This method is virtual so it can be overridden in unit tests.
   virtual bool Send(IPC::Message* msg);
 
+  int32_t AddIDBObserver(int32_t ipc_database_id,
+                         int64_t transaction_id,
+                         std::unique_ptr<blink::WebIDBObserver> observer);
+
+  //  The observer with ID's in |observer_ids_to_remove| observe the
+  //  |ipc_database_id|.
+  //  We remove our local references to these observer objects, and send an IPC
+  //  to clean up the observers from the backend.
+  void RemoveIDBObserversFromDatabase(
+      int32_t ipc_database_id,
+      const std::vector<int32_t>& observer_ids_to_remove);
+
+  // Removes observers from our local map observers_ . No IPC message generated.
+  void RemoveIDBObservers(const std::set<int32_t>& observer_ids_to_remove);
+
   void RequestIDBFactoryGetDatabaseNames(blink::WebIDBCallbacks* callbacks,
                                          const url::Origin& origin);
 
@@ -264,6 +280,7 @@
   IDMap<blink::WebIDBCallbacks, IDMapOwnPointer> pending_callbacks_;
   IDMap<blink::WebIDBDatabaseCallbacks, IDMapOwnPointer>
       pending_database_callbacks_;
+  IDMap<blink::WebIDBObserver, IDMapOwnPointer> observers_;
 
   // Maps the ipc_callback_id from an open cursor request to the request's
   // transaction_id. Used to assign the transaction_id to the WebIDBCursorImpl
diff --git a/content/child/indexed_db/webidbdatabase_impl.cc b/content/child/indexed_db/webidbdatabase_impl.cc
index fedb0e7..1895b5af 100644
--- a/content/child/indexed_db/webidbdatabase_impl.cc
+++ b/content/child/indexed_db/webidbdatabase_impl.cc
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "base/stl_util.h"
 #include "content/child/indexed_db/indexed_db_dispatcher.h"
 #include "content/child/indexed_db/indexed_db_key_builders.h"
 #include "content/child/thread_safe_sender.h"
@@ -29,6 +30,7 @@
 using blink::WebIDBKey;
 using blink::WebIDBKeyPath;
 using blink::WebIDBKeyRange;
+using blink::WebIDBObserver;
 using blink::WebString;
 using blink::WebVector;
 
@@ -90,6 +92,7 @@
 void WebIDBDatabaseImpl::close() {
   IndexedDBDispatcher* dispatcher =
       IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get());
+  dispatcher->RemoveIDBObservers(observer_ids_);
   dispatcher->RequestIDBDatabaseClose(ipc_database_id_,
                                       ipc_database_callbacks_id_);
 }
@@ -100,6 +103,33 @@
   dispatcher->NotifyIDBDatabaseVersionChangeIgnored(ipc_database_id_);
 }
 
+int32_t WebIDBDatabaseImpl::addObserver(
+    std::unique_ptr<WebIDBObserver> observer,
+    long long transaction_id) {
+  IndexedDBDispatcher* dispatcher =
+      IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get());
+
+  int32_t observer_id = dispatcher->AddIDBObserver(
+      ipc_database_id_, transaction_id, std::move(observer));
+  observer_ids_.insert(observer_id);
+  return observer_id;
+}
+
+bool WebIDBDatabaseImpl::containsObserverId(int32_t id) const {
+  return ContainsValue(observer_ids_, id);
+}
+
+void WebIDBDatabaseImpl::removeObservers(
+    const std::vector<int32_t>& observer_ids_to_remove) {
+  for (int32_t id : observer_ids_to_remove)
+    observer_ids_.erase(id);
+
+  IndexedDBDispatcher* dispatcher =
+      IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get());
+  dispatcher->RemoveIDBObserversFromDatabase(ipc_database_id_,
+                                             observer_ids_to_remove);
+}
+
 void WebIDBDatabaseImpl::get(long long transaction_id,
                              long long object_store_id,
                              long long index_id,
diff --git a/content/child/indexed_db/webidbdatabase_impl.h b/content/child/indexed_db/webidbdatabase_impl.h
index 7d214bb..2be351f 100644
--- a/content/child/indexed_db/webidbdatabase_impl.h
+++ b/content/child/indexed_db/webidbdatabase_impl.h
@@ -16,6 +16,7 @@
 class WebBlobInfo;
 class WebIDBCallbacks;
 class WebIDBDatabaseCallbacks;
+class WebIDBObserver;
 class WebString;
 }
 
@@ -45,6 +46,12 @@
   void close() override;
   void versionChangeIgnored() override;
 
+  int32_t addObserver(std::unique_ptr<blink::WebIDBObserver>,
+                      long long transactionId) override;
+  bool containsObserverId(int32_t id) const override;
+  void removeObservers(
+      const std::vector<int32_t>& observer_ids_to_remove) override;
+
   void get(long long transactionId,
            long long objectStoreId,
            long long indexId,
@@ -113,6 +120,7 @@
  private:
   int32_t ipc_database_id_;
   int32_t ipc_database_callbacks_id_;
+  std::set<int32_t> observer_ids_;
   scoped_refptr<ThreadSafeSender> thread_safe_sender_;
 };
 
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 66c8556f..9c508f7e 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -232,8 +232,8 @@
   if (base::FeatureList::IsEnabled(features::kPointerEvents))
     WebRuntimeFeatures::enablePointerEvent(true);
 
-  WebRuntimeFeatures::enablePassiveDocumentEventListeners(
-      base::FeatureList::IsEnabled(features::kPassiveDocumentEventListeners));
+  if (base::FeatureList::IsEnabled(features::kPassiveDocumentEventListeners))
+    WebRuntimeFeatures::enablePassiveDocumentEventListeners(true);
 
   WebRuntimeFeatures::enableFeatureFromString(
       "FontCacheScaling",
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc
index 7f2fcf3..b3b2cdaf 100644
--- a/content/child/web_url_loader_impl.cc
+++ b/content/child/web_url_loader_impl.cc
@@ -603,7 +603,6 @@
       this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
 
   WebURLResponse response;
-  response.initialize();
   PopulateURLResponse(request_.url(), info, &response,
                       request_.reportRawHeaders());
 
@@ -654,7 +653,6 @@
   }
 
   WebURLResponse response;
-  response.initialize();
   PopulateURLResponse(request_.url(), info, &response,
                       request_.reportRawHeaders());
 
diff --git a/content/child/web_url_loader_impl_unittest.cc b/content/child/web_url_loader_impl_unittest.cc
index 9a4c2d7..d71e1aa 100644
--- a/content/child/web_url_loader_impl_unittest.cc
+++ b/content/child/web_url_loader_impl_unittest.cc
@@ -670,7 +670,6 @@
     content::ResourceResponseInfo info;
     info.socket_address = net::HostPortPair(test.ip, 443);
     blink::WebURLResponse response;
-    response.initialize();
     WebURLLoaderImpl::PopulateURLResponse(url, info, &response, true);
     EXPECT_EQ(test.expected, response.remoteIPAddress().utf8());
   };
diff --git a/content/common/android/media_metadata_android.cc b/content/common/android/media_metadata_android.cc
index 0bd1563..4e2228b 100644
--- a/content/common/android/media_metadata_android.cc
+++ b/content/common/android/media_metadata_android.cc
@@ -4,12 +4,30 @@
 
 #include "content/common/android/media_metadata_android.h"
 
+#include <string>
+#include <vector>
+
+#include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "content/public/common/media_metadata.h"
 #include "jni/MediaMetadata_jni.h"
 
 namespace content {
 
+namespace {
+
+std::vector<int> GetFlattenedSizeArray(const std::vector<gfx::Size>& sizes) {
+  std::vector<int> flattened_array;
+  flattened_array.reserve(2 * sizes.size());
+  for (const auto& size : sizes) {
+    flattened_array.push_back(size.width());
+    flattened_array.push_back(size.height());
+  }
+  return flattened_array;
+}
+
+}  // anonymous namespace
+
 // static
 base::android::ScopedJavaLocalRef<jobject>
 MediaMetadataAndroid::CreateJavaObject(
@@ -21,8 +39,26 @@
   ScopedJavaLocalRef<jstring> j_album(
       base::android::ConvertUTF16ToJavaString(env, metadata.album));
 
-  return Java_MediaMetadata_create(
+  ScopedJavaLocalRef<jobject> j_metadata = Java_MediaMetadata_create(
       env, j_title.obj(), j_artist.obj(), j_album.obj());
+
+  for (const auto& artwork : metadata.artwork) {
+    std::string src = artwork.src.spec();
+    base::string16 type = artwork.type.is_null() ?
+        base::string16() : artwork.type.string();
+    ScopedJavaLocalRef<jstring> j_src(
+        base::android::ConvertUTF8ToJavaString(env, src));
+    ScopedJavaLocalRef<jstring> j_type(
+        base::android::ConvertUTF16ToJavaString(env, type));
+    ScopedJavaLocalRef<jintArray> j_sizes(
+        base::android::ToJavaIntArray(
+            env, GetFlattenedSizeArray(artwork.sizes)));
+
+    Java_MediaMetadata_createAndAddArtwork(
+        env, j_metadata.obj(), j_src.obj(), j_type.obj(), j_sizes.obj());
+  }
+
+  return j_metadata;
 }
 
 // static
diff --git a/content/common/indexed_db/indexed_db_messages.h b/content/common/indexed_db/indexed_db_messages.h
index 68af020..977bb658 100644
--- a/content/common/indexed_db/indexed_db_messages.h
+++ b/content/common/indexed_db/indexed_db_messages.h
@@ -485,6 +485,17 @@
 IPC_MESSAGE_CONTROL1(IndexedDBHostMsg_AckReceivedBlobs,
                      std::vector<std::string>) /* uuids */
 
+// WebIDBDatabase::observe() message.
+IPC_MESSAGE_CONTROL3(IndexedDBHostMsg_DatabaseObserve,
+                     int32_t, /* ipc_database_id */
+                     int64_t, /* transaction_id */
+                     int32_t) /* observer_id */
+
+// WebIDBDatabase::unobserve() message.
+IPC_MESSAGE_CONTROL2(IndexedDBHostMsg_DatabaseUnobserve,
+                     int32_t,              /* ipc_database_id */
+                     std::vector<int32_t>) /* list of observer_id */
+
 // WebIDBDatabase::createObjectStore() message.
 IPC_MESSAGE_CONTROL1(IndexedDBHostMsg_DatabaseCreateObjectStore,
                      IndexedDBHostMsg_DatabaseCreateObjectStore_Params)
diff --git a/content/common/manifest_manager_messages.h b/content/common/manifest_manager_messages.h
index 6bdb98f..c052f27 100644
--- a/content/common/manifest_manager_messages.h
+++ b/content/common/manifest_manager_messages.h
@@ -30,6 +30,7 @@
   IPC_STRUCT_TRAITS_MEMBER(name)
   IPC_STRUCT_TRAITS_MEMBER(short_name)
   IPC_STRUCT_TRAITS_MEMBER(start_url)
+  IPC_STRUCT_TRAITS_MEMBER(scope)
   IPC_STRUCT_TRAITS_MEMBER(display)
   IPC_STRUCT_TRAITS_MEMBER(orientation)
   IPC_STRUCT_TRAITS_MEMBER(icons)
diff --git a/content/common/media/aec_dump_messages.h b/content/common/media/aec_dump_messages.h
index f6031d0..0f98f27 100644
--- a/content/common/media/aec_dump_messages.h
+++ b/content/common/media/aec_dump_messages.h
@@ -21,18 +21,9 @@
                      int /* id */,
                      IPC::PlatformFileForTransit /* file_handle */)
 
-// The browser hands over a file handle to the consumer in the renderer
-// identified by |id| to use for the event log.
-IPC_MESSAGE_CONTROL2(WebRTCEventLogMsg_EnableEventLog,
-                     int /* id */,
-                     IPC::PlatformFileForTransit /* file_handle */)
-
 // Tell the renderer to disable AEC dump in all consumers.
 IPC_MESSAGE_CONTROL0(AecDumpMsg_DisableAecDump)
 
-// Tell the renderer to disable event log in all consumers.
-IPC_MESSAGE_CONTROL0(WebRTCEventLogMsg_DisableEventLog)
-
 // Messages sent from the renderer to the browser.
 
 // Registers a consumer with the browser. The consumer will then get a file
@@ -40,13 +31,6 @@
 IPC_MESSAGE_CONTROL1(AecDumpMsg_RegisterAecDumpConsumer,
                      int /* id */)
 
-// Registers a consumer with the browser. The consumer will then get a file
-// handle when the dump is enabled.
-IPC_MESSAGE_CONTROL1(WebRTCEventLogMsg_RegisterEventLogConsumer, int /* id */)
-
 // Unregisters a consumer with the browser.
 IPC_MESSAGE_CONTROL1(AecDumpMsg_UnregisterAecDumpConsumer,
                      int /* id */)
-
-// Unregisters a consumer with the browser.
-IPC_MESSAGE_CONTROL1(WebRTCEventLogMsg_UnregisterEventLogConsumer, int /* id */)
diff --git a/content/common/media/media_metadata_sanitizer.cc b/content/common/media/media_metadata_sanitizer.cc
new file mode 100644
index 0000000..ad3bf02
--- /dev/null
+++ b/content/common/media/media_metadata_sanitizer.cc
@@ -0,0 +1,113 @@
+// 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 "content/common/media/media_metadata_sanitizer.h"
+
+#include <algorithm>
+#include <string>
+
+namespace content {
+
+namespace {
+
+// Maximum length for all the strings inside the MediaMetadata when it is sent
+// over IPC. The renderer process should truncate the strings before sending
+// the MediaMetadata and the browser process must do the same when receiving
+// it.
+const size_t kMaxIPCStringLength = 4 * 1024;
+
+// Maximum type length of Artwork, which conforms to RFC 4288
+// (https://tools.ietf.org/html/rfc4288).
+const size_t kMaxArtworkTypeLength = 2 * 127 + 1;
+
+// Maximum number of artwork images inside the MediaMetadata.
+const size_t kMaxNumberOfArtworkImages = 10;
+
+// Maximum of sizes in an artwork image.
+const size_t kMaxNumberOfArtworkSizes = 10;
+
+bool CheckArtworkSrcSanity(const GURL& src) {
+  if (!src.is_valid())
+    return false;
+  if (!src.SchemeIsHTTPOrHTTPS() && !src.SchemeIs(url::kDataScheme))
+    return false;
+  if (src.spec().size() > url::kMaxURLChars)
+    return false;
+
+  return true;
+}
+
+bool CheckArtworkSanity(const MediaMetadata::Artwork& artwork) {
+  if (!CheckArtworkSrcSanity(artwork.src))
+    return false;
+  if (artwork.type.is_null())
+    return false;
+  if (artwork.type.string().size() > kMaxArtworkTypeLength)
+    return false;
+  if (artwork.sizes.size() > kMaxNumberOfArtworkSizes)
+    return false;
+
+  return true;
+}
+
+// Sanitize artwork. The method should not be called if |artwork.src| is bad.
+MediaMetadata::Artwork SanitizeArtwork(const MediaMetadata::Artwork& artwork) {
+  MediaMetadata::Artwork sanitized_artwork;
+
+  sanitized_artwork.src = artwork.src;
+  sanitized_artwork.type = artwork.type.is_null() ?
+      base::NullableString16() :
+      base::NullableString16(
+          artwork.type.string().substr(0, kMaxArtworkTypeLength), false);
+  for (const auto& size : artwork.sizes) {
+    sanitized_artwork.sizes.push_back(size);
+    if (sanitized_artwork.sizes.size() == kMaxNumberOfArtworkSizes)
+      break;
+  }
+
+  return sanitized_artwork;
+}
+
+}  // anonymous namespace
+
+bool MediaMetadataSanitizer::CheckSanity(const MediaMetadata& metadata) {
+  if (metadata.title.size() > kMaxIPCStringLength)
+    return false;
+  if (metadata.artist.size() > kMaxIPCStringLength)
+    return false;
+  if (metadata.album.size() > kMaxIPCStringLength)
+    return false;
+  if (metadata.artwork.size() > kMaxNumberOfArtworkImages)
+    return false;
+
+  for (const auto& artwork : metadata.artwork) {
+    if (!CheckArtworkSanity(artwork))
+        return false;
+  }
+
+  return true;
+}
+
+MediaMetadata MediaMetadataSanitizer::Sanitize(const MediaMetadata& metadata) {
+  MediaMetadata sanitized_metadata;
+
+  sanitized_metadata.title = metadata.title.substr(0, kMaxIPCStringLength);
+  sanitized_metadata.artist = metadata.artist.substr(0, kMaxIPCStringLength);
+  sanitized_metadata.album = metadata.album.substr(0, kMaxIPCStringLength);
+
+  for (const auto& artwork : metadata.artwork) {
+    if (!CheckArtworkSrcSanity(artwork.src))
+      continue;
+
+    sanitized_metadata.artwork.push_back(
+        CheckArtworkSanity(artwork) ? artwork : SanitizeArtwork(artwork));
+
+    if (sanitized_metadata.artwork.size() == kMaxNumberOfArtworkImages)
+      break;
+  }
+
+  return sanitized_metadata;
+}
+
+}  // namespace content
diff --git a/content/common/media/media_metadata_sanitizer.h b/content/common/media/media_metadata_sanitizer.h
new file mode 100644
index 0000000..fa08ebb7
--- /dev/null
+++ b/content/common/media/media_metadata_sanitizer.h
@@ -0,0 +1,23 @@
+// 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_COMMON_MEDIA_MEDIA_METADATA_SANITIZER_H_
+#define CONTENT_COMMON_MEDIA_MEDIA_METADATA_SANITIZER_H_
+
+#include "content/public/common/media_metadata.h"
+
+namespace content {
+
+class MediaMetadataSanitizer {
+ public:
+  // Check the sanity of |metadata|.
+  static bool CheckSanity(const MediaMetadata& metadata);
+
+  // Sanitizes |metadata| and return the result.
+  static MediaMetadata Sanitize(const MediaMetadata& metadata);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_MEDIA_MEDIA_METADATA_SANITIZER_H_
diff --git a/content/common/media/media_session_messages_android.h b/content/common/media/media_session_messages_android.h
index 266ee27..7e951d13 100644
--- a/content/common/media/media_session_messages_android.h
+++ b/content/common/media/media_session_messages_android.h
@@ -18,6 +18,7 @@
   IPC_STRUCT_TRAITS_MEMBER(title)
   IPC_STRUCT_TRAITS_MEMBER(artist)
   IPC_STRUCT_TRAITS_MEMBER(album)
+  IPC_STRUCT_TRAITS_MEMBER(artwork)
 IPC_STRUCT_TRAITS_END()
 
 // Messages for notifying the render process of media session status -------
diff --git a/content/common/media/peer_connection_tracker_messages.h b/content/common/media/peer_connection_tracker_messages.h
index cd774bea..130f3b6 100644
--- a/content/common/media/peer_connection_tracker_messages.h
+++ b/content/common/media/peer_connection_tracker_messages.h
@@ -5,6 +5,7 @@
 #include "base/values.h"
 #include "content/common/content_export.h"
 #include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_platform_file.h"
 
 #undef IPC_MESSAGE_EXPORT
 #define IPC_MESSAGE_EXPORT CONTENT_EXPORT
@@ -41,3 +42,8 @@
 // Messages sent to PeerConnectionTracker.
 IPC_MESSAGE_CONTROL0(PeerConnectionTracker_GetAllStats)
 IPC_MESSAGE_CONTROL0(PeerConnectionTracker_OnSuspend)
+IPC_MESSAGE_CONTROL2(PeerConnectionTracker_StartEventLog,
+                     int /* peer_connection_local_id */,
+                     IPC::PlatformFileForTransit /* file */)
+IPC_MESSAGE_CONTROL1(PeerConnectionTracker_StopEventLog,
+                     int /* peer_connection_local_id */)
diff --git a/content/common/mojo/embedded_application_runner.cc b/content/common/mojo/embedded_application_runner.cc
index 39a5eb13..c0257e1 100644
--- a/content/common/mojo/embedded_application_runner.cc
+++ b/content/common/mojo/embedded_application_runner.cc
@@ -13,7 +13,7 @@
 #include "base/threading/thread.h"
 #include "base/threading/thread_checker.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service_context.h"
 
 namespace content {
 
@@ -68,8 +68,8 @@
           base::Bind(&Instance::Quit, base::Unretained(this)));
     }
 
-    shell::ShellConnection* new_connection =
-        new shell::ShellConnection(service_.get(), std::move(request));
+    shell::ServiceContext* new_connection =
+        new shell::ServiceContext(service_.get(), std::move(request));
     shell_connections_.push_back(base::WrapUnique(new_connection));
     new_connection->SetConnectionLostClosure(
         base::Bind(&Instance::OnStop, base::Unretained(this),
@@ -85,7 +85,7 @@
     DCHECK(!thread_);
   }
 
-  void OnStop(shell::ShellConnection* connection) {
+  void OnStop(shell::ServiceContext* connection) {
     DCHECK(application_task_runner_->BelongsToCurrentThread());
 
     for (auto it = shell_connections_.begin(); it != shell_connections_.end();
@@ -130,7 +130,7 @@
   // the destructor which may run on either the runner thread or the application
   // thread.
   std::unique_ptr<shell::Service> service_;
-  std::vector<std::unique_ptr<shell::ShellConnection>> shell_connections_;
+  std::vector<std::unique_ptr<shell::ServiceContext>> shell_connections_;
 
   DISALLOW_COPY_AND_ASSIGN(Instance);
 };
diff --git a/content/common/mojo/mojo_shell_connection_impl.cc b/content/common/mojo/mojo_shell_connection_impl.cc
index 86bb712..5311ba6c 100644
--- a/content/common/mojo/mojo_shell_connection_impl.cc
+++ b/content/common/mojo/mojo_shell_connection_impl.cc
@@ -10,7 +10,7 @@
 #include "base/threading/thread_local.h"
 #include "content/common/mojo/embedded_application_runner.h"
 #include "services/shell/public/cpp/service.h"
-#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service_context.h"
 #include "services/shell/runner/common/client_util.h"
 
 namespace content {
@@ -70,7 +70,7 @@
 
 MojoShellConnectionImpl::MojoShellConnectionImpl(
     shell::mojom::ServiceRequest request)
-    : shell_connection_(new shell::ShellConnection(this, std::move(request))) {}
+    : shell_connection_(new shell::ServiceContext(this, std::move(request))) {}
 
 MojoShellConnectionImpl::~MojoShellConnectionImpl() {}
 
@@ -150,7 +150,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // MojoShellConnectionImpl, MojoShellConnection implementation:
 
-shell::ShellConnection* MojoShellConnectionImpl::GetShellConnection() {
+shell::ServiceContext* MojoShellConnectionImpl::GetShellConnection() {
   return shell_connection_.get();
 }
 
diff --git a/content/common/mojo/mojo_shell_connection_impl.h b/content/common/mojo/mojo_shell_connection_impl.h
index c47961d..6a6882413 100644
--- a/content/common/mojo/mojo_shell_connection_impl.h
+++ b/content/common/mojo/mojo_shell_connection_impl.h
@@ -13,7 +13,7 @@
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 #include "services/shell/public/cpp/service.h"
-#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service_context.h"
 #include "services/shell/public/interfaces/service_factory.mojom.h"
 
 namespace content {
@@ -32,7 +32,7 @@
 
  private:
   // MojoShellConnection:
-  shell::ShellConnection* GetShellConnection() override;
+  shell::ServiceContext* GetShellConnection() override;
   shell::Connector* GetConnector() override;
   const shell::Identity& GetIdentity() const override;
   void SetConnectionLostClosure(const base::Closure& closure) override;
@@ -60,7 +60,7 @@
   void CreateService(shell::mojom::ServiceRequest request,
                          const mojo::String& name) override;
 
-  std::unique_ptr<shell::ShellConnection> shell_connection_;
+  std::unique_ptr<shell::ServiceContext> shell_connection_;
   mojo::BindingSet<shell::mojom::ServiceFactory> factory_bindings_;
   std::vector<shell::Service*> embedded_services_;
   std::vector<std::unique_ptr<shell::Service>> owned_services_;
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 33d7c73..7aa2ca6 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -917,6 +917,8 @@
       'browser/indexed_db/indexed_db_leveldb_coding.h',
       'browser/indexed_db/indexed_db_metadata.cc',
       'browser/indexed_db/indexed_db_metadata.h',
+      'browser/indexed_db/indexed_db_observer.cc',
+      'browser/indexed_db/indexed_db_observer.h',
       'browser/indexed_db/indexed_db_pending_connection.cc',
       'browser/indexed_db/indexed_db_pending_connection.h',
       'browser/indexed_db/indexed_db_quota_client.cc',
@@ -1693,6 +1695,8 @@
       'browser/accessibility/browser_accessibility_manager_auralinux.h',
     ],
     'webrtc_browser_sources': [
+      'browser/media/webrtc/webrtc_eventlog_host.cc',
+      'browser/media/webrtc/webrtc_eventlog_host.h',
       'browser/media/webrtc/webrtc_internals.cc',
       'browser/media/webrtc/webrtc_internals.h',
       'browser/media/webrtc/webrtc_internals_message_handler.cc',
diff --git a/content/content_common.gypi b/content/content_common.gypi
index d867849..10cc09f7 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -411,6 +411,8 @@
       'common/media/cdm_info.cc',
       'common/media/cdm_messages.h',
       'common/media/cdm_messages_enums.h',
+      'common/media/media_metadata_sanitizer.cc',
+      'common/media/media_metadata_sanitizer.h',
       'common/media/media_player_delegate_messages.h',
       'common/media/media_player_messages_android.h',
       'common/media/media_session_messages_android.h',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index d7e3f627..1d634bc 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -248,6 +248,7 @@
       'browser/media/media_redirect_browsertest.cc',
       'browser/media/media_source_browsertest.cc',
       'browser/media/midi_browsertest.cc',
+      'browser/media/android/browser_media_session_manager_browsertest.cc',
       'browser/media/session/media_session_browsertest.cc',
       'browser/media/session/media_session_delegate_default_browsertest.cc',
       'browser/media/session/media_session_visibility_browsertest.cc',
@@ -774,6 +775,7 @@
     # WebRTC-specific sources. Put WebRTC plugin-related stuff further below.
     'content_unittests_webrtc_sources': [
       'browser/media/webrtc/webrtc_internals_unittest.cc',
+      'browser/media/webrtc/webrtc_eventlog_host_unittest.cc',
       'browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc',
       'browser/renderer_host/p2p/socket_host_tcp_unittest.cc',
       'browser/renderer_host/p2p/socket_host_test_utils.cc',
diff --git a/content/gpu/gpu_child_thread.cc b/content/gpu/gpu_child_thread.cc
index 993265e..af207ab 100644
--- a/content/gpu/gpu_child_thread.cc
+++ b/content/gpu/gpu_child_thread.cc
@@ -173,7 +173,6 @@
     gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory)
     : ChildThreadImpl(ChildThreadImpl::Options::Builder()
                           .InBrowserProcess(params)
-                          .UseMojoChannel(true)
                           .AddStartupFilter(new GpuMemoryBufferMessageFilter(
                               gpu_memory_buffer_factory))
                           .Build()),
diff --git a/content/ppapi_plugin/ppapi_thread.cc b/content/ppapi_plugin/ppapi_thread.cc
index ea5e4bc..a32122d 100644
--- a/content/ppapi_plugin/ppapi_thread.cc
+++ b/content/ppapi_plugin/ppapi_thread.cc
@@ -18,6 +18,7 @@
 #include "base/metrics/histogram.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/rand_util.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/platform_thread.h"
@@ -149,7 +150,7 @@
 
 bool PpapiThread::Send(IPC::Message* msg) {
   // Allow access from multiple threads.
-  if (base::MessageLoop::current() == message_loop())
+  if (message_loop()->task_runner()->BelongsToCurrentThread())
     return ChildThreadImpl::Send(msg);
 
   return sync_message_filter()->Send(msg);
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentView.java b/content/public/android/java/src/org/chromium/content/browser/ContentView.java
index f1f2720..0886e4cb 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentView.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentView.java
@@ -11,6 +11,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.view.DragEvent;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
@@ -146,6 +147,11 @@
     }
 
     @Override
+    public boolean onDragEvent(DragEvent event) {
+        return mContentViewCore.onDragEvent(event);
+    }
+
+    @Override
     public boolean onTouchEvent(MotionEvent event) {
         return mContentViewCore.onTouchEvent(event);
     }
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index 561c165..0fe099be 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -1793,12 +1793,13 @@
     }
 
     /**
-     * Sets the current amount to offset incoming touch events by.  This is used to handle content
-     * moving and not lining up properly with the android input system.
+     * Sets the current amount to offset incoming touch events by (including MotionEvent and
+     * DragEvent). This is used to handle content moving and not lining up properly with the
+     * android input system.
      * @param dx The X offset in pixels to shift touch events.
      * @param dy The Y offset in pixels to shift touch events.
      */
-    public void setCurrentMotionEventOffsets(float dx, float dy) {
+    public void setCurrentTouchEventOffsets(float dx, float dy) {
         mCurrentTouchOffsetX = dx;
         mCurrentTouchOffsetY = dy;
     }
@@ -3312,17 +3313,19 @@
             }
         }
 
-        float scale = (float) DeviceDisplayInfo.create(mContainerView.getContext()).getDIPScale();
         int[] locationOnScreen = new int[2];
         mContainerView.getLocationOnScreen(locationOnScreen);
 
-        int x = (int) (event.getX() / scale);
-        int y = (int) (event.getY() / scale);
-        int screenX = (int) ((event.getX() + locationOnScreen[0]) / scale);
-        int screenY = (int) ((event.getY() + locationOnScreen[1]) / scale);
+        float xPix = event.getX() + mRenderCoordinates.getScrollXPixInt() + mCurrentTouchOffsetX;
+        float yPix = event.getY() + mRenderCoordinates.getScrollYPixInt() + mCurrentTouchOffsetY;
 
-        nativeOnDragEvent(mNativeContentViewCore, event.getAction(), x, y, screenX, screenY,
-                mimeTypes, content.toString());
+        int xCss = (int) mRenderCoordinates.fromPixToLocalCss(xPix);
+        int yCss = (int) mRenderCoordinates.fromPixToLocalCss(yPix);
+        int screenXCss = (int) mRenderCoordinates.fromPixToLocalCss(xPix + locationOnScreen[0]);
+        int screenYCss = (int) mRenderCoordinates.fromPixToLocalCss(yPix + locationOnScreen[1]);
+
+        nativeOnDragEvent(mNativeContentViewCore, event.getAction(), xCss, yCss, screenXCss,
+                screenYCss, mimeTypes, content.toString());
         return true;
     }
 
diff --git a/content/public/android/java/src/org/chromium/content_public/common/MediaMetadata.java b/content/public/android/java/src/org/chromium/content_public/common/MediaMetadata.java
index a1e9828..9303347 100644
--- a/content/public/android/java/src/org/chromium/content_public/common/MediaMetadata.java
+++ b/content/public/android/java/src/org/chromium/content_public/common/MediaMetadata.java
@@ -4,18 +4,87 @@
 
 package org.chromium.content_public.common;
 
+import android.graphics.Rect;
 import android.support.annotation.NonNull;
 import android.text.TextUtils;
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * The MediaMetadata class carries information related to a media session. It is
  * the Java counterpart of content::MediaMetadata.
  */
 @JNINamespace("content")
 public class MediaMetadata {
+    /**
+     * The Artwork class carries the artwork information in MediaMetadata. It is the Java
+     * counterpart of content::MediaMetadata::Artwork.
+     */
+    public static class Artwork {
+        @NonNull
+        private String mSrc;
+
+        private String mType;
+
+        @NonNull
+        private List<Rect> mSizes = new ArrayList<Rect>();
+
+        /**
+         * Creates a new Artwork.
+         */
+        public Artwork(@NonNull String src, String type, List<Rect> sizes) {
+            mSrc = src;
+            mType = type;
+            mSizes = sizes;
+        }
+
+        /**
+         * Returns the URL of this Artwork.
+         */
+        @NonNull
+        public String getSrc() {
+            return mSrc;
+        }
+
+        /**
+         * Returns the MIME type of this Artwork.
+         */
+        public String getType() {
+            return mType;
+        }
+
+        /**
+         * Returns the hinted sizes of this Artwork.
+         */
+        public List<Rect> getSizes() {
+            return mSizes;
+        }
+
+        /**
+         * Sets the URL of this Artwork.
+         */
+        public void setSrc(String src) {
+            mSrc = src;
+        }
+
+        /**
+         * Sets the MIME type of this Artwork.
+         */
+        public void setType(String type) {
+            mType = type;
+        }
+
+        /**
+         * Sets the sizes of this Artwork.
+         */
+        public void setSizes(List<Rect> sizes) {
+            mSizes = sizes;
+        }
+    }
 
     @NonNull
     private String mTitle;
@@ -26,6 +95,9 @@
     @NonNull
     private String mAlbum;
 
+    @NonNull
+    private List<Artwork> mArtwork = new ArrayList<Artwork>();
+
     /**
      * Returns the title associated with the media session.
      */
@@ -47,6 +119,10 @@
         return mAlbum;
     }
 
+    public List<Artwork> getArtwork() {
+        return mArtwork;
+    }
+
     /**
      * Sets the title associated with the media session.
      * @param title The title to use for the media session.
@@ -72,6 +148,23 @@
     }
 
     /**
+     * Create a new MediaArtwork from the C++ code, and add it to the Metadata.
+     * @param src The URL of the artwork.
+     * @param type The MIME type of the artwork.
+     * @param flattenedSizes The flattened array of Artwork sizes. In native code, it is of type
+     *         `std::vector<gfx::Size>` before flattening.
+     */
+    @CalledByNative
+    private void createAndAddArtwork(String src, String type, int[] flattenedSizes) {
+        assert (flattenedSizes.length % 2) == 0;
+        List<Rect> sizes = new ArrayList<Rect>();
+        for (int i = 0; (i + 1) < flattenedSizes.length; i += 2) {
+            sizes.add(new Rect(0, 0, flattenedSizes[i], flattenedSizes[i + 1]));
+        }
+        mArtwork.add(new Artwork(src, type, sizes));
+    }
+
+    /**
      * Creates a new MediaMetadata from the C++ code. This is exactly like the
      * constructor below apart that it can be called by native code.
      */
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index cb4418c0..8526ef7e 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -220,8 +220,15 @@
   virtual void EnableAudioDebugRecordings(const base::FilePath& file) = 0;
   virtual void DisableAudioDebugRecordings() = 0;
 
-  virtual void EnableEventLogRecordings(const base::FilePath& file) = 0;
-  virtual void DisableEventLogRecordings() = 0;
+  // Starts a WebRTC event log for each peerconnection on the render process.
+  // A base file_path can be supplied, which will be extended to include several
+  // identifiers to ensure uniqueness. If a recording was already in progress,
+  // this call will return false and have no other effect.
+  virtual bool StartWebRTCEventLog(const base::FilePath& file_path) = 0;
+
+  // Stops recording a WebRTC event log for each peerconnection on the render
+  // process. If no recording was in progress, this call will return false.
+  virtual bool StopWebRTCEventLog() = 0;
 
   // When set, |callback| receives log messages regarding, for example, media
   // devices (webcams, mics, etc) that were initially requested in the render
diff --git a/content/public/browser/security_style_explanations.h b/content/public/browser/security_style_explanations.h
index adba598e..3b8a28d5 100644
--- a/content/public/browser/security_style_explanations.h
+++ b/content/public/browser/security_style_explanations.h
@@ -23,7 +23,7 @@
 // SecurityStyleExplanation is a single security property of a page (for
 // example, an expired certificate, a valid certificate, or the presence
 // of a deprecated crypto algorithm). A single site may have multiple
-// different explanations of "secure", "warning", and "broken" severity
+// different explanations of "secure", "warning", "broken", and "info" severity
 // levels.
 struct SecurityStyleExplanations {
   CONTENT_EXPORT SecurityStyleExplanations();
@@ -49,9 +49,12 @@
   // True if PKP was bypassed due to a local trust anchor.
   bool pkp_bypassed;
 
+  // Explanations corresponding to each security level. The embedder should
+  // display explanations in the order: broken, unauthenticated, secure, info.
   std::vector<SecurityStyleExplanation> secure_explanations;
   std::vector<SecurityStyleExplanation> unauthenticated_explanations;
   std::vector<SecurityStyleExplanation> broken_explanations;
+  std::vector<SecurityStyleExplanation> info_explanations;
 };
 
 }  // namespace content
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 72da725..06b7faab 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -65,8 +65,7 @@
 // Non-validating reload for desktop.
 // See https://crbug.com/591245
 const base::Feature kNonValidatingReloadOnNormalReload{
-    "NonValidatingReloadOnNormalReload",
-    base::FEATURE_DISABLED_BY_DEFAULT};
+    "NonValidatingReloadOnNormalReload", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Non-validating reload on reload-to-refresh-content (e.g. pull-to-refresh).
 // See https://crbug.com/591245
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 4383bb3..2521300 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -243,6 +243,9 @@
 // Disables the Permissions API.
 const char kDisablePermissionsAPI[]         = "disable-permissions-api";
 
+// Disable Image Chromium for Pepper 3d.
+const char kDisablePepper3DImageChromium[] = "disable-pepper-3d-image-chromium";
+
 // Disables compositor-accelerated touch-screen pinch gestures.
 const char kDisablePinch[]                  = "disable-pinch";
 
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 75cc469..a5fa59c 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -79,6 +79,7 @@
 CONTENT_EXPORT extern const char kDisablePartialRaster[];
 CONTENT_EXPORT extern const char kEnablePartialRaster[];
 extern const char kDisablePepper3d[];
+CONTENT_EXPORT extern const char kDisablePepper3DImageChromium[];
 CONTENT_EXPORT extern const char kDisablePermissionsAPI[];
 CONTENT_EXPORT extern const char kDisablePinch[];
 CONTENT_EXPORT extern const char kDisablePresentationAPI[];
diff --git a/content/public/common/manifest.cc b/content/public/common/manifest.cc
index cde3498f..8e09aad2 100644
--- a/content/public/common/manifest.cc
+++ b/content/public/common/manifest.cc
@@ -21,6 +21,10 @@
 Manifest::Icon::~Icon() {
 }
 
+bool Manifest::Icon::operator==(const Manifest::Icon& other) const {
+  return src == other.src && type == other.type && sizes == other.sizes;
+}
+
 Manifest::RelatedApplication::RelatedApplication() {
 }
 
diff --git a/content/public/common/manifest.h b/content/public/common/manifest.h
index 2fba5d4e..71e8f605 100644
--- a/content/public/common/manifest.h
+++ b/content/public/common/manifest.h
@@ -30,6 +30,8 @@
     Icon(const Icon& other);
     ~Icon();
 
+    bool operator==(const Icon& other) const;
+
     // MUST be a valid url. If an icon doesn't have a valid URL, it will not be
     // successfully parsed, thus will not be represented in the Manifest.
     GURL src;
diff --git a/content/public/common/media_metadata.cc b/content/public/common/media_metadata.cc
index dc3824c2..32b353a5 100644
--- a/content/public/common/media_metadata.cc
+++ b/content/public/common/media_metadata.cc
@@ -4,16 +4,20 @@
 
 #include "content/public/common/media_metadata.h"
 
-namespace content {
+#include <algorithm>
+#include <iterator>
 
-const size_t MediaMetadata::kMaxIPCStringLength = 4 * 1024;
+namespace content {
 
 MediaMetadata::MediaMetadata() = default;
 
 MediaMetadata::~MediaMetadata() = default;
 
+MediaMetadata::MediaMetadata(const MediaMetadata& other) = default;
+
 bool MediaMetadata::operator==(const MediaMetadata& other) const {
-  return title == other.title && artist == other.artist && album == other.album;
+  return title == other.title && artist == other.artist &&
+      album == other.album && artwork == other.artwork;
 }
 
 bool MediaMetadata::operator!=(const MediaMetadata& other) const {
diff --git a/content/public/common/media_metadata.h b/content/public/common/media_metadata.h
index 3d7f13c..6cd662a 100644
--- a/content/public/common/media_metadata.h
+++ b/content/public/common/media_metadata.h
@@ -5,17 +5,26 @@
 #ifndef CONTENT_PUBLIC_COMMON_MEDIA_METADATA_H_
 #define CONTENT_PUBLIC_COMMON_MEDIA_METADATA_H_
 
+#include <vector>
+
 #include "base/strings/string16.h"
 #include "content/common/content_export.h"
+#include "content/public/common/manifest.h"
 
 namespace content {
 
 // The MediaMetadata is a structure carrying information associated to a
 // content::MediaSession.
 struct CONTENT_EXPORT MediaMetadata {
+  // TODO(zqzhang): move |Manifest::Icon| to a common place. See
+  // https://crbug.com/621859.
+  using Artwork = Manifest::Icon;
+
   MediaMetadata();
   ~MediaMetadata();
 
+  MediaMetadata(const MediaMetadata& other);
+
   bool operator==(const MediaMetadata& other) const;
   bool operator!=(const MediaMetadata& other) const;
 
@@ -28,11 +37,8 @@
   // Album associated to the MediaSession.
   base::string16 album;
 
-  // Maximum length for all the strings inside the MediaMetadata when it is sent
-  // over IPC. The renderer process should truncate the strings before sending
-  // the MediaMetadata and the browser process must do the same when receiving
-  // it.
-  static const size_t kMaxIPCStringLength;
+  // Artwork associated to the MediaSession.
+  std::vector<Artwork> artwork;
 };
 
 }  // namespace content
diff --git a/content/public/common/mojo_shell_connection.h b/content/public/common/mojo_shell_connection.h
index 63428b4..7014034 100644
--- a/content/public/common/mojo_shell_connection.h
+++ b/content/public/common/mojo_shell_connection.h
@@ -16,13 +16,13 @@
 namespace shell {
 class Connection;
 class Connector;
-class ShellConnection;
+class ServiceContext;
 }
 
 namespace content {
 
 // Encapsulates a connection to a //services/shell.
-// Access a global instance on the thread the ShellConnection was bound by
+// Access a global instance on the thread the ServiceContext was bound by
 // calling Holder::Get().
 // Clients can add shell::Service implementations whose exposed interfaces
 // will be exposed to inbound connections to this object's Service.
@@ -59,9 +59,9 @@
   static std::unique_ptr<MojoShellConnection> Create(
       shell::mojom::ServiceRequest request);
 
-  // Returns the bound shell::ShellConnection object.
+  // Returns the bound shell::ServiceContext object.
   // TODO(rockot): remove.
-  virtual shell::ShellConnection* GetShellConnection() = 0;
+  virtual shell::ServiceContext* GetShellConnection() = 0;
 
   // Returns the shell::Connector received via this connection's Service
   // implementation. Use this to initiate connections as this object's Identity.
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 873a153..4cf34819 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -22,11 +22,17 @@
 #include "base/test/test_timeouts.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "cc/surfaces/surface.h"
+#include "cc/surfaces/surface_manager.h"
 #include "content/browser/accessibility/accessibility_mode_helper.h"
 #include "content/browser/accessibility/browser_accessibility.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/browser/browser_plugin/browser_plugin_guest.h"
+#include "content/browser/compositor/surface_utils.h"
+#include "content/browser/frame_host/cross_process_frame_connector.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/frame_host/render_widget_host_view_child_frame.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/browser/web_contents/web_contents_view.h"
@@ -1002,6 +1008,90 @@
   return manager->SnapshotAXTreeForTesting();
 }
 
+bool IsWebContentsBrowserPluginFocused(content::WebContents* web_contents) {
+  WebContentsImpl* web_contents_impl =
+      static_cast<WebContentsImpl*>(web_contents);
+  BrowserPluginGuest* browser_plugin_guest =
+      web_contents_impl->GetBrowserPluginGuest();
+  return browser_plugin_guest ? browser_plugin_guest->focused() : false;
+}
+
+#if defined(USE_AURA)
+void SendRoutedTouchTapSequence(content::WebContents* web_contents,
+                                gfx::Point point) {
+  RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
+      web_contents->GetRenderWidgetHostView());
+  ui::TouchEvent touch_start(ui::ET_TOUCH_PRESSED, point, 0,
+                             base::TimeTicks::Now());
+  rwhva->OnTouchEvent(&touch_start);
+  ui::TouchEvent touch_end(ui::ET_TOUCH_RELEASED, point, 0,
+                           base::TimeTicks::Now());
+  rwhva->OnTouchEvent(&touch_end);
+}
+
+void SendRoutedGestureTapSequence(content::WebContents* web_contents,
+                                  gfx::Point point) {
+  RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
+      web_contents->GetRenderWidgetHostView());
+  ui::GestureEventDetails gesture_tap_down_details(ui::ET_GESTURE_TAP_DOWN);
+  gesture_tap_down_details.set_device_type(
+      ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
+  ui::GestureEvent gesture_tap_down(point.x(), point.y(), 0,
+                                    base::TimeTicks::Now(),
+                                    gesture_tap_down_details);
+  rwhva->OnGestureEvent(&gesture_tap_down);
+  ui::GestureEventDetails gesture_tap_details(ui::ET_GESTURE_TAP);
+  gesture_tap_details.set_device_type(
+      ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
+  gesture_tap_details.set_tap_count(1);
+  ui::GestureEvent gesture_tap(point.x(), point.y(), 0, base::TimeTicks::Now(),
+                               gesture_tap_details);
+  rwhva->OnGestureEvent(&gesture_tap);
+}
+
+// TODO(wjmaclean): The next two functions are a modified version of
+// SurfaceHitTestReadyNotifier that (1) works for BrowserPlugin-based guests,
+// and (2) links outside of content-browsertests. At some point in time we
+// should probably merge these.
+namespace {
+
+bool ContainsSurfaceId(cc::SurfaceId container_surface_id,
+                       RenderWidgetHostViewChildFrame* target_view) {
+  if (container_surface_id.is_null())
+    return false;
+  for (cc::SurfaceId id :
+       GetSurfaceManager()->GetSurfaceForId(container_surface_id)
+           ->referenced_surfaces()) {
+    if (id == target_view->SurfaceIdForTesting() ||
+        ContainsSurfaceId(id, target_view))
+      return true;
+  }
+  return false;
+}
+
+}  // namespace
+
+void WaitForGuestSurfaceReady(content::WebContents* guest_web_contents) {
+  RenderWidgetHostViewChildFrame* child_view =
+      static_cast<RenderWidgetHostViewChildFrame*>(
+          guest_web_contents->GetRenderWidgetHostView());
+
+  cc::SurfaceId root_surface_id =
+      static_cast<RenderWidgetHostViewAura*>(
+          static_cast<content::WebContentsImpl*>(guest_web_contents)
+              ->GetOuterWebContents()
+              ->GetRenderWidgetHostView())
+          ->SurfaceIdForTesting();
+
+  while (!ContainsSurfaceId(root_surface_id, child_view)) {
+    base::RunLoop run_loop;
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
+    run_loop.Run();
+  }
+}
+#endif
+
 TitleWatcher::TitleWatcher(WebContents* web_contents,
                            const base::string16& expected_title)
     : WebContentsObserver(web_contents),
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index 52c44381..3793c11 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -310,6 +310,33 @@
 // Get a snapshot of a web page's accessibility tree.
 ui::AXTreeUpdate GetAccessibilityTreeSnapshot(WebContents* web_contents);
 
+// Find out if the BrowserPlugin for a guest WebContents is focused. Returns
+// false if the WebContents isn't a guest with a BrowserPlugin.
+bool IsWebContentsBrowserPluginFocused(content::WebContents* web_contents);
+
+#if defined(USE_AURA)
+// The following two methods allow a test to send a touch tap sequence, and
+// a corresponding gesture tap sequence, by sending it to the top-level
+// WebContents for the page.
+
+// Send a TouchStart/End sequence routed via the main frame's
+// RenderWidgetHostViewAura.
+void SendRoutedTouchTapSequence(content::WebContents* web_contents,
+                                gfx::Point point);
+
+// Send a GestureTapDown/GestureTap sequence routed via the main frame's
+// RenderWidgetHostViewAura.
+void SendRoutedGestureTapSequence(content::WebContents* web_contents,
+                                  gfx::Point point);
+//
+// Waits until the cc::Surface associated with a guest/cross-process-iframe
+// has been drawn for the first time. Once this method returns it should be
+// safe to assume that events sent to the top-level RenderWidgetHostView can
+// be expected to properly hit-test to this surface, if appropriate.
+void WaitForGuestSurfaceReady(content::WebContents* web_contents);
+
+#endif
+
 // Watches title changes on a WebContents, blocking until an expected title is
 // set.
 class TitleWatcher : public WebContentsObserver {
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc
index 4eed8a7..a75a3f9 100644
--- a/content/public/test/mock_render_process_host.cc
+++ b/content/public/test/mock_render_process_host.cc
@@ -317,10 +317,14 @@
 
 void MockRenderProcessHost::DisableAudioDebugRecordings() {}
 
-void MockRenderProcessHost::EnableEventLogRecordings(
-    const base::FilePath& file) {}
+bool MockRenderProcessHost::StartWebRTCEventLog(
+    const base::FilePath& file_path) {
+  return false;
+}
 
-void MockRenderProcessHost::DisableEventLogRecordings() {}
+bool MockRenderProcessHost::StopWebRTCEventLog() {
+  return false;
+}
 
 void MockRenderProcessHost::SetWebRtcLogMessageCallback(
     base::Callback<void(const std::string&)> callback) {
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h
index 8b14db91..38030657 100644
--- a/content/public/test/mock_render_process_host.h
+++ b/content/public/test/mock_render_process_host.h
@@ -82,8 +82,8 @@
 #if defined(ENABLE_WEBRTC)
   void EnableAudioDebugRecordings(const base::FilePath& file) override;
   void DisableAudioDebugRecordings() override;
-  void EnableEventLogRecordings(const base::FilePath& file) override;
-  void DisableEventLogRecordings() override;
+  bool StartWebRTCEventLog(const base::FilePath& file_path) override;
+  bool StopWebRTCEventLog() override;
   void SetWebRtcLogMessageCallback(
       base::Callback<void(const std::string&)> callback) override;
   void ClearWebRtcLogMessageCallback() override;
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc
index 932c42e..72c1e356 100644
--- a/content/public/test/render_view_test.cc
+++ b/content/public/test/render_view_test.cc
@@ -38,6 +38,7 @@
 #include "content/test/test_content_client.h"
 #include "content/test/test_render_frame.h"
 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
+#include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
 #include "third_party/WebKit/public/web/WebHistoryItem.h"
@@ -186,6 +187,7 @@
   url_string.append(html);
   GURL url(url_string);
   WebURLRequest request(url);
+  request.setRequestorOrigin(blink::WebSecurityOrigin::createUnique());
   request.setCheckForBrowserSideNavigation(false);
   GetMainFrame()->loadRequest(request);
   // The load actually happens asynchronously, so we pump messages to process
diff --git a/content/public/test/text_input_test_utils.cc b/content/public/test/text_input_test_utils.cc
index ed3e7483..594c4be 100644
--- a/content/public/test/text_input_test_utils.cc
+++ b/content/public/test/text_input_test_utils.cc
@@ -13,6 +13,7 @@
 #include "content/browser/renderer_host/text_input_manager.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/text_input_state.h"
+#include "content/common/view_messages.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -35,7 +36,6 @@
  public:
   InternalObserver(WebContents* web_contents, TextInputManagerTester* tester)
       : WebContentsObserver(web_contents),
-        tester_(tester),
         updated_view_(nullptr),
         text_input_state_changed_(false) {
     text_input_manager_ =
@@ -50,10 +50,14 @@
   }
 
   void set_update_text_input_state_called_callback(
-      const TextInputManagerTester::Callback& callback) {
+      const base::Closure& callback) {
     update_text_input_state_callback_ = callback;
   }
 
+  void set_on_selection_bounds_changed_callback(const base::Closure& callback) {
+    on_selection_bounds_changed_callback_ = callback;
+  }
+
   const RenderWidgetHostView* GetUpdatedView() const { return updated_view_; }
 
   bool text_input_state_changed() const { return text_input_state_changed_; }
@@ -68,18 +72,27 @@
       return;
     text_input_state_changed_ = did_change_state;
     updated_view_ = updated_view;
-    update_text_input_state_callback_.Run(tester_);
+    if (!update_text_input_state_callback_.is_null())
+      update_text_input_state_callback_.Run();
+  }
+
+  void OnSelectionBoundsChanged(
+      TextInputManager* text_input_manager_,
+      RenderWidgetHostViewBase* updated_view) override {
+    updated_view_ = updated_view;
+    if (!on_selection_bounds_changed_callback_.is_null())
+      on_selection_bounds_changed_callback_.Run();
   }
 
   // WebContentsObserver implementation.
   void WebContentsDestroyed() override { text_input_manager_ = nullptr; }
 
  private:
-  TextInputManagerTester* tester_;
   TextInputManager* text_input_manager_;
   RenderWidgetHostViewBase* updated_view_;
   bool text_input_state_changed_;
-  TextInputManagerTester::Callback update_text_input_state_callback_;
+  base::Closure update_text_input_state_callback_;
+  base::Closure on_selection_bounds_changed_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(InternalObserver);
 };
@@ -222,10 +235,15 @@
 TextInputManagerTester::~TextInputManagerTester() {}
 
 void TextInputManagerTester::SetUpdateTextInputStateCalledCallback(
-    const Callback& callback) {
+    const base::Closure& callback) {
   observer_->set_update_text_input_state_called_callback(callback);
 }
 
+void TextInputManagerTester::SetOnSelectionBoundsChangedCallback(
+    const base::Closure& callback) {
+  observer_->set_on_selection_bounds_changed_callback(callback);
+}
+
 bool TextInputManagerTester::GetTextInputType(ui::TextInputType* type) {
   DCHECK(observer_->text_input_manager());
   const TextInputState* state =
diff --git a/content/public/test/text_input_test_utils.h b/content/public/test/text_input_test_utils.h
index 92be4ae..f87e9fe 100644
--- a/content/public/test/text_input_test_utils.h
+++ b/content/public/test/text_input_test_utils.h
@@ -42,14 +42,16 @@
 // observing the TextInputManager for WebContents.
 class TextInputManagerTester {
  public:
-  using Callback = base::Callback<void(TextInputManagerTester*)>;
-
   TextInputManagerTester(WebContents* web_contents);
   virtual ~TextInputManagerTester();
 
   // Sets a callback which is invoked when a RWHV calls UpdateTextInputState
   // on the TextInputManager which is being observed.
-  void SetUpdateTextInputStateCalledCallback(const Callback& callback);
+  void SetUpdateTextInputStateCalledCallback(const base::Closure& callback);
+
+  // Sets a callback which is invoked when a RWHV calls SelectionBoundsChanged
+  // on the TextInputManager which is being observed.
+  void SetOnSelectionBoundsChangedCallback(const base::Closure& callback);
 
   // Returns true if there is a focused <input> and populates |type| with
   // |TextInputState.type| of the TextInputManager.
@@ -63,9 +65,8 @@
   // if none exists.
   const RenderWidgetHostView* GetActiveView();
 
-  // Returns the RenderWidgetHostView which has most recently called
-  // TextInputManager::UpdateTextInputState on the TextInputManager which is
-  // being observed.
+  // Returns the RenderWidgetHostView which has most recently updated any of its
+  // state (e.g., TextInputState or otherwise).
   const RenderWidgetHostView* GetUpdatedView();
 
   // Returns true if a call to TextInputManager::UpdateTextInputState has led
diff --git a/content/renderer/android/synchronous_compositor_output_surface.cc b/content/renderer/android/synchronous_compositor_output_surface.cc
index 37d3a23..7919e83a 100644
--- a/content/renderer/android/synchronous_compositor_output_surface.cc
+++ b/content/renderer/android/synchronous_compositor_output_surface.cc
@@ -16,7 +16,13 @@
 #include "cc/output/compositor_frame.h"
 #include "cc/output/context_provider.h"
 #include "cc/output/output_surface_client.h"
+#include "cc/output/renderer_settings.h"
 #include "cc/output/software_output_device.h"
+#include "cc/output/texture_mailbox_deleter.h"
+#include "cc/surfaces/display.h"
+#include "cc/surfaces/surface_factory.h"
+#include "cc/surfaces/surface_id_allocator.h"
+#include "cc/surfaces/surface_manager.h"
 #include "content/common/android/sync_compositor_messages.h"
 #include "content/renderer/android/synchronous_compositor_filter.h"
 #include "content/renderer/android/synchronous_compositor_registry.h"
@@ -38,39 +44,42 @@
 namespace {
 
 const int64_t kFallbackTickTimeoutInMilliseconds = 100;
+const uint32_t kCompositorSurfaceNamespace = 1;
 
 // Do not limit number of resources, so use an unrealistically high value.
 const size_t kNumResourcesLimit = 10 * 1000 * 1000;
 
 }  // namespace
 
-class SynchronousCompositorOutputSurface::SoftwareDevice
-  : public cc::SoftwareOutputDevice {
+class SoftwareDevice : public cc::SoftwareOutputDevice {
  public:
-  SoftwareDevice(SynchronousCompositorOutputSurface* surface)
-    : surface_(surface) {
-  }
+  SoftwareDevice(SkCanvas** canvas) : canvas_(canvas) {}
+
   void Resize(const gfx::Size& pixel_size, float scale_factor) override {
     // Intentional no-op: canvas size is controlled by the embedder.
   }
   SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override {
-    if (!surface_->current_sw_canvas_) {
-      NOTREACHED() << "BeginPaint with no canvas set";
-      return &null_canvas_;
-    }
-    LOG_IF(WARNING, surface_->did_swap_)
-        << "Mutliple calls to BeginPaint per frame";
-    return surface_->current_sw_canvas_;
+    DCHECK(*canvas_) << "BeginPaint with no canvas set";
+    return *canvas_;
   }
   void EndPaint() override {}
 
  private:
-  SynchronousCompositorOutputSurface* surface_;
-  SkCanvas null_canvas_;
+  SkCanvas** canvas_;
 
   DISALLOW_COPY_AND_ASSIGN(SoftwareDevice);
 };
 
+class SoftwareOutputSurface : public cc::OutputSurface {
+ public:
+  SoftwareOutputSurface(std::unique_ptr<SoftwareDevice> software_device)
+      : cc::OutputSurface(nullptr, nullptr, std::move(software_device)) {}
+
+  // cc::OutputSurface implementation.
+  uint32_t GetFramebufferCopyTextureFormat() override { return 0; }
+  void SwapBuffers(cc::CompositorFrame frame) override {}
+};
+
 SynchronousCompositorOutputSurface::SynchronousCompositorOutputSurface(
     scoped_refptr<cc::ContextProvider> context_provider,
     scoped_refptr<cc::ContextProvider> worker_context_provider,
@@ -80,19 +89,17 @@
     scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue)
     : cc::OutputSurface(std::move(context_provider),
                         std::move(worker_context_provider),
-                        base::MakeUnique<SoftwareDevice>(this)),
+                        nullptr),
       routing_id_(routing_id),
       output_surface_id_(output_surface_id),
       registry_(registry),
       sender_(RenderThreadImpl::current()->sync_compositor_message_filter()),
-      registered_(false),
-      sync_client_(nullptr),
-      current_sw_canvas_(nullptr),
       memory_policy_(0u),
-      did_swap_(false),
       frame_swap_message_queue_(frame_swap_message_queue),
-      fallback_tick_pending_(false),
-      fallback_tick_running_(false) {
+      surface_manager_(new cc::SurfaceManager),
+      surface_id_allocator_(
+          new cc::SurfaceIdAllocator(kCompositorSurfaceNamespace)),
+      surface_factory_(new cc::SurfaceFactory(surface_manager_.get(), this)) {
   DCHECK(registry_);
   DCHECK(sender_);
   thread_checker_.DetachFromThread();
@@ -100,6 +107,7 @@
   capabilities_.delegated_rendering = true;
   memory_policy_.priority_cutoff_when_visible =
       gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
+  surface_id_allocator_->RegisterSurfaceIdNamespace(surface_manager_.get());
 }
 
 SynchronousCompositorOutputSurface::~SynchronousCompositorOutputSurface() {}
@@ -135,6 +143,24 @@
                  base::Unretained(this)));
   registry_->RegisterOutputSurface(routing_id_, this);
   registered_ = true;
+
+  surface_manager_->RegisterSurfaceFactoryClient(
+      surface_id_allocator_->id_namespace(), this);
+
+  cc::RendererSettings software_renderer_settings;
+
+  // The shared_bitmap_manager and gpu_memory_buffer_manager here are null as
+  // this Display is only used for resourcesless software draws, where no
+  // resources are included in the frame swapped from the compositor. So there
+  // is no need for these.
+  display_.reset(new cc::Display(
+      surface_manager_.get(), nullptr /* shared_bitmap_manager */,
+      nullptr /* gpu_memory_buffer_manager */, software_renderer_settings,
+      surface_id_allocator_->id_namespace(), nullptr /* begin_frame_source */,
+      base::MakeUnique<SoftwareOutputSurface>(
+          base::MakeUnique<SoftwareDevice>(&current_sw_canvas_)),
+      nullptr /* scheduler */, nullptr /* texture_mailbox_deleter */));
+  display_->Initialize(&display_client_);
   return true;
 }
 
@@ -144,6 +170,14 @@
     registry_->UnregisterOutputSurface(routing_id_, this);
   }
   client_->SetTreeActivationCallback(base::Closure());
+  if (!delegated_surface_id_.is_null())
+    surface_factory_->Destroy(delegated_surface_id_);
+  surface_manager_->UnregisterSurfaceFactoryClient(
+      surface_id_allocator_->id_namespace());
+  display_ = nullptr;
+  surface_factory_ = nullptr;
+  surface_id_allocator_ = nullptr;
+  surface_manager_ = nullptr;
   cc::OutputSurface::DetachFromClient();
   CancelFallbackTick();
 }
@@ -156,14 +190,52 @@
   // Intentional no-op: surface size is controlled by the embedder.
 }
 
+static void NoOpDrawCallback(cc::SurfaceDrawStatus s) {}
+
 void SynchronousCompositorOutputSurface::SwapBuffers(
     cc::CompositorFrame frame) {
   DCHECK(CalledOnValidThread());
   DCHECK(sync_client_);
-  if (!fallback_tick_running_) {
-    sync_client_->SwapBuffers(output_surface_id_, std::move(frame));
-    DeliverMessages();
+
+  if (fallback_tick_running_) {
+    client_->DidSwapBuffers();
+    client_->DidSwapBuffersComplete();
+    DCHECK(frame.delegated_frame_data->resource_list.empty());
+    cc::ReturnedResourceArray return_resources;
+    ReturnResources(return_resources);
+    return;
   }
+
+  cc::CompositorFrame swap_frame;
+
+  if (in_software_draw_) {
+    // The frame we send to the client is actually just the metadata. Preserve
+    // the |frame| for the software path below.
+    swap_frame.metadata = frame.metadata.Clone();
+
+    if (delegated_surface_id_.is_null()) {
+      delegated_surface_id_ = surface_id_allocator_->GenerateId();
+      surface_factory_->Create(delegated_surface_id_);
+    }
+
+    display_->SetSurfaceId(delegated_surface_id_,
+                           frame.metadata.device_scale_factor);
+
+    gfx::Size frame_size =
+        frame.delegated_frame_data->render_pass_list.back()->output_rect.size();
+    display_->Resize(frame_size);
+
+    surface_factory_->SubmitCompositorFrame(
+        delegated_surface_id_, std::move(frame), base::Bind(&NoOpDrawCallback));
+    display_->DrawAndSwap();
+  } else {
+    // For hardware draws we send the whole frame to the client so it can draw
+    // the content in it.
+    swap_frame = std::move(frame);
+  }
+
+  sync_client_->SwapBuffers(output_surface_id_, std::move(swap_frame));
+  DeliverMessages();
   client_->DidSwapBuffers();
   did_swap_ = true;
 }
@@ -228,8 +300,7 @@
   surface_size_ = surface_size;
   client_->SetExternalTilePriorityConstraints(viewport_rect_for_tile_priority,
                                               transform_for_tile_priority);
-  const bool software_draw = false;
-  InvokeComposite(transform, viewport, clip, software_draw);
+  InvokeComposite(transform, viewport, clip);
 }
 
 void SynchronousCompositorOutputSurface::DemandDrawSw(SkCanvas* canvas) {
@@ -249,19 +320,18 @@
 
   surface_size_ = gfx::Size(canvas->getBaseLayerSize().width(),
                             canvas->getBaseLayerSize().height());
-  const bool software_draw = true;
-  InvokeComposite(transform, clip, clip, software_draw);
+  base::AutoReset<bool> set_in_software_draw(&in_software_draw_, true);
+  InvokeComposite(transform, clip, clip);
 }
 
 void SynchronousCompositorOutputSurface::InvokeComposite(
     const gfx::Transform& transform,
     const gfx::Rect& viewport,
-    const gfx::Rect& clip,
-    bool software_draw) {
+    const gfx::Rect& clip) {
   gfx::Transform adjusted_transform = transform;
   adjusted_transform.matrix().postTranslate(-viewport.x(), -viewport.y(), 0);
   did_swap_ = false;
-  client_->OnDraw(adjusted_transform, viewport, clip, software_draw);
+  client_->OnDraw(adjusted_transform, viewport, clip, in_software_draw_);
 
   if (did_swap_)
     client_->DidSwapBuffersComplete();
@@ -325,4 +395,17 @@
   return thread_checker_.CalledOnValidThread();
 }
 
+void SynchronousCompositorOutputSurface::ReturnResources(
+    const cc::ReturnedResourceArray& resources) {
+  DCHECK(resources.empty());
+  cc::CompositorFrameAck ack;
+  client_->ReclaimResources(&ack);
+}
+
+void SynchronousCompositorOutputSurface::SetBeginFrameSource(
+    cc::BeginFrameSource* begin_frame_source) {
+  // Software output is synchronous and doesn't use a BeginFrameSource.
+  NOTREACHED();
+}
+
 }  // namespace content
diff --git a/content/renderer/android/synchronous_compositor_output_surface.h b/content/renderer/android/synchronous_compositor_output_surface.h
index 0972094..b26e18ac 100644
--- a/content/renderer/android/synchronous_compositor_output_surface.h
+++ b/content/renderer/android/synchronous_compositor_output_surface.h
@@ -18,12 +18,18 @@
 #include "cc/output/compositor_frame.h"
 #include "cc/output/managed_memory_policy.h"
 #include "cc/output/output_surface.h"
+#include "cc/surfaces/display_client.h"
+#include "cc/surfaces/surface_factory_client.h"
 #include "ipc/ipc_message.h"
 #include "ui/gfx/transform.h"
 
 namespace cc {
 class ContextProvider;
 class CompositorFrameMetadata;
+class Display;
+class SurfaceFactory;
+class SurfaceIdAllocator;
+class SurfaceManager;
 }
 
 namespace IPC {
@@ -57,7 +63,8 @@
 // This class can be created only on the main thread, but then becomes pinned
 // to a fixed thread when BindToClient is called.
 class SynchronousCompositorOutputSurface
-    : NON_EXPORTED_BASE(public cc::OutputSurface) {
+    : NON_EXPORTED_BASE(public cc::OutputSurface),
+      public cc::SurfaceFactoryClient {
  public:
   SynchronousCompositorOutputSurface(
       scoped_refptr<cc::ContextProvider> context_provider,
@@ -92,14 +99,14 @@
                     const gfx::Transform& transform_for_tile_priority);
   void DemandDrawSw(SkCanvas* canvas);
 
- private:
-  class SoftwareDevice;
-  friend class SoftwareDevice;
+  // SurfaceFactoryClient implementation.
+  void ReturnResources(const cc::ReturnedResourceArray& resources) override;
+  void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) override;
 
+ private:
   void InvokeComposite(const gfx::Transform& transform,
                        const gfx::Rect& viewport,
-                       const gfx::Rect& clip,
-                       bool hardware_draw);
+                       const gfx::Rect& clip);
   bool Send(IPC::Message* message);
   void DidActivatePendingTree();
   void DeliverMessages();
@@ -117,21 +124,39 @@
   const uint32_t output_surface_id_;
   SynchronousCompositorRegistry* const registry_;  // Not owned.
   IPC::Sender* const sender_;  // Not owned.
-  bool registered_;
+  bool registered_ = false;
 
   // Not owned.
-  SynchronousCompositorOutputSurfaceClient* sync_client_;
+  SynchronousCompositorOutputSurfaceClient* sync_client_ = nullptr;
 
   // Only valid (non-NULL) during a DemandDrawSw() call.
-  SkCanvas* current_sw_canvas_;
+  SkCanvas* current_sw_canvas_ = nullptr;
 
   cc::ManagedMemoryPolicy memory_policy_;
-  bool did_swap_;
+  bool in_software_draw_ = false;
+  bool did_swap_ = false;
   scoped_refptr<FrameSwapMessageQueue> frame_swap_message_queue_;
 
   base::CancelableClosure fallback_tick_;
-  bool fallback_tick_pending_;
-  bool fallback_tick_running_;
+  bool fallback_tick_pending_ = false;
+  bool fallback_tick_running_ = false;
+
+  class StubDisplayClient : public cc::DisplayClient {
+    void DisplayOutputSurfaceLost() override {}
+    void DisplaySetMemoryPolicy(
+        const cc::ManagedMemoryPolicy& policy) override {}
+  };
+
+  // TODO(danakj): These don't to be stored in unique_ptrs when OutputSurface
+  // is owned/destroyed on the compositor thread.
+  std::unique_ptr<cc::SurfaceManager> surface_manager_;
+  std::unique_ptr<cc::SurfaceIdAllocator> surface_id_allocator_;
+  cc::SurfaceId delegated_surface_id_;
+  // Uses surface_manager_.
+  std::unique_ptr<cc::SurfaceFactory> surface_factory_;
+  StubDisplayClient display_client_;
+  // Uses surface_manager_.
+  std::unique_ptr<cc::Display> display_;
 
   base::ThreadChecker thread_checker_;
 
diff --git a/content/renderer/devtools/devtools_agent.cc b/content/renderer/devtools/devtools_agent.cc
index 9dcd5904..066f0bb 100644
--- a/content/renderer/devtools/devtools_agent.cc
+++ b/content/renderer/devtools/devtools_agent.cc
@@ -13,6 +13,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/threading/non_thread_safe.h"
 #include "base/trace_event/trace_event.h"
 #include "content/common/devtools_messages.h"
 #include "content/common/frame_messages.h"
@@ -23,6 +24,7 @@
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_widget.h"
 #include "ipc/ipc_channel.h"
+#include "third_party/WebKit/public/platform/WebFloatRect.h"
 #include "third_party/WebKit/public/platform/WebPoint.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/web/WebDevToolsAgent.h"
@@ -43,20 +45,34 @@
 const size_t kMaxMessageChunkSize = IPC::Channel::kMaximumMessageSize / 4;
 const char kPageGetAppManifest[] = "Page.getAppManifest";
 
-
 class WebKitClientMessageLoopImpl
-    : public WebDevToolsAgentClient::WebKitClientMessageLoop {
+    : public WebDevToolsAgentClient::WebKitClientMessageLoop,
+      public base::NonThreadSafe {
  public:
-  WebKitClientMessageLoopImpl() : message_loop_(base::MessageLoop::current()) {}
-  ~WebKitClientMessageLoopImpl() override { message_loop_ = NULL; }
+  WebKitClientMessageLoopImpl() = default;
+  ~WebKitClientMessageLoopImpl() override { DCHECK(CalledOnValidThread()); }
   void run() override {
-    base::MessageLoop::ScopedNestableTaskAllower allow(message_loop_);
-    base::RunLoop().Run();
+    DCHECK(CalledOnValidThread());
+
+    base::RunLoop* const previous_run_loop = run_loop_;
+    base::RunLoop run_loop;
+    run_loop_ = &run_loop;
+
+    base::MessageLoop::ScopedNestableTaskAllower allow(
+        base::MessageLoop::current());
+    run_loop.Run();
+
+    run_loop_ = previous_run_loop;
   }
-  void quitNow() override { message_loop_->QuitNow(); }
+  void quitNow() override {
+    DCHECK(CalledOnValidThread());
+    DCHECK(run_loop_);
+
+    run_loop_->Quit();
+  }
 
  private:
-  base::MessageLoop* message_loop_;
+  base::RunLoop* run_loop_ = nullptr;
 };
 
 typedef std::map<int, DevToolsAgent*> IdToAgentMap;
@@ -263,7 +279,9 @@
 }
 
 void DevToolsAgent::OnInspectElement(int x, int y) {
-  GetWebAgent()->inspectElementAt(WebPoint(x, y));
+  blink::WebFloatRect point_rect(x, y, 0, 0);
+  frame_->GetRenderWidget()->convertWindowToViewport(&point_rect);
+  GetWebAgent()->inspectElementAt(WebPoint(point_rect.x, point_rect.y));
 }
 
 void DevToolsAgent::OnRequestNewWindowACK(bool success) {
diff --git a/content/renderer/devtools/devtools_agent_filter.cc b/content/renderer/devtools/devtools_agent_filter.cc
index 1e015f79..f84b56d 100644
--- a/content/renderer/devtools/devtools_agent_filter.cc
+++ b/content/renderer/devtools/devtools_agent_filter.cc
@@ -5,7 +5,6 @@
 #include "content/renderer/devtools/devtools_agent_filter.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
 #include "content/child/child_process.h"
 #include "content/common/devtools_messages.h"
 #include "content/renderer/devtools/devtools_agent.h"
@@ -48,10 +47,8 @@
 }  // namespace
 
 DevToolsAgentFilter::DevToolsAgentFilter()
-    : render_thread_loop_(base::MessageLoop::current()),
-      io_task_runner_(ChildProcess::current()->io_task_runner()),
-      current_routing_id_(0) {
-}
+    : io_task_runner_(ChildProcess::current()->io_task_runner()),
+      current_routing_id_(0) {}
 
 bool DevToolsAgentFilter::OnMessageReceived(const IPC::Message& message) {
   // Dispatch debugger commands directly from IO.
diff --git a/content/renderer/devtools/devtools_agent_filter.h b/content/renderer/devtools/devtools_agent_filter.h
index 899bad74..69fcb29e4 100644
--- a/content/renderer/devtools/devtools_agent_filter.h
+++ b/content/renderer/devtools/devtools_agent_filter.h
@@ -16,7 +16,6 @@
 struct DevToolsMessageData;
 
 namespace base {
-class MessageLoop;
 class SingleThreadTaskRunner;
 }
 
@@ -56,7 +55,6 @@
   void AddEmbeddedWorkerRoute(int32_t routing_id);
   void RemoveEmbeddedWorkerRoute(int32_t routing_id);
 
-  base::MessageLoop* render_thread_loop_;
   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
   int current_routing_id_;
 
diff --git a/content/renderer/media/aec_dump_message_filter.cc b/content/renderer/media/aec_dump_message_filter.cc
index 01a6d0b..1d6ac4b 100644
--- a/content/renderer/media/aec_dump_message_filter.cc
+++ b/content/renderer/media/aec_dump_message_filter.cc
@@ -6,7 +6,6 @@
 
 #include "base/single_thread_task_runner.h"
 #include "content/common/media/aec_dump_messages.h"
-#include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
 #include "content/renderer/media/webrtc_logging.h"
 #include "ipc/ipc_logging.h"
 #include "ipc/ipc_sender.h"
@@ -21,13 +20,11 @@
 
 AecDumpMessageFilter::AecDumpMessageFilter(
     const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
-    const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
-    PeerConnectionDependencyFactory* peerconnection_dependency_factory)
+    const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner)
     : sender_(NULL),
       delegate_id_counter_(1),
       io_task_runner_(io_task_runner),
-      main_task_runner_(main_task_runner),
-      peerconnection_dependency_factory_(peerconnection_dependency_factory) {
+      main_task_runner_(main_task_runner) {
   DCHECK(!g_filter);
   g_filter = this;
 }
@@ -91,9 +88,7 @@
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(AecDumpMessageFilter, message)
     IPC_MESSAGE_HANDLER(AecDumpMsg_EnableAecDump, OnEnableAecDump)
-    IPC_MESSAGE_HANDLER(WebRTCEventLogMsg_EnableEventLog, OnEnableEventLog)
     IPC_MESSAGE_HANDLER(AecDumpMsg_DisableAecDump, OnDisableAecDump)
-    IPC_MESSAGE_HANDLER(WebRTCEventLogMsg_DisableEventLog, OnDisableEventLog)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -129,27 +124,12 @@
                             file_handle));
 }
 
-void AecDumpMessageFilter::OnEnableEventLog(
-    int id,
-    IPC::PlatformFileForTransit file_handle) {
-  DCHECK(io_task_runner_->BelongsToCurrentThread());
-  main_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&AecDumpMessageFilter::DoEnableEventLog, this, id,
-                            file_handle));
-}
-
 void AecDumpMessageFilter::OnDisableAecDump() {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
   main_task_runner_->PostTask(
       FROM_HERE, base::Bind(&AecDumpMessageFilter::DoDisableAecDump, this));
 }
 
-void AecDumpMessageFilter::OnDisableEventLog() {
-  DCHECK(io_task_runner_->BelongsToCurrentThread());
-  main_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&AecDumpMessageFilter::DoDisableEventLog, this));
-}
-
 void AecDumpMessageFilter::DoEnableAecDump(
     int id,
     IPC::PlatformFileForTransit file_handle) {
@@ -165,14 +145,6 @@
   }
 }
 
-void AecDumpMessageFilter::DoEnableEventLog(
-    int id,
-    IPC::PlatformFileForTransit file_handle) {
-  DCHECK(main_task_runner_->BelongsToCurrentThread());
-  peerconnection_dependency_factory_->StartRtcEventLog(
-      IPC::PlatformFileForTransitToPlatformFile(file_handle));
-}
-
 void AecDumpMessageFilter::DoDisableAecDump() {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
   for (DelegateMap::iterator it = delegates_.begin();
@@ -181,11 +153,6 @@
   }
 }
 
-void AecDumpMessageFilter::DoDisableEventLog() {
-  DCHECK(main_task_runner_->BelongsToCurrentThread());
-  peerconnection_dependency_factory_->StopRtcEventLog();
-}
-
 void AecDumpMessageFilter::DoChannelClosingOnDelegates() {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
   for (DelegateMap::iterator it = delegates_.begin();
diff --git a/content/renderer/media/aec_dump_message_filter.h b/content/renderer/media/aec_dump_message_filter.h
index a211a8ae..f0bccc6b 100644
--- a/content/renderer/media/aec_dump_message_filter.h
+++ b/content/renderer/media/aec_dump_message_filter.h
@@ -33,8 +33,7 @@
 
   AecDumpMessageFilter(
       const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
-      const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
-      PeerConnectionDependencyFactory* peerconnection_dependency_factory);
+      const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner);
 
   // Getter for the one AecDumpMessageFilter object.
   static scoped_refptr<AecDumpMessageFilter> Get();
@@ -73,15 +72,11 @@
 
   // Accessed on |io_task_runner_|.
   void OnEnableAecDump(int id, IPC::PlatformFileForTransit file_handle);
-  void OnEnableEventLog(int id, IPC::PlatformFileForTransit file_handle);
   void OnDisableAecDump();
-  void OnDisableEventLog();
 
   // Accessed on |main_task_runner_|.
   void DoEnableAecDump(int id, IPC::PlatformFileForTransit file_handle);
-  void DoEnableEventLog(int id, IPC::PlatformFileForTransit file_handle);
   void DoDisableAecDump();
-  void DoDisableEventLog();
   void DoChannelClosingOnDelegates();
   int GetIdForDelegate(AecDumpMessageFilter::AecDumpDelegate* delegate);
 
@@ -106,9 +101,6 @@
   // The singleton instance for this filter.
   static AecDumpMessageFilter* g_filter;
 
-  // This pointer is used for calls to enable/disable the RTC event log.
-  PeerConnectionDependencyFactory* const peerconnection_dependency_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(AecDumpMessageFilter);
 };
 
diff --git a/content/renderer/media/android/renderer_media_session_manager.cc b/content/renderer/media/android/renderer_media_session_manager.cc
index b5331c7..da956ece 100644
--- a/content/renderer/media/android/renderer_media_session_manager.cc
+++ b/content/renderer/media/android/renderer_media_session_manager.cc
@@ -5,6 +5,7 @@
 #include "content/renderer/media/android/renderer_media_session_manager.h"
 
 #include "base/logging.h"
+#include "content/common/media/media_metadata_sanitizer.h"
 #include "content/common/media/media_session_messages_android.h"
 #include "content/public/common/media_metadata.h"
 #include "content/public/renderer/render_thread.h"
@@ -65,18 +66,13 @@
 void RendererMediaSessionManager::SetMetadata(
     int session_id,
     const MediaMetadata& metadata) {
-  // Apply some sanity checks on the MediaMetadata before sending over IPC.
-  MediaMetadata ipc_metadata;
-  ipc_metadata.title =
-      metadata.title.substr(0, MediaMetadata::kMaxIPCStringLength);
-  ipc_metadata.artist =
-      metadata.artist.substr(0, MediaMetadata::kMaxIPCStringLength);
-  ipc_metadata.album =
-      metadata.album.substr(0, MediaMetadata::kMaxIPCStringLength);
 
-  Send(new MediaSessionHostMsg_SetMetadata(routing_id(),
-                                           session_id,
-                                           ipc_metadata));
+  // TODO(zqzhang): print a console warning when metadata is dirty. See
+  // https://crbug.com/625244.
+  Send(new MediaSessionHostMsg_SetMetadata(
+      routing_id(), session_id,
+      MediaMetadataSanitizer::CheckSanity(metadata) ?
+      metadata : MediaMetadataSanitizer::Sanitize(metadata)));
 }
 
 void RendererMediaSessionManager::OnDidActivate(int request_id, bool success) {
diff --git a/content/renderer/media/android/webmediasession_android.cc b/content/renderer/media/android/webmediasession_android.cc
index c1a936d..3601d7f4 100644
--- a/content/renderer/media/android/webmediasession_android.cc
+++ b/content/renderer/media/android/webmediasession_android.cc
@@ -10,6 +10,8 @@
 #include "base/memory/ptr_util.h"
 #include "content/public/common/media_metadata.h"
 #include "content/renderer/media/android/renderer_media_session_manager.h"
+#include "third_party/WebKit/public/platform/WebIconSizesParser.h"
+#include "third_party/WebKit/public/platform/WebSize.h"
 #include "third_party/WebKit/public/platform/modules/mediasession/WebMediaMetadata.h"
 
 namespace content {
@@ -42,6 +44,17 @@
     metadata.title = web_metadata->title;
     metadata.artist = web_metadata->artist;
     metadata.album = web_metadata->album;
+    for (const auto& web_artwork : web_metadata->artwork) {
+      MediaMetadata::Artwork artwork;
+      artwork.src = GURL(base::string16(web_artwork.src));
+      artwork.type = web_artwork.type;
+      blink::WebVector<blink::WebSize> web_sizes =
+          blink::WebIconSizesParser::parseIconSizes(web_artwork.sizes);
+      artwork.sizes.insert(artwork.sizes.end(),
+                           web_sizes.begin(),
+                           web_sizes.end());
+      metadata.artwork.push_back(artwork);
+    }
   }
 
   session_manager_->SetMetadata(media_session_id_, metadata);
diff --git a/content/renderer/media/gpu/rtc_video_decoder.cc b/content/renderer/media/gpu/rtc_video_decoder.cc
index 1729882..78528311 100644
--- a/content/renderer/media/gpu/rtc_video_decoder.cc
+++ b/content/renderer/media/gpu/rtc_video_decoder.cc
@@ -35,7 +35,14 @@
 const int32_t RTCVideoDecoder::ID_LAST = 0x3FFFFFFF;
 const int32_t RTCVideoDecoder::ID_HALF = 0x20000000;
 const int32_t RTCVideoDecoder::ID_INVALID = -1;
+
+// Android vp8, vp9 decoders are quite finicky and often out of date, so give
+// them much less leeway on errors than other platforms.
+#if defined(OS_ANDROID)
+const uint32_t kNumVDAErrorsBeforeSWFallback = 5;
+#else
 const uint32_t kNumVDAErrorsBeforeSWFallback = 50;
+#endif
 
 // Maximum number of concurrent VDA::Decode() operations RVD will maintain.
 // Higher values allow better pipelining in the GPU, but also require more
diff --git a/content/renderer/media/gpu/rtc_video_encoder_factory.cc b/content/renderer/media/gpu/rtc_video_encoder_factory.cc
index 9295464..6734d45 100644
--- a/content/renderer/media/gpu/rtc_video_encoder_factory.cc
+++ b/content/renderer/media/gpu/rtc_video_encoder_factory.cc
@@ -33,13 +33,18 @@
         webrtc::kVideoCodecVP8, "VP8", width, height, fps));
   } else if (profile.profile >= media::H264PROFILE_MIN &&
              profile.profile <= media::H264PROFILE_MAX) {
-    bool webrtc_h264_enabled = false;
-#if BUILDFLAG(RTC_USE_H264) && defined(OS_MACOSX)
-    webrtc_h264_enabled =
+    // Enable H264 HW encode for WebRTC when SW fallback is available, which is
+    // checked by kWebRtcH264WithOpenH264FFmpeg flag. This check should be
+    // removed when SW implementation is fully enabled.
+    // kEnableWebRtcHWH264Encoding flag is only enabled for extensions, and
+    // can be used without SW fallback.
+    bool webrtc_h264_sw_enabled = false;
+#if BUILDFLAG(RTC_USE_H264)
+    webrtc_h264_sw_enabled =
         base::FeatureList::IsEnabled(kWebRtcH264WithOpenH264FFmpeg);
-#endif  // BUILDFLAG(RTC_USE_H264) && defined(OS_MACOSX)
+#endif  // BUILDFLAG(RTC_USE_H264)
     if (cmd_line->HasSwitch(switches::kEnableWebRtcHWH264Encoding) ||
-        webrtc_h264_enabled) {
+        webrtc_h264_sw_enabled) {
       codecs->push_back(cricket::WebRtcVideoEncoderFactory::VideoCodec(
           webrtc::kVideoCodecH264, "H264", width, height, fps));
     }
diff --git a/content/renderer/media/media_stream_audio_processor_unittest.cc b/content/renderer/media/media_stream_audio_processor_unittest.cc
index 0b5e138e..2b96d745 100644
--- a/content/renderer/media/media_stream_audio_processor_unittest.cc
+++ b/content/renderer/media/media_stream_audio_processor_unittest.cc
@@ -483,7 +483,7 @@
   base::MessageLoopForUI message_loop;
   scoped_refptr<AecDumpMessageFilter> aec_dump_message_filter_(
       new AecDumpMessageFilter(message_loop.task_runner(),
-                               message_loop.task_runner(), nullptr));
+                               message_loop.task_runner()));
 
   MockConstraintFactory constraint_factory;
   scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
diff --git a/content/renderer/media/mock_peer_connection_impl.h b/content/renderer/media/mock_peer_connection_impl.h
index da60d59..c6a1d19 100644
--- a/content/renderer/media/mock_peer_connection_impl.h
+++ b/content/renderer/media/mock_peer_connection_impl.h
@@ -62,6 +62,13 @@
     return PeerConnectionInterface::kIceGatheringNew;
   }
 
+  bool StartRtcEventLog(rtc::PlatformFile file,
+                        int64_t max_size_bytes) override {
+    NOTIMPLEMENTED();
+    return false;
+  }
+  void StopRtcEventLog() override { NOTIMPLEMENTED(); }
+
   MOCK_METHOD0(Close, void());
 
   const webrtc::SessionDescriptionInterface* local_description() const override;
diff --git a/content/renderer/media/peer_connection_tracker.cc b/content/renderer/media/peer_connection_tracker.cc
index efeb029e..c76674b 100644
--- a/content/renderer/media/peer_connection_tracker.cc
+++ b/content/renderer/media/peer_connection_tracker.cc
@@ -343,6 +343,8 @@
   IPC_BEGIN_MESSAGE_MAP(PeerConnectionTracker, message)
     IPC_MESSAGE_HANDLER(PeerConnectionTracker_GetAllStats, OnGetAllStats)
     IPC_MESSAGE_HANDLER(PeerConnectionTracker_OnSuspend, OnSuspend)
+    IPC_MESSAGE_HANDLER(PeerConnectionTracker_StartEventLog, OnStartEventLog)
+    IPC_MESSAGE_HANDLER(PeerConnectionTracker_StopEventLog, OnStopEventLog)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -380,6 +382,36 @@
   }
 }
 
+void PeerConnectionTracker::OnStartEventLog(int peer_connection_id,
+                                            IPC::PlatformFileForTransit file) {
+  DCHECK(main_thread_.CalledOnValidThread());
+  for (auto& it : peer_connection_id_map_) {
+    if (it.second == peer_connection_id) {
+#if defined(OS_ANDROID)
+      // A lower maximum filesize is used on Android because storage space is
+      // more scarce on mobile. This upper limit applies to each peerconnection
+      // individually, so the total amount of used storage can be a multiple of
+      // this.
+      const int64_t kMaxFilesizeBytes = 10000000;
+#else
+      const int64_t kMaxFilesizeBytes = 60000000;
+#endif
+      it.first->StartEventLog(file, kMaxFilesizeBytes);
+      return;
+    }
+  }
+}
+
+void PeerConnectionTracker::OnStopEventLog(int peer_connection_id) {
+  DCHECK(main_thread_.CalledOnValidThread());
+  for (auto& it : peer_connection_id_map_) {
+    if (it.second == peer_connection_id) {
+      it.first->StopEventLog();
+      return;
+    }
+  }
+}
+
 void PeerConnectionTracker::RegisterPeerConnection(
     RTCPeerConnectionHandler* pc_handler,
     const webrtc::PeerConnectionInterface::RTCConfiguration& config,
diff --git a/content/renderer/media/peer_connection_tracker.h b/content/renderer/media/peer_connection_tracker.h
index 679ca45..6cc19999 100644
--- a/content/renderer/media/peer_connection_tracker.h
+++ b/content/renderer/media/peer_connection_tracker.h
@@ -12,6 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
 #include "content/public/renderer/render_thread_observer.h"
+#include "ipc/ipc_platform_file.h"
 #include "third_party/WebKit/public/platform/WebMediaStream.h"
 #include "third_party/WebKit/public/platform/WebRTCPeerConnectionHandlerClient.h"
 #include "third_party/WebKit/public/platform/WebRTCSessionDescription.h"
@@ -186,6 +187,13 @@
   // Called when the browser process reports a suspend event from the OS.
   void OnSuspend();
 
+  // IPC Message handler for starting event log.
+  void OnStartEventLog(int peer_connection_id,
+                       IPC::PlatformFileForTransit file);
+
+  // IPC Message handler for stopping event log.
+  void OnStopEventLog(int peer_connection_id);
+
   // Called to deliver an update to the host (PeerConnectionTrackerHost).
   // |local_id| - The id of the registered RTCPeerConnectionHandler.
   //              Using an id instead of the hander pointer is done on purpose
diff --git a/content/renderer/media/rtc_peer_connection_handler.cc b/content/renderer/media/rtc_peer_connection_handler.cc
index 361948c..fcf1b82 100644
--- a/content/renderer/media/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/rtc_peer_connection_handler.cc
@@ -1437,6 +1437,19 @@
     client_->closePeerConnection();
 }
 
+void RTCPeerConnectionHandler::StartEventLog(IPC::PlatformFileForTransit file,
+                                             int64_t max_file_size_bytes) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(file != IPC::InvalidPlatformFileForTransit());
+  native_peer_connection_->StartRtcEventLog(
+      IPC::PlatformFileForTransitToPlatformFile(file), max_file_size_bytes);
+}
+
+void RTCPeerConnectionHandler::StopEventLog() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  native_peer_connection_->StopRtcEventLog();
+}
+
 blink::WebRTCDataChannelHandler* RTCPeerConnectionHandler::createDataChannel(
     const blink::WebString& label, const blink::WebRTCDataChannelInit& init) {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/content/renderer/media/rtc_peer_connection_handler.h b/content/renderer/media/rtc_peer_connection_handler.h
index 04941df..93ad683 100644
--- a/content/renderer/media/rtc_peer_connection_handler.h
+++ b/content/renderer/media/rtc_peer_connection_handler.h
@@ -20,6 +20,7 @@
 #include "base/threading/thread_checker.h"
 #include "content/common/content_export.h"
 #include "content/renderer/media/webrtc/media_stream_track_metrics.h"
+#include "ipc/ipc_platform_file.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
 #include "third_party/WebKit/public/platform/WebRTCPeerConnectionHandler.h"
 #include "third_party/WebKit/public/platform/WebRTCStatsRequest.h"
@@ -168,6 +169,12 @@
   // Tells the |client_| to close RTCPeerConnection.
   void CloseClientPeerConnection();
 
+  // Start recording an event log.
+  void StartEventLog(IPC::PlatformFileForTransit file,
+                     int64_t max_file_size_bytes);
+  // Stop recording an event log.
+  void StopEventLog();
+
  protected:
   webrtc::PeerConnectionInterface* native_peer_connection() {
     return native_peer_connection_.get();
diff --git a/content/renderer/media/webmediaplayer_ms.cc b/content/renderer/media/webmediaplayer_ms.cc
index b03fedd..d437247 100644
--- a/content/renderer/media/webmediaplayer_ms.cc
+++ b/content/renderer/media/webmediaplayer_ms.cc
@@ -152,8 +152,8 @@
   }
   if (video_frame_provider_)
     video_frame_provider_->Start();
-  if (audio_renderer_) {
-    // Do not wait for first video frame to start playing
+  if (audio_renderer_ && !video_frame_provider_) {
+    // This is audio-only mode.
     SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
     SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
   }
@@ -488,10 +488,8 @@
 
   if (!received_first_frame_) {
     received_first_frame_ = true;
-    if (getReadyState() < WebMediaPlayer::ReadyStateHaveEnoughData) {
-      SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
-      SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
-    }
+    SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
+    SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
 
     if (video_frame_provider_.get()) {
       video_weblayer_.reset(new cc_blink::WebLayerImpl(
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
index 631ea1c4..4e9da8b9 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
@@ -453,15 +453,6 @@
   return webrtc::CreateIceCandidate(sdp_mid, sdp_mline_index, sdp, nullptr);
 }
 
-bool PeerConnectionDependencyFactory::StartRtcEventLog(
-    base::PlatformFile file) {
-  return GetPcFactory()->StartRtcEventLog(file);
-}
-
-void PeerConnectionDependencyFactory::StopRtcEventLog() {
-  GetPcFactory()->StopRtcEventLog();
-}
-
 WebRtcAudioDeviceImpl*
 PeerConnectionDependencyFactory::GetWebRtcAudioDevice() {
   DCHECK(CalledOnValidThread());
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.h b/content/renderer/media/webrtc/peer_connection_dependency_factory.h
index fc69d22..0486380 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.h
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.h
@@ -108,12 +108,6 @@
       int sdp_mline_index,
       const std::string& sdp);
 
-  // Starts recording an RTC event log.
-  virtual bool StartRtcEventLog(base::PlatformFile file);
-
-  // Starts recording an RTC event log.
-  virtual void StopRtcEventLog();
-
   WebRtcAudioDeviceImpl* GetWebRtcAudioDevice();
 
   void EnsureInitialized();
diff --git a/content/renderer/media/webrtc_local_audio_source_provider.cc b/content/renderer/media/webrtc_local_audio_source_provider.cc
index af46501..72166ddb 100644
--- a/content/renderer/media/webrtc_local_audio_source_provider.cc
+++ b/content/renderer/media/webrtc_local_audio_source_provider.cc
@@ -5,11 +5,13 @@
 #include "content/renderer/media/webrtc_local_audio_source_provider.h"
 
 #include "base/logging.h"
-#include "content/renderer/render_thread_impl.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/renderer/media/audio_device_factory.h"
 #include "media/base/audio_fifo.h"
-#include "media/base/audio_hardware_config.h"
 #include "media/base/audio_parameters.h"
 #include "third_party/WebKit/public/platform/WebAudioSourceProviderClient.h"
+#include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
 
 using blink::WebVector;
 
@@ -28,17 +30,21 @@
       track_(track),
       track_stopped_(false) {
   // Get the native audio output hardware sample-rate for the sink.
-  // We need to check if RenderThreadImpl is valid here since the unittests
+  // We need to check if there is a valid frame since the unittests
   // do not have one and they will inject their own |sink_params_| for testing.
-  if (RenderThreadImpl::current()) {
-    media::AudioHardwareConfig* hardware_config =
-        RenderThreadImpl::current()->GetAudioHardwareConfig();
-    int sample_rate = hardware_config->GetOutputSampleRate();
+  blink::WebLocalFrame* const web_frame =
+      blink::WebLocalFrame::frameForCurrentContext();
+  RenderFrame* const render_frame = RenderFrame::FromWebFrame(web_frame);
+  if (render_frame) {
+    int sample_rate = AudioDeviceFactory::GetOutputDeviceInfo(
+                          render_frame->GetRoutingID(), 0, std::string(),
+                          web_frame->getSecurityOrigin())
+                          .output_params()
+                          .sample_rate();
     sink_params_.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
                        media::CHANNEL_LAYOUT_STEREO, sample_rate, 16,
                        kWebAudioRenderBufferSize);
   }
-
   // Connect the source provider to the track as a sink.
   MediaStreamAudioSink::AddToAudioTrack(this, track_);
 }
diff --git a/content/renderer/p2p/ipc_socket_factory.cc b/content/renderer/p2p/ipc_socket_factory.cc
index e0d93d34..4563aa3 100644
--- a/content/renderer/p2p/ipc_socket_factory.cc
+++ b/content/renderer/p2p/ipc_socket_factory.cc
@@ -10,13 +10,14 @@
 #include <list>
 
 #include "base/compiler_specific.h"
+#include "base/logging.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/non_thread_safe.h"
+#include "base/threading/thread_checker.h"
 #include "base/trace_event/trace_event.h"
 #include "content/renderer/media/webrtc_logging.h"
 #include "content/renderer/p2p/host_address_request.h"
@@ -155,8 +156,8 @@
 
   P2PSocketType type_;
 
-  // Message loop on which this socket was created and being used.
-  base::MessageLoop* message_loop_;
+  // Used to verify that a method runs on the thread that created this socket.
+  base::ThreadChecker thread_checker_;
 
   // Corresponding P2P socket client.
   scoped_refptr<P2PSocketClient> client_;
@@ -232,7 +233,6 @@
 
 IpcPacketSocket::IpcPacketSocket()
     : type_(P2P_SOCKET_UDP),
-      message_loop_(base::MessageLoop::current()),
       state_(IS_UNINITIALIZED),
       send_bytes_available_(kMaximumInFlightBytes),
       writable_signal_expected_(false),
@@ -293,7 +293,7 @@
                            P2PSocketClientImpl* client,
                            const rtc::SocketAddress& local_address,
                            const rtc::SocketAddress& remote_address) {
-  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK_EQ(state_, IS_UNINITIALIZED);
 
   type_ = type;
@@ -341,7 +341,7 @@
     P2PSocketClient* client,
     const rtc::SocketAddress& local_address,
     const rtc::SocketAddress& remote_address) {
-  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK_EQ(state_, IS_UNINITIALIZED);
 
   client_ = client;
@@ -354,25 +354,25 @@
 
 // rtc::AsyncPacketSocket interface.
 rtc::SocketAddress IpcPacketSocket::GetLocalAddress() const {
-  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+  DCHECK(thread_checker_.CalledOnValidThread());
   return local_address_;
 }
 
 rtc::SocketAddress IpcPacketSocket::GetRemoteAddress() const {
-  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+  DCHECK(thread_checker_.CalledOnValidThread());
   return remote_address_;
 }
 
 int IpcPacketSocket::Send(const void *data, size_t data_size,
                           const rtc::PacketOptions& options) {
-  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+  DCHECK(thread_checker_.CalledOnValidThread());
   return SendTo(data, data_size, remote_address_, options);
 }
 
 int IpcPacketSocket::SendTo(const void *data, size_t data_size,
                             const rtc::SocketAddress& address,
                             const rtc::PacketOptions& options) {
-  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   switch (state_) {
     case IS_UNINITIALIZED:
@@ -453,7 +453,7 @@
 }
 
 int IpcPacketSocket::Close() {
-  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   client_->Close();
   state_ = IS_CLOSED;
@@ -462,7 +462,7 @@
 }
 
 rtc::AsyncPacketSocket::State IpcPacketSocket::GetState() const {
-  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   switch (state_) {
     case IS_UNINITIALIZED:
@@ -500,7 +500,7 @@
 }
 
 int IpcPacketSocket::SetOption(rtc::Socket::Option option, int value) {
-  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   P2PSocketOption p2p_socket_option = P2P_SOCKET_OPT_MAX;
   if (!JingleSocketOptionToP2PSocketOption(option, &p2p_socket_option)) {
@@ -518,7 +518,7 @@
 }
 
 int IpcPacketSocket::DoSetOption(P2PSocketOption option, int value) {
-  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+  DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK_EQ(state_, IS_OPEN);
 
   client_->SetOption(option, value);
@@ -526,18 +526,18 @@
 }
 
 int IpcPacketSocket::GetError() const {
-  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+  DCHECK(thread_checker_.CalledOnValidThread());
   return error_;
 }
 
 void IpcPacketSocket::SetError(int error) {
-  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+  DCHECK(thread_checker_.CalledOnValidThread());
   error_ = error;
 }
 
 void IpcPacketSocket::OnOpen(const net::IPEndPoint& local_address,
                              const net::IPEndPoint& remote_address) {
-  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   if (!jingle_glue::IPEndPointToSocketAddress(local_address, &local_address_)) {
     // Always expect correct IPv4 address to be allocated.
@@ -581,7 +581,7 @@
 void IpcPacketSocket::OnIncomingTcpConnection(
     const net::IPEndPoint& address,
     P2PSocketClient* client) {
-  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   std::unique_ptr<IpcPacketSocket> socket(new IpcPacketSocket());
 
@@ -595,7 +595,7 @@
 }
 
 void IpcPacketSocket::OnSendComplete(const P2PSendPacketMetrics& send_metrics) {
-  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   CHECK(!in_flight_packet_records_.empty());
 
@@ -632,7 +632,7 @@
 }
 
 void IpcPacketSocket::OnError() {
-  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+  DCHECK(thread_checker_.CalledOnValidThread());
   bool was_closed = (state_ == IS_ERROR || state_ == IS_CLOSED);
   state_ = IS_ERROR;
   error_ = ECONNABORTED;
@@ -644,7 +644,7 @@
 void IpcPacketSocket::OnDataReceived(const net::IPEndPoint& address,
                                      const std::vector<char>& data,
                                      const base::TimeTicks& timestamp) {
-  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
+  DCHECK(thread_checker_.CalledOnValidThread());
 
   rtc::SocketAddress address_lj;
 
diff --git a/content/renderer/pepper/ppb_graphics_3d_impl.cc b/content/renderer/pepper/ppb_graphics_3d_impl.cc
index 5e0b5f3..927d10b 100644
--- a/content/renderer/pepper/ppb_graphics_3d_impl.cc
+++ b/content/renderer/pepper/ppb_graphics_3d_impl.cc
@@ -18,6 +18,7 @@
 #include "content/renderer/pepper/plugin_module.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/render_view_impl.h"
+#include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
 #include "gpu/ipc/client/command_buffer_proxy_impl.h"
 #include "gpu/ipc/client/gpu_channel_host.h"
@@ -44,7 +45,18 @@
       bound_to_instance_(false),
       commit_pending_(false),
       has_alpha_(false),
-      weak_ptr_factory_(this) {}
+      use_image_chromium_(false),
+      weak_ptr_factory_(this) {
+#if defined(OS_MACOSX)
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  bool use_image_chromium =
+      !command_line->HasSwitch(switches::kDisablePepper3DImageChromium);
+  use_image_chromium_ = use_image_chromium;
+
+  // TODO(erikchen): Remove this line to enable the feature.
+  use_image_chromium_ = false;
+#endif
+}
 
 PPB_Graphics3D_Impl::~PPB_Graphics3D_Impl() {
   // Unset the client before the command_buffer_ is destroyed, similar to how
@@ -158,7 +170,9 @@
   return command_buffer_.get();
 }
 
-int32_t PPB_Graphics3D_Impl::DoSwapBuffers(const gpu::SyncToken& sync_token) {
+int32_t PPB_Graphics3D_Impl::DoSwapBuffers(const gpu::SyncToken& sync_token,
+                                           int32_t width,
+                                           int32_t height) {
   DCHECK(command_buffer_);
   if (taken_front_buffer_.IsZero()) {
     DLOG(ERROR) << "TakeFrontBuffer should be called before DoSwapBuffers";
@@ -173,8 +187,16 @@
     //
     // Don't need to check for NULL from GetPluginInstance since when we're
     // bound, we know our instance is valid.
-    cc::TextureMailbox texture_mailbox(taken_front_buffer_, sync_token,
-                                       GL_TEXTURE_2D);
+    if (width < 0 || height < 0) {
+      width = original_width_;
+      height = original_height_;
+    }
+    bool is_overlay_candidate = use_image_chromium_;
+    GLenum target =
+        is_overlay_candidate ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D;
+    cc::TextureMailbox texture_mailbox(taken_front_buffer_, sync_token, target,
+                                       gfx::Size(width, height),
+                                       is_overlay_candidate, false);
     taken_front_buffer_.SetZero();
     HostGlobals::Get()
         ->GetInstance(pp_instance())
@@ -260,6 +282,7 @@
   }
   if (!attrib_helper.Parse(attribs))
     return false;
+  attrib_helper.should_use_native_gmb_for_backbuffer = use_image_chromium_;
 
   gpu::CommandBufferProxyImpl* share_buffer = NULL;
   if (share_context) {
@@ -272,6 +295,8 @@
       std::move(channel), gpu::kNullSurfaceHandle, share_buffer,
       gpu::GPU_STREAM_DEFAULT, gpu::GpuStreamPriority::NORMAL, attrib_helper,
       GURL::EmptyGURL(), base::ThreadTaskRunnerHandle::Get());
+  original_width_ = attrib_helper.offscreen_framebuffer_size.width();
+  original_height_ = attrib_helper.offscreen_framebuffer_size.height();
   if (!command_buffer_)
     return false;
 
diff --git a/content/renderer/pepper/ppb_graphics_3d_impl.h b/content/renderer/pepper/ppb_graphics_3d_impl.h
index abafd2c..5d926ec1 100644
--- a/content/renderer/pepper/ppb_graphics_3d_impl.h
+++ b/content/renderer/pepper/ppb_graphics_3d_impl.h
@@ -70,7 +70,9 @@
   // ppapi::PPB_Graphics3D_Shared overrides.
   gpu::CommandBuffer* GetCommandBuffer() override;
   gpu::GpuControl* GetGpuControl() override;
-  int32_t DoSwapBuffers(const gpu::SyncToken& sync_token) override;
+  int32_t DoSwapBuffers(const gpu::SyncToken& sync_token,
+                        int32_t width,
+                        int32_t height) override;
 
  private:
   explicit PPB_Graphics3D_Impl(PP_Instance instance);
@@ -110,7 +112,14 @@
   bool lost_context_ = false;
 #endif
 
+  // The width and height of the command buffer back buffer are first sized from
+  // this process, but then resized by the pepper process. Cache the original
+  // size.
+  int32_t original_width_ = 0;
+  int32_t original_height_ = 0;
+
   bool has_alpha_;
+  bool use_image_chromium_;
   std::unique_ptr<gpu::CommandBufferProxyImpl> command_buffer_;
 
   base::WeakPtrFactory<PPB_Graphics3D_Impl> weak_ptr_factory_;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 304c589e..0845883 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -692,8 +692,7 @@
       new PeerConnectionDependencyFactory(p2p_socket_dispatcher_.get()));
 
   aec_dump_message_filter_ = new AecDumpMessageFilter(
-      GetIOMessageLoopProxy(), message_loop()->task_runner(),
-      peer_connection_factory_.get());
+      GetIOMessageLoopProxy(), message_loop()->task_runner());
 
   AddFilter(aec_dump_message_filter_.get());
 
@@ -2057,7 +2056,7 @@
 
 scoped_refptr<base::SingleThreadTaskRunner>
 RenderThreadImpl::GetFileThreadMessageLoopProxy() {
-  DCHECK(message_loop() == base::MessageLoop::current());
+  DCHECK(message_loop()->task_runner()->BelongsToCurrentThread());
   if (!file_thread_) {
     file_thread_.reset(new base::Thread("Renderer::FILE"));
     file_thread_->Start();
@@ -2067,7 +2066,7 @@
 
 scoped_refptr<base::SingleThreadTaskRunner>
 RenderThreadImpl::GetMediaThreadTaskRunner() {
-  DCHECK(message_loop() == base::MessageLoop::current());
+  DCHECK(message_loop()->task_runner()->BelongsToCurrentThread());
   if (!media_thread_) {
     media_thread_.reset(new base::Thread("Media"));
     media_thread_->Start();
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index 57747020..91080b1 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -1900,7 +1900,6 @@
 #endif
 TEST_F(RendererErrorPageTest, MAYBE_HttpStatusCodeErrorWithEmptyBody) {
   blink::WebURLResponse response;
-  response.initialize();
   response.setHTTPStatusCode(503);
   WebLocalFrame* web_frame = GetMainFrame();
 
diff --git a/content/shell/browser/shell_devtools_manager_delegate.cc b/content/shell/browser/shell_devtools_manager_delegate.cc
index c360d97..9361e9a5 100644
--- a/content/shell/browser/shell_devtools_manager_delegate.cc
+++ b/content/shell/browser/shell_devtools_manager_delegate.cc
@@ -229,8 +229,11 @@
 
 base::DictionaryValue* ShellDevToolsManagerDelegate::HandleCommand(
     DevToolsAgentHost* agent_host,
-    base::DictionaryValue* command) {
-  return NULL;
+    base::DictionaryValue* command_dict) {
+  std::unique_ptr<base::DictionaryValue> result =
+      devtools_discovery::DevToolsDiscoveryManager::GetInstance()
+          ->HandleNewTargetCommand(command_dict);
+  return result.release();  // Caller takes ownership.
 }
 
 }  // namespace content
diff --git a/content/shell/renderer/layout_test/blink_test_runner.cc b/content/shell/renderer/layout_test/blink_test_runner.cc
index 327d40d..d40068a 100644
--- a/content/shell/renderer/layout_test/blink_test_runner.cc
+++ b/content/shell/renderer/layout_test/blink_test_runner.cc
@@ -64,6 +64,7 @@
 #include "third_party/WebKit/public/platform/Platform.h"
 #include "third_party/WebKit/public/platform/WebPoint.h"
 #include "third_party/WebKit/public/platform/WebRect.h"
+#include "third_party/WebKit/public/platform/WebSecurityOrigin.h"
 #include "third_party/WebKit/public/platform/WebSize.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebTaskRunner.h"
@@ -982,8 +983,9 @@
   Reset(true /* for_new_test */);
   // Navigating to about:blank will make sure that no new loads are initiated
   // by the renderer.
-  render_view()->GetWebView()->mainFrame()->loadRequest(
-      WebURLRequest(GURL(url::kAboutBlankURL)));
+  WebURLRequest request = WebURLRequest(GURL(url::kAboutBlankURL));
+  request.setRequestorOrigin(blink::WebSecurityOrigin::createUnique());
+  render_view()->GetWebView()->mainFrame()->loadRequest(request);
   Send(new ShellViewHostMsg_ResetDone(routing_id()));
 }
 
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index d84f743..bab905c 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -928,4 +928,5 @@
     ":test_support",
     "//content/shell:content_shell_lib",
   ]
+  dict = "data/fuzzer_dictionaries/renderer_fuzzer.dict"
 }
diff --git a/content/test/data/fuzzer_dictionaries/renderer_fuzzer.dict b/content/test/data/fuzzer_dictionaries/renderer_fuzzer.dict
new file mode 100644
index 0000000..5fd1dc44
--- /dev/null
+++ b/content/test/data/fuzzer_dictionaries/renderer_fuzzer.dict
@@ -0,0 +1,2079 @@
+# 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.
+
+# This file has been generated with testing/libfuzzer/dictionary_generator.py
+# using renderer_fuzzer binary and RFC 1866.
+"limited"
+"all"
+"consider"
+"forbidden"
+"lack"
+"aring"
+"GRPGTCNT"
+"four"
+"prefix"
+"consists"
+"follow"
+"integrity"
+"REV=...>"
+"whose"
+"2.0//EN'"
+"2.0//EN\""
+"(for"
+"NUMERIC"
+"Heading"
+"to"
+"tail"
+"Western"
+"TAB"
+"TEXT"
+"ACTION"
+"Oacute"
+"presentation"
+"(STD"
+"COMPACT"
+"returned"
+"Keyword"
+"</BODY></HTML>"
+"far"
+"activation"
+"(URI),"
+"splitting"
+"cedil"
+"handling"
+"updates"
+"N=Z27>"
+"[MIME])"
+"2//EN\""
+"<LINK>"
+"1//EN\">"
+"(IRV)//ESC"
+"Reference"
+"WIDTH"
+"--"
+"cause"
+"(`</DT>'),"
+"list"
+"present."
+"present,"
+"large"
+"contexts"
+"TYPE=TEXT"
+"TYPE=SUBMIT>"
+"small"
+"->"
+"ASCII"
+"heading"
+"allowed:"
+"[IMEDIA]."
+"direction."
+"Otilde"
+"tag:"
+"Number"
+"translating"
+"second"
+"Version"
+"allowed."
+"query"
+"tag."
+"implemented"
+"even"
+"material"
+"errors"
+"MINIMIZE"
+"EMPTY>"
+"specification"
+"selected"
+"contributed"
+"nested."
+"KBD"
+"decoding"
+"characters."
+"characters,"
+"item."
+"above"
+"new"
+"method"
+"edited"
+"full"
+"escaping"
+"(aka"
+"&#9;"
+"WWW."
+"THORN"
+"\"SDAPREF"
+"component"
+"here"
+"According"
+"H1)"
+"(SDA)"
+"General"
+"represented"
+"100"
+"strong"
+"placeholder"
+"WWW:"
+"obtained"
+"UNUSED"
+"Aring"
+"646:1983//CHARSET"
+"-(A)>"
+"items"
+"[RELURL]."
+"allows"
+"monospaced"
+"CONTROLS"
+"PUBLIC"
+"prior"
+"amount"
+"Agrave"
+"METHOD=POST\"."
+"action"
+"suitable"
+"iuml"
+"SEPCHAR"
+"</OL>"
+"via"
+"Group"
+"divide"
+"family"
+"Support"
+"REV"
+"replace"
+"C.,"
+"visible"
+"\"H6\""
+"MULTIPLE>"
+"REL"
+"Basic"
+"support"
+"ICADD"
+"select"
+"Elements"
+"CAPACITY"
+"takes"
+"would"
+"distinct"
+"beginning"
+"used:"
+"contains"
+"June"
+"two"
+"ACTION=\"...\">"
+"UCNMCHAR"
+"9]"
+"Block"
+"6"
+"HTML\")"
+"DOCUMENT"
+"type"
+"HTML\"."
+"used."
+"more"
+"`GET'."
+"successful"
+"level,"
+"`MIDDLE'"
+"ENTCAP"
+"text,"
+"`TYPE=IMAGE'"
+"icirc"
+"..."
+"known"
+"Representation"
+"documents."
+"Uniform"
+"<DIR"
+"<input"
+"must"
+"parse"
+"none"
+"word"
+"SCOPE"
+"Strict"
+"Text"
+"work"
+"doctype"
+"<STRIKE>"
+"paragraph"
+"indicating"
+"(`</P>'),"
+"example"
+"def"
+"history"
+"type,"
+"type."
+"\"BLOCKQUOTE\">"
+"CHARSET"
+"table"
+"1//EN\""
+"accept"
+"currency"
+"</SELECT>"
+"interpreted"
+"sharp"
+"unordered"
+"simple"
+"absolute"
+"LF"
+"information"
+"end"
+"`METHOD=GET'."
+"quot"
+"provide"
+"\"H4\""
+"breaking"
+"feature"
+"LI"
+"how"
+"<DT>"
+"<OPTION>"
+"A"
+"HEAD"
+"description"
+"FORM"
+"Ccedil"
+"typed"
+"number,"
+"earlier"
+"List"
+"mapping"
+"reflect"
+"catalog"
+"OTHER"
+"horizontal"
+"SYNTAX"
+"response"
+"types"
+"a"
+"&#13;"
+"short"
+"attempt"
+"SUBDOC"
+"third"
+"sets"
+"(HREF)>\""
+"U.S.A."
+"documentation"
+"MENU"
+")"
+"maintain"
+"Comma"
+"sect"
+"HTTP-EQUIV"
+"map:"
+"BASE?"
+"order"
+"oacute"
+"checkbox"
+"Imported"
+"help"
+"<!SGML"
+"ograve"
+"over"
+"vary"
+"installed"
+"circumflex"
+"\"REL"
+"through"
+"<html>"
+"`<BLOCKQUOTE>',"
+"its"
+"\\-EM"
+"before"
+"PRE"
+"25"
+"style"
+"March"
+"21"
+"fit"
+"[IMEDIA]"
+"28"
+"otilde"
+"2:"
+"writing"
+"L.,"
+"parts"
+"font,"
+"font."
+"2,"
+"hidden"
+"might"
+"</DL>"
+"then"
+"them"
+"good"
+"</UL>"
+"combination"
+"fragment"
+"2]"
+"URN"
+"URI"
+"number"
+"break"
+"9"
+"effects"
+"they"
+"nested"
+"finite"
+"grammar"
+"\"ISO"
+"cell"
+"Permission"
+"2//EN\">"
+"acirc"
+"micro"
+"token"
+"each"
+"types."
+"<BODY>"
+"Content-Type"
+"Check"
+"referred"
+"ordinal"
+"<B>"
+"schemes"
+"Specification"
+"reduce"
+"numeric"
+"szlig"
+"<P>"
+"CERN</ADDRESS>"
+"Handling"
+"HTTP/1.0\","
+"combining"
+"<H5>"
+"TAGLVL"
+"Entity"
+"Type"
+"message"
+"COLS=64>"
+"is:"
+"PILEN"
+"network"
+"since"
+"DL,"
+"content"
+"message."
+"(e.g.,"
+"#REQUIRED"
+"7"
+"print"
+"plusmn"
+"H3),"
+"EM"
+"HTML+"
+"University"
+"ICADD22//EN\"."
+"given"
+"standard"
+"base"
+"\"SDA\""
+"put"
+"POST"
+"Registration"
+"Soft"
+"generate"
+"scheme."
+"Superscript"
+"conform"
+"definition"
+"pairs"
+"</ADDRESS>"
+"<TT>"
+"created"
+"September"
+"starts"
+"(URL)\","
+"Its"
+"MIT"
+"`HEAD'"
+"BASESET"
+"signature"
+"HIDDEN"
+"`ISO-2022-JP'"
+"+="
+"user"
+"[URL];"
+"features"
+"render"
+"encoding"
+"*"
+"Please"
+"token."
+"LCNMSTRT"
+"Maps"
+"CODE"
+"construct"
+"another"
+"blank"
+"SRC"
+"NAMING"
+"\""
+"service"
+"their"
+"leading"
+"top"
+"least"
+"ignored."
+"too"
+"passed"
+"scheme"
+"listed"
+"B"
+"option"
+"Language"
+"instance."
+"tokens"
+"part"
+"selected."
+"feature."
+"translation"
+"DTD"
+"information."
+"information,"
+"#FIXED\""
+"begins"
+"<!ENTITY"
+"Set"
+"Consider"
+"body."
+"double"
+"instruction"
+"tree"
+"zero"
+"<HEAD>"
+"See"
+"determined"
+"similar"
+"treated"
+"minus"
+"Exclamation"
+"ISMAP>"
+"navigate"
+"<CITE>"
+"-->"
+"A.8,"
+"(<PRE>,"
+"METHOD=GET"
+"null"
+"TYPE=...>"
+"contents"
+"(MULTIPLE)"
+"data,"
+"data."
+"providers"
+"on,"
+"TYPE=SUBMIT"
+"Uacute"
+"-(INPUT|SELECT|TEXTAREA)>"
+"-"
+"<BASE"
+"indexes"
+"also"
+"recommended"
+"internal"
+"window."
+"They"
+"7]"
+"brace"
+"CHECKED>"
+"content,"
+"play"
+"content."
+"macr"
+"supported."
+"quote"
+"newline"
+"ordm"
+"PLAINTEXT?\">"
+"most"
+"regular"
+"letter"
+"entry"
+"nothing"
+"The"
+"Charset"
+"[MIME]"
+"grave"
+"(e.g."
+"up"
+"clear"
+"flow"
+"Sample"
+"PLAINTEXT"
+"bracket"
+"\"-//IETF//DTD"
+"in-line"
+"(`</LI>'),"
+"parenthesis"
+"<CODE>"
+"If"
+"+"
+"dot"
+"\"MIME"
+"Caret"
+"THORN,"
+"BR\">"
+"SHUNCHAR"
+"syntax"
+"Ntilde"
+"radio"
+"Atilde"
+"font"
+"&#10;"
+"DESCSET"
+"European"
+"access"
+"</DIR>"
+"layout"
+"quoted"
+"copyright"
+"preformatted"
+"implementation"
+"menu"
+"explain"
+"yen"
+"Iuml"
+"<body>"
+"version"
+"specify"
+"Eacute"
+"<PRE"
+"METHOD"
+"columns"
+"resources."
+"(LI)+>"
+"etc.)"
+"notation"
+"wide"
+"capital"
+"preferred"
+"Variable"
+"Copyright"
+"ROWS"
+"<IMG>"
+"during"
+"body,"
+"bar"
+"Attributes"
+"fields"
+"01234<BR>"
+"public"
+"J."
+"protocols"
+"common"
+"Ucirc"
+"x"
+"<OL>"
+"Universal"
+"DTD\""
+"set"
+"mandatory"
+"Auml"
+"reference"
+"(underscore)"
+"Internet"
+"DTD,"
+"DTD."
+"\"INCLUDE\""
+"Entities"
+"depends"
+"individual"
+"1//EN//HTML\">"
+"result"
+"\\-BODY"
+"2.0"
+"TEXTAREA"
+"OMITTAG"
+"subject"
+"<EM>"
+"TYPE=PASSWORD"
+"iexcl"
+"GET"
+"Registered"
+"tags"
+"<IMG"
+"request:"
+"various"
+"atilde"
+"consecutive"
+"numerous"
+"preserve"
+"latin"
+"terms"
+"responses"
+"extend"
+"missing"
+"description."
+"modify"
+"ISOlat1"
+"<NEXTID"
+"identical"
+"`TYPE=SUBMIT'"
+"`METHOD=GET'"
+"ALIGN"
+"title."
+"interface"
+"news"
+"<MENU"
+"[SGML]"
+"both"
+"ALIGN=...>"
+"reverse"
+"hyperlink"
+"Ugrave"
+"N}"
+"context"
+"Query"
+"requests"
+"browser"
+"whole"
+"Compact"
+"LISTING\">"
+"Egrave"
+"(SGML)."
+"\"SGML"
+"point"
+"sign,"
+"Initial"
+"igrave"
+"Strict//EN\""
+"active"
+"[ISO-10646]"
+"),"
+"TYPE=CHECKBOX"
+"`TOP'"
+"ETH"
+"throughout"
+"Method"
+"SHORTREF"
+"described"
+"+(INPUT|SELECT|TEXTAREA)>"
+"Position"
+"Tags"
+"create"
+"Processing"
+"Oslash"
+"three"
+"been"
+"16]"
+"much"
+"non-breaking"
+"entered"
+"empty"
+"Quotation"
+"digits"
+"anchors"
+"agent."
+"search"
+"N"
+"understand"
+"CR"
+"XMP"
+"CT"
+"-(FORM)"
+"has"
+"NAME"
+"ccedil"
+"ROWS=...>"
+"1//EN//HTML\""
+"particular,"
+"while"
+"replaced"
+"behavior"
+"applies"
+"voice"
+"anchor"
+"1//EN."
+"City"
+"concurrently"
+"pound"
+"<DD>"
+"played"
+"Menu"
+"is"
+"character."
+"multi-line"
+"it"
+"(see"
+"HTML//EN\""
+"itself"
+"MIME"
+"in"
+"\\-</EM>"
+"mouse"
+"use:"
+"if"
+"containing"
+"\"H1|H2|H3|H4|H5|H6\">"
+"ISO/IEC"
+"baseline"
+":"
+"make"
+"H3."
+"\\-TITLE"
+"linked"
+"[URL].."
+"\"P"
+"<H1>"
+"widely"
+"Address"
+"modification"
+"several"
+"[ISO-8859-1],"
+"HTML\""
+"used"
+"Presentation"
+"[ISO-8859-1]."
+"HTML,"
+"HTML."
+"hand"
+"Item"
+"levels"
+"uses"
+"purpose"
+"characters"
+"<a"
+"along"
+"\">"
+"nickname"
+"NEXTID?\">"
+"recent"
+"lower"
+"Latin"
+"database"
+"Technology"
+"</a>"
+"items."
+"\"SDASUSP"
+"["
+"+(META|LINK)>"
+"Names"
+"<A"
+"y"
+"Table"
+"the"
+"left"
+"QUANTITY"
+"Status"
+"O,"
+"protocol"
+"proposed"
+"sentence"
+"HTML</TITLE>"
+"<UL"
+"MAXLENGTH"
+"%SDASUFF;"
+"quotes"
+"Permanent"
+"identify"
+"(OPTION+)"
+"tilde"
+"followed"
+"alternative"
+"yet"
+"alignment"
+"previous"
+"$"
+"(CHECKED)"
+"regarded"
+"BODY,"
+"character"
+"ideal"
+"source"
+"<P><INPUT"
+"input"
+"save"
+"---------"
+"transformation"
+"yacute"
+"Reset"
+"On"
+"usable"
+"Graphic"
+"format"
+"quote."
+"possible"
+"required."
+"URI:"
+"</HEAD><BODY>"
+"30"
+"integer"
+"bit"
+"formal"
+"[DEXTER]"
+"[IANA]"
+"OL"
+"TOTALCAP"
+"submission"
+"laquo"
+"signal"
+"Encoding"
+"specific"
+"destination"
+"<OPTION"
+"prologue"
+"security"
+"\\-</TITLE>"
+"right"
+"old"
+"methods"
+"truncated"
+"HR"
+"some"
+"<!ELEMENT"
+"HT"
+"Application"
+"added"
+"3.2"
+"Igrave"
+"Italic"
+"apply"
+"unless"
+"[ISO-10646]."
+"ignore"
+"and/or"
+"CONCUR"
+"for"
+"bottom"
+"REF"
+"[ISO-10646],"
+"LISTING\"."
+"comments"
+"<BR>"
+"<P"
+"Let"
+"Broken"
+"integer."
+"METHOD=POST"
+"8879-1986//ENTITIES"
+"be"
+"usage:"
+"bold"
+"example,"
+"no-break"
+"`CHECKED',"
+"<A>"
+"O"
+"\"IGNORE\">"
+"\"J&D\""
+"<STRONG>"
+"method."
+"<HTML>"
+"by"
+"SIZE"
+"Comment"
+"[ISO-10646];"
+"Square"
+"#IMPLIED"
+"Communications"
+"\"PRE"
+"H3"
+"Image"
+"H1"
+"UL,"
+"(DIR|MENU)"
+"H4"
+"H5"
+"range"
+"<MENU>"
+"plus"
+"ATTSPLEN"
+"value."
+"(HTML"
+"book"
+"block"
+"Use"
+"eth,"
+"-(META|LINK)>"
+"into"
+"within"
+"parsing"
+"rendering"
+"appropriate"
+"NET"
+"reducing"
+"file."
+"\\-<TITLE>"
+"often"
+"rows"
+"sup1"
+"sup2"
+"sup3"
+"question"
+"transform"
+"Lists"
+"behavior."
+"fields:"
+"width"
+"\"SDARULE"
+"CDATA,"
+"&lt;"
+"way"
+"Typewriter"
+"translate"
+"was"
+"(i.e."
+"PASSWORD"
+"teletype"
+"head"
+"form"
+"registered"
+"Declaration"
+"Most"
+"feminine"
+"state"
+"link"
+"UCNMSTRT"
+"atom"
+"encoded"
+"</PRE>"
+"Left"
+"reset"
+"[URI]"
+"Office"
+"Ograve"
+"Attribute"
+"inside"
+"declarations"
+"maximum"
+"...,"
+"META"
+"<INPUT>"
+"8-bit"
+"etc."
+"called"
+"Numeric"
+"(URN)"
+"150"
+"ordered"
+"semicolon"
+"computing"
+"Introduction"
+"Some"
+"specified"
+"influence"
+"NUMBER"
+"To"
+"single"
+"initial"
+"METHOD=GET\""
+"element,"
+"check"
+"element."
+"defines"
+"Euml"
+"%"
+"Iacute"
+"no"
+"Fragment"
+"TT"
+"when"
+"A,"
+"application"
+"role"
+"SHORTTAG"
+"undeclared"
+"test"
+"NAME=...>"
+"[ISO-646]"
+"Markup"
+"elements"
+"AE"
+"frac14"
+"Double"
+"asterisk"
+"aacute"
+"Definition"
+"T."
+"generated"
+"eacute"
+"\"H5\""
+"IMPLICIT"
+"structure"
+"<!--"
+"TITLE"
+"\"GET"
+"<SAMP>"
+"ending"
+"document,"
+"code:"
+"frac12"
+"`BOTTOM'"
+"pilcrow"
+"<DL>"
+"An"
+"NOTE"
+"As"
+"presenting"
+"time"
+"Open"
+"TAGLEN"
+"code,"
+"scroll"
+"others"
+"code"
+"Title"
+"SIMPLE"
+"skip"
+"global"
+"activated"
+"results"
+"\"H2\""
+"existing"
+"documents,"
+"BLOCKQUOTE"
+"Yacute"
+"100//CHARSET"
+"text;"
+"digits,"
+"ALT"
+"compact"
+"`GET'"
+"Bold"
+"TYPE=IMAGE"
+"[URL]"
+"name:"
+"\"HEAD,"
+"RCDATA"
+"Standard"
+"languages"
+"0"
+"does"
+"position."
+"Icirc"
+"masculine"
+"Not"
+"(code"
+"include"
+"resources"
+"(TITLE)"
+"string"
+"outside"
+"choice"
+"P"
+"Plus"
+"entries"
+"VAR"
+"Multiple"
+"AElig"
+"exact"
+"`%HH',"
+"entire"
+"resource."
+"Protocol"
+"immediately"
+"level"
+"mark,"
+"gender"
+"button"
+"SIZE=...>"
+"fewer"
+"standards"
+"leave"
+"item"
+"section"
+"Select"
+"prevent"
+"</FORM>"
+"SP"
+"HTTP"
+"3]"
+"(OL|UL)"
+"M."
+"discover"
+"sign"
+"[ISO-8859-1]"
+"CHECKBOX"
+"Orange"
+"<TEXTAREA>"
+"METHODS=\"...\">"
+"SELECT"
+"MIT/W3C"
+"index"
+"egrave"
+"set,"
+"appear"
+"Form"
+"giving"
+"ordf"
+"J.R."
+"EXPLICIT"
+"Public"
+"current"
+"ntilde"
+"HTML"
+"Link"
+"template"
+"large."
+"RADIO"
+"Line"
+"<LI>"
+"body"
+"C,"
+"<TEXTAREA>),"
+"processing"
+"submitted"
+"degree"
+"<BLOCKQUOTE>"
+"NCSA"
+"generic"
+"address"
+"ecirc"
+"Distribution"
+"implicit"
+"set."
+"box"
+"Selection"
+"MA"
+"parameters"
+"DT,"
+"32"
+"31"
+"larger"
+"36"
+"[ISO-646]."
+"delimiter"
+"resulting"
+"User"
+"........................................."
+"usually"
+"however,"
+"J.,"
+"navigation"
+"CONTENT=\"...\">"
+"named"
+"RFC1521)"
+"useful"
+"FEATURES"
+"extra"
+"URL"
+"MAXLENGTH=...>"
+"[SGML])."
+"</HEAD>"
+"When"
+"\",<P>,\""
+"marked"
+"\"&#RE;\""
+"boolean"
+"names"
+"form's"
+"Input"
+"\"B\""
+"GENERAL"
+"<DFN>"
+"are"
+"use"
+"from"
+"working"
+"&"
+"positive"
+"value,"
+"next"
+"few"
+"Base"
+"attribute"
+"encode"
+"scope"
+"associated"
+"selects"
+"value:"
+"%SDAPREF;"
+"October"
+"N=...>"
+"src"
+"These"
+"appending"
+"name,"
+"Required"
+"name)"
+"CONTENT"
+"uuml"
+"fixed"
+"`-//IETF//DTD"
+"8"
+"rendered"
+"NEXTID"
+"Expression"
+"behalf"
+"Constraints"
+"Strong"
+"HTML//EN\">"
+"indicates"
+"this"
+"Hyphen"
+"Period"
+"Syntax"
+"H2"
+"values"
+"can"
+"December"
+"following"
+"`%0D%0A'."
+"closing"
+"Abstract"
+"something"
+"control"
+"reserved"
+"e.g."
+"do"
+"process"
+"Media"
+"\\-HEAD"
+"agent"
+"escaped"
+"tag"
+"specification."
+"allowed"
+"CHECKED"
+"occur"
+"UL"
+"IMAGE"
+"charset"
+"1"
+"line."
+"<UL>."
+"pair"
+"SELECTED>"
+"s,"
+"Text:"
+"ensure"
+"</MENU>"
+"encoded."
+"SDASUFF"
+"attributes,"
+"STD"
+"map"
+"may"
+"`TEXT',"
+"Request"
+"collection"
+"11]"
+"produce"
+"such"
+"data"
+"compatibility"
+"ROWS=6"
+"`TYPE=RESET'"
+"Y."
+"CERN"
+"bind"
+"parameter"
+"Format"
+"explicit"
+"One"
+"rather"
+"MIT,"
+"Paragraph"
+"so"
+"<OL"
+"allow"
+"representation"
+"<LISTING>"
+"instead,"
+"superscript"
+"RESET"
+"valid"
+"Zip"
+"move"
+"below."
+"entity"
+"<KBD>"
+"referenced"
+"including"
+"nbsp"
+"differs"
+"White"
+"`INCLUDE'."
+"<meta"
+"Body"
+"<PLAINTEXT>"
+"group"
+"auml"
+"curly"
+"maps"
+"Rules"
+"<META>"
+"H5."
+"Ouml"
+"<LI>A-H<LI>I-M"
+"coordinates"
+"<H3>"
+"forms"
+"platform"
+"window"
+"choose"
+"listing"
+"Multiply"
+"mail"
+"main"
+"defining"
+"<"
+"`<BR>'"
+"greater"
+"<PRE>"
+"views"
+"uacute"
+"option."
+"`<IMG"
+"Maximum"
+"METHOD=...>"
+"Option"
+"BASE"
+"Extensions"
+"half"
+"not"
+"sorted"
+"However,"
+"superset"
+"quote,"
+"cedilla"
+"&gt;"
+"term"
+"SDA"
+"name"
+"edit"
+"plus-or-minus"
+"form."
+"mode"
+"(WWW)"
+"<H4>"
+"identifier"
+"|"
+"constraints"
+"subset"
+"domain"
+"square"
+"Network"
+"8,"
+"TYPE"
+"Generic"
+"ISINDEX"
+"HTTP-EQUIV=...>"
+"COLS"
+"related"
+"Next"
+"fraction"
+"agrave"
+"Ocirc"
+"SDAPREF"
+"Parameter"
+"ALT=\"...\">"
+"special"
+"out"
+"exclamation"
+"Added"
+"container"
+"space"
+"GRPCNT"
+"SGML"
+"Uuml"
+"contained"
+"<META"
+"<LINK"
+"\\-P"
+"supports"
+"reg"
+"DATATAG"
+"FUNCTION"
+"<H6>,"
+"mandatory."
+"older"
+"This"
+"derived"
+"mapped"
+"DTD)."
+"<img"
+"state."
+"RFC"
+"ECMA-94"
+"N.,"
+"conflicts"
+"Security"
+"[IANA]."
+"YES"
+"<!ATTLIST"
+"advance"
+"interaction"
+"indent"
+"REFERENCE"
+"language"
+"deprecated"
+"area"
+"times"
+"ENCTYPE=\"...\">"
+"length"
+"place"
+"\"VERSION"
+"hexadecimal"
+"TITLE=\"...\">"
+"Eric"
+"<LI>M-R<LI>S-Z"
+"first"
+"\"(TEXT"
+"suspend"
+"suffix"
+"(RFC"
+"ignored"
+"<I>"
+"There"
+"1]"
+"one"
+"CHAR"
+"list."
+"ISO"
+"submit"
+"directly"
+"representations"
+"\"INCLUDE\">"
+"ring"
+"STRONG"
+"open"
+"size"
+"city"
+"little"
+"long"
+"sheet"
+"For"
+"Vertical"
+"strict"
+"unknown"
+"<FORM>"
+"frac34"
+"Commercial"
+"system"
+"unspecified"
+"indicate"
+"2"
+"IGNORE;"
+"\"&#RE;&#RE;\""
+"DTD)"
+"DTD\"."
+"white"
+"Data"
+"gives"
+"\\-<P>"
+"iacute"
+"IMG"
+"that"
+"completed"
+"exactly"
+"REV=\"X\"."
+"released"
+"(DT"
+"copy"
+"\"BLOCKQUOTE"
+"than"
+"Inc."
+"Y,"
+"11"
+"structure."
+"13"
+"12"
+"15"
+"14"
+"16"
+"require"
+"see"
+"accesses"
+"(COMPACT)"
+"\\-</P>"
+"future"
+"BODY\">"
+"were"
+"1)"
+"ENCTYPE"
+"1,"
+"1."
+"and"
+"Information"
+"DL"
+"1.1"
+"1.2"
+"aelig"
+"lines"
+"DD"
+"(ICADD)"
+"`ISO-10646-UCS-2'"
+"(and"
+"<TITLE>HTML"
+"Field"
+"say"
+"HREF"
+"have"
+"need"
+"Mail"
+"DT"
+"element"
+"any"
+"'>'"
+"<INPUT"
+"documents"
+"angle"
+"NAME=\"...\">"
+"URN=\"...\">"
+"database."
+"SELECTED"
+"able"
+"mechanism"
+"iquest"
+"note"
+"instance"
+"emphasis"
+"<ADDRESS>"
+"which"
+"ICADD:"
+"[HTTP]"
+"inverted"
+"="
+"cases."
+"<XMP>,"
+"begin"
+"sure"
+"multiple"
+"Name"
+"`TYPE=CHECKBOX'"
+"normal"
+"track"
+"deprecated."
+"who"
+"Enter"
+"multiply"
+"TYPE=RADIO"
+"middot"
+"<U>"
+"icon"
+"D."
+"SAMP"
+"Part"
+"#FIXED"
+"document:"
+"request"
+"raquo"
+"8879:1986//ENTITIES"
+"<BASE>"
+"not."
+"typically"
+"CITE"
+"document."
+"Web"
+"selection"
+"YES,"
+"text"
+"supported"
+"Character"
+"SGML."
+"Width"
+"SGML,"
+"spaces"
+"Test"
+"MULTIPLE"
+"WIDTH=...>"
+"Document"
+"line"
+"FORMAL"
+"TYPE=RESET>"
+"based"
+"title"
+"("
+"3"
+"(#PCDATA)*>"
+"should"
+"buttons"
+"hierarchy"
+"only"
+"explicitly"
+"<!DOCTYPE"
+"GMT"
+"POST\""
+"get"
+"=>"
+"space,"
+"cannot"
+"\"TITLE"
+"words"
+"127"
+"128"
+"ENTITY"
+"scrolling"
+"Once"
+"processes"
+"Right"
+"resource"
+"W."
+"ISMAP"
+"<DIR>"
+"subtype"
+"GLYPH"
+"W3"
+"contain"
+"</BODY>"
+"LINK"
+"\"SDAFORM"
+"At"
+"where"
+"view"
+"available"
+"declared"
+"<SELECT"
+"exists"
+"brvbar"
+"(HTML)"
+"ismap"
+"relative"
+"Source"
+"</TEXTAREA>"
+"computer"
+"SUBMIT"
+"Fraction"
+"LISTING"
+"PARC,"
+"(XMP|LISTING)"
+"attribute."
+"attribute,"
+"macron"
+"`TYPE=PASSWORD'"
+"label"
+"boundaries"
+"written"
+"<TEXTAREA"
+"enumerated"
+"between"
+"progress"
+"reading"
+"across"
+"ends"
+"ability"
+"vertical"
+"yuml"
+"para"
+"REL=\"X\""
+"Directory"
+"20"
+"Identifier"
+"optional"
+"Anchor"
+"exclusion"
+"observable"
+"WWW"
+"SGMLREF"
+"limits"
+"many"
+"taking"
+"RS"
+"according"
+"HREF=\"...\">"
+"present"
+"way."
+"<UL>"
+"attributes"
+"expression"
+"values,"
+"Contents"
+"otherwise"
+"comment"
+"among"
+"protocol."
+"World"
+"`ISO-8859-1'"
+"BODY"
+"DELIM"
+"hyphen"
+"29"
+"Note"
+"63"
+"64"
+"66"
+"INPUT"
+"constant"
+"allocated"
+"ISINDEX\">"
+"DTD\")."
+"RE"
+"parsed"
+"curren"
+"Aacute"
+"cent"
+"mark"
+"defined"
+"literal"
+"`ISO"
+"combined"
+"(`</DD>')"
+"SRC=\"...\">"
+"Horizontal"
+"GMT\">"
+">"
+"name."
+"euml"
+"optionally"
+"controlled"
+"\"#PCDATA"
+"CHARACTER"
+"sequence."
+"SDARULE"
+"[RELURL]"
+"CERN,"
+"[SQ91]"
+"external"
+"declaration"
+"<XMP>"
+"an"
+"2."
+"those"
+"quotation"
+"case"
+"[SGML])"
+"[SGML]."
+"indicator,"
+"these"
+"plain"
+"means"
+"(LI)+"
+"&quot;"
+"value"
+"pixel"
+"will"
+"(UCS)"
+"SIZE=\"42\">"
+"\"CDATA\""
+"COLS=...>"
+"E,"
+"Level"
+"SDAFORM"
+"margin"
+"6]"
+"`<EM/.../';"
+"LITLEN"
+"ucirc"
+"thus"
+"(DT)"
+"equal"
+"Content"
+"middle"
+"ugrave"
+"`METHOD=POST'"
+"`TYPE=HIDDEN'"
+"ADDRESS)*\">"
+"You"
+"DIR"
+"<DL"
+"<TITLE>,"
+"different"
+"Return"
+"COMPACT>"
+"perhaps"
+"media"
+"granted"
+"`GET',"
+"REL=...>"
+"same"
+"Acirc"
+"strings."
+"\"IGNORE\""
+"html"
+"identifier,"
+"I,"
+"identifier."
+"Oxford"
+"document"
+"%SDAFORM;"
+"infer"
+"</html>"
+"status"
+"extended"
+"Resource"
+"I"
+"effect"
+"\"H3\""
+"frequently"
+"validate"
+"ACM,"
+"ID"
+"H6\"),"
+"transaction"
+"VALUE=\"...\">"
+"center"
+"NAMELEN"
+"markup"
+"identifiers"
+"It"
+"object"
+"Track"
+"without"
+"extensible"
+"In"
+"very"
+"position"
+"model"
+"values."
+"dimension"
+"bodies"
+"Specifying"
+"<H2>"
+"less"
+"being"
+"percent"
+"obtain"
+"1521[MIME])"
+"Access"
+"sources"
+"stored"
+"BR"
+"positions"
+"Scope"
+"`US-ASCII'"
+"4."
+"Button:"
+"hint"
+"<TITLE>"
+"except"
+"capabilities"
+"reasons"
+"terminating"
+"4"
+"Although"
+"\\-<EM>"
+"coded"
+"XMP,"
+"resolved"
+"aspects"
+"around"
+"read"
+"Many"
+"CRLF,"
+"source."
+"Recording"
+"\"BQ\""
+"makes"
+"nor"
+"using"
+"[ISO"
+"left-hand"
+"descendant"
+"oslash"
+"acute"
+"IMG\")."
+"like"
+"text/html"
+"header"
+"serves"
+"server"
+"<LISTING>,"
+"(or"
+"either"
+"soft"
+"page"
+"specifies"
+"because"
+"couldn't"
+"sequence"
+"Section"
+"Since"
+"\"HTML"
+"U,"
+"4]"
+"respect"
+"images"
+"International"
+"matching"
+"glyph"
+"nonzero"
+"provided"
+"entities"
+"SPACE"
+"Catalog"
+"critical"
+"`PASSWORD'"
+"\"NAMES\">"
+"ocirc"
+"URI."
+"<SELECT>"
+"refer"
+"locate"
+"Term"
+"accessing"
+"1//ESC"
+"`NAMELEN'"
+"equivalent"
+"Official"
+"PRE\")"
+"broken"
+"(SELECTED)"
+"A-Z"
+"VALUE"
+"\"H1\""
+"\"SDASUFF"
+"</BLOCKQUOTE>"
+"&amp;"
+"includes"
+"2.0//EN\">"
+"after"
+"on"
+"about"
+"actual"
+"H6"
+"column"
+"of"
+"R.,"
+"recognized"
+"side"
+"TYPE=RESET"
+"addition"
+"statement"
+"URI,"
+"mixed"
+"Message"
+"introduced"
+"<H6>"
+"or"
+"UC"
+"software"
+"(DTD)"
+"document's"
+"letters"
+"OPTION"
+"accent"
+"`&AMP;'."
+"image"
+"RANK"
+"due"
+"HTTP-EQUIV."
+"activate"
+"references"
+"renderer"
+"determine"
+"<ISINDEX>"
+"names."
+"your"
+"summary."
+"per"
+"CGI"
+"terminated"
+"APPINFO"
+"[GOLD90]"
+"<NEXTID>"
+"additional"
+"<FORM"
+"NO"
+"transfer"
+"there"
+"Unused"
+"start"
+"describes"
+"italic"
+"\"-//EC-USA-CDA/ICADD//DTD"
+"November"
+"context."
+"function"
+"`TYPE=RADIO'"
+"METHOD=\"POST\""
+"N,"
+"complete"
+"N."
+"enough"
+"<HR>"
+"INPUT\")"
+"compatible)"
+"but"
+"SDASUSP"
+"Error"
+"Small"
+"DD)+>"
+"(C)"
+"with"
+"1024"
+"made"
+"arranged"
+"(HTML)."
+"embedded"
+"default"
+"A\")."
+"robustness"
+"[HTTP]."
+"record"
+"below"
+"ISINDEX?"
+"limit"
+"CDATA"
+"H4."
+"`IGNORE'"
+"define"
+"are:"
+"display"
+"specified."
+"Field:"
+"METHODS"
+"required"
+"ae"
+"Space"
+"(ISMAP)"
+"certain"
+"moved"
+"NAMES"
+"<VAR>"
+"general"
+"as"
+"(#PCDATA)*"
+"at"
+"file"
+"\"HTML\""
+"format."
+"TYPE=HIDDEN"
+"fill"
+"string."
+"again"
+"beyond"
+"(SGML),"
+"variety"
+"ADDRESS"
+"storage"
+"detail"
+"40"
+"NAMECASE"
+"details."
+"field"
+"other"
+"5"
+"details"
+"LCNMCHAR"
+"Ecirc"
+"you"
+"`POST',"
+"`POST'."
+"10"
+"Wide"
+"Any"
+"kinds"
+"separate"
+"SMTP"
+"symbol"
+"numbers."
+"Element"
+"chance"
+"important"
+"H."
+"URLs"
+"<div"
+"included"
+"T.,"
+"`INCLUDE'"
+"attributes."
+"text:"
+"DESCRIPTION"
+"\"EM"
+"resolution"
+"thorn"
+"ouml"
+"persistent"
+"rule"
+"\"PRE\">"
+"directory"
+"GRPCAP"
+"validation"
+"starting"
+"strings"
+"&#39;"
+
diff --git a/content/test/data/media/getusermedia.html b/content/test/data/media/getusermedia.html
index a54ba7f..f066a8a 100644
--- a/content/test/data/media/getusermedia.html
+++ b/content/test/data/media/getusermedia.html
@@ -461,16 +461,8 @@
     var detectorFunction = function() {
       var width = videoElement.videoWidth;
       var height = videoElement.videoHeight;
-      if (width == 0 || height == 0) {
-        if (++attempt > maxAttempts) {
-          clearInterval(detectorInterval);
-          failTest("VideoElement width or height set to 0.");
-        }
-        else {
-          // We have zero size now; give a chance to shape up.
-          return;
-        }
-      }
+      if (width == 0 || height == 0)
+        failTest("VideoElement width and height set to 0.");
 
       canvas.width = width;
       canvas.height = height;
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index eb168a64..14ccb117 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -496,8 +496,6 @@
         ['mac', 'intel'], bug=483282)
 
     # Linux only.
-    self.Fail('deqp/data/gles3/shaders/functions.html',
-        ['linux'], bug=483282)
     self.Fail('conformance2/glsl3/vector-dynamic-indexing.html',
         ['linux'], bug=483282)
     self.Fail('deqp/functional/gles3/fbodepthbuffer.html',
@@ -506,24 +504,23 @@
     # Behavior difference between GL compatibility profile and ES3.
     self.Fail('conformance2/rendering/draw-buffers.html',
         ['linux'], bug=617410)
-
-    self.Skip('deqp/data/gles3/shaders/qualification_order.html',
-        ['linux', 'amd', 'intel'], bug=483282)
-    self.Fail('deqp/functional/gles3/clipping.html',
-        ['linux', 'amd', 'intel'], bug=483282)
-
-    self.Flaky('deqp/functional/gles3/texturespecification/' +
-        'random_teximage2d_2d.html',
-        ['linux'], bug=618447)
     self.Fail('deqp/functional/gles3/texturespecification/' +
         'random_teximage2d_cube.html',
         ['linux'], bug=483282)
     self.Fail('deqp/functional/gles3/fboinvalidate/whole.html',
         ['linux'], bug=624506)
 
+    self.Fail('deqp/data/gles3/shaders/functions.html',
+        ['linux', 'amd', 'intel'], bug=483282)
+    self.Skip('deqp/data/gles3/shaders/qualification_order.html',
+        ['linux', 'amd', 'intel'], bug=483282)
+    self.Fail('deqp/functional/gles3/clipping.html',
+        ['linux', 'amd', 'intel'], bug=483282)
+    self.Flaky('deqp/functional/gles3/texturespecification/' +
+        'random_teximage2d_2d.html',
+        ['linux', 'amd', 'intel'], bug=618447)
+
     # Linux NVIDIA only.
-    self.Fail('conformance2/glsl3/array-complex-indexing.html',
-        ['linux', 'nvidia', 'no_angle'], bug=606498)
     self.Fail('deqp/functional/gles3/uniformapi/random.html',
         ['linux', 'nvidia'], bug=621178)
 
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index 7de93d4d..53a2f39 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -116,8 +116,6 @@
               ['android', ('qualcomm', 'Adreno (TM) 330')], bug=611943)
     self.Fail('conformance/state/state-uneffected-after-compositing.html',
               ['android', ('qualcomm', 'Adreno (TM) 330')], bug=611943)
-    self.Fail('deqp/data/gles2/shaders/preprocessor.html',
-              ['android', ('qualcomm', 'Adreno (TM) 330')], bug=611943)
 
     # Nexus 5X
     self.Fail('conformance/extensions/oes-texture-float-with-image-data.html',
@@ -299,8 +297,6 @@
               ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951)
     self.Fail('conformance/uniforms/uniform-samplers-test.html',
               ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951)
-    self.Fail('deqp/data/gles2/shaders/preprocessor.html',
-              ['android', ('qualcomm', 'Adreno (TM) 418')], bug=610951)
 
     # Nexus 6 (Adreno 420) and 6P (Adreno 430)
     self.Fail('WebglExtension.EXT_sRGB',
@@ -514,10 +510,6 @@
     self.Fail('conformance/textures/image_bitmap_from_image_bitmap/' +
               'tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html',
               ['android', ('qualcomm', 'Adreno (TM) 430')], bug=611945)
-    self.Fail('deqp/data/gles2/shaders/preprocessor.html',
-              ['android',
-              ('qualcomm', 'Adreno (TM) 420'),
-              ('qualcomm', 'Adreno (TM) 430')], bug=611945)
     self.Fail('conformance/glsl/misc/shader-with-_webgl-identifier.vert.html',
               ['android', ('qualcomm', 'Adreno (TM) 420')], bug=611945)
 
@@ -550,6 +542,7 @@
         bug=625363)
 
     # Fails on multiple platforms
+    self.Skip('deqp/data/gles2/shaders/preprocessor.html', bug=625363)
 
     # OpenGL / NVIDIA failures
     self.Fail('conformance/attribs/gl-disabled-vertex-attrib.html',
@@ -626,8 +619,6 @@
         ['win', 'amd', 'opengl'], bug=1007) # angle bug ID
     self.Fail('conformance/glsl/misc/struct-nesting-of-variable-names.html',
         ['win', 'amd', 'opengl'], bug=1007) # angle bug ID
-    self.Fail('deqp/data/gles2/shaders/preprocessor.html',
-        ['win', 'amd', 'opengl'], bug=478572)
 
     # Win / OpenGL / Intel failures
     self.Fail('conformance/glsl/functions/glsl-function-normalize.html',
@@ -640,8 +631,6 @@
     # Mac failures
     self.Fail('conformance/glsl/misc/shaders-with-invariance.html',
         ['mac'], bug=421710)
-    self.Fail('deqp/data/gles2/shaders/preprocessor.html',
-        ['mac'], bug=478572)
     self.Fail('deqp/data/gles2/shaders/scoping.html',
         ['mac'], bug=478572)
 
@@ -670,8 +659,6 @@
     # AMD
     self.Flaky('conformance/more/functions/uniformi.html',
                ['linux', 'amd'], bug=550989)
-    self.Fail('deqp/data/gles2/shaders/preprocessor.html',
-              ['linux', 'amd'], bug=478572)
 
     # AMD Radeon 6450
     self.Fail('conformance/extensions/angle-instanced-arrays.html',
@@ -717,8 +704,6 @@
         ['linux', 'intel', 'opengl'], bug=1312)  # ANGLE bug id
     self.Fail('deqp/data/gles2/shaders/linkage.html',
         ['linux', 'intel'], bug=540543)
-    self.Fail('deqp/data/gles2/shaders/preprocessor.html',
-        ['linux', 'intel'], bug=1312)  # ANGLE bug id. See also 598910
     # The Mesa Intel driver has a scoping bug, see
     # https://bugs.freedesktop.org/show_bug.cgi?id=95184
     self.Fail('deqp/data/gles2/shaders/scoping.html',
diff --git a/content/test/test_render_view_host.h b/content/test/test_render_view_host.h
index 29654bbd..b467c0e 100644
--- a/content/test/test_render_view_host.h
+++ b/content/test/test_render_view_host.h
@@ -108,8 +108,6 @@
                          int error_code) override;
   void Destroy() override;
   void SetTooltipText(const base::string16& tooltip_text) override {}
-  void SelectionBoundsChanged(
-      const ViewHostMsg_SelectionBounds_Params& params) override {}
   void CopyFromCompositingSurface(
       const gfx::Rect& src_subrect,
       const gfx::Size& dst_size,
diff --git a/device/gamepad/gamepad.gyp b/device/gamepad/gamepad.gyp
index f82c5048..792843c 100644
--- a/device/gamepad/gamepad.gyp
+++ b/device/gamepad/gamepad.gyp
@@ -51,10 +51,23 @@
         ['OS=="win"', {
           'msvs_disabled_warnings': [4267, ],
         }],
+        ['OS=="linux" and use_udev==1', {
+          'dependencies': [
+            '../udev_linux/udev.gyp:udev_linux',
+          ]
+        }],
         ['OS!="win" and OS!="mac" and OS!="android" and (OS!="linux" or use_udev==0)', {
           'sources': [
             'gamepad_platform_data_fetcher.cc',
-          ]
+          ],
+          'sources!': [
+            'gamepad_platform_data_fetcher_linux.cc',
+          ],
+        }],
+        ['use_udev == 1', {
+          'dependencies': [
+            '<(DEPTH)/device/udev_linux/udev.gyp:udev_linux',
+          ],
         }],
       ],
     },
diff --git a/device/gamepad/gamepad_provider.cc b/device/gamepad/gamepad_provider.cc
index dded267..c37c38a 100644
--- a/device/gamepad/gamepad_provider.cc
+++ b/device/gamepad/gamepad_provider.cc
@@ -159,7 +159,7 @@
 
 void GamepadProvider::DoInitializePollingThread(
     std::unique_ptr<GamepadDataFetcher> fetcher) {
-  DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
+  DCHECK(polling_thread_->task_runner()->BelongsToCurrentThread());
   DCHECK(!data_fetcher_.get());  // Should only initialize once.
 
   if (!fetcher)
@@ -168,7 +168,7 @@
 }
 
 void GamepadProvider::SendPauseHint(bool paused) {
-  DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
+  DCHECK(polling_thread_->task_runner()->BelongsToCurrentThread());
   if (data_fetcher_)
     data_fetcher_->PauseHint(paused);
 }
@@ -207,7 +207,7 @@
 }
 
 void GamepadProvider::DoPoll() {
-  DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
+  DCHECK(polling_thread_->task_runner()->BelongsToCurrentThread());
   DCHECK(have_scheduled_do_poll_);
   have_scheduled_do_poll_ = false;
 
@@ -256,7 +256,7 @@
 }
 
 void GamepadProvider::ScheduleDoPoll() {
-  DCHECK(base::MessageLoop::current() == polling_thread_->message_loop());
+  DCHECK(polling_thread_->task_runner()->BelongsToCurrentThread());
   if (have_scheduled_do_poll_)
     return;
 
diff --git a/extensions/renderer/resources/guest_view/guest_view_container.js b/extensions/renderer/resources/guest_view/guest_view_container.js
index acba9fb..8cfc8cb 100644
--- a/extensions/renderer/resources/guest_view/guest_view_container.js
+++ b/extensions/renderer/resources/guest_view/guest_view_container.js
@@ -101,14 +101,6 @@
     // See http://crbug.com/231664.
     this.element.setAttribute('tabIndex', -1);
   }
-  this.element.addEventListener('focus', this.weakWrapper(function(e) {
-    // Focus the BrowserPlugin when the GuestViewContainer takes focus.
-    privates(this).internalElement.focus();
-  }));
-  this.element.addEventListener('blur', this.weakWrapper(function(e) {
-    // Blur the BrowserPlugin when the GuestViewContainer loses focus.
-    privates(this).internalElement.blur();
-  }));
 };
 
 GuestViewContainer.prototype.focus = function() {
diff --git a/gpu/command_buffer/common/capabilities.cc b/gpu/command_buffer/common/capabilities.cc
index ad20e41..2462384b 100644
--- a/gpu/command_buffer/common/capabilities.cc
+++ b/gpu/command_buffer/common/capabilities.cc
@@ -84,7 +84,7 @@
       surfaceless(false),
       flips_vertically(false),
       msaa_is_slow(false),
-      disable_webgl_multisampling_color_mask_usage(false),
+      disable_multisampling_color_mask_usage(false),
       disable_webgl_rgb_multisampling_usage(false),
       chromium_image_rgb_emulation(false),
       emulate_rgb_buffer_with_rgba(false),
diff --git a/gpu/command_buffer/common/capabilities.h b/gpu/command_buffer/common/capabilities.h
index 4443e61c..a3d1ffe 100644
--- a/gpu/command_buffer/common/capabilities.h
+++ b/gpu/command_buffer/common/capabilities.h
@@ -144,7 +144,7 @@
   bool surfaceless;
   bool flips_vertically;
   bool msaa_is_slow;
-  bool disable_webgl_multisampling_color_mask_usage;
+  bool disable_multisampling_color_mask_usage;
   bool disable_webgl_rgb_multisampling_usage;
 
   // When this parameter is true, a CHROMIUM image created with RGB format will
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
index ab46ede0..500dd09 100644
--- 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
@@ -348,8 +348,7 @@
 
   {
     glUseProgram(edges0_shader_);
-    glUniform1f(0, 1.0f);
-    glUniform2f(1, 1.0f / width_, 1.0f / height_);
+    glUniform2f(0, 1.0f / width_, 1.0f / height_);
     glDepthMask(GL_TRUE);
     glDepthFunc(GL_ALWAYS);
     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
@@ -378,8 +377,7 @@
   //  image2D g_resultTexture             edge_texture_b               image0
   {
     glUseProgram(edges1_shader_);
-    glUniform1f(0, 0.0f);
-    glUniform2f(1, 1.0f / width_, 1.0f / height_);
+    glUniform2f(0, 1.0f / width_, 1.0f / height_);
     glDepthMask(GL_FALSE);
     glDepthFunc(GL_LESS);
     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
@@ -399,9 +397,7 @@
   }
 
   //  - 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).
+  //    RightBottomLeftTop (.xyzw) edges and output it into the mask.
   //  - 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).
@@ -415,13 +411,12 @@
   //  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
+    // bottom, left) edges; also mark depth 1 value on all pixels with any edge
+    // and 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_);
+    glUniform2f(0, 1.0f / width_, 1.0f / height_);
     glDepthMask(GL_TRUE);
-    glDepthFunc(GL_ALWAYS);
+    glDepthFunc(GL_LESS);
     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
 
     if (!is_gles31_compatible_) {
@@ -455,8 +450,7 @@
   //  gl_FragDepth                         mini4_edge_texture_         fbo.depth
   {
     glUseProgram(process_and_apply_shader_);
-    glUniform1f(0, 0.0f);
-    glUniform2f(1, 1.0f / width_, 1.0f / height_);
+    glUniform2f(0, 1.0f / width_, 1.0f / height_);
     glDepthMask(GL_FALSE);
     glDepthFunc(GL_LESS);
     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
@@ -690,7 +684,6 @@
 const char ApplyFramebufferAttachmentCMAAINTELResourceManager::vert_str_[] =
   SHADER(
     precision highp float;
-    layout(location = 0) uniform float g_Depth;
     // No input data.
     // Verts are autogenerated.
     //
@@ -703,7 +696,7 @@
     {
        float x = -1.0 + float((gl_VertexID & 1) << 2);
        float y = -1.0 + float((gl_VertexID & 2) << 1);
-       gl_Position = vec4(x, y, g_Depth, 1.0);
+       gl_Position = vec4(x, y, 0.0, 1.0);
     }
   );
 
@@ -716,12 +709,10 @@
     \n#define EDGE_DETECT_THRESHOLD 13.0f\n
     \n#define saturate(x) clamp((x), 0.0, 1.0)\n
 
-    // bind to location 0
-    layout(location = 0) uniform float g_Depth;
     // bind to a uniform buffer bind point 0
-    layout(location = 1) uniform vec2 g_OneOverScreenSize;
+    layout(location = 0) uniform vec2 g_OneOverScreenSize;
     \n#ifndef EDGE_DETECT_THRESHOLD\n
-    layout(location = 2) uniform float g_ColorThreshold;
+    layout(location = 1) uniform float g_ColorThreshold;
     \n#endif\n
 
     \n#ifdef SUPPORTS_USAMPLER2D\n
diff --git a/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.cc b/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.cc
index d42dd195..6a21c49fd 100644
--- a/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.cc
+++ b/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.cc
@@ -56,10 +56,9 @@
 namespace gpu {
 
 ClearFramebufferResourceManager::ClearFramebufferResourceManager(
-    const gles2::GLES2Decoder* decoder,
-    const gles2::FeatureInfo::FeatureFlags& feature_flags)
-    : initialized_(false), program_(0u), vao_(0), buffer_id_(0u) {
-  Initialize(decoder, feature_flags);
+    const gles2::GLES2Decoder* decoder)
+    : initialized_(false), program_(0u), buffer_id_(0u) {
+  Initialize(decoder);
 }
 
 ClearFramebufferResourceManager::~ClearFramebufferResourceManager() {
@@ -68,13 +67,12 @@
 }
 
 void ClearFramebufferResourceManager::Initialize(
-    const gles2::GLES2Decoder* decoder,
-    const gles2::FeatureInfo::FeatureFlags& feature_flags) {
+    const gles2::GLES2Decoder* decoder) {
   static_assert(
       kVertexPositionAttrib == 0u,
       "kVertexPositionAttrib must be 0");
-
   DCHECK(!buffer_id_);
+
   glGenBuffersARB(1, &buffer_id_);
   glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
   const GLfloat kQuadVertices[] = {-1.0f, -1.0f,
@@ -83,19 +81,6 @@
                                    -1.0f,  1.0f};
   glBufferData(
       GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
-
-  DCHECK(!vao_);
-
-  if (feature_flags.native_vertex_array_object) {
-    glGenVertexArraysOES(1, &vao_);
-
-    glBindVertexArrayOES(vao_);
-    glEnableVertexAttribArray(kVertexPositionAttrib);
-    glVertexAttribPointer(kVertexPositionAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
-
-    decoder->RestoreAllAttributes();
-  }
-
   decoder->RestoreBufferBindings();
   initialized_ = true;
 }
@@ -105,12 +90,6 @@
     return;
 
   glDeleteProgram(program_);
-
-  if (vao_ != 0) {
-    glDeleteVertexArraysOES(1, &vao_);
-    vao_ = 0;
-  }
-
   glDeleteBuffersARB(1, &buffer_id_);
   buffer_id_ = 0;
 }
@@ -161,14 +140,11 @@
     DLOG(ERROR) << "Invalid shader.";
 #endif
 
-  if (vao_) {
-    glBindVertexArrayOES(vao_);
-  } else {
-    decoder->ClearAllAttributes();
-    glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
-    glEnableVertexAttribArray(kVertexPositionAttrib);
-    glVertexAttribPointer(kVertexPositionAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
-  }
+  decoder->ClearAllAttributes();
+  glEnableVertexAttribArray(kVertexPositionAttrib);
+
+  glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
+  glVertexAttribPointer(kVertexPositionAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
 
   glUniform1f(depth_handle_, clear_depth_value);
   glUniform4f(color_handle_, clear_color_red, clear_color_green,
@@ -203,11 +179,9 @@
   glViewport(0, 0, framebuffer_size.width(), framebuffer_size.height());
   glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 
-  if (vao_ == 0) {
-    decoder->RestoreBufferBindings();
-  }
   decoder->RestoreAllAttributes();
   decoder->RestoreProgramBindings();
+  decoder->RestoreBufferBindings();
   decoder->RestoreGlobalState();
 }
 
diff --git a/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h b/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h
index 2095d80..750b0d68 100644
--- a/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h
+++ b/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h
@@ -6,7 +6,6 @@
 #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_CLEAR_FRAMEBUFFER_H_
 
 #include "base/macros.h"
-#include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/gl_utils.h"
 #include "gpu/gpu_export.h"
 
@@ -21,9 +20,7 @@
 
 class GPU_EXPORT ClearFramebufferResourceManager {
  public:
-  ClearFramebufferResourceManager(
-      const gles2::GLES2Decoder* decoder,
-      const gles2::FeatureInfo::FeatureFlags& feature_flags);
+  ClearFramebufferResourceManager(const gles2::GLES2Decoder* decoder);
   ~ClearFramebufferResourceManager();
 
 
@@ -38,8 +35,7 @@
                         GLint clear_stencil_value);
 
  private:
-  void Initialize(const gles2::GLES2Decoder* decoder,
-                  const gles2::FeatureInfo::FeatureFlags& feature_flags);
+  void Initialize(const gles2::GLES2Decoder* decoder);
   void Destroy();
 
   // The attributes used during invocation of the extension.
@@ -47,7 +43,6 @@
 
   bool initialized_;
   GLuint program_;
-  GLuint vao_;
   GLuint depth_handle_;
   GLuint color_handle_;
   GLuint buffer_id_;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 90f897b..6df7f6a2 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -2371,13 +2371,28 @@
        enforce_internal_framebuffer));
   if (!resolve_and_bind_)
     return;
-
-  // TODO(erikchen): On old AMD GPUs on macOS, glColorMask doesn't work
-  // correctly for multisampled renderbuffers and the alpha channel can be
-  // overwritten. Add a workaround to clear the alpha channel before resolving.
-  // https://crbug.com/602484.
   ScopedGLErrorSuppressor suppressor(
       "ScopedResolvedFrameBufferBinder::ctor", decoder_->GetErrorState());
+
+  // On old AMD GPUs on macOS, glColorMask doesn't work correctly for
+  // multisampled renderbuffers and the alpha channel can be overwritten. This
+  // workaround clears the alpha channel before resolving.
+  bool alpha_channel_needs_clear =
+      decoder_->should_use_native_gmb_for_backbuffer_ &&
+      !decoder_->offscreen_buffer_should_have_alpha_ &&
+      decoder_->ChromiumImageNeedsRGBEmulation() &&
+      decoder_->feature_info_->workarounds()
+          .disable_multisampling_color_mask_usage;
+  if (alpha_channel_needs_clear) {
+    glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT,
+                         decoder_->offscreen_target_frame_buffer_->id());
+    decoder_->state_.SetDeviceColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
+    decoder->state_.SetDeviceCapabilityState(GL_SCISSOR_TEST, false);
+    glClearColor(0, 0, 0, 1);
+    glClear(GL_COLOR_BUFFER_BIT);
+    decoder_->RestoreClearState();
+  }
+
   glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT,
                        decoder_->offscreen_target_frame_buffer_->id());
   GLuint targetid;
@@ -3400,8 +3415,7 @@
   if (workarounds().gl_clear_broken) {
     DCHECK(!clear_framebuffer_blit_.get());
     LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glClearWorkaroundInit");
-    clear_framebuffer_blit_.reset(
-        new ClearFramebufferResourceManager(this, features()));
+    clear_framebuffer_blit_.reset(new ClearFramebufferResourceManager(this));
     if (LOCAL_PEEK_GL_ERROR("glClearWorkaroundInit") != GL_NO_ERROR)
       return false;
   }
@@ -3558,8 +3572,8 @@
       feature_info_->feature_flags().occlusion_query_boolean;
   caps.timer_queries =
       query_manager_->GPUTimingAvailable();
-  caps.disable_webgl_multisampling_color_mask_usage =
-      feature_info_->workarounds().disable_webgl_multisampling_color_mask_usage;
+  caps.disable_multisampling_color_mask_usage =
+      feature_info_->workarounds().disable_multisampling_color_mask_usage;
   caps.disable_webgl_rgb_multisampling_usage =
       feature_info_->workarounds().disable_webgl_rgb_multisampling_usage;
   caps.emulate_rgb_buffer_with_rgba =
@@ -14397,15 +14411,19 @@
   // The destination format should be GL_RGB, or GL_RGBA. GL_ALPHA,
   // GL_LUMINANCE, and GL_LUMINANCE_ALPHA are not supported because they are not
   // renderable on some platforms.
-  bool valid_dest_format = dest_internal_format == GL_RGB ||
-                           dest_internal_format == GL_RGBA ||
-                           dest_internal_format == GL_BGRA_EXT;
+  bool valid_dest_format =
+      dest_internal_format == GL_RGB || dest_internal_format == GL_RGBA ||
+      dest_internal_format == GL_RGB8 || dest_internal_format == GL_RGBA8 ||
+      dest_internal_format == GL_BGRA_EXT ||
+      dest_internal_format == GL_BGRA8_EXT;
   bool valid_source_format =
       source_internal_format == GL_RED || source_internal_format == GL_ALPHA ||
       source_internal_format == GL_RGB || source_internal_format == GL_RGBA ||
+      source_internal_format == GL_RGB8 || source_internal_format == GL_RGBA8 ||
       source_internal_format == GL_LUMINANCE ||
       source_internal_format == GL_LUMINANCE_ALPHA ||
       source_internal_format == GL_BGRA_EXT ||
+      source_internal_format == GL_BGRA8_EXT ||
       source_internal_format == GL_RGB_YCBCR_420V_CHROMIUM ||
       source_internal_format == GL_RGB_YCBCR_422_CHROMIUM;
   if (!valid_source_format || !valid_dest_format) {
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
index 99c9538..f6a75dd 100644
--- a/gpu/command_buffer/service/texture_manager.cc
+++ b/gpu/command_buffer/service/texture_manager.cc
@@ -124,111 +124,111 @@
   FormatTypeValidator() {
     static const FormatType kSupportedFormatTypes[] = {
         // ES2.
-        { GL_RGB, GL_RGB, GL_UNSIGNED_BYTE },
-        { GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 },
-        { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE },
-        { GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 },
-        { GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 },
-        { GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE },
-        { GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE },
-        { GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE },
+        {GL_RGB, GL_RGB, GL_UNSIGNED_BYTE},
+        {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5},
+        {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE},
+        {GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4},
+        {GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1},
+        {GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE},
+        {GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE},
+        {GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE},
         // Exposed by GL_OES_texture_float and GL_OES_texture_half_float
-        { GL_RGB, GL_RGB, GL_FLOAT },
-        { GL_RGBA, GL_RGBA, GL_FLOAT },
-        { GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT },
-        { GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT },
-        { GL_ALPHA, GL_ALPHA, GL_FLOAT },
-        { GL_RGB, GL_RGB, GL_HALF_FLOAT_OES },
-        { GL_RGBA, GL_RGBA, GL_HALF_FLOAT_OES },
-        { GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES },
-        { GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT_OES },
-        { GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT_OES },
+        {GL_RGB, GL_RGB, GL_FLOAT},
+        {GL_RGBA, GL_RGBA, GL_FLOAT},
+        {GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_FLOAT},
+        {GL_LUMINANCE, GL_LUMINANCE, GL_FLOAT},
+        {GL_ALPHA, GL_ALPHA, GL_FLOAT},
+        {GL_RGB, GL_RGB, GL_HALF_FLOAT_OES},
+        {GL_RGBA, GL_RGBA, GL_HALF_FLOAT_OES},
+        {GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT_OES},
+        {GL_LUMINANCE, GL_LUMINANCE, GL_HALF_FLOAT_OES},
+        {GL_ALPHA, GL_ALPHA, GL_HALF_FLOAT_OES},
         // Exposed by GL_ANGLE_depth_texture
-        { GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT },
-        { GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT },
-        { GL_DEPTH_STENCIL, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 },
+        {GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT},
+        {GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT},
+        {GL_DEPTH_STENCIL, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8},
         // Exposed by GL_EXT_sRGB
-        { GL_SRGB, GL_SRGB, GL_UNSIGNED_BYTE },
-        { GL_SRGB_ALPHA, GL_SRGB_ALPHA, GL_UNSIGNED_BYTE },
+        {GL_SRGB, GL_SRGB, GL_UNSIGNED_BYTE},
+        {GL_SRGB_ALPHA, GL_SRGB_ALPHA, GL_UNSIGNED_BYTE},
         // Exposed by GL_EXT_texture_format_BGRA8888
-        { GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE },
+        {GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE},
         // Exposed by GL_EXT_texture_rg
-        { GL_RED, GL_RED, GL_UNSIGNED_BYTE },
-        { GL_RG, GL_RG, GL_UNSIGNED_BYTE },
-        { GL_RED, GL_RED, GL_FLOAT },
-        { GL_RG, GL_RG, GL_FLOAT },
-        { GL_RED, GL_RED, GL_HALF_FLOAT_OES },
-        { GL_RG, GL_RG, GL_HALF_FLOAT_OES },
+        {GL_RED, GL_RED, GL_UNSIGNED_BYTE},
+        {GL_RG, GL_RG, GL_UNSIGNED_BYTE},
+        {GL_RED, GL_RED, GL_FLOAT},
+        {GL_RG, GL_RG, GL_FLOAT},
+        {GL_RED, GL_RED, GL_HALF_FLOAT_OES},
+        {GL_RG, GL_RG, GL_HALF_FLOAT_OES},
 
         // ES3.
-        { GL_R8, GL_RED, GL_UNSIGNED_BYTE },
-        { GL_R8_SNORM, GL_RED, GL_BYTE },
-        { GL_R16F, GL_RED, GL_HALF_FLOAT },
-        { GL_R16F, GL_RED, GL_FLOAT },
-        { GL_R32F, GL_RED, GL_FLOAT },
-        { GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE },
-        { GL_R8I, GL_RED_INTEGER, GL_BYTE },
-        { GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT },
-        { GL_R16I, GL_RED_INTEGER, GL_SHORT },
-        { GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT },
-        { GL_R32I, GL_RED_INTEGER, GL_INT },
-        { GL_RG8, GL_RG, GL_UNSIGNED_BYTE },
-        { GL_RG8_SNORM, GL_RG, GL_BYTE },
-        { GL_RG16F, GL_RG, GL_HALF_FLOAT },
-        { GL_RG16F, GL_RG, GL_FLOAT },
-        { GL_RG32F, GL_RG, GL_FLOAT },
-        { GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE },
-        { GL_RG8I, GL_RG_INTEGER, GL_BYTE },
-        { GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT },
-        { GL_RG16I, GL_RG_INTEGER, GL_SHORT },
-        { GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT },
-        { GL_RG32I, GL_RG_INTEGER, GL_INT },
-        { GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE },
-        { GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE },
-        { GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE, },
-        { GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 },
-        { GL_RGB8_SNORM, GL_RGB, GL_BYTE },
-        { GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV },
-        { GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT },
-        { GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT },
-        { GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV },
-        { GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT },
-        { GL_RGB9_E5, GL_RGB, GL_FLOAT },
-        { GL_RGB16F, GL_RGB, GL_HALF_FLOAT },
-        { GL_RGB16F, GL_RGB, GL_FLOAT },
-        { GL_RGB32F, GL_RGB, GL_FLOAT },
-        { GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE },
-        { GL_RGB8I, GL_RGB_INTEGER, GL_BYTE },
-        { GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT },
-        { GL_RGB16I, GL_RGB_INTEGER, GL_SHORT },
-        { GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT },
-        { GL_RGB32I, GL_RGB_INTEGER, GL_INT },
-        { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE },
-        { GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE },
-        { GL_RGBA8_SNORM, GL_RGBA, GL_BYTE },
-        { GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE },
-        { GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 },
-        { GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV },
-        { GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE },
-        { GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 },
-        { GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV },
-        { GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT },
-        { GL_RGBA16F, GL_RGBA, GL_FLOAT },
-        { GL_RGBA32F, GL_RGBA, GL_FLOAT },
-        { GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE },
-        { GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE },
-        { GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV },
-        { GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT },
-        { GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT },
-        { GL_RGBA32I, GL_RGBA_INTEGER, GL_INT },
-        { GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT },
-        { GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT },
-        { GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT },
-        { GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT },
-        { GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT },
-        { GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 },
-        { GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL,
-          GL_FLOAT_32_UNSIGNED_INT_24_8_REV },
+        {GL_R8, GL_RED, GL_UNSIGNED_BYTE},
+        {GL_R8_SNORM, GL_RED, GL_BYTE},
+        {GL_R16F, GL_RED, GL_HALF_FLOAT},
+        {GL_R16F, GL_RED, GL_FLOAT},
+        {GL_R32F, GL_RED, GL_FLOAT},
+        {GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE},
+        {GL_R8I, GL_RED_INTEGER, GL_BYTE},
+        {GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT},
+        {GL_R16I, GL_RED_INTEGER, GL_SHORT},
+        {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT},
+        {GL_R32I, GL_RED_INTEGER, GL_INT},
+        {GL_RG8, GL_RG, GL_UNSIGNED_BYTE},
+        {GL_RG8_SNORM, GL_RG, GL_BYTE},
+        {GL_RG16F, GL_RG, GL_HALF_FLOAT},
+        {GL_RG16F, GL_RG, GL_FLOAT},
+        {GL_RG32F, GL_RG, GL_FLOAT},
+        {GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE},
+        {GL_RG8I, GL_RG_INTEGER, GL_BYTE},
+        {GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT},
+        {GL_RG16I, GL_RG_INTEGER, GL_SHORT},
+        {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT},
+        {GL_RG32I, GL_RG_INTEGER, GL_INT},
+        {GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE},
+        {GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE},
+        {GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE},
+        {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5},
+        {GL_RGB8_SNORM, GL_RGB, GL_BYTE},
+        {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV},
+        {GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT},
+        {GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT},
+        {GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV},
+        {GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT},
+        {GL_RGB9_E5, GL_RGB, GL_FLOAT},
+        {GL_RGB16F, GL_RGB, GL_HALF_FLOAT},
+        {GL_RGB16F, GL_RGB, GL_FLOAT},
+        {GL_RGB32F, GL_RGB, GL_FLOAT},
+        {GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE},
+        {GL_RGB8I, GL_RGB_INTEGER, GL_BYTE},
+        {GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT},
+        {GL_RGB16I, GL_RGB_INTEGER, GL_SHORT},
+        {GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT},
+        {GL_RGB32I, GL_RGB_INTEGER, GL_INT},
+        {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE},
+        {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE},
+        {GL_RGBA8_SNORM, GL_RGBA, GL_BYTE},
+        {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE},
+        {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1},
+        {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV},
+        {GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE},
+        {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4},
+        {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV},
+        {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT},
+        {GL_RGBA16F, GL_RGBA, GL_FLOAT},
+        {GL_RGBA32F, GL_RGBA, GL_FLOAT},
+        {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE},
+        {GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE},
+        {GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV},
+        {GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT},
+        {GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT},
+        {GL_RGBA32I, GL_RGBA_INTEGER, GL_INT},
+        {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT},
+        {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT},
+        {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT},
+        {GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT},
+        {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT},
+        {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8},
+        {GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL,
+         GL_FLOAT_32_UNSIGNED_INT_24_8_REV},
     };
 
     for (size_t ii = 0; ii < arraysize(kSupportedFormatTypes); ++ii) {
diff --git a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc
index 4b8fa4a5..44701c96 100644
--- a/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc
+++ b/gpu/command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc
@@ -73,6 +73,20 @@
     }
   }
 
+  GLenum ExtractFormatFrom(GLenum internalformat) {
+    switch (internalformat) {
+      case GL_RGBA8_OES:
+        return GL_RGBA;
+      case GL_RGB8_OES:
+        return GL_RGB;
+      case GL_BGRA8_EXT:
+        return GL_BGRA_EXT;
+      default:
+        NOTREACHED();
+        return GL_NONE;
+    }
+  }
+
   GLManager gl_;
   GLuint textures_[2];
   GLuint framebuffer_id_;
@@ -124,41 +138,53 @@
     return;
   }
   CopyType copy_type = GetParam();
+  GLenum src_internal_formats[] = {GL_RGB8_OES, GL_RGBA8_OES, GL_BGRA8_EXT};
+  GLenum dest_internal_formats[] = {GL_RGB8_OES, GL_RGBA8_OES, GL_BGRA8_EXT};
 
-  uint8_t pixels[1 * 4] = {255u, 0u, 0u, 255u};
+  uint8_t pixels[1 * 4] = {255u, 0u, 255u, 255u};
 
-  glBindTexture(GL_TEXTURE_2D, textures_[0]);
-  glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8_OES, 1, 1);
-  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
-                  pixels);
+  for (auto src_internal_format : src_internal_formats) {
+    for (auto dest_internal_format : dest_internal_formats) {
+      glDeleteTextures(2, textures_);
+      glDeleteFramebuffers(1, &framebuffer_id_);
+      CreateAndBindDestinationTextureAndFBO(GL_TEXTURE_2D);
 
-  glBindTexture(GL_TEXTURE_2D, textures_[1]);
-  glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8_OES, 1, 1);
-  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
-                         textures_[1], 0);
-  EXPECT_TRUE(glGetError() == GL_NO_ERROR);
+      glBindTexture(GL_TEXTURE_2D, textures_[0]);
+      glTexStorage2DEXT(GL_TEXTURE_2D, 1, src_internal_format, 1, 1);
+      glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1,
+                      ExtractFormatFrom(src_internal_format), GL_UNSIGNED_BYTE,
+                      pixels);
 
-  if (copy_type == TexImage) {
-    glCopyTextureCHROMIUM(textures_[0], textures_[1], GL_RGBA,
-                          GL_UNSIGNED_BYTE, false, false, false);
-    EXPECT_TRUE(glGetError() == GL_INVALID_OPERATION);
-  } else {
-    glCopySubTextureCHROMIUM(textures_[0], textures_[1], 0, 0, 0,
-                             0, 1, 1, false, false, false);
-    EXPECT_TRUE(glGetError() == GL_NO_ERROR);
+      glBindTexture(GL_TEXTURE_2D, textures_[1]);
+      glTexStorage2DEXT(GL_TEXTURE_2D, 1, dest_internal_format, 1, 1);
+      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                             GL_TEXTURE_2D, textures_[1], 0);
+      EXPECT_TRUE(glGetError() == GL_NO_ERROR);
 
-    // Check the FB is still bound.
-    GLint value = 0;
-    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &value);
-    GLuint fb_id = value;
-    EXPECT_EQ(framebuffer_id_, fb_id);
+      if (copy_type == TexImage) {
+        glCopyTextureCHROMIUM(textures_[0], textures_[1],
+                              ExtractFormatFrom(dest_internal_format),
+                              GL_UNSIGNED_BYTE, false, false, false);
+        EXPECT_TRUE(glGetError() == GL_INVALID_OPERATION);
+      } else {
+        glCopySubTextureCHROMIUM(textures_[0], textures_[1], 0, 0, 0, 0, 1, 1,
+                                 false, false, false);
+        EXPECT_TRUE(glGetError() == GL_NO_ERROR);
 
-    // Check that FB is complete.
-    EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
-              glCheckFramebufferStatus(GL_FRAMEBUFFER));
+        // Check the FB is still bound.
+        GLint value = 0;
+        glGetIntegerv(GL_FRAMEBUFFER_BINDING, &value);
+        GLuint fb_id = value;
+        EXPECT_EQ(framebuffer_id_, fb_id);
 
-    GLTestHelper::CheckPixels(0, 0, 1, 1, 0, pixels);
-    EXPECT_TRUE(GL_NO_ERROR == glGetError());
+        // Check that FB is complete.
+        EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+                  glCheckFramebufferStatus(GL_FRAMEBUFFER));
+
+        GLTestHelper::CheckPixels(0, 0, 1, 1, 0, pixels);
+        EXPECT_TRUE(GL_NO_ERROR == glGetError());
+      }
+    }
   }
 }
 
diff --git a/gpu/config/gpu_driver_bug_list_json.cc b/gpu/config/gpu_driver_bug_list_json.cc
index 03a8dd06..8b81fa8 100644
--- a/gpu/config/gpu_driver_bug_list_json.cc
+++ b/gpu/config/gpu_driver_bug_list_json.cc
@@ -1754,7 +1754,7 @@
       "vendor_id": "0x1002",
       "device_id": ["0x68b8"],
       "features": [
-        "disable_webgl_multisampling_color_mask_usage"
+        "disable_multisampling_color_mask_usage"
       ]
     },
     {
diff --git a/gpu/config/gpu_driver_bug_workaround_type.h b/gpu/config/gpu_driver_bug_workaround_type.h
index 2f1f865f..4b59789 100644
--- a/gpu/config/gpu_driver_bug_workaround_type.h
+++ b/gpu/config/gpu_driver_bug_workaround_type.h
@@ -65,8 +65,8 @@
          disable_texture_storage)                            \
   GPU_OP(DISABLE_TIMESTAMP_QUERIES,                          \
          disable_timestamp_queries)                          \
-  GPU_OP(DISABLE_WEBGL_MULTISAMPLING_COLOR_MASK_USAGE,       \
-         disable_webgl_multisampling_color_mask_usage)       \
+  GPU_OP(DISABLE_MULTISAMPLING_COLOR_MASK_USAGE,             \
+         disable_multisampling_color_mask_usage)             \
   GPU_OP(DISABLE_WEBGL_RGB_MULTISAMPLING_USAGE,              \
          disable_webgl_rgb_multisampling_usage)              \
   GPU_OP(ETC1_POWER_OF_TWO_ONLY,                             \
diff --git a/gpu/ipc/common/gpu_command_buffer_traits_multi.h b/gpu/ipc/common/gpu_command_buffer_traits_multi.h
index 78cd98e..4994e42 100644
--- a/gpu/ipc/common/gpu_command_buffer_traits_multi.h
+++ b/gpu/ipc/common/gpu_command_buffer_traits_multi.h
@@ -111,7 +111,7 @@
   IPC_STRUCT_TRAITS_MEMBER(timer_queries)
   IPC_STRUCT_TRAITS_MEMBER(surfaceless)
   IPC_STRUCT_TRAITS_MEMBER(flips_vertically)
-  IPC_STRUCT_TRAITS_MEMBER(disable_webgl_multisampling_color_mask_usage)
+  IPC_STRUCT_TRAITS_MEMBER(disable_multisampling_color_mask_usage)
   IPC_STRUCT_TRAITS_MEMBER(disable_webgl_rgb_multisampling_usage)
   IPC_STRUCT_TRAITS_MEMBER(msaa_is_slow)
   IPC_STRUCT_TRAITS_MEMBER(chromium_image_rgb_emulation)
diff --git a/gpu/ipc/common/gpu_param_traits_macros.h b/gpu/ipc/common/gpu_param_traits_macros.h
index 514f464..971c38f 100644
--- a/gpu/ipc/common/gpu_param_traits_macros.h
+++ b/gpu/ipc/common/gpu_param_traits_macros.h
@@ -129,6 +129,7 @@
   IPC_STRUCT_TRAITS_MEMBER(fail_if_major_perf_caveat)
   IPC_STRUCT_TRAITS_MEMBER(lose_context_when_out_of_memory)
   IPC_STRUCT_TRAITS_MEMBER(context_type)
+  IPC_STRUCT_TRAITS_MEMBER(should_use_native_gmb_for_backbuffer)
 IPC_STRUCT_TRAITS_END()
 
 
diff --git a/headless/BUILD.gn b/headless/BUILD.gn
index d142d15c..40e3230 100644
--- a/headless/BUILD.gn
+++ b/headless/BUILD.gn
@@ -74,6 +74,8 @@
     "$target_gen_dir/public/domains/animation.h",
     "$target_gen_dir/public/domains/application_cache.cc",
     "$target_gen_dir/public/domains/application_cache.h",
+    "$target_gen_dir/public/domains/browser.cc",
+    "$target_gen_dir/public/domains/browser.h",
     "$target_gen_dir/public/domains/cache_storage.cc",
     "$target_gen_dir/public/domains/cache_storage.h",
     "$target_gen_dir/public/domains/console.cc",
@@ -155,6 +157,8 @@
     "$target_gen_dir/public/domains/animation.h",
     "$target_gen_dir/public/domains/application_cache.cc",
     "$target_gen_dir/public/domains/application_cache.h",
+    "$target_gen_dir/public/domains/browser.cc",
+    "$target_gen_dir/public/domains/browser.h",
     "$target_gen_dir/public/domains/cache_storage.cc",
     "$target_gen_dir/public/domains/cache_storage.h",
     "$target_gen_dir/public/domains/console.cc",
@@ -222,6 +226,8 @@
     "lib/browser/headless_devtools.h",
     "lib/browser/headless_devtools_client_impl.cc",
     "lib/browser/headless_devtools_client_impl.h",
+    "lib/browser/headless_devtools_manager_delegate.cc",
+    "lib/browser/headless_devtools_manager_delegate.h",
     "lib/browser/headless_screen.cc",
     "lib/browser/headless_screen.h",
     "lib/browser/headless_url_request_context_getter.cc",
diff --git a/headless/lib/browser/headless_browser_impl.cc b/headless/lib/browser/headless_browser_impl.cc
index a3eb1ba..04ce85f 100644
--- a/headless/lib/browser/headless_browser_impl.cc
+++ b/headless/lib/browser/headless_browser_impl.cc
@@ -105,10 +105,10 @@
 
 std::vector<HeadlessWebContents*> HeadlessBrowserImpl::GetAllWebContents() {
   std::vector<HeadlessWebContents*> result;
-  result.reserve(web_contents_.size());
+  result.reserve(web_contents_map_.size());
 
-  for (const auto& web_contents_pair : web_contents_) {
-    result.push_back(web_contents_pair.first);
+  for (const auto& web_contents_pair : web_contents_map_) {
+    result.push_back(web_contents_pair.second.get());
   }
 
   return result;
@@ -144,15 +144,24 @@
     std::unique_ptr<HeadlessWebContentsImpl> web_contents) {
   DCHECK(web_contents);
   HeadlessWebContentsImpl* unowned_web_contents = web_contents.get();
-  web_contents_[unowned_web_contents] = std::move(web_contents);
+  web_contents_map_[unowned_web_contents->GetDevtoolsAgentHostId()] =
+      std::move(web_contents);
   return unowned_web_contents;
 }
 
 void HeadlessBrowserImpl::DestroyWebContents(
     HeadlessWebContentsImpl* web_contents) {
-  auto it = web_contents_.find(web_contents);
-  DCHECK(it != web_contents_.end());
-  web_contents_.erase(it);
+  auto it = web_contents_map_.find(web_contents->GetDevtoolsAgentHostId());
+  DCHECK(it != web_contents_map_.end());
+  web_contents_map_.erase(it);
+}
+
+HeadlessWebContents* HeadlessBrowserImpl::GetWebContentsForDevtoolsAgentHostId(
+    const std::string& devtools_agent_host_id) {
+  auto it = web_contents_map_.find(devtools_agent_host_id);
+  if (it == web_contents_map_.end())
+    return nullptr;
+  return it->second.get();
 }
 
 void HeadlessBrowserImpl::SetOptionsForTesting(
diff --git a/headless/lib/browser/headless_browser_impl.h b/headless/lib/browser/headless_browser_impl.h
index 68dc676e..50d59848 100644
--- a/headless/lib/browser/headless_browser_impl.h
+++ b/headless/lib/browser/headless_browser_impl.h
@@ -46,6 +46,8 @@
   void Shutdown() override;
 
   std::vector<HeadlessWebContents*> GetAllWebContents() override;
+  HeadlessWebContents* GetWebContentsForDevtoolsAgentHostId(
+      const std::string& devtools_agent_host_id) override;
 
   void set_browser_main_parts(HeadlessBrowserMainParts* browser_main_parts);
   HeadlessBrowserMainParts* browser_main_parts() const;
@@ -73,8 +75,8 @@
   std::unique_ptr<aura::WindowTreeHost> window_tree_host_;
   std::unique_ptr<aura::client::WindowTreeClient> window_tree_client_;
 
-  std::unordered_map<HeadlessWebContents*, std::unique_ptr<HeadlessWebContents>>
-      web_contents_;
+  std::unordered_map<std::string, std::unique_ptr<HeadlessWebContents>>
+      web_contents_map_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(HeadlessBrowserImpl);
diff --git a/headless/lib/browser/headless_content_browser_client.cc b/headless/lib/browser/headless_content_browser_client.cc
index a56a1fe..23ddee0 100644
--- a/headless/lib/browser/headless_content_browser_client.cc
+++ b/headless/lib/browser/headless_content_browser_client.cc
@@ -10,6 +10,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "headless/lib/browser/headless_browser_impl.h"
 #include "headless/lib/browser/headless_browser_main_parts.h"
+#include "headless/lib/browser/headless_devtools_manager_delegate.h"
 
 namespace headless {
 
@@ -27,4 +28,9 @@
   return browser_main_parts.release();
 }
 
+content::DevToolsManagerDelegate*
+HeadlessContentBrowserClient::GetDevToolsManagerDelegate() {
+  return new HeadlessDevToolsManagerDelegate(browser_);
+}
+
 }  // namespace headless
diff --git a/headless/lib/browser/headless_content_browser_client.h b/headless/lib/browser/headless_content_browser_client.h
index 16d9ef3..222c3d7 100644
--- a/headless/lib/browser/headless_content_browser_client.h
+++ b/headless/lib/browser/headless_content_browser_client.h
@@ -11,6 +11,7 @@
 
 class HeadlessBrowserImpl;
 class HeadlessBrowserMainParts;
+class HeadlessDevToolsManagerDelegate;
 
 class HeadlessContentBrowserClient : public content::ContentBrowserClient {
  public:
@@ -21,6 +22,8 @@
   content::BrowserMainParts* CreateBrowserMainParts(
       const content::MainFunctionParams&) override;
 
+  content::DevToolsManagerDelegate* GetDevToolsManagerDelegate() override;
+
  private:
   HeadlessBrowserImpl* browser_;  // Not owned.
 
diff --git a/headless/lib/browser/headless_devtools_client_impl.cc b/headless/lib/browser/headless_devtools_client_impl.cc
index 41aa4fc..a00aa7e 100644
--- a/headless/lib/browser/headless_devtools_client_impl.cc
+++ b/headless/lib/browser/headless_devtools_client_impl.cc
@@ -33,6 +33,7 @@
       accessibility_domain_(this),
       animation_domain_(this),
       application_cache_domain_(this),
+      browser_domain_(this),
       cache_storage_domain_(this),
       console_domain_(this),
       css_domain_(this),
@@ -158,6 +159,10 @@
   return &application_cache_domain_;
 }
 
+browser::Domain* HeadlessDevToolsClientImpl::GetBrowser() {
+  return &browser_domain_;
+}
+
 cache_storage::Domain* HeadlessDevToolsClientImpl::GetCacheStorage() {
   return &cache_storage_domain_;
 }
diff --git a/headless/lib/browser/headless_devtools_client_impl.h b/headless/lib/browser/headless_devtools_client_impl.h
index c7dbb52..fed7050 100644
--- a/headless/lib/browser/headless_devtools_client_impl.h
+++ b/headless/lib/browser/headless_devtools_client_impl.h
@@ -11,6 +11,7 @@
 #include "headless/public/domains/accessibility.h"
 #include "headless/public/domains/animation.h"
 #include "headless/public/domains/application_cache.h"
+#include "headless/public/domains/browser.h"
 #include "headless/public/domains/cache_storage.h"
 #include "headless/public/domains/console.h"
 #include "headless/public/domains/css.h"
@@ -63,6 +64,7 @@
   accessibility::Domain* GetAccessibility() override;
   animation::Domain* GetAnimation() override;
   application_cache::Domain* GetApplicationCache() override;
+  browser::Domain* GetBrowser() override;
   cache_storage::Domain* GetCacheStorage() override;
   console::Domain* GetConsole() override;
   css::Domain* GetCSS() override;
@@ -154,6 +156,7 @@
   accessibility::ExperimentalDomain accessibility_domain_;
   animation::ExperimentalDomain animation_domain_;
   application_cache::ExperimentalDomain application_cache_domain_;
+  browser::ExperimentalDomain browser_domain_;
   cache_storage::ExperimentalDomain cache_storage_domain_;
   console::ExperimentalDomain console_domain_;
   css::ExperimentalDomain css_domain_;
diff --git a/headless/lib/browser/headless_devtools_manager_delegate.cc b/headless/lib/browser/headless_devtools_manager_delegate.cc
new file mode 100644
index 0000000..5c4f962
--- /dev/null
+++ b/headless/lib/browser/headless_devtools_manager_delegate.cc
@@ -0,0 +1,154 @@
+// 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 "headless/lib/browser/headless_devtools_manager_delegate.h"
+
+#include <string>
+
+#include "base/guid.h"
+#include "content/public/browser/web_contents.h"
+#include "headless/lib/browser/headless_browser_context_impl.h"
+#include "headless/lib/browser/headless_browser_impl.h"
+#include "headless/lib/browser/headless_web_contents_impl.h"
+#include "headless/public/domains/browser.h"
+
+namespace headless {
+
+HeadlessDevToolsManagerDelegate::HeadlessDevToolsManagerDelegate(
+    HeadlessBrowserImpl* browser)
+    : browser_(browser) {
+  command_map_["Browser.createTarget"] =
+      &HeadlessDevToolsManagerDelegate::CreateTarget;
+  command_map_["Browser.closeTarget"] =
+      &HeadlessDevToolsManagerDelegate::CloseTarget;
+  command_map_["Browser.createBrowserContext"] =
+      &HeadlessDevToolsManagerDelegate::CreateBrowserContext;
+  command_map_["Browser.disposeBrowserContext"] =
+      &HeadlessDevToolsManagerDelegate::DisposeBrowserContext;
+}
+
+HeadlessDevToolsManagerDelegate::~HeadlessDevToolsManagerDelegate() {}
+
+base::DictionaryValue* HeadlessDevToolsManagerDelegate::HandleCommand(
+    content::DevToolsAgentHost* agent_host,
+    base::DictionaryValue* command) {
+  int id;
+  std::string method;
+  const base::DictionaryValue* params = nullptr;
+  if (!command->GetInteger("id", &id) ||
+      !command->GetString("method", &method) ||
+      !command->GetDictionary("params", &params)) {
+    return nullptr;
+  }
+  auto find_it = command_map_.find(method);
+  if (find_it == command_map_.end())
+    return nullptr;
+  CommandMemberFnPtr command_fn_ptr = find_it->second;
+  std::unique_ptr<base::Value> cmd_result(((this)->*command_fn_ptr)(params));
+  if (!cmd_result)
+    return nullptr;
+
+  std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
+  result->SetInteger("id", id);
+  result->Set("result", std::move(cmd_result));
+  return result.release();
+}
+
+std::unique_ptr<base::Value> HeadlessDevToolsManagerDelegate::CreateTarget(
+    const base::DictionaryValue* params) {
+  std::string initial_url;
+  std::string browser_context_id;
+  int width = 800;
+  int height = 600;
+  params->GetString("initialUrl", &initial_url);
+  params->GetString("browserContextId", &browser_context_id);
+  params->GetInteger("width", &width);
+  params->GetInteger("height", &height);
+  HeadlessWebContentsImpl* web_contents_impl;
+  auto find_it = browser_context_map_.find(browser_context_id);
+  if (find_it != browser_context_map_.end()) {
+    web_contents_impl = HeadlessWebContentsImpl::From(
+        browser_->CreateWebContentsBuilder()
+            .SetInitialURL(GURL(initial_url))
+            .SetWindowSize(gfx::Size(width, height))
+            .SetBrowserContext(find_it->second.get())
+            .Build());
+  } else {
+    web_contents_impl = HeadlessWebContentsImpl::From(
+        browser_->CreateWebContentsBuilder()
+            .SetInitialURL(GURL(initial_url))
+            .SetWindowSize(gfx::Size(width, height))
+            .Build());
+  }
+  return browser::CreateTargetResult::Builder()
+      .SetTargetId(web_contents_impl->GetDevtoolsAgentHostId())
+      .Build()
+      ->Serialize();
+}
+
+std::unique_ptr<base::Value> HeadlessDevToolsManagerDelegate::CloseTarget(
+    const base::DictionaryValue* params) {
+  std::string target_id;
+  if (!params->GetString("targetId", &target_id)) {
+    return nullptr;
+  }
+  HeadlessWebContents* web_contents =
+      browser_->GetWebContentsForDevtoolsAgentHostId(target_id);
+  bool success = false;
+  if (web_contents) {
+    web_contents->Close();
+    success = true;
+  }
+  return browser::CloseTargetResult::Builder()
+      .SetSuccess(success)
+      .Build()
+      ->Serialize();
+}
+
+std::unique_ptr<base::Value>
+HeadlessDevToolsManagerDelegate::CreateBrowserContext(
+    const base::DictionaryValue* params) {
+  std::string browser_context_id = base::GenerateGUID();
+  browser_context_map_[browser_context_id] =
+      browser_->CreateBrowserContextBuilder().Build();
+  std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
+  return browser::CreateBrowserContextResult::Builder()
+      .SetBrowserContextId(browser_context_id)
+      .Build()
+      ->Serialize();
+}
+
+std::unique_ptr<base::Value>
+HeadlessDevToolsManagerDelegate::DisposeBrowserContext(
+    const base::DictionaryValue* params) {
+  std::string browser_context_id;
+  if (!params->GetString("browserContextId", &browser_context_id)) {
+    return nullptr;
+  }
+  auto find_it = browser_context_map_.find(browser_context_id);
+  bool success = false;
+  if (find_it != browser_context_map_.end()) {
+    success = true;
+    HeadlessBrowserContextImpl* headless_browser_context =
+        HeadlessBrowserContextImpl::From(find_it->second.get());
+    // Make sure |headless_browser_context| isn't in use!
+    for (HeadlessWebContents* headless_web_contents :
+         browser_->GetAllWebContents()) {
+      content::WebContents* web_contents =
+          HeadlessWebContentsImpl::From(headless_web_contents)->web_contents();
+      if (web_contents->GetBrowserContext() == headless_browser_context) {
+        success = false;
+        break;
+      }
+    }
+    if (success)
+      browser_context_map_.erase(find_it);
+  }
+  return browser::DisposeBrowserContextResult::Builder()
+      .SetSuccess(success)
+      .Build()
+      ->Serialize();
+}
+
+}  // namespace headless
diff --git a/headless/lib/browser/headless_devtools_manager_delegate.h b/headless/lib/browser/headless_devtools_manager_delegate.h
new file mode 100644
index 0000000..fa4cd17
--- /dev/null
+++ b/headless/lib/browser/headless_devtools_manager_delegate.h
@@ -0,0 +1,56 @@
+// 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 HEADLESS_LIB_BROWSER_HEADLESS_DEVTOOLS_MANAGER_DELEGATE_H_
+#define HEADLESS_LIB_BROWSER_HEADLESS_DEVTOOLS_MANAGER_DELEGATE_H_
+
+#include "content/public/browser/devtools_manager_delegate.h"
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/values.h"
+
+namespace headless {
+class HeadlessBrowserImpl;
+class HeadlessBrowserContext;
+class HeadlessWebContentsImpl;
+
+class HeadlessDevToolsManagerDelegate
+    : public content::DevToolsManagerDelegate {
+ public:
+  explicit HeadlessDevToolsManagerDelegate(HeadlessBrowserImpl* browser);
+  ~HeadlessDevToolsManagerDelegate() override;
+
+  // DevToolsManagerDelegate implementation:
+  void Inspect(content::BrowserContext* browser_context,
+               content::DevToolsAgentHost* agent_host) override {}
+  void DevToolsAgentStateChanged(content::DevToolsAgentHost* agent_host,
+                                 bool attached) override{};
+  base::DictionaryValue* HandleCommand(content::DevToolsAgentHost* agent_host,
+                                       base::DictionaryValue* command) override;
+
+ private:
+  std::unique_ptr<base::Value> CreateTarget(
+      const base::DictionaryValue* params);
+  std::unique_ptr<base::Value> CloseTarget(const base::DictionaryValue* params);
+  std::unique_ptr<base::Value> CreateBrowserContext(
+      const base::DictionaryValue* params);
+  std::unique_ptr<base::Value> DisposeBrowserContext(
+      const base::DictionaryValue* params);
+
+  HeadlessBrowserImpl* browser_;  // Not owned.
+  std::map<std::string, std::unique_ptr<HeadlessBrowserContext>>
+      browser_context_map_;
+
+  using CommandMemberFnPtr = std::unique_ptr<base::Value> (
+      HeadlessDevToolsManagerDelegate::*)(const base::DictionaryValue* params);
+
+  std::map<std::string, CommandMemberFnPtr> command_map_;
+};
+
+}  // namespace headless
+
+#endif  // HEADLESS_LIB_BROWSER_HEADLESS_DEVTOOLS_MANAGER_DELEGATE_H_
diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc
index b07cb2c..0b10161f 100644
--- a/headless/lib/browser/headless_web_contents_impl.cc
+++ b/headless/lib/browser/headless_web_contents_impl.cc
@@ -27,6 +27,14 @@
 
 namespace headless {
 
+// static
+HeadlessWebContentsImpl* HeadlessWebContentsImpl::From(
+    HeadlessWebContents* web_contents) {
+  // This downcast is safe because there is only one implementation of
+  // HeadlessWebContents.
+  return static_cast<HeadlessWebContentsImpl*>(web_contents);
+}
+
 class WebContentsObserverAdapter : public content::WebContentsObserver {
  public:
   WebContentsObserverAdapter(content::WebContents* web_contents,
@@ -114,6 +122,7 @@
     HeadlessBrowserImpl* browser)
     : web_contents_delegate_(new HeadlessWebContentsImpl::Delegate(browser)),
       web_contents_(web_contents),
+      agent_host_(content::DevToolsAgentHost::GetOrCreateFor(web_contents)),
       browser_(browser) {
   web_contents_->SetDelegate(web_contents_delegate_.get());
 }
@@ -137,6 +146,10 @@
   browser_->DestroyWebContents(this);
 }
 
+std::string HeadlessWebContentsImpl::GetDevtoolsAgentHostId() {
+  return agent_host_->GetId();
+}
+
 void HeadlessWebContentsImpl::AddObserver(Observer* observer) {
   DCHECK(observer_map_.find(observer) == observer_map_.end());
   observer_map_[observer] = base::WrapUnique(
@@ -154,8 +167,6 @@
 }
 
 void HeadlessWebContentsImpl::AttachClient(HeadlessDevToolsClient* client) {
-  if (!agent_host_)
-    agent_host_ = content::DevToolsAgentHost::GetOrCreateFor(web_contents());
   HeadlessDevToolsClientImpl::From(client)->AttachToHost(agent_host_.get());
 }
 
diff --git a/headless/lib/browser/headless_web_contents_impl.h b/headless/lib/browser/headless_web_contents_impl.h
index e0eec04..dde41581d 100644
--- a/headless/lib/browser/headless_web_contents_impl.h
+++ b/headless/lib/browser/headless_web_contents_impl.h
@@ -35,6 +35,8 @@
  public:
   ~HeadlessWebContentsImpl() override;
 
+  static HeadlessWebContentsImpl* From(HeadlessWebContents* web_contents);
+
   static std::unique_ptr<HeadlessWebContentsImpl> Create(
       HeadlessWebContents::Builder* builder,
       aura::Window* parent_window,
@@ -59,6 +61,8 @@
 
   void Close() override;
 
+  std::string GetDevtoolsAgentHostId();
+
  private:
   // Takes ownership of |web_contents|.
   HeadlessWebContentsImpl(content::WebContents* web_contents,
diff --git a/headless/lib/headless_devtools_client_browsertest.cc b/headless/lib/headless_devtools_client_browsertest.cc
index 8b51fec..daceba5d 100644
--- a/headless/lib/headless_devtools_client_browsertest.cc
+++ b/headless/lib/headless_devtools_client_browsertest.cc
@@ -4,7 +4,9 @@
 
 #include <memory>
 
+#include "base/json/json_reader.h"
 #include "content/public/test/browser_test.h"
+#include "headless/public/domains/browser.h"
 #include "headless/public/domains/network.h"
 #include "headless/public/domains/page.h"
 #include "headless/public/domains/runtime.h"
@@ -172,4 +174,324 @@
 
 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessDevToolsClientExperimentalTest);
 
+class BrowserDomainCreateAndDeletePageTest
+    : public HeadlessAsyncDevTooledBrowserTest {
+  void RunDevTooledTest() override {
+    EXPECT_TRUE(embedded_test_server()->Start());
+
+    EXPECT_EQ(1u, browser()->GetAllWebContents().size());
+
+    devtools_client_->GetBrowser()->GetExperimental()->CreateTarget(
+        browser::CreateTargetParams::Builder()
+            .SetInitialUrl(embedded_test_server()->GetURL("/hello.html").spec())
+            .SetWidth(1)
+            .SetHeight(1)
+            .Build(),
+        base::Bind(&BrowserDomainCreateAndDeletePageTest::OnCreateTargetResult,
+                   base::Unretained(this)));
+  }
+
+  void OnCreateTargetResult(
+      std::unique_ptr<browser::CreateTargetResult> result) {
+    EXPECT_EQ(2u, browser()->GetAllWebContents().size());
+
+    devtools_client_->GetBrowser()->GetExperimental()->CloseTarget(
+        browser::CloseTargetParams::Builder()
+            .SetTargetId(result->GetTargetId())
+            .Build(),
+        base::Bind(&BrowserDomainCreateAndDeletePageTest::OnCloseTargetResult,
+                   base::Unretained(this)));
+  }
+
+  void OnCloseTargetResult(std::unique_ptr<browser::CloseTargetResult> result) {
+    EXPECT_EQ(1u, browser()->GetAllWebContents().size());
+    FinishAsynchronousTest();
+  }
+};
+
+HEADLESS_ASYNC_DEVTOOLED_TEST_F(BrowserDomainCreateAndDeletePageTest);
+
+class BrowserDomainDisposeContextFailsIfInUse
+    : public HeadlessAsyncDevTooledBrowserTest {
+  void RunDevTooledTest() override {
+    EXPECT_TRUE(embedded_test_server()->Start());
+
+    EXPECT_EQ(1u, browser()->GetAllWebContents().size());
+    devtools_client_->GetBrowser()->GetExperimental()->CreateBrowserContext(
+        browser::CreateBrowserContextParams::Builder().Build(),
+        base::Bind(&BrowserDomainDisposeContextFailsIfInUse::OnContextCreated,
+                   base::Unretained(this)));
+  }
+
+  void OnContextCreated(
+      std::unique_ptr<browser::CreateBrowserContextResult> result) {
+    context_id_ = result->GetBrowserContextId();
+
+    devtools_client_->GetBrowser()->GetExperimental()->CreateTarget(
+        browser::CreateTargetParams::Builder()
+            .SetInitialUrl(embedded_test_server()->GetURL("/hello.html").spec())
+            .SetBrowserContextId(context_id_)
+            .Build(),
+        base::Bind(
+            &BrowserDomainDisposeContextFailsIfInUse::OnCreateTargetResult,
+            base::Unretained(this)));
+  }
+
+  void OnCreateTargetResult(
+      std::unique_ptr<browser::CreateTargetResult> result) {
+    page_id_ = result->GetTargetId();
+
+    devtools_client_->GetBrowser()->GetExperimental()->DisposeBrowserContext(
+        browser::DisposeBrowserContextParams::Builder()
+            .SetBrowserContextId(context_id_)
+            .Build(),
+        base::Bind(&BrowserDomainDisposeContextFailsIfInUse::
+                       OnDisposeBrowserContextResult,
+                   base::Unretained(this)));
+  }
+
+  void OnDisposeBrowserContextResult(
+      std::unique_ptr<browser::DisposeBrowserContextResult> result) {
+    EXPECT_FALSE(result->GetSuccess());
+
+    // Close the page and try again.
+    devtools_client_->GetBrowser()->GetExperimental()->CloseTarget(
+        browser::CloseTargetParams::Builder().SetTargetId(page_id_).Build(),
+        base::Bind(
+            &BrowserDomainDisposeContextFailsIfInUse::OnCloseTargetResult,
+            base::Unretained(this)));
+  }
+
+  void OnCloseTargetResult(std::unique_ptr<browser::CloseTargetResult> result) {
+    EXPECT_TRUE(result->GetSuccess());
+
+    devtools_client_->GetBrowser()->GetExperimental()->DisposeBrowserContext(
+        browser::DisposeBrowserContextParams::Builder()
+            .SetBrowserContextId(context_id_)
+            .Build(),
+        base::Bind(&BrowserDomainDisposeContextFailsIfInUse::
+                       OnDisposeBrowserContextResult2,
+                   base::Unretained(this)));
+  }
+
+  void OnDisposeBrowserContextResult2(
+      std::unique_ptr<browser::DisposeBrowserContextResult> result) {
+    EXPECT_TRUE(result->GetSuccess());
+    FinishAsynchronousTest();
+  }
+
+ private:
+  std::string context_id_;
+  std::string page_id_;
+};
+
+HEADLESS_ASYNC_DEVTOOLED_TEST_F(BrowserDomainDisposeContextFailsIfInUse);
+
+class BrowserDomainCreateTwoContexts : public HeadlessAsyncDevTooledBrowserTest,
+                                       public browser::ExperimentalObserver {
+ public:
+  void RunDevTooledTest() override {
+    EXPECT_TRUE(embedded_test_server()->Start());
+
+    devtools_client_->GetBrowser()->GetExperimental()->AddObserver(this);
+    devtools_client_->GetBrowser()->GetExperimental()->CreateBrowserContext(
+        browser::CreateBrowserContextParams::Builder().Build(),
+        base::Bind(&BrowserDomainCreateTwoContexts::OnContextOneCreated,
+                   base::Unretained(this)));
+
+    devtools_client_->GetBrowser()->GetExperimental()->CreateBrowserContext(
+        browser::CreateBrowserContextParams::Builder().Build(),
+        base::Bind(&BrowserDomainCreateTwoContexts::OnContextTwoCreated,
+                   base::Unretained(this)));
+  }
+
+  void OnContextOneCreated(
+      std::unique_ptr<browser::CreateBrowserContextResult> result) {
+    context_id_one_ = result->GetBrowserContextId();
+    MaybeCreatePages();
+  }
+
+  void OnContextTwoCreated(
+      std::unique_ptr<browser::CreateBrowserContextResult> result) {
+    context_id_two_ = result->GetBrowserContextId();
+    MaybeCreatePages();
+  }
+
+  void MaybeCreatePages() {
+    if (context_id_one_.empty() || context_id_two_.empty())
+      return;
+
+    devtools_client_->GetBrowser()->GetExperimental()->CreateTarget(
+        browser::CreateTargetParams::Builder()
+            .SetInitialUrl(embedded_test_server()->GetURL("/hello.html").spec())
+            .SetBrowserContextId(context_id_one_)
+            .Build(),
+        base::Bind(&BrowserDomainCreateTwoContexts::OnCreateTargetOneResult,
+                   base::Unretained(this)));
+
+    devtools_client_->GetBrowser()->GetExperimental()->CreateTarget(
+        browser::CreateTargetParams::Builder()
+            .SetInitialUrl(embedded_test_server()->GetURL("/hello.html").spec())
+            .SetBrowserContextId(context_id_two_)
+            .Build(),
+        base::Bind(&BrowserDomainCreateTwoContexts::OnCreateTargetTwoResult,
+                   base::Unretained(this)));
+  }
+
+  void OnCreateTargetOneResult(
+      std::unique_ptr<browser::CreateTargetResult> result) {
+    page_id_one_ = result->GetTargetId();
+    MaybeTestIsolation();
+  }
+
+  void OnCreateTargetTwoResult(
+      std::unique_ptr<browser::CreateTargetResult> result) {
+    page_id_two_ = result->GetTargetId();
+    MaybeTestIsolation();
+  }
+
+  void MaybeTestIsolation() {
+    if (page_id_one_.empty() || page_id_two_.empty())
+      return;
+
+    devtools_client_->GetBrowser()->GetExperimental()->Attach(
+        browser::AttachParams::Builder().SetTargetId(page_id_one_).Build(),
+        base::Bind(&BrowserDomainCreateTwoContexts::OnAttachedOne,
+                   base::Unretained(this)));
+
+    devtools_client_->GetBrowser()->GetExperimental()->Attach(
+        browser::AttachParams::Builder().SetTargetId(page_id_two_).Build(),
+        base::Bind(&BrowserDomainCreateTwoContexts::OnAttachedTwo,
+                   base::Unretained(this)));
+  }
+
+  void OnAttachedOne(std::unique_ptr<browser::AttachResult> result) {
+    devtools_client_->GetBrowser()->GetExperimental()->SendMessage(
+        browser::SendMessageParams::Builder()
+            .SetTargetId(page_id_one_)
+            .SetMessage("{\"id\":101, \"method\": \"Page.enable\"}")
+            .Build());
+  }
+
+  void OnAttachedTwo(std::unique_ptr<browser::AttachResult> result) {
+    devtools_client_->GetBrowser()->GetExperimental()->SendMessage(
+        browser::SendMessageParams::Builder()
+            .SetTargetId(page_id_two_)
+            .SetMessage("{\"id\":102, \"method\": \"Page.enable\"}")
+            .Build());
+  }
+
+  void MaybeSetCookieOnPageOne() {
+    if (!page_one_loaded_ || !page_two_loaded_)
+      return;
+
+    devtools_client_->GetBrowser()->GetExperimental()->SendMessage(
+        browser::SendMessageParams::Builder()
+            .SetTargetId(page_id_one_)
+            .SetMessage("{\"id\":201, \"method\": \"Runtime.evaluate\", "
+                        "\"params\": {\"expression\": "
+                        "\"document.cookie = 'foo=bar';\"}}")
+            .Build());
+  }
+
+  void OnDispatchMessage(
+      const browser::DispatchMessageParams& params) override {
+    std::unique_ptr<base::Value> message =
+        base::JSONReader::Read(params.GetMessage(), base::JSON_PARSE_RFC);
+    const base::DictionaryValue* message_dict;
+    if (!message || !message->GetAsDictionary(&message_dict)) {
+      return;
+    }
+    std::string method;
+    if (message_dict->GetString("method", &method) &&
+        method == "Page.loadEventFired") {
+      if (params.GetTargetId() == page_id_one_) {
+        page_one_loaded_ = true;
+      } else if (params.GetTargetId() == page_id_two_) {
+        page_two_loaded_ = true;
+      }
+      MaybeSetCookieOnPageOne();
+      return;
+    }
+    const base::DictionaryValue* result_dict;
+    if (message_dict->GetDictionary("result", &result_dict)) {
+      // There's a nested result. We want the inner one.
+      if (!result_dict->GetDictionary("result", &result_dict))
+        return;
+      std::string value;
+      if (params.GetTargetId() == page_id_one_) {
+        // TODO(alexclarke): Make some better bindings for Browser.sendMessage.
+        devtools_client_->GetBrowser()->GetExperimental()->SendMessage(
+            browser::SendMessageParams::Builder()
+                .SetTargetId(page_id_two_)
+                .SetMessage("{\"id\":202, \"method\": \"Runtime.evaluate\", "
+                            "\"params\": {\"expression\": "
+                            "\"document.cookie;\"}}")
+                .Build());
+      } else if (params.GetTargetId() == page_id_two_ &&
+                 result_dict->GetString("value", &value)) {
+        EXPECT_EQ("", value) << "Page 2 should not share cookies from page one";
+
+        devtools_client_->GetBrowser()->GetExperimental()->CloseTarget(
+            browser::CloseTargetParams::Builder()
+                .SetTargetId(page_id_one_)
+                .Build(),
+            base::Bind(&BrowserDomainCreateTwoContexts::OnCloseTarget,
+                       base::Unretained(this)));
+
+        devtools_client_->GetBrowser()->GetExperimental()->CloseTarget(
+            browser::CloseTargetParams::Builder()
+                .SetTargetId(page_id_two_)
+                .Build(),
+            base::Bind(&BrowserDomainCreateTwoContexts::OnCloseTarget,
+                       base::Unretained(this)));
+
+        devtools_client_->GetBrowser()->GetExperimental()->RemoveObserver(this);
+      }
+    }
+  }
+
+  void OnCloseTarget(std::unique_ptr<browser::CloseTargetResult> result) {
+    page_close_count_++;
+
+    if (page_close_count_ < 2)
+      return;
+
+    devtools_client_->GetBrowser()->GetExperimental()->DisposeBrowserContext(
+        browser::DisposeBrowserContextParams::Builder()
+            .SetBrowserContextId(context_id_one_)
+            .Build(),
+        base::Bind(&BrowserDomainCreateTwoContexts::OnCloseContext,
+                   base::Unretained(this)));
+
+    devtools_client_->GetBrowser()->GetExperimental()->DisposeBrowserContext(
+        browser::DisposeBrowserContextParams::Builder()
+            .SetBrowserContextId(context_id_two_)
+            .Build(),
+        base::Bind(&BrowserDomainCreateTwoContexts::OnCloseContext,
+                   base::Unretained(this)));
+  }
+
+  void OnCloseContext(
+      std::unique_ptr<browser::DisposeBrowserContextResult> result) {
+    EXPECT_TRUE(result->GetSuccess());
+    if (++context_closed_count_ < 2)
+      return;
+
+    FinishAsynchronousTest();
+  }
+
+ private:
+  std::string context_id_one_;
+  std::string context_id_two_;
+  std::string page_id_one_;
+  std::string page_id_two_;
+  bool page_one_loaded_ = false;
+  bool page_two_loaded_ = false;
+  int page_close_count_ = 0;
+  int context_closed_count_ = 0;
+};
+
+HEADLESS_ASYNC_DEVTOOLED_TEST_F(BrowserDomainCreateTwoContexts);
+
 }  // namespace headless
diff --git a/headless/public/headless_browser.h b/headless/public/headless_browser.h
index 2e9145153..b98a40a 100644
--- a/headless/public/headless_browser.h
+++ b/headless/public/headless_browser.h
@@ -48,6 +48,11 @@
 
   virtual std::vector<HeadlessWebContents*> GetAllWebContents() = 0;
 
+  // Returns the HeadlessWebContents associated with the
+  // |devtools_agent_host_id| if any.  Otherwise returns null.
+  virtual HeadlessWebContents* GetWebContentsForDevtoolsAgentHostId(
+      const std::string& devtools_agent_host_id) = 0;
+
   // Returns a task runner for submitting work to the browser main thread.
   virtual scoped_refptr<base::SingleThreadTaskRunner> BrowserMainThread()
       const = 0;
diff --git a/headless/public/headless_devtools_client.h b/headless/public/headless_devtools_client.h
index a71ce657..89d686c 100644
--- a/headless/public/headless_devtools_client.h
+++ b/headless/public/headless_devtools_client.h
@@ -21,6 +21,9 @@
 namespace application_cache {
 class Domain;
 }
+namespace browser {
+class Domain;
+}
 namespace cache_storage {
 class Domain;
 }
@@ -115,6 +118,7 @@
   virtual accessibility::Domain* GetAccessibility() = 0;
   virtual animation::Domain* GetAnimation() = 0;
   virtual application_cache::Domain* GetApplicationCache() = 0;
+  virtual browser::Domain* GetBrowser() = 0;
   virtual cache_storage::Domain* GetCacheStorage() = 0;
   virtual console::Domain* GetConsole() = 0;
   virtual css::Domain* GetCSS() = 0;
diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg
index 65f3348..841960b8 100644
--- a/infra/config/cq.cfg
+++ b/infra/config/cq.cfg
@@ -65,7 +65,10 @@
       builders { name: "ios-simulator" }
       builders { name: "ios-simulator-gn" }
       builders { name: "mac_chromium_compile_dbg_ng" }
-      builders { name: "mac_chromium_gyp_rel" }
+      builders {
+        name: "mac_chromium_gyp_rel"
+        experiment_percentage: 10
+      }
       builders { name: "mac_chromium_rel_ng" }
       builders {
         name: "mac_chromium_10.10_rel_ng"
@@ -81,7 +84,7 @@
       builders { name: "win_chromium_compile_dbg_ng" }
       builders {
         name: "win8_chromium_gyp_rel"
-        experiment_percentage: 50
+        experiment_percentage: 10
       }
       builders { name: "win_chromium_rel_ng" }
       builders { name: "win_chromium_x64_rel_ng" }
diff --git a/ios/chrome/browser/signin/fake_oauth2_token_service_builder.mm b/ios/chrome/browser/signin/fake_oauth2_token_service_builder.mm
index a7735d82d..5d90b36 100644
--- a/ios/chrome/browser/signin/fake_oauth2_token_service_builder.mm
+++ b/ios/chrome/browser/signin/fake_oauth2_token_service_builder.mm
@@ -6,10 +6,10 @@
 
 #include "base/memory/ptr_util.h"
 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
-#include "components/signin/ios/browser/fake_profile_oauth2_token_service_ios_delegate.h"
-#include "components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.h"
+#include "components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/signin/account_tracker_service_factory.h"
+#include "ios/chrome/browser/signin/profile_oauth2_token_service_ios_provider_impl.h"
 #include "ios/chrome/browser/signin/signin_client_factory.h"
 #include "ios/chrome/browser/signin/signin_error_controller_factory.h"
 
@@ -18,9 +18,9 @@
   ios::ChromeBrowserState* browser_state =
       ios::ChromeBrowserState::FromBrowserState(context);
   OAuth2TokenServiceDelegate* delegate =
-      new FakeProfileOAuth2TokenServiceIOSDelegate(
+      new ProfileOAuth2TokenServiceIOSDelegate(
           SigninClientFactory::GetForBrowserState(browser_state),
-          base::MakeUnique<FakeProfileOAuth2TokenServiceIOSProvider>(),
+          base::MakeUnique<ProfileOAuth2TokenServiceIOSProviderImpl>(),
           ios::AccountTrackerServiceFactory::GetForBrowserState(browser_state),
           ios::SigninErrorControllerFactory::GetForBrowserState(browser_state));
   return base::WrapUnique(new FakeProfileOAuth2TokenService(delegate));
diff --git a/ios/chrome/browser/ui/webui/history/browsing_history_handler.cc b/ios/chrome/browser/ui/webui/history/browsing_history_handler.cc
index 5b5b8d5..ff0cf8e 100644
--- a/ios/chrome/browser/ui/webui/history/browsing_history_handler.cc
+++ b/ios/chrome/browser/ui/webui/history/browsing_history_handler.cc
@@ -801,7 +801,11 @@
   exploded.day_of_month = 1;
 
   if (offset == 0) {
-    options->begin_time = base::Time::FromLocalExploded(exploded);
+    if (!base::Time::FromLocalExploded(exploded, &options->begin_time)) {
+      // This file will be deprecated soon. No need to implement failure
+      // handling here.
+      NOTIMPLEMENTED();
+    }
 
     // Set the end time of this first search to null (which will
     // show results from the future, should the user's clock have
@@ -815,12 +819,20 @@
     exploded.month -= offset - 1;
     // Set the correct year.
     NormalizeMonths(&exploded);
-    options->end_time = base::Time::FromLocalExploded(exploded);
+    if (!base::Time::FromLocalExploded(exploded, &options->end_time)) {
+      // This file will be deprecated soon. No need to implement failure
+      // handling here.
+      NOTIMPLEMENTED();
+    }
 
     exploded.month -= 1;
     // Set the correct year
     NormalizeMonths(&exploded);
-    options->begin_time = base::Time::FromLocalExploded(exploded);
+    if (!base::Time::FromLocalExploded(exploded, &options->begin_time)) {
+      // This file will be deprecated soon. No need to implement failure
+      // handling here.
+      NOTIMPLEMENTED();
+    }
   }
 }
 
diff --git a/ios/chrome/tools/strings/generate_localizable_strings.mm b/ios/chrome/tools/strings/generate_localizable_strings.mm
index 95e733f..cec1154 100644
--- a/ios/chrome/tools/strings/generate_localizable_strings.mm
+++ b/ios/chrome/tools/strings/generate_localizable_strings.mm
@@ -88,22 +88,15 @@
   return nil;
 }
 
-NSString* EscapeStringForLocalizableStrings(NSString* string) {
-  NSString* slashEscapedString =
-      [string stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"];
-  return [slashEscapedString stringByReplacingOccurrencesOfString:@"\""
-                                                       withString:@"\\\""];
-}
-
-// Generate the content of the Localizable.string file for |locale| from the
-// resource data pack |data_pack|. The content should have the format of:
-//   "IDS_PRINT_TO_PHONE" = "Print to phone jobs are available.";
-//   "IDS_SNAPSHOTS" = "Snapshots are available.";
-NSString* GenerateLocalizableStringsFileContent(const ui::DataPack& data_pack,
-                                                const char* locale,
-                                                NSArray* resources,
-                                                NSDictionary* resources_ids) {
-  NSMutableString* localizable_strings = [NSMutableString string];
+// Generates a NSDictionary mapping string IDs to localized strings. The
+// dictionary can be written as a Property List (only contains types that
+// are valid in Propery Lists).
+NSDictionary* GenerateLocalizableStringsDictionary(
+    const ui::DataPack& data_pack,
+    const char* locale,
+    NSArray* resources,
+    NSDictionary* resources_ids) {
+  NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
   for (id resource : resources) {
     NSString* resource_name = nil;
     NSString* resource_output_name = nil;
@@ -128,10 +121,7 @@
         [[resources_ids objectForKey:resource_name] integerValue];
     NSString* string = GetStringFromDataPack(data_pack, resource_id);
     if (string) {
-      const char* output_string_name = [resource_output_name UTF8String];
-      [localizable_strings
-          appendFormat:@" \"%s\" = \"%@\";\n", output_string_name,
-                       EscapeStringForLocalizableStrings(string)];
+      [dictionary setObject:string forKey:resource_output_name];
     } else {
       fprintf(stderr, "ERROR: fail to load string '%s' for locale '%s'\n",
               [resource_name UTF8String], locale);
@@ -139,7 +129,7 @@
     }
   }
 
-  return localizable_strings;
+  return dictionary;
 }
 
 NSDictionary* LoadResourcesListFromHeaders(NSArray* header_list,
@@ -199,12 +189,12 @@
   return resources_ids;
 }
 
-// Save |localizable_strings| with |locale| to
-// |output_dir|/|locale|.lproj/|output_filename|.
-bool SaveLocalizableFile(NSString* localizable_strings,
-                         NSString* locale,
-                         NSString* output_dir,
-                         NSString* output_filename) {
+// Save |dictionary| as a Property List file (in binary1 encoding)
+// with |locale| to |output_dir|/|locale|.lproj/|output_filename|.
+bool SavePropertyList(NSDictionary* dictionary,
+                      NSString* locale,
+                      NSString* output_dir,
+                      NSString* output_filename) {
   // Compute the path to the output directory with locale.
   NSString* output_path = [output_dir
       stringByAppendingPathComponent:[NSString
@@ -222,12 +212,22 @@
     return false;
   }
 
+  // Convert to property list in binary format.
+  NSError* error = nil;
+  NSData* data = [NSPropertyListSerialization
+      dataWithPropertyList:dictionary
+                    format:NSPropertyListBinaryFormat_v1_0
+                   options:0
+                     error:&error];
+  if (!data) {
+    fprintf(stderr, "ERROR: conversion to property list failed: %s\n",
+            [[error localizedDescription] UTF8String]);
+    return false;
+  }
+
   // Save the strings to the disk.
   output_path = [output_path stringByAppendingPathComponent:output_filename];
-  if (![localizable_strings writeToFile:output_path
-                             atomically:YES
-                               encoding:NSUTF16StringEncoding
-                                  error:nil]) {
+  if (![data writeToFile:output_path atomically:YES]) {
     fprintf(stderr, "ERROR: Failed to write out '%s'\n",
             [output_filename UTF8String]);
     return false;
@@ -358,11 +358,10 @@
         exit(1);
       }
 
-      NSString* localizable_strings = GenerateLocalizableStringsFileContent(
+      NSDictionary* dictionary = GenerateLocalizableStringsDictionary(
           *data_pack, [locale UTF8String], output_strings, resources_ids);
-      if (localizable_strings) {
-        SaveLocalizableFile(localizable_strings, locale, output_dir,
-                            output_name);
+      if (dictionary) {
+        SavePropertyList(dictionary, locale, output_dir, output_name);
       } else {
         fprintf(stderr, "ERROR: Unable to create %s.\n",
                 [output_name UTF8String]);
diff --git a/ipc/ipc_sync_channel.cc b/ipc/ipc_sync_channel.cc
index fe2b61b..e8eeec6d 100644
--- a/ipc/ipc_sync_channel.cc
+++ b/ipc/ipc_sync_channel.cc
@@ -13,10 +13,10 @@
 #include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/synchronization/waitable_event_watcher.h"
 #include "base/threading/thread_local.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
@@ -24,12 +24,49 @@
 #include "ipc/ipc_logging.h"
 #include "ipc/ipc_message_macros.h"
 #include "ipc/ipc_sync_message.h"
+#include "ipc/mojo_event.h"
+#include "mojo/public/cpp/bindings/sync_handle_registry.h"
 
-using base::TimeDelta;
-using base::TimeTicks;
 using base::WaitableEvent;
 
 namespace IPC {
+
+namespace {
+
+// A generic callback used when watching handles synchronously. Sets |*signal|
+// to true. Also sets |*error| to true in case of an error.
+void OnSyncHandleReady(bool* signal, bool* error, MojoResult result) {
+  *signal = true;
+  *error = result != MOJO_RESULT_OK;
+}
+
+// A ReadyCallback for use with mojo::Watcher. Ignores the result (DCHECKs, but
+// is only used in cases where failure should be impossible) and runs
+// |callback|.
+void RunOnHandleReady(const base::Closure& callback, MojoResult result) {
+  DCHECK(result == MOJO_RESULT_OK || result == MOJO_RESULT_ABORTED);
+  if (result == MOJO_RESULT_OK)
+    callback.Run();
+}
+
+class PumpMessagesEvent {
+ public:
+  PumpMessagesEvent() { event_.Signal(); }
+  ~PumpMessagesEvent() {}
+
+  const MojoEvent* event() const { return &event_; }
+
+ private:
+  MojoEvent event_;
+
+  DISALLOW_COPY_AND_ASSIGN(PumpMessagesEvent);
+};
+
+base::LazyInstance<PumpMessagesEvent>::Leaky g_pump_messages_event =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
 // When we're blocked in a Send(), we need to process incoming synchronous
 // messages right away because it could be blocking our reply (either
 // directly from the same object we're calling, or indirectly through one or
@@ -156,7 +193,7 @@
     }
   }
 
-  WaitableEvent* dispatch_event() { return &dispatch_event_; }
+  MojoEvent* dispatch_event() { return &dispatch_event_; }
   base::SingleThreadTaskRunner* listener_task_runner() {
     return listener_task_runner_.get();
   }
@@ -178,11 +215,11 @@
     }
   }
 
-  base::WaitableEventWatcher* top_send_done_watcher() {
+  mojo::Watcher* top_send_done_watcher() {
     return top_send_done_watcher_;
   }
 
-  void set_top_send_done_watcher(base::WaitableEventWatcher* watcher) {
+  void set_top_send_done_watcher(mojo::Watcher* watcher) {
     top_send_done_watcher_ = watcher;
   }
 
@@ -193,8 +230,6 @@
   // as manual reset.
   ReceivedSyncMsgQueue()
       : message_queue_version_(0),
-        dispatch_event_(base::WaitableEvent::ResetPolicy::MANUAL,
-                        base::WaitableEvent::InitialState::NOT_SIGNALED),
         listener_task_runner_(base::ThreadTaskRunnerHandle::Get()),
         task_pending_(false),
         listener_count_(0),
@@ -215,19 +250,19 @@
 
   std::vector<QueuedMessage> received_replies_;
 
-  // Set when we got a synchronous message that we must respond to as the
+  // Signaled when we get a synchronous message that we must respond to, as the
   // sender needs its reply before it can reply to our original synchronous
   // message.
-  WaitableEvent dispatch_event_;
+  MojoEvent dispatch_event_;
   scoped_refptr<base::SingleThreadTaskRunner> listener_task_runner_;
   base::Lock message_lock_;
   bool task_pending_;
   int listener_count_;
 
-  // The current send done event watcher for this thread. Used to maintain
-  // a local global stack of send done watchers to ensure that nested sync
+  // The current send done handle watcher for this thread. Used to maintain
+  // a thread-local stack of send done watchers to ensure that nested sync
   // message loops complete correctly.
-  base::WaitableEventWatcher* top_send_done_watcher_;
+  mojo::Watcher* top_send_done_watcher_;
 };
 
 base::LazyInstance<base::ThreadLocalPointer<SyncChannel::ReceivedSyncMsgQueue> >
@@ -250,9 +285,9 @@
 }
 
 // Adds information about an outgoing sync message to the context so that
-// we know how to deserialize the reply.  Returns a handle that's set when
-// the reply has arrived.
-void SyncChannel::SyncContext::Push(SyncMessage* sync_msg) {
+// we know how to deserialize the reply. Returns |true| if the message was added
+// to the context or |false| if it was rejected (e.g. due to shutdown.)
+bool SyncChannel::SyncContext::Push(SyncMessage* sync_msg) {
   // Create the tracking information for this message. This object is stored
   // by value since all members are pointers that are cheap to copy. These
   // pointers are cleaned up in the Pop() function.
@@ -261,12 +296,14 @@
   // OnObjectSignalled, another Send can happen which would stop the watcher
   // from being called.  The event would get watched later, when the nested
   // Send completes, so the event will need to remain set.
+  base::AutoLock auto_lock(deserializers_lock_);
+  if (reject_new_deserializers_)
+    return false;
   PendingSyncMsg pending(
       SyncMessage::GetMessageId(*sync_msg), sync_msg->GetReplyDeserializer(),
-      new WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
-                        base::WaitableEvent::InitialState::NOT_SIGNALED));
-  base::AutoLock auto_lock(deserializers_lock_);
+      new MojoEvent);
   deserializers_.push_back(pending);
+  return true;
 }
 
 bool SyncChannel::SyncContext::Pop() {
@@ -276,7 +313,7 @@
     PendingSyncMsg msg = deserializers_.back();
     delete msg.deserializer;
     delete msg.done_event;
-    msg.done_event = NULL;
+    msg.done_event = nullptr;
     deserializers_.pop_back();
     result = msg.send_result;
   }
@@ -293,12 +330,12 @@
   return result;
 }
 
-WaitableEvent* SyncChannel::SyncContext::GetSendDoneEvent() {
+MojoEvent* SyncChannel::SyncContext::GetSendDoneEvent() {
   base::AutoLock auto_lock(deserializers_lock_);
   return deserializers_.back().done_event;
 }
 
-WaitableEvent* SyncChannel::SyncContext::GetDispatchEvent() {
+MojoEvent* SyncChannel::SyncContext::GetDispatchEvent() {
   return received_sync_msgs_->dispatch_event();
 }
 
@@ -322,7 +359,7 @@
     DVLOG(1) << "Received error reply";
   }
 
-  base::WaitableEvent* done_event = deserializers_.back().done_event;
+  MojoEvent* done_event = deserializers_.back().done_event;
   TRACE_EVENT_FLOW_BEGIN0(
       TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
       "SyncChannel::SyncContext::TryToUnblockListener", done_event);
@@ -368,7 +405,7 @@
 void SyncChannel::SyncContext::OnChannelOpened() {
   shutdown_watcher_.StartWatching(
       shutdown_event_,
-      base::Bind(&SyncChannel::SyncContext::OnWaitableEventSignaled,
+      base::Bind(&SyncChannel::SyncContext::OnShutdownEventSignaled,
                  base::Unretained(this)));
   Context::OnChannelOpened();
 }
@@ -381,6 +418,7 @@
 
 void SyncChannel::SyncContext::CancelPendingSends() {
   base::AutoLock auto_lock(deserializers_lock_);
+  reject_new_deserializers_ = true;
   PendingSyncMessageQueue::iterator iter;
   DVLOG(1) << "Canceling pending sends";
   for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++) {
@@ -391,21 +429,12 @@
   }
 }
 
-void SyncChannel::SyncContext::OnWaitableEventSignaled(WaitableEvent* event) {
-  if (event == shutdown_event_) {
-    // Process shut down before we can get a reply to a synchronous message.
-    // Cancel pending Send calls, which will end up setting the send done event.
-    CancelPendingSends();
-  } else {
-    // We got the reply, timed out or the process shutdown.
-    DCHECK_EQ(GetSendDoneEvent(), event);
-    base::MessageLoop::current()->QuitNow();
-  }
-}
+void SyncChannel::SyncContext::OnShutdownEventSignaled(WaitableEvent* event) {
+  DCHECK_EQ(event, shutdown_event_);
 
-base::WaitableEventWatcher::EventCallback
-    SyncChannel::SyncContext::MakeWaitableEventCallback() {
-  return base::Bind(&SyncChannel::SyncContext::OnWaitableEventSignaled, this);
+  // Process shut down before we can get a reply to a synchronous message.
+  // Cancel pending Send calls, which will end up setting the send done event.
+  CancelPendingSends();
 }
 
 // static
@@ -448,7 +477,8 @@
     Listener* listener,
     const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
     WaitableEvent* shutdown_event)
-    : ChannelProxy(new SyncContext(listener, ipc_task_runner, shutdown_event)) {
+    : ChannelProxy(new SyncContext(listener, ipc_task_runner, shutdown_event)),
+      sync_handle_registry_(mojo::SyncHandleRegistry::current()) {
   // The current (listener) thread must be distinct from the IPC thread, or else
   // sending synchronous messages will deadlock.
   DCHECK_NE(ipc_task_runner.get(), base::ThreadTaskRunnerHandle::Get().get());
@@ -487,23 +517,23 @@
     return true;
   }
 
+  SyncMessage* sync_msg = static_cast<SyncMessage*>(message);
+  bool pump_messages = sync_msg->ShouldPumpMessages();
+
   // *this* might get deleted in WaitForReply.
   scoped_refptr<SyncContext> context(sync_context());
-  if (context->shutdown_event()->IsSignaled()) {
-    DVLOG(1) << "shutdown event is signaled";
+  if (!context->Push(sync_msg)) {
+    DVLOG(1) << "Channel is shutting down. Dropping sync message.";
     delete message;
     return false;
   }
 
-  SyncMessage* sync_msg = static_cast<SyncMessage*>(message);
-  context->Push(sync_msg);
-  WaitableEvent* pump_messages_event = sync_msg->pump_messages_event();
-
   ChannelProxy::Send(message);
 
   // Wait for reply, or for any other incoming synchronous messages.
   // *this* might get deleted, so only call static functions at this point.
-  WaitForReply(context.get(), pump_messages_event);
+  scoped_refptr<mojo::SyncHandleRegistry> registry = sync_handle_registry_;
+  WaitForReply(registry.get(), context.get(), pump_messages);
 
   TRACE_EVENT_FLOW_END0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
                         "SyncChannel::Send", context->GetSendDoneEvent());
@@ -511,19 +541,43 @@
   return context->Pop();
 }
 
-void SyncChannel::WaitForReply(
-    SyncContext* context, WaitableEvent* pump_messages_event) {
+void SyncChannel::WaitForReply(mojo::SyncHandleRegistry* registry,
+                               SyncContext* context,
+                               bool pump_messages) {
   context->DispatchMessages();
-  while (true) {
-    WaitableEvent* objects[] = {
-      context->GetDispatchEvent(),
-      context->GetSendDoneEvent(),
-      pump_messages_event
-    };
 
-    unsigned count = pump_messages_event ? 3: 2;
-    size_t result = WaitableEvent::WaitMany(objects, count);
-    if (result == 0 /* dispatch event */) {
+  const MojoEvent* pump_messages_event = nullptr;
+  if (pump_messages)
+    pump_messages_event = g_pump_messages_event.Get().event();
+
+  while (true) {
+    bool dispatch = false;
+    bool send_done = false;
+    bool should_pump_messages = false;
+    bool error = false;
+    registry->RegisterHandle(context->GetDispatchEvent()->GetHandle(),
+                             MOJO_HANDLE_SIGNAL_READABLE,
+                             base::Bind(&OnSyncHandleReady, &dispatch, &error));
+    registry->RegisterHandle(
+        context->GetSendDoneEvent()->GetHandle(),
+        MOJO_HANDLE_SIGNAL_READABLE,
+        base::Bind(&OnSyncHandleReady, &send_done, &error));
+    if (pump_messages_event) {
+      registry->RegisterHandle(
+          pump_messages_event->GetHandle(), MOJO_HANDLE_SIGNAL_READABLE,
+          base::Bind(&OnSyncHandleReady, &should_pump_messages, &error));
+    }
+
+    const bool* stop_flags[] = { &dispatch, &send_done, &should_pump_messages };
+    registry->WatchAllHandles(stop_flags, 3);
+    DCHECK(!error);
+
+    registry->UnregisterHandle(context->GetDispatchEvent()->GetHandle());
+    registry->UnregisterHandle(context->GetSendDoneEvent()->GetHandle());
+    if (pump_messages_event)
+      registry->UnregisterHandle(pump_messages_event->GetHandle());
+
+    if (dispatch) {
       // We're waiting for a reply, but we received a blocking synchronous
       // call.  We must process it or otherwise a deadlock might occur.
       context->GetDispatchEvent()->Reset();
@@ -531,7 +585,7 @@
       continue;
     }
 
-    if (result == 2 /* pump_messages_event */)
+    if (should_pump_messages)
       WaitForReplyWithNestedMessageLoop(context);  // Run a nested message loop.
 
     break;
@@ -539,64 +593,59 @@
 }
 
 void SyncChannel::WaitForReplyWithNestedMessageLoop(SyncContext* context) {
-  base::WaitableEventWatcher send_done_watcher;
+  mojo::Watcher send_done_watcher;
 
   ReceivedSyncMsgQueue* sync_msg_queue = context->received_sync_msgs();
-  DCHECK(sync_msg_queue != NULL);
+  DCHECK_NE(sync_msg_queue, nullptr);
 
-  base::WaitableEventWatcher* old_send_done_event_watcher =
-      sync_msg_queue->top_send_done_watcher();
+  mojo::Watcher* old_watcher = sync_msg_queue->top_send_done_watcher();
+  mojo::Handle old_handle(mojo::kInvalidHandleValue);
+  mojo::Watcher::ReadyCallback old_callback;
 
-  base::WaitableEventWatcher::EventCallback old_callback;
-  base::WaitableEvent* old_event = NULL;
-
-  // Maintain a local global stack of send done delegates to ensure that
-  // nested sync calls complete in the correct sequence, i.e. the
-  // outermost call completes first, etc.
-  if (old_send_done_event_watcher) {
-    old_callback = old_send_done_event_watcher->callback();
-    old_event = old_send_done_event_watcher->GetWatchedEvent();
-    old_send_done_event_watcher->StopWatching();
+  // Maintain a thread-local stack of watchers to ensure nested calls complete
+  // in the correct sequence, i.e. the outermost call completes first, etc.
+  if (old_watcher) {
+    old_callback = old_watcher->ready_callback();
+    old_handle = old_watcher->handle();
+    old_watcher->Cancel();
   }
 
   sync_msg_queue->set_top_send_done_watcher(&send_done_watcher);
 
-  send_done_watcher.StartWatching(context->GetSendDoneEvent(),
-                                  context->MakeWaitableEventCallback());
-
   {
+    base::RunLoop nested_loop;
+    send_done_watcher.Start(
+        context->GetSendDoneEvent()->GetHandle(), MOJO_HANDLE_SIGNAL_READABLE,
+        base::Bind(&RunOnHandleReady, nested_loop.QuitClosure()));
+
     base::MessageLoop::ScopedNestableTaskAllower allow(
         base::MessageLoop::current());
-    base::RunLoop().Run();
+    nested_loop.Run();
+    send_done_watcher.Cancel();
   }
 
-  sync_msg_queue->set_top_send_done_watcher(old_send_done_event_watcher);
-  if (old_send_done_event_watcher && old_event) {
-    old_send_done_event_watcher->StartWatching(old_event, old_callback);
-  }
+  sync_msg_queue->set_top_send_done_watcher(old_watcher);
+  if (old_watcher)
+    old_watcher->Start(old_handle, MOJO_HANDLE_SIGNAL_READABLE, old_callback);
 }
 
-void SyncChannel::OnWaitableEventSignaled(WaitableEvent* event) {
-  DCHECK(event == sync_context()->GetDispatchEvent());
-  // The call to DispatchMessages might delete this object, so reregister
-  // the object watcher first.
-  event->Reset();
-  dispatch_watcher_.StartWatching(event, dispatch_watcher_callback_);
-  sync_context()->DispatchMessages();
+void SyncChannel::OnDispatchHandleReady(MojoResult result) {
+  DCHECK(result == MOJO_RESULT_OK || result == MOJO_RESULT_ABORTED);
+  if (result == MOJO_RESULT_OK) {
+    sync_context()->GetDispatchEvent()->Reset();
+    sync_context()->DispatchMessages();
+  }
 }
 
 void SyncChannel::StartWatching() {
   // Ideally we only want to watch this object when running a nested message
   // loop.  However, we don't know when it exits if there's another nested
   // message loop running under it or not, so we wouldn't know whether to
-  // stop or keep watching.  So we always watch it, and create the event as
-  // manual reset since the object watcher might otherwise reset the event
-  // when we're doing a WaitMany.
-  dispatch_watcher_callback_ =
-      base::Bind(&SyncChannel::OnWaitableEventSignaled,
-                  base::Unretained(this));
-  dispatch_watcher_.StartWatching(sync_context()->GetDispatchEvent(),
-                                  dispatch_watcher_callback_);
+  // stop or keep watching.  So we always watch it.
+  dispatch_watcher_.Start(sync_context()->GetDispatchEvent()->GetHandle(),
+                          MOJO_HANDLE_SIGNAL_READABLE,
+                          base::Bind(&SyncChannel::OnDispatchHandleReady,
+                                     base::Unretained(this)));
 }
 
 void SyncChannel::OnChannelInit() {
diff --git a/ipc/ipc_sync_channel.h b/ipc/ipc_sync_channel.h
index 103925a..e8c96d20 100644
--- a/ipc/ipc_sync_channel.h
+++ b/ipc/ipc_sync_channel.h
@@ -18,15 +18,23 @@
 #include "ipc/ipc_channel_proxy.h"
 #include "ipc/ipc_sync_message.h"
 #include "ipc/ipc_sync_message_filter.h"
+#include "mojo/public/c/system/types.h"
+#include "mojo/public/cpp/system/watcher.h"
 
 namespace base {
 class WaitableEvent;
 };
 
+namespace mojo {
+class SyncHandleRegistry;
+class Watcher;
+}
+
 namespace IPC {
 
-class SyncMessage;
 class ChannelFactory;
+class MojoEvent;
+class SyncMessage;
 
 // This is similar to ChannelProxy, with the added feature of supporting sending
 // synchronous messages.
@@ -136,19 +144,19 @@
 
     // Adds information about an outgoing sync message to the context so that
     // we know how to deserialize the reply.
-    void Push(SyncMessage* sync_msg);
+    bool Push(SyncMessage* sync_msg);
 
     // Cleanly remove the top deserializer (and throw it away).  Returns the
     // result of the Send call for that message.
     bool Pop();
 
-    // Returns an event that's set when the send is complete, timed out or the
-    // process shut down.
-    base::WaitableEvent* GetSendDoneEvent();
+    // Returns a Mojo Event that signals when a sync send is complete or timed
+    // out or the process shut down.
+    MojoEvent* GetSendDoneEvent();
 
-    // Returns an event that's set when an incoming message that's not the reply
-    // needs to get dispatched (by calling SyncContext::DispatchMessages).
-    base::WaitableEvent* GetDispatchEvent();
+    // Returns a Mojo Event that signals when an incoming message that's not the
+    // pending reply needs to get dispatched (by calling DispatchMessages.)
+    MojoEvent* GetDispatchEvent();
 
     void DispatchMessages();
 
@@ -171,8 +179,6 @@
       return restrict_dispatch_group_;
     }
 
-    base::WaitableEventWatcher::EventCallback MakeWaitableEventCallback();
-
    private:
     ~SyncContext() override;
     // ChannelProxy methods that we override.
@@ -189,10 +195,11 @@
     // Cancels all pending Send calls.
     void CancelPendingSends();
 
-    void OnWaitableEventSignaled(base::WaitableEvent* event);
+    void OnShutdownEventSignaled(base::WaitableEvent* event);
 
     typedef std::deque<PendingSyncMsg> PendingSyncMessageQueue;
     PendingSyncMessageQueue deserializers_;
+    bool reject_new_deserializers_ = false;
     base::Lock deserializers_lock_;
 
     scoped_refptr<ReceivedSyncMsgQueue> received_sync_msgs_;
@@ -209,7 +216,7 @@
       const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
       base::WaitableEvent* shutdown_event);
 
-  void OnWaitableEventSignaled(base::WaitableEvent* arg);
+  void OnDispatchHandleReady(MojoResult result);
 
   SyncContext* sync_context() {
     return reinterpret_cast<SyncContext*>(context());
@@ -217,8 +224,9 @@
 
   // Both these functions wait for a reply, timeout or process shutdown.  The
   // latter one also runs a nested message loop in the meantime.
-  static void WaitForReply(
-      SyncContext* context, base::WaitableEvent* pump_messages_event);
+  static void WaitForReply(mojo::SyncHandleRegistry* registry,
+                           SyncContext* context,
+                           bool pump_messages);
 
   // Runs a nested message loop until a reply arrives, times out, or the process
   // shuts down.
@@ -230,9 +238,10 @@
   // ChannelProxy overrides:
   void OnChannelInit() override;
 
+  scoped_refptr<mojo::SyncHandleRegistry> sync_handle_registry_;
+
   // Used to signal events between the IPC and listener threads.
-  base::WaitableEventWatcher dispatch_watcher_;
-  base::WaitableEventWatcher::EventCallback dispatch_watcher_callback_;
+  mojo::Watcher dispatch_watcher_;
 
   // Tracks SyncMessageFilters created before complete channel initialization.
   std::vector<scoped_refptr<SyncMessageFilter>> pre_init_sync_message_filters_;
diff --git a/ipc/ipc_sync_message.cc b/ipc/ipc_sync_message.cc
index 7f9df7bd..ba87de8 100644
--- a/ipc/ipc_sync_message.cc
+++ b/ipc/ipc_sync_message.cc
@@ -9,26 +9,11 @@
 #include <stack>
 
 #include "base/atomic_sequence_num.h"
-#include "base/lazy_instance.h"
 #include "base/logging.h"
-#include "base/synchronization/waitable_event.h"
 #include "build/build_config.h"
 
 namespace {
 
-struct WaitableEventLazyInstanceTraits
-    : public base::DefaultLazyInstanceTraits<base::WaitableEvent> {
-  static base::WaitableEvent* New(void* instance) {
-    // Use placement new to initialize our instance in our preallocated space.
-    return new (instance)
-        base::WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
-                            base::WaitableEvent::InitialState::SIGNALED);
-  }
-};
-
-base::LazyInstance<base::WaitableEvent, WaitableEventLazyInstanceTraits>
-    dummy_event = LAZY_INSTANCE_INITIALIZER;
-
 base::StaticAtomicSequenceNumber g_next_id;
 
 }  // namespace
@@ -42,8 +27,7 @@
                          PriorityValue priority,
                          MessageReplyDeserializer* deserializer)
     : Message(routing_id, type, priority),
-      deserializer_(deserializer),
-      pump_messages_event_(NULL) {
+      deserializer_(deserializer) {
   set_sync();
   set_unblock(true);
 
@@ -61,11 +45,6 @@
   return deserializer_.release();
 }
 
-void SyncMessage::EnableMessagePumping() {
-  DCHECK(!pump_messages_event_);
-  set_pump_messages_event(dummy_event.Pointer());
-}
-
 bool SyncMessage::IsMessageReplyTo(const Message& msg, int request_id) {
   if (!msg.is_reply())
     return false;
diff --git a/ipc/ipc_sync_message.h b/ipc/ipc_sync_message.h
index cb259b1..ed5204f 100644
--- a/ipc/ipc_sync_message.h
+++ b/ipc/ipc_sync_message.h
@@ -17,13 +17,10 @@
 #include "build/build_config.h"
 #include "ipc/ipc_message.h"
 
-namespace base {
-class WaitableEvent;
-}
-
 namespace IPC {
 
 class MessageReplyDeserializer;
+class MojoEvent;
 
 class IPC_EXPORT SyncMessage : public Message {
  public:
@@ -41,24 +38,16 @@
   // If this message can cause the receiver to block while waiting for user
   // input (i.e. by calling MessageBox), then the caller needs to pump window
   // messages and dispatch asynchronous messages while waiting for the reply.
-  // If this event is passed in, then window messages will start being pumped
-  // when it's set.  Note that this behavior will continue even if the event is
-  // later reset.  The event must be valid until after the Send call returns.
-  void set_pump_messages_event(base::WaitableEvent* event) {
-    pump_messages_event_ = event;
-    if (event) {
-      header()->flags |= PUMPING_MSGS_BIT;
-    } else {
-      header()->flags &= ~PUMPING_MSGS_BIT;
-    }
+  // This call enables message pumping behavior while waiting for a reply to
+  // this message.
+  void EnableMessagePumping() {
+    header()->flags |= PUMPING_MSGS_BIT;
   }
 
-  // Call this if you always want to pump messages.  You can call this method
-  // or set_pump_messages_event but not both.
-  void EnableMessagePumping();
-
-  base::WaitableEvent* pump_messages_event() const {
-    return pump_messages_event_;
+  // Indicates whether window messages should be pumped while waiting for a
+  // reply to this message.
+  bool ShouldPumpMessages() const {
+    return (header()->flags & PUMPING_MSGS_BIT) != 0;
   }
 
   // Returns true if the message is a reply to the given request id.
@@ -84,7 +73,6 @@
   static bool WriteSyncHeader(Message* msg, const SyncHeader& header);
 
   std::unique_ptr<MessageReplyDeserializer> deserializer_;
-  base::WaitableEvent* pump_messages_event_;
 };
 
 // Used to deserialize parameters from a reply to a synchronous message
@@ -102,13 +90,12 @@
 // When sending a synchronous message, this structure contains an object
 // that knows how to deserialize the response.
 struct PendingSyncMsg {
-  PendingSyncMsg(int id,
-                 MessageReplyDeserializer* d,
-                 base::WaitableEvent* e)
+  PendingSyncMsg(int id, MessageReplyDeserializer* d, MojoEvent* e)
       : id(id), deserializer(d), done_event(e), send_result(false) { }
+
   int id;
   MessageReplyDeserializer* deserializer;
-  base::WaitableEvent* done_event;
+  MojoEvent* done_event;
   bool send_result;
 };
 
diff --git a/ipc/ipc_sync_message_filter.cc b/ipc/ipc_sync_message_filter.cc
index 1d17432..53ead2c 100644
--- a/ipc/ipc_sync_message_filter.cc
+++ b/ipc/ipc_sync_message_filter.cc
@@ -7,14 +7,94 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "ipc/ipc_channel.h"
 #include "ipc/ipc_sync_message.h"
+#include "ipc/mojo_event.h"
+#include "mojo/public/cpp/bindings/sync_handle_registry.h"
 
 namespace IPC {
 
+namespace {
+
+// A generic callback used when watching handles synchronously. Sets |*signal|
+// to true. Also sets |*error| to true in case of an error.
+void OnSyncHandleReady(bool* signal, bool* error, MojoResult result) {
+  *signal = true;
+  *error = result != MOJO_RESULT_OK;
+}
+
+}  // namespace
+
+// A helper class created by SyncMessageFilter to watch the lifetime of the IO
+// MessageLoop. This holds a weak ref to the SyncMessageFilter and notifies it
+// on its own thread if the SyncMessageFilter is still alive at the time of
+// IO MessageLoop destruction.
+class SyncMessageFilter::IOMessageLoopObserver
+    : public base::MessageLoop::DestructionObserver,
+      public base::RefCountedThreadSafe<IOMessageLoopObserver> {
+ public:
+  IOMessageLoopObserver(
+      base::WeakPtr<SyncMessageFilter> weak_filter,
+      scoped_refptr<base::SingleThreadTaskRunner> filter_task_runner)
+      : weak_filter_(weak_filter), filter_task_runner_(filter_task_runner) {}
+
+  void StartOnIOThread() {
+    DCHECK(!watching_);
+    watching_ = true;
+    io_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+    base::MessageLoop::current()->AddDestructionObserver(this);
+  }
+
+  void Stop() {
+    if (!io_task_runner_)
+      return;
+
+    if (io_task_runner_->BelongsToCurrentThread()) {
+      StopOnIOThread();
+    } else {
+      io_task_runner_->PostTask(
+          FROM_HERE, base::Bind(&IOMessageLoopObserver::StopOnIOThread, this));
+    }
+  }
+
+ private:
+  void StopOnIOThread() {
+    DCHECK(io_task_runner_->BelongsToCurrentThread());
+    if (!watching_)
+      return;
+    watching_ = false;
+    base::MessageLoop::current()->RemoveDestructionObserver(this);
+  }
+
+  // base::MessageLoop::DestructionObserver:
+  void WillDestroyCurrentMessageLoop() override {
+    DCHECK(io_task_runner_ && io_task_runner_->BelongsToCurrentThread());
+    DCHECK(watching_);
+    StopOnIOThread();
+    filter_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&SyncMessageFilter::OnIOMessageLoopDestroyed, weak_filter_));
+  }
+
+  friend class base::RefCountedThreadSafe<IOMessageLoopObserver>;
+
+  ~IOMessageLoopObserver() override {}
+
+  bool watching_ = false;
+  base::WeakPtr<SyncMessageFilter> weak_filter_;
+  scoped_refptr<base::SingleThreadTaskRunner> filter_task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(IOMessageLoopObserver);
+};
+
 bool SyncMessageFilter::Send(Message* message) {
   if (!message->is_sync()) {
     {
@@ -23,7 +103,7 @@
         sender_->Send(message);
         return true;
       } else if (!io_task_runner_.get()) {
-        pending_messages_.push_back(message);
+        pending_messages_.emplace_back(base::WrapUnique(message));
         return true;
       }
     }
@@ -33,9 +113,7 @@
     return true;
   }
 
-  base::WaitableEvent done_event(
-      base::WaitableEvent::ResetPolicy::MANUAL,
-      base::WaitableEvent::InitialState::NOT_SIGNALED);
+  MojoEvent done_event;
   PendingSyncMsg pending_message(
       SyncMessage::GetMessageId(*message),
       static_cast<SyncMessage*>(message)->GetReplyDeserializer(),
@@ -56,15 +134,32 @@
           FROM_HERE,
           base::Bind(&SyncMessageFilter::SendOnIOThread, this, message));
     } else {
-      pending_messages_.push_back(message);
+      pending_messages_.emplace_back(base::WrapUnique(message));
     }
   }
 
-  base::WaitableEvent* events[2] = { shutdown_event_, &done_event };
-  if (base::WaitableEvent::WaitMany(events, 2) == 1) {
+  bool done = false;
+  bool shutdown = false;
+  bool error = false;
+  scoped_refptr<mojo::SyncHandleRegistry> registry =
+      mojo::SyncHandleRegistry::current();
+  registry->RegisterHandle(shutdown_mojo_event_.GetHandle(),
+                           MOJO_HANDLE_SIGNAL_READABLE,
+                           base::Bind(&OnSyncHandleReady, &shutdown, &error));
+  registry->RegisterHandle(done_event.GetHandle(),
+                           MOJO_HANDLE_SIGNAL_READABLE,
+                           base::Bind(&OnSyncHandleReady, &done, &error));
+
+  const bool* stop_flags[] = { &done, &shutdown };
+  registry->WatchAllHandles(stop_flags, 2);
+  DCHECK(!error);
+
+  if (done) {
     TRACE_EVENT_FLOW_END0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
                           "SyncMessageFilter::Send", &done_event);
   }
+  registry->UnregisterHandle(shutdown_mojo_event_.GetHandle());
+  registry->UnregisterHandle(done_event.GetHandle());
 
   {
     base::AutoLock auto_lock(lock_);
@@ -76,26 +171,32 @@
 }
 
 void SyncMessageFilter::OnFilterAdded(Sender* sender) {
-  std::vector<Message*> pending_messages;
+  std::vector<std::unique_ptr<Message>> pending_messages;
   {
     base::AutoLock auto_lock(lock_);
     sender_ = sender;
     io_task_runner_ = base::ThreadTaskRunnerHandle::Get();
-    pending_messages_.release(&pending_messages);
+    shutdown_watcher_.StartWatching(
+        shutdown_event_,
+        base::Bind(&SyncMessageFilter::OnShutdownEventSignaled, this));
+    io_message_loop_observer_->StartOnIOThread();
+    std::swap(pending_messages_, pending_messages);
   }
-  for (auto* msg : pending_messages)
-    SendOnIOThread(msg);
+  for (auto& msg : pending_messages)
+    SendOnIOThread(msg.release());
 }
 
 void SyncMessageFilter::OnChannelError() {
   base::AutoLock auto_lock(lock_);
   sender_ = NULL;
+  shutdown_watcher_.StopWatching();
   SignalAllEvents();
 }
 
 void SyncMessageFilter::OnChannelClosing() {
   base::AutoLock auto_lock(lock_);
   sender_ = NULL;
+  shutdown_watcher_.StopWatching();
   SignalAllEvents();
 }
 
@@ -124,10 +225,14 @@
     : sender_(NULL),
       is_channel_send_thread_safe_(is_channel_send_thread_safe),
       listener_task_runner_(base::ThreadTaskRunnerHandle::Get()),
-      shutdown_event_(shutdown_event) {
+      shutdown_event_(shutdown_event),
+      weak_factory_(this) {
+  io_message_loop_observer_ = new IOMessageLoopObserver(
+      weak_factory_.GetWeakPtr(), listener_task_runner_);
 }
 
 SyncMessageFilter::~SyncMessageFilter() {
+  io_message_loop_observer_->Stop();
 }
 
 void SyncMessageFilter::SendOnIOThread(Message* message) {
@@ -157,4 +262,17 @@
   }
 }
 
+void SyncMessageFilter::OnShutdownEventSignaled(base::WaitableEvent* event) {
+  DCHECK_EQ(event, shutdown_event_);
+  shutdown_mojo_event_.Signal();
+}
+
+void SyncMessageFilter::OnIOMessageLoopDestroyed() {
+  // Since we use an async WaitableEventWatcher to watch the shutdown event
+  // from the IO thread, we can't forward the shutdown signal after the IO
+  // message loop is destroyed. Since that destruction indicates shutdown
+  // anyway, we manually signal the shutdown event in this case.
+  shutdown_mojo_event_.Signal();
+}
+
 }  // namespace IPC
diff --git a/ipc/ipc_sync_message_filter.h b/ipc/ipc_sync_message_filter.h
index 27584359..dead5b32 100644
--- a/ipc/ipc_sync_message_filter.h
+++ b/ipc/ipc_sync_message_filter.h
@@ -6,14 +6,17 @@
 #define IPC_IPC_SYNC_MESSAGE_FILTER_H_
 
 #include <set>
+#include <vector>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
 #include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event_watcher.h"
 #include "ipc/ipc_sender.h"
 #include "ipc/ipc_sync_message.h"
 #include "ipc/message_filter.h"
+#include "ipc/mojo_event.h"
 
 namespace base {
 class SingleThreadTaskRunner;
@@ -46,7 +49,10 @@
   ~SyncMessageFilter() override;
 
  private:
+  class IOMessageLoopObserver;
+
   friend class SyncChannel;
+  friend class IOMessageLoopObserver;
 
   void set_is_channel_send_thread_safe(bool is_channel_send_thread_safe) {
     is_channel_send_thread_safe_ = is_channel_send_thread_safe;
@@ -56,6 +62,9 @@
   // Signal all the pending sends as done, used in an error condition.
   void SignalAllEvents();
 
+  void OnShutdownEventSignaled(base::WaitableEvent* event);
+  void OnIOMessageLoopDestroyed();
+
   // The channel to which this filter was added.
   Sender* sender_;
 
@@ -72,12 +81,24 @@
   PendingSyncMessages pending_sync_messages_;
 
   // Messages waiting to be delivered after IO initialization.
-  ScopedVector<Message> pending_messages_;
+  std::vector<std::unique_ptr<Message>> pending_messages_;
 
   // Locks data members above.
   base::Lock lock_;
 
-  base::WaitableEvent* shutdown_event_;
+  base::WaitableEvent* const shutdown_event_;
+
+  // Used to asynchronously watch |shutdown_event_| on the IO thread and forward
+  // to |shutdown_mojo_event_| (see below.)
+  base::WaitableEventWatcher shutdown_watcher_;
+
+  // A Mojo event which can be watched for shutdown. Signals are forwarded to
+  // this event asynchronously from |shutdown_event_|.
+  MojoEvent shutdown_mojo_event_;
+
+  scoped_refptr<IOMessageLoopObserver> io_message_loop_observer_;
+
+  base::WeakPtrFactory<SyncMessageFilter> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(SyncMessageFilter);
 };
diff --git a/mash/example/common/mus_views_init.h b/mash/example/common/mus_views_init.h
index f92e703..a37d7b86 100644
--- a/mash/example/common/mus_views_init.h
+++ b/mash/example/common/mus_views_init.h
@@ -13,8 +13,8 @@
 #include "ui/views/mus/aura_init.h"
 #include "ui/views/views_delegate.h"
 
-namespace mojo {
-class ShellConnection;
+namespace shell {
+class ServiceContext;
 }
 
 namespace views {
@@ -25,7 +25,7 @@
 class MUSViewsInit : public views::ViewsDelegate,
                      public ui::WindowTreeClientDelegate {
  public:
-  explicit MUSViewsInit(shell::ShellConnection* app);
+  explicit MUSViewsInit(shell::ServiceContext* app);
   ~MUSViewsInit() override;
 
  private:
@@ -45,7 +45,7 @@
   HICON GetSmallWindowIcon() const override;
 #endif
 
-  shell::ShellConnection* app_;
+  shell::ServiceContext* app_;
   std::unique_ptr<views::AuraInit> aura_init_;
   ui::mojom::WindowManagerPtr window_manager_;
 
diff --git a/mash/example/window_type_launcher/main.cc b/mash/example/window_type_launcher/main.cc
index 170dc80..69097738 100644
--- a/mash/example/window_type_launcher/main.cc
+++ b/mash/example/window_type_launcher/main.cc
@@ -16,7 +16,7 @@
 #include "mash/example/window_type_launcher/window_type_launcher.h"
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/edk/embedder/process_delegate.h"
-#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service_context.h"
 #include "services/shell/public/interfaces/service.mojom.h"
 #include "services/shell/runner/common/client_util.h"
 #include "services/shell/runner/init.h"
@@ -65,7 +65,7 @@
 
     base::MessageLoop loop;
     WindowTypeLauncher delegate;
-    shell::ShellConnection impl(&delegate,
+    shell::ServiceContext impl(&delegate,
                                 shell::GetServiceRequestFromCommandLine());
     loop.Run();
 
diff --git a/mash/quick_launch/quick_launch_application.cc b/mash/quick_launch/quick_launch_application.cc
index f93baa2a..4db711cc 100644
--- a/mash/quick_launch/quick_launch_application.cc
+++ b/mash/quick_launch/quick_launch_application.cc
@@ -16,7 +16,6 @@
 #include "services/shell/public/cpp/connector.h"
 #include "services/shell/public/cpp/service.h"
 #include "services/tracing/public/cpp/tracing_impl.h"
-#include "services/ui/common/gpu_service.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
@@ -168,7 +167,6 @@
                                      const shell::Identity& identity,
                                      uint32_t id) {
   connector_ = connector;
-  ui::GpuService::Initialize(connector);
   tracing_.Initialize(connector, identity.name());
 
   aura_init_.reset(new views::AuraInit(connector, "views_mus_resources.pak"));
diff --git a/media/blink/buffered_resource_loader.cc b/media/blink/buffered_resource_loader.cc
index b608884..bb946cc 100644
--- a/media/blink/buffered_resource_loader.cc
+++ b/media/blink/buffered_resource_loader.cc
@@ -728,8 +728,10 @@
     int64_t* last_byte_position,
     int64_t* instance_size) {
   const std::string kUpThroughBytesUnit = "bytes ";
-  if (content_range_str.find(kUpThroughBytesUnit) != 0)
+  if (!base::StartsWith(content_range_str, kUpThroughBytesUnit,
+                        base::CompareCase::SENSITIVE)) {
     return false;
+  }
   std::string range_spec =
       content_range_str.substr(kUpThroughBytesUnit.length());
   size_t dash_offset = range_spec.find("-");
diff --git a/media/blink/cache_util_unittest.cc b/media/blink/cache_util_unittest.cc
index a9c409e..1e7d45f 100644
--- a/media/blink/cache_util_unittest.cc
+++ b/media/blink/cache_util_unittest.cc
@@ -35,7 +35,6 @@
 // Create a new WebURLResponse object.
 static WebURLResponse CreateResponse(const GRFUTestCase& test) {
   WebURLResponse response;
-  response.initialize();
   response.setHTTPVersion(test.version);
   response.setHTTPStatusCode(test.status_code);
   for (const std::string& line :
diff --git a/media/blink/resource_multibuffer_data_provider.cc b/media/blink/resource_multibuffer_data_provider.cc
index e107270..d8f3458 100644
--- a/media/blink/resource_multibuffer_data_provider.cc
+++ b/media/blink/resource_multibuffer_data_provider.cc
@@ -14,6 +14,7 @@
 #include "base/metrics/histogram.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "media/blink/active_loader.h"
 #include "media/blink/cache_util.h"
@@ -461,11 +462,13 @@
     int64_t* first_byte_position,
     int64_t* last_byte_position,
     int64_t* instance_size) {
-  const std::string kUpThroughBytesUnit = "bytes ";
-  if (content_range_str.find(kUpThroughBytesUnit) != 0)
+  const char kUpThroughBytesUnit[] = "bytes ";
+  if (!base::StartsWith(content_range_str, kUpThroughBytesUnit,
+                        base::CompareCase::SENSITIVE)) {
     return false;
+  }
   std::string range_spec =
-      content_range_str.substr(kUpThroughBytesUnit.length());
+      content_range_str.substr(sizeof(kUpThroughBytesUnit) - 1);
   size_t dash_offset = range_spec.find("-");
   size_t slash_offset = range_spec.find("/");
 
diff --git a/media/gpu/android_video_decode_accelerator.cc b/media/gpu/android_video_decode_accelerator.cc
index 35d8421bd..5b8c8567 100644
--- a/media/gpu/android_video_decode_accelerator.cc
+++ b/media/gpu/android_video_decode_accelerator.cc
@@ -509,9 +509,7 @@
 
   // Only use MediaCodec for VP8/9 if it's likely backed by hardware
   // or if the stream is encrypted.
-  if ((codec_config_->codec_ == kCodecVP8 ||
-       codec_config_->codec_ == kCodecVP9) &&
-      !config_.is_encrypted &&
+  if (IsMediaCodecSoftwareDecodingForbidden() &&
       VideoCodecBridge::IsKnownUnaccelerated(codec_config_->codec_,
                                              MEDIA_CODEC_DECODER)) {
     DVLOG(1) << "Initialization failed: "
@@ -1097,6 +1095,15 @@
   // outgoing codec for ReleaseMediaCodec().
   codec_config_->allow_autodetection_ =
       g_avda_timer.Pointer()->IsCodecAutodetectionProbablySafe();
+
+  // If autodetection is disallowed, fall back to Chrome's software decoders
+  // instead of using the software decoders provided by MediaCodec.
+  if (!codec_config_->allow_autodetection_ &&
+      IsMediaCodecSoftwareDecodingForbidden()) {
+    OnCodecConfigured(nullptr);
+    return;
+  }
+
   codec_config_->notify_completion_ = codec_config_->allow_autodetection_;
   if (codec_config_->allow_autodetection_)
     g_avda_timer.Pointer()->OnAsyncCodecAutodetectionStarted();
@@ -1771,4 +1778,12 @@
   return capabilities;
 }
 
+bool AndroidVideoDecodeAccelerator::IsMediaCodecSoftwareDecodingForbidden()
+    const {
+  // Prevent MediaCodec from using its internal software decoders when we have
+  // more secure and up to date versions in the renderer process.
+  return !config_.is_encrypted && (codec_config_->codec_ == media::kCodecVP8 ||
+                                   codec_config_->codec_ == media::kCodecVP9);
+}
+
 }  // namespace media
diff --git a/media/gpu/android_video_decode_accelerator.h b/media/gpu/android_video_decode_accelerator.h
index 658c230..fd99ebc0 100644
--- a/media/gpu/android_video_decode_accelerator.h
+++ b/media/gpu/android_video_decode_accelerator.h
@@ -367,6 +367,10 @@
   static bool UseTextureCopyForDeferredStrategy(
       const gpu::GpuPreferences& gpu_preferences);
 
+  // Indicates if MediaCodec should not be used for software decoding since we
+  // have safer versions elsewhere.
+  bool IsMediaCodecSoftwareDecodingForbidden() const;
+
   // Used to DCHECK that we are called on the correct thread.
   base::ThreadChecker thread_checker_;
 
diff --git a/media/gpu/vaapi_drm_picture.cc b/media/gpu/vaapi_drm_picture.cc
index 4d547df..3de36d3 100644
--- a/media/gpu/vaapi_drm_picture.cc
+++ b/media/gpu/vaapi_drm_picture.cc
@@ -43,6 +43,20 @@
   }
 }
 
+static unsigned BufferFormatToInternalFormat(gfx::BufferFormat format) {
+  switch (format) {
+    case gfx::BufferFormat::BGRA_8888:
+      return GL_BGRA_EXT;
+
+    case gfx::BufferFormat::YVU_420:
+      return GL_RGB_YCRCB_420_CHROMIUM;
+
+    default:
+      NOTREACHED();
+      return GL_BGRA_EXT;
+  }
+}
+
 bool VaapiDrmPicture::Initialize() {
   DCHECK(pixmap_);
 
@@ -61,9 +75,13 @@
 
     gl::ScopedTextureBinder texture_binder(GL_TEXTURE_EXTERNAL_OES,
                                            texture_id_);
+
+    gfx::BufferFormat format = pixmap_->GetBufferFormat();
+
     scoped_refptr<gl::GLImageOzoneNativePixmap> image(
-        new gl::GLImageOzoneNativePixmap(size_, GL_BGRA_EXT));
-    if (!image->Initialize(pixmap_.get(), pixmap_->GetBufferFormat())) {
+        new gl::GLImageOzoneNativePixmap(size_,
+                                         BufferFormatToInternalFormat(format)));
+    if (!image->Initialize(pixmap_.get(), format)) {
       LOG(ERROR) << "Failed to create GLImage";
       return false;
     }
diff --git a/media/gpu/vaapi_video_decode_accelerator.cc b/media/gpu/vaapi_video_decode_accelerator.cc
index 3d162ae..a92e757 100644
--- a/media/gpu/vaapi_video_decode_accelerator.cc
+++ b/media/gpu/vaapi_video_decode_accelerator.cc
@@ -41,7 +41,8 @@
 
 // Buffer format to use for output buffers backing PictureBuffers. This is the
 // format decoded frames in VASurfaces are converted into.
-const gfx::BufferFormat kOutputPictureFormat = gfx::BufferFormat::BGRA_8888;
+const gfx::BufferFormat kAllocatePictureFormat = gfx::BufferFormat::BGRA_8888;
+const gfx::BufferFormat kImportPictureFormat = gfx::BufferFormat::YVU_420;
 }
 
 static void ReportToUMA(VAVDADecoderFailure failure) {
@@ -310,6 +311,7 @@
       finish_flush_pending_(false),
       awaiting_va_surfaces_recycle_(false),
       requested_num_pics_(0),
+      output_format_(kAllocatePictureFormat),
       make_context_current_cb_(make_context_current_cb),
       bind_image_cb_(bind_image_cb),
       weak_this_factory_(this) {
@@ -331,9 +333,18 @@
     return false;
   }
 
-  if (config.output_mode != Config::OutputMode::ALLOCATE &&
-      config.output_mode != Config::OutputMode::IMPORT) {
-    NOTREACHED() << "Only ALLOCATE and IMPORT OutputModes are supported";
+  switch (config.output_mode) {
+    case Config::OutputMode::ALLOCATE:
+      output_format_ = kAllocatePictureFormat;
+      break;
+
+    case Config::OutputMode::IMPORT:
+      output_format_ = kImportPictureFormat;
+      break;
+
+    default:
+      NOTREACHED() << "Only ALLOCATE and IMPORT OutputModes are supported";
+      return false;
   }
 
   client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client));
@@ -642,6 +653,9 @@
     case gfx::BufferFormat::BGRA_8888:
       return PIXEL_FORMAT_ARGB;
 
+    case gfx::BufferFormat::YVU_420:
+      return PIXEL_FORMAT_YV12;
+
     default:
       LOG(FATAL) << "Add more cases as needed";
       return PIXEL_FORMAT_UNKNOWN;
@@ -687,8 +701,7 @@
   DVLOG(1) << "Requesting " << requested_num_pics_
            << " pictures of size: " << requested_pic_size_.ToString();
 
-  VideoPixelFormat format =
-      BufferFormatToVideoPixelFormat(kOutputPictureFormat);
+  VideoPixelFormat format = BufferFormatToVideoPixelFormat(output_format_);
   task_runner_->PostTask(
       FROM_HERE, base::Bind(&Client::ProvidePictureBuffers, client_,
                             requested_num_pics_, format, 1, requested_pic_size_,
@@ -789,7 +802,7 @@
 
     if (output_mode_ == Config::OutputMode::ALLOCATE) {
       RETURN_AND_NOTIFY_ON_FAILURE(
-          picture->Allocate(kOutputPictureFormat),
+          picture->Allocate(output_format_),
           "Failed to allocate memory for a VaapiPicture", PLATFORM_FAILURE, );
       output_buffers_.push(buffers[i].id());
     }
@@ -827,13 +840,6 @@
     return;
   }
 
-  if (gpu_memory_buffer_handle.native_pixmap_handle.fds.size() != 1) {
-    CloseGpuMemoryBufferHandle(gpu_memory_buffer_handle);
-    LOG(ERROR) << "Handles backed by multple fds unsupported";
-    NotifyError(INVALID_ARGUMENT);
-    return;
-  }
-
   VaapiPicture* picture = PictureById(picture_buffer_id);
   if (!picture) {
     CloseGpuMemoryBufferHandle(gpu_memory_buffer_handle);
@@ -847,7 +853,7 @@
     return;
   }
 
-  if (!picture->ImportGpuMemoryBufferHandle(kOutputPictureFormat,
+  if (!picture->ImportGpuMemoryBufferHandle(output_format_,
                                             gpu_memory_buffer_handle)) {
     // ImportGpuMemoryBufferHandle will close the handles even on failure, so
     // we don't need to do this ourselves.
diff --git a/media/gpu/vaapi_video_decode_accelerator.h b/media/gpu/vaapi_video_decode_accelerator.h
index 819537f..8228a928 100644
--- a/media/gpu/vaapi_video_decode_accelerator.h
+++ b/media/gpu/vaapi_video_decode_accelerator.h
@@ -305,9 +305,11 @@
   // to be returned before we can free them.
   bool awaiting_va_surfaces_recycle_;
 
-  // Last requested number/resolution of output picture buffers.
+  // Last requested number/resolution of output picture buffers and their
+  // format.
   size_t requested_num_pics_;
   gfx::Size requested_pic_size_;
+  gfx::BufferFormat output_format_;
 
   // Callback to make GL context current.
   MakeGLContextCurrentCallback make_context_current_cb_;
diff --git a/media/gpu/vaapi_wrapper.cc b/media/gpu/vaapi_wrapper.cc
index fa4a1c8..dcec8b9 100644
--- a/media/gpu/vaapi_wrapper.cc
+++ b/media/gpu/vaapi_wrapper.cc
@@ -27,6 +27,7 @@
 #elif defined(USE_OZONE)
 #include "third_party/libva/va/drm/va_drm.h"
 #include "third_party/libva/va/va_drmcommon.h"
+#include "ui/gfx/buffer_format_util.h"
 #include "ui/ozone/public/ozone_platform.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
 #endif  // USE_X11
@@ -71,6 +72,8 @@
       return VA_FOURCC_BGRA;
     case gfx::BufferFormat::UYVY_422:
       return VA_FOURCC_UYVY;
+    case gfx::BufferFormat::YVU_420:
+      return VA_FOURCC_YV12;
     default:
       NOTREACHED();
       return 0;
@@ -84,6 +87,8 @@
     case gfx::BufferFormat::BGRX_8888:
     case gfx::BufferFormat::BGRA_8888:
       return VA_RT_FORMAT_RGB32;
+    case gfx::BufferFormat::YVU_420:
+      return VA_RT_FORMAT_YUV420;
     default:
       NOTREACHED();
       return 0;
@@ -614,33 +619,49 @@
 #if defined(USE_OZONE)
 scoped_refptr<VASurface> VaapiWrapper::CreateVASurfaceForPixmap(
     const scoped_refptr<ui::NativePixmap>& pixmap) {
-  // Get the dmabuf of the created buffer.
-  int dmabuf_fd = pixmap->GetDmaBufFd(0);
-  if (dmabuf_fd < 0) {
-    LOG(ERROR) << "Failed to get dmabuf from an Ozone NativePixmap";
-    return nullptr;
-  }
-  int dmabuf_pitch = pixmap->GetDmaBufPitch(0);
-  gfx::Size pixmap_size = pixmap->GetBufferSize();
-
-  // Create a VASurface out of the created buffer using the dmabuf.
+  // Create a VASurface for a NativePixmap by importing the underlying dmabufs.
   VASurfaceAttribExternalBuffers va_attrib_extbuf;
   memset(&va_attrib_extbuf, 0, sizeof(va_attrib_extbuf));
+
   va_attrib_extbuf.pixel_format =
       BufferFormatToVAFourCC(pixmap->GetBufferFormat());
-  va_attrib_extbuf.width = pixmap_size.width();
-  va_attrib_extbuf.height = pixmap_size.height();
-  va_attrib_extbuf.data_size = pixmap_size.height() * dmabuf_pitch;
-  va_attrib_extbuf.num_planes = 1;
-  va_attrib_extbuf.pitches[0] = dmabuf_pitch;
-  va_attrib_extbuf.offsets[0] = 0;
-  va_attrib_extbuf.buffers = reinterpret_cast<unsigned long*>(&dmabuf_fd);
-  va_attrib_extbuf.num_buffers = 1;
+  gfx::Size size = pixmap->GetBufferSize();
+  va_attrib_extbuf.width = size.width();
+  va_attrib_extbuf.height = size.height();
+
+  size_t num_fds = pixmap->GetDmaBufFdCount();
+  size_t num_planes =
+      gfx::NumberOfPlanesForBufferFormat(pixmap->GetBufferFormat());
+  if (num_fds == 0 || num_fds > num_planes) {
+    LOG(ERROR) << "Invalid number of dmabuf fds: " << num_fds
+               << " , planes: " << num_planes;
+    return nullptr;
+  }
+
+  for (size_t i = 0; i < num_planes; ++i) {
+    va_attrib_extbuf.pitches[i] = pixmap->GetDmaBufPitch(i);
+    va_attrib_extbuf.offsets[i] = pixmap->GetDmaBufOffset(i);
+    DVLOG(4) << "plane " << i << ": pitch: " << va_attrib_extbuf.pitches[i]
+             << " offset: " << va_attrib_extbuf.offsets[i];
+  }
+  va_attrib_extbuf.num_planes = num_planes;
+
+  std::vector<unsigned long> fds(num_fds);
+  for (size_t i = 0; i < num_fds; ++i) {
+    int dmabuf_fd = pixmap->GetDmaBufFd(i);
+    if (dmabuf_fd < 0) {
+      LOG(ERROR) << "Failed to get dmabuf from an Ozone NativePixmap";
+      return nullptr;
+    }
+    fds[i] = dmabuf_fd;
+  }
+  va_attrib_extbuf.buffers = fds.data();
+  va_attrib_extbuf.num_buffers = fds.size();
+
   va_attrib_extbuf.flags = 0;
   va_attrib_extbuf.private_data = NULL;
 
-  std::vector<VASurfaceAttrib> va_attribs;
-  va_attribs.resize(2);
+  std::vector<VASurfaceAttrib> va_attribs(2);
 
   va_attribs[0].type = VASurfaceAttribMemoryType;
   va_attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
@@ -652,9 +673,8 @@
   va_attribs[1].value.type = VAGenericValueTypePointer;
   va_attribs[1].value.value.p = &va_attrib_extbuf;
 
-  scoped_refptr<VASurface> va_surface =
-      CreateUnownedSurface(BufferFormatToVARTFormat(pixmap->GetBufferFormat()),
-                           pixmap_size, va_attribs);
+  scoped_refptr<VASurface> va_surface = CreateUnownedSurface(
+      BufferFormatToVARTFormat(pixmap->GetBufferFormat()), size, va_attribs);
   if (!va_surface) {
     LOG(ERROR) << "Failed to create VASurface for an Ozone NativePixmap";
     return nullptr;
diff --git a/media/midi/midi_manager_alsa.cc b/media/midi/midi_manager_alsa.cc
index 751b736..9dc0582 100644
--- a/media/midi/midi_manager_alsa.cc
+++ b/media/midi/midi_manager_alsa.cc
@@ -269,7 +269,7 @@
   out_client_.reset(out_client.release());
   decoder_.reset(decoder.release());
   udev_.reset(udev.release());
-  udev_monitor_.reset(udev_monitor_.release());
+  udev_monitor_.reset(udev_monitor.release());
 
   // Generate hotplug events for existing ports.
   // TODO(agoode): Check the return value for failure.
diff --git a/media/mojo/services/BUILD.gn b/media/mojo/services/BUILD.gn
index ca03efc..dfe7bd1 100644
--- a/media/mojo/services/BUILD.gn
+++ b/media/mojo/services/BUILD.gn
@@ -160,7 +160,7 @@
     "//media/mojo/clients",
     "//media/mojo/common",
     "//media/mojo/interfaces",
-    "//services/shell/public/cpp:shell_test_support",
+    "//services/shell/public/cpp:service_test_support",
     "//services/shell/public/cpp/test:run_all_shelltests",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/media/mojo/services/media_mojo_unittest.cc b/media/mojo/services/media_mojo_unittest.cc
index db87a1f7..e9079e6 100644
--- a/media/mojo/services/media_mojo_unittest.cc
+++ b/media/mojo/services/media_mojo_unittest.cc
@@ -20,7 +20,7 @@
 #include "media/mojo/interfaces/decryptor.mojom.h"
 #include "media/mojo/interfaces/renderer.mojom.h"
 #include "media/mojo/interfaces/service_factory.mojom.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_test.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 using testing::Exactly;
@@ -54,20 +54,20 @@
   DISALLOW_COPY_AND_ASSIGN(MockRendererClient);
 };
 
-class MediaShellTest : public shell::test::ShellTest {
+class MediaServiceTest : public shell::test::ServiceTest {
  public:
-  MediaShellTest()
-      : ShellTest("exe:media_mojo_unittests"),
+  MediaServiceTest()
+      : ServiceTest("exe:media_mojo_unittests"),
         renderer_client_binding_(&renderer_client_),
         video_stream_(DemuxerStream::VIDEO) {}
-  ~MediaShellTest() override {}
+  ~MediaServiceTest() override {}
 
   void SetUp() override {
-    ShellTest::SetUp();
+    ServiceTest::SetUp();
 
     connection_ = connector()->Connect("mojo:media");
-    connection_->SetConnectionLostClosure(
-        base::Bind(&MediaShellTest::ConnectionClosed, base::Unretained(this)));
+    connection_->SetConnectionLostClosure(base::Bind(
+        &MediaServiceTest::ConnectionClosed, base::Unretained(this)));
 
     connection_->GetInterface(&service_factory_);
 
@@ -91,9 +91,10 @@
     EXPECT_CALL(*this, OnCdmInitializedInternal(expected_result, cdm_id))
         .Times(Exactly(1))
         .WillOnce(InvokeWithoutArgs(run_loop_.get(), &base::RunLoop::Quit));
-    cdm_->Initialize(
-        key_system, kSecurityOrigin, mojom::CdmConfig::From(CdmConfig()),
-        base::Bind(&MediaShellTest::OnCdmInitialized, base::Unretained(this)));
+    cdm_->Initialize(key_system, kSecurityOrigin,
+                     mojom::CdmConfig::From(CdmConfig()),
+                     base::Bind(&MediaServiceTest::OnCdmInitialized,
+                                base::Unretained(this)));
   }
 
   MOCK_METHOD1(OnRendererInitialized, void(bool));
@@ -113,7 +114,7 @@
         .WillOnce(InvokeWithoutArgs(run_loop_.get(), &base::RunLoop::Quit));
     renderer_->Initialize(renderer_client_binding_.CreateInterfacePtrAndBind(),
                           nullptr, std::move(video_stream_proxy),
-                          base::Bind(&MediaShellTest::OnRendererInitialized,
+                          base::Bind(&MediaServiceTest::OnRendererInitialized,
                                      base::Unretained(this)));
   }
 
@@ -135,7 +136,7 @@
  private:
   std::unique_ptr<shell::Connection> connection_;
 
-  DISALLOW_COPY_AND_ASSIGN(MediaShellTest);
+  DISALLOW_COPY_AND_ASSIGN(MediaServiceTest);
 };
 
 }  // namespace
@@ -144,12 +145,12 @@
 // even when the loop is idle, we may still have pending events in the pipe.
 
 #if defined(ENABLE_MOJO_CDM)
-TEST_F(MediaShellTest, InitializeCdm_Success) {
+TEST_F(MediaServiceTest, InitializeCdm_Success) {
   InitializeCdm(kClearKeyKeySystem, true, 1);
   run_loop_->Run();
 }
 
-TEST_F(MediaShellTest, InitializeCdm_InvalidKeySystem) {
+TEST_F(MediaServiceTest, InitializeCdm_InvalidKeySystem) {
   InitializeCdm(kInvalidKeySystem, false, 0);
   run_loop_->Run();
 }
@@ -163,18 +164,18 @@
 #define MAYBE_InitializeRenderer_Success InitializeRenderer_Success
 #endif
 
-TEST_F(MediaShellTest, MAYBE_InitializeRenderer_Success) {
+TEST_F(MediaServiceTest, MAYBE_InitializeRenderer_Success) {
   InitializeRenderer(TestVideoConfig::Normal(), true);
   run_loop_->Run();
 }
 
-TEST_F(MediaShellTest, InitializeRenderer_InvalidConfig) {
+TEST_F(MediaServiceTest, InitializeRenderer_InvalidConfig) {
   InitializeRenderer(TestVideoConfig::Invalid(), false);
   run_loop_->Run();
 }
 #endif  // defined(ENABLE_MOJO_RENDERER)
 
-TEST_F(MediaShellTest, Lifetime) {
+TEST_F(MediaServiceTest, Lifetime) {
   // Disconnecting CDM and Renderer services doesn't terminate the app.
   cdm_.reset();
   renderer_.reset();
diff --git a/media/mojo/services/mojo_media_application.h b/media/mojo/services/mojo_media_application.h
index 7533fcb6..1c093a3 100644
--- a/media/mojo/services/mojo_media_application.h
+++ b/media/mojo/services/mojo_media_application.h
@@ -16,7 +16,7 @@
 #include "media/mojo/services/media_mojo_export.h"
 #include "services/shell/public/cpp/interface_factory.h"
 #include "services/shell/public/cpp/service.h"
-#include "services/shell/public/cpp/shell_connection_ref.h"
+#include "services/shell/public/cpp/service_context_ref.h"
 #include "url/gurl.h"
 
 namespace media {
@@ -51,7 +51,7 @@
 
   shell::Connector* connector_;
   scoped_refptr<MediaLog> media_log_;
-  shell::ShellConnectionRefFactory ref_factory_;
+  shell::ServiceContextRefFactory ref_factory_;
 };
 
 }  // namespace media
diff --git a/media/mojo/services/service_factory_impl.cc b/media/mojo/services/service_factory_impl.cc
index adc5107..433a8a9b 100644
--- a/media/mojo/services/service_factory_impl.cc
+++ b/media/mojo/services/service_factory_impl.cc
@@ -34,7 +34,7 @@
     mojo::InterfaceRequest<mojom::ServiceFactory> request,
     shell::mojom::InterfaceProvider* interfaces,
     scoped_refptr<MediaLog> media_log,
-    std::unique_ptr<shell::ShellConnectionRef> connection_ref,
+    std::unique_ptr<shell::ServiceContextRef> connection_ref,
     MojoMediaClient* mojo_media_client)
     : binding_(this, std::move(request)),
 #if defined(ENABLE_MOJO_CDM)
diff --git a/media/mojo/services/service_factory_impl.h b/media/mojo/services/service_factory_impl.h
index 8053571..19a1e74 100644
--- a/media/mojo/services/service_factory_impl.h
+++ b/media/mojo/services/service_factory_impl.h
@@ -12,7 +12,7 @@
 #include "media/mojo/services/mojo_cdm_service_context.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/shell/public/cpp/connector.h"
-#include "services/shell/public/cpp/shell_connection_ref.h"
+#include "services/shell/public/cpp/service_context_ref.h"
 
 namespace shell {
 namespace mojom {
@@ -32,7 +32,7 @@
   ServiceFactoryImpl(mojo::InterfaceRequest<mojom::ServiceFactory> request,
                      shell::mojom::InterfaceProvider* interfaces,
                      scoped_refptr<MediaLog> media_log,
-                     std::unique_ptr<shell::ShellConnectionRef> connection_ref,
+                     std::unique_ptr<shell::ServiceContextRef> connection_ref,
                      MojoMediaClient* mojo_media_client);
   ~ServiceFactoryImpl() final;
 
@@ -62,7 +62,7 @@
 #endif
 
   scoped_refptr<MediaLog> media_log_;
-  std::unique_ptr<shell::ShellConnectionRef> connection_ref_;
+  std::unique_ptr<shell::ServiceContextRef> connection_ref_;
   MojoMediaClient* mojo_media_client_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceFactoryImpl);
diff --git a/media/renderers/skcanvas_video_renderer.cc b/media/renderers/skcanvas_video_renderer.cc
index df59249..74e72bc 100644
--- a/media/renderers/skcanvas_video_renderer.cc
+++ b/media/renderers/skcanvas_video_renderer.cc
@@ -109,9 +109,9 @@
     source_textures[i].fTarget = mailbox_holder.texture_target;
 
     // TODO(dcastagna): avoid this copy once Skia supports native textures
-    // with a texture target different than TEXTURE_2D.
+    // with a GL_TEXTURE_RECTANGLE_ARB texture target.
     // crbug.com/505026
-    if (mailbox_holder.texture_target != GL_TEXTURE_2D) {
+    if (mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB) {
       unsigned texture_copy = 0;
       gl->GenTextures(1, &texture_copy);
       DCHECK(texture_copy);
diff --git a/media/test/BUILD.gn b/media/test/BUILD.gn
index 1bedb1f..ca6ea349 100644
--- a/media/test/BUILD.gn
+++ b/media/test/BUILD.gn
@@ -99,7 +99,7 @@
       "//media/mojo/clients",
       "//media/mojo/interfaces",
       "//media/mojo/services",
-      "//services/shell/public/cpp:shell_test_support",
+      "//services/shell/public/cpp:service_test_support",
       "//testing/gtest",
       "//ui/gfx:test_support",
       "//ui/gfx/geometry",
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index 42c80892..e244dde2 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -43,7 +43,7 @@
 #include "media/mojo/interfaces/renderer.mojom.h"
 #include "media/mojo/interfaces/service_factory.mojom.h"
 #include "services/shell/public/cpp/connect.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_test.h"
 
 // TODO(dalecurtis): The mojo renderer is in another process, so we have no way
 // currently to get hashes for video and audio samples.  This also means that
@@ -700,14 +700,14 @@
 //               preferably by eliminating multiple inheritance here which is
 //               banned by Google C++ style.
 #if defined(MOJO_RENDERER) && defined(ENABLE_MOJO_PIPELINE_INTEGRATION_TEST)
-class PipelineIntegrationTestHost : public shell::test::ShellTest,
+class PipelineIntegrationTestHost : public shell::test::ServiceTest,
                                     public PipelineIntegrationTestBase {
  public:
   PipelineIntegrationTestHost()
-      : shell::test::ShellTest("exe:media_pipeline_integration_shelltests") {}
+      : shell::test::ServiceTest("exe:media_pipeline_integration_shelltests") {}
 
   void SetUp() override {
-    ShellTest::SetUp();
+    ServiceTest::SetUp();
     InitializeMediaLibrary();
   }
 
diff --git a/mojo/edk/system/node_controller.cc b/mojo/edk/system/node_controller.cc
index 5fc55f5..a7f247a 100644
--- a/mojo/edk/system/node_controller.cc
+++ b/mojo/edk/system/node_controller.cc
@@ -23,6 +23,7 @@
 #include "mojo/edk/system/broker_host.h"
 #include "mojo/edk/system/core.h"
 #include "mojo/edk/system/ports_message.h"
+#include "mojo/edk/system/request_context.h"
 
 #if defined(OS_MACOSX) && !defined(OS_IOS)
 #include "mojo/edk/system/mach_port_relay.h"
@@ -545,6 +546,8 @@
     node_->ClosePort(port);
 
   node_->LostConnectionToNode(name);
+
+  AcceptIncomingMessages();
 }
 
 void NodeController::SendPeerMessage(const ports::NodeName& name,
@@ -646,6 +649,11 @@
   AttemptShutdownIfRequested();
 }
 
+void NodeController::ProcessIncomingMessages() {
+  RequestContext request_context(RequestContext::Source::SYSTEM);
+  AcceptIncomingMessages();
+}
+
 void NodeController::DropAllPeers() {
   DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
 
@@ -693,17 +701,39 @@
 void NodeController::ForwardMessage(const ports::NodeName& node,
                                     ports::ScopedMessage message) {
   DCHECK(message);
+  bool schedule_pump_task = false;
   if (node == name_) {
     // NOTE: We need to avoid re-entering the Node instance within
     // ForwardMessage. Because ForwardMessage is only ever called
     // (synchronously) in response to Node's ClosePort, SendMessage, or
     // AcceptMessage, we flush the queue after calling any of those methods.
     base::AutoLock lock(messages_lock_);
+    schedule_pump_task = incoming_messages_.empty();
     incoming_messages_.emplace(std::move(message));
     incoming_messages_flag_.Set(true);
   } else {
     SendPeerMessage(node, std::move(message));
   }
+
+  // |io_task_runner_| may be null in tests or processes that don't require
+  // multi-process Mojo.
+  if (schedule_pump_task && io_task_runner_) {
+    // Normally, the queue is processed after the action that added the local
+    // message is done (i.e. SendMessage, ClosePort, etc). However, it's also
+    // possible for a local message to be added as a result of a remote message,
+    // and OnChannelMessage() doesn't process this queue (although
+    // OnPortsMessage() does). There may also be other code paths, now or added
+    // in the future, which cause local messages to be added but don't process
+    // this message queue.
+    //
+    // Instead of adding a call to AcceptIncomingMessages() on every possible
+    // code path, post a task to the IO thread to process the queue. If the
+    // current call stack processes the queue, this may end up doing nothing.
+    io_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&NodeController::ProcessIncomingMessages,
+                   base::Unretained(this)));
+  }
 }
 
 void NodeController::BroadcastMessage(ports::ScopedMessage message) {
@@ -740,14 +770,16 @@
   scoped_refptr<NodeChannel> parent;
   {
     base::AutoLock lock(parent_lock_);
-    if (!bootstrap_parent_channel_ || parent_name_ != ports::kInvalidNodeName) {
-      DLOG(ERROR) << "Unexpected AcceptChild message from " << from_node;
-      DropPeer(from_node);
-      return;
+    if (bootstrap_parent_channel_ && parent_name_ == ports::kInvalidNodeName) {
+      parent_name_ = parent_name;
+      parent = bootstrap_parent_channel_;
     }
+  }
 
-    parent_name_ = parent_name;
-    parent = bootstrap_parent_channel_;
+  if (!parent) {
+    DLOG(ERROR) << "Unexpected AcceptChild message from " << from_node;
+    DropPeer(from_node);
+    return;
   }
 
   parent->SetRemoteNodeName(parent_name);
@@ -996,6 +1028,8 @@
   int rv = node_->MergePorts(local_port, from_node, connector_port_name);
   if (rv != ports::OK)
     DLOG(ERROR) << "MergePorts failed: " << rv;
+
+  AcceptIncomingMessages();
 }
 
 void NodeController::OnRequestIntroduction(const ports::NodeName& from_node,
diff --git a/mojo/edk/system/node_controller.h b/mojo/edk/system/node_controller.h
index d0f3d6a7..c96b4f44 100644
--- a/mojo/edk/system/node_controller.h
+++ b/mojo/edk/system/node_controller.h
@@ -157,6 +157,7 @@
   void SendPeerMessage(const ports::NodeName& name,
                        ports::ScopedMessage message);
   void AcceptIncomingMessages();
+  void ProcessIncomingMessages();
   void DropAllPeers();
 
   // ports::NodeDelegate:
diff --git a/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h b/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h
index a976f2c..4550526 100644
--- a/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h
+++ b/mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h
@@ -101,8 +101,8 @@
 
   // Fields in test::PassByValueStructWithTraits.
   // See src/mojo/public/interfaces/bindings/tests/struct_with_traits.mojom.
-  static ScopedHandle& f_handle(test::PassByValueStructWithTraitsImpl& value) {
-    return value.get_mutable_handle();
+  static ScopedHandle f_handle(test::PassByValueStructWithTraitsImpl& value) {
+    return std::move(value.get_mutable_handle());
   }
 };
 
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
index f95b33d4..c59f3178 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
@@ -66,13 +66,17 @@
 {%-   set name = pf.field.name %}
 {%-   set kind = pf.field.kind %}
 {%-   set serializer_type = kind|unmapped_type_for_serializer %}
-{%-   if kind|is_object_kind %}
+
+{%-   if kind|is_object_kind or kind|is_any_handle_or_interface_kind %}
 {%-     set original_input_field = input_field_pattern|format(name) %}
 {%-     set input_field = "in_%s"|format(name) if input_may_be_temp
                                                else original_input_field %}
 {%-     if input_may_be_temp %}
   decltype({{original_input_field}}) in_{{name}} = {{original_input_field}};
 {%-     endif %}
+{%-   endif %}
+
+{%-   if kind|is_object_kind %}
 {%-     if kind|is_array_kind or kind|is_map_kind %}
   typename decltype({{output}}->{{name}})::BaseType* {{name}}_ptr;
   const mojo::internal::ContainerValidateParams {{name}}_validate_params(
diff --git a/net/BUILD.gn b/net/BUILD.gn
index b17c8ad..2623fc4 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -263,10 +263,6 @@
         "dns/mdns_client.h",
         "dns/mdns_client_impl.cc",
         "dns/mdns_client_impl.h",
-        "dns/record_parsed.cc",
-        "dns/record_parsed.h",
-        "dns/record_rdata.cc",
-        "dns/record_rdata.h",
       ]
     }
 
@@ -1597,8 +1593,6 @@
     sources -= [
       "dns/mdns_cache_unittest.cc",
       "dns/mdns_client_unittest.cc",
-      "dns/record_parsed_unittest.cc",
-      "dns/record_rdata_unittest.cc",
     ]
   }
 
@@ -1795,6 +1789,7 @@
     "//base",
     "//net",
   ]
+  dict = "data/fuzzer_dictionaries/net_mime_sniffer_fuzzer.dict"
 }
 
 fuzzer_test("net_parse_proxy_list_pac_fuzzer") {
@@ -1846,6 +1841,7 @@
     "//base",
     "//net",
   ]
+  dict = "data/fuzzer_dictionaries/net_parse_data_url_fuzzer.dict"
 }
 
 fuzzer_test("net_parse_ip_pattern_fuzzer") {
@@ -1867,6 +1863,7 @@
     "//base",
     "//net",
   ]
+  dict = "data/fuzzer_dictionaries/net_get_domain_and_registry_fuzzer.dict"
 }
 
 fuzzer_test("net_cert_verify_name_match_fuzzer") {
@@ -1930,6 +1927,7 @@
     "//base",
     "//net",
   ]
+  dict = "data/fuzzer_dictionaries/net_dns_record_fuzzer.dict"
 }
 
 fuzzer_test("net_dns_hosts_parse_fuzzer") {
@@ -1941,6 +1939,7 @@
     "//base",
     "//net",
   ]
+  dict = "data/fuzzer_dictionaries/net_dns_hosts_parse_fuzzer.dict"
 }
 
 fuzzer_test("net_host_resolver_impl_fuzzer") {
@@ -1955,7 +1954,7 @@
     "//base",
     "//net",
   ]
-  dict = "data/dns/dns.dict"
+  dict = "data/fuzzer_dictionaries/net_host_resolver_impl_fuzzer.dict"
 }
 
 fuzzer_test("net_http_stream_parser_fuzzer") {
@@ -1968,7 +1967,7 @@
     "//base",
     "//net",
   ]
-  dict = "data/http/http.dict"
+  dict = "data/fuzzer_dictionaries/net_http_stream_parser_fuzzer.dict"
 }
 
 fuzzer_test("net_ftp_ctrl_response_fuzzer") {
@@ -2014,6 +2013,7 @@
     ":net_fuzzer_test_support",
     "//net",
   ]
+  dict = "data/fuzzer_dictionaries/net_websocket_frame_parser_fuzzer.dict"
 }
 
 fuzzer_test("net_http_chunked_decoder_fuzzer") {
@@ -2024,7 +2024,6 @@
     ":net_fuzzer_test_support",
     "//net",
   ]
-  dict = "http/http_chunked_decoder_fuzzer.dict"
 }
 
 fuzzer_test("net_http_proxy_client_socket_fuzzer") {
@@ -2037,7 +2036,7 @@
     "//base",
     "//net",
   ]
-  dict = "data/http/http.dict"
+  dict = "data/fuzzer_dictionaries/net_http_proxy_client_socket_fuzzer.dict"
 }
 
 fuzzer_test("net_quic_crypto_framer_parse_message_fuzzer") {
@@ -2085,5 +2084,5 @@
     "//base",
     "//net",
   ]
-  dict = "data/http/http.dict"
+  dict = "data/fuzzer_dictionaries/net_url_request_fuzzer.dict"
 }
diff --git a/net/base/filename_util.cc b/net/base/filename_util.cc
index 153ce43d..1e1d51c0 100644
--- a/net/base/filename_util.cc
+++ b/net/base/filename_util.cc
@@ -174,8 +174,10 @@
     if (filename_lower == known_devices[i])
       return true;
     // Starts with "DEVICE.".
-    if (filename_lower.find(std::string(known_devices[i]) + ".") == 0)
+    if (base::StartsWith(filename_lower, std::string(known_devices[i]) + ".",
+                         base::CompareCase::SENSITIVE)) {
       return true;
+    }
   }
 
   static const char* const magic_names[] = {
diff --git a/net/base/registry_controlled_domains/effective_tld_names.dat b/net/base/registry_controlled_domains/effective_tld_names.dat
index 39db97a..8ff464c 100644
--- a/net/base/registry_controlled_domains/effective_tld_names.dat
+++ b/net/base/registry_controlled_domains/effective_tld_names.dat
@@ -270,18 +270,14 @@
 pro.az
 biz.az
 
-// ba : https://en.wikipedia.org/wiki/.ba
+// ba : http://nic.ba/users_data/files/pravilnik_o_registraciji.pdf
 ba
-org.ba
-net.ba
+com.ba
 edu.ba
 gov.ba
 mil.ba
-unsa.ba
-unbi.ba
-co.ba
-com.ba
-rs.ba
+net.ba
+org.ba
 
 // bb : https://en.wikipedia.org/wiki/.bb
 bb
@@ -2552,7 +2548,6 @@
 kamiamakusa.kumamoto.jp
 kashima.kumamoto.jp
 kikuchi.kumamoto.jp
-kosa.kumamoto.jp
 kumamoto.kumamoto.jp
 mashiki.kumamoto.jp
 mifune.kumamoto.jp
@@ -2637,7 +2632,6 @@
 kakuda.miyagi.jp
 kami.miyagi.jp
 kawasaki.miyagi.jp
-kesennuma.miyagi.jp
 marumori.miyagi.jp
 matsushima.miyagi.jp
 minamisanriku.miyagi.jp
@@ -10636,6 +10630,10 @@
 // ===BEGIN PRIVATE DOMAINS===
 // (Note: these are in alphabetical order by company name)
 
+// Agnat sp. z o.o. : https://domena.pl
+// Submitted by Przemyslaw Plewa <it-admin@domena.pl>
+beep.pl
+
 // Alces Software Ltd : http://alces-software.com
 // Submitted by Mark J. Titorenko <mark.titorenko@alces-software.com>
 *.compute.estate
@@ -10646,24 +10644,24 @@
 cloudfront.net
 
 // Amazon Elastic Compute Cloud: https://aws.amazon.com/ec2/
-// Submitted by Luke Wells <lawells@amazon.com>
+// Submitted by Philip Allchin <pallchin@amazon.com>
+compute.amazonaws.com
 ap-northeast-1.compute.amazonaws.com
 ap-northeast-2.compute.amazonaws.com
 ap-southeast-1.compute.amazonaws.com
 ap-southeast-2.compute.amazonaws.com
-cn-north-1.compute.amazonaws.cn
-compute-1.amazonaws.com
-compute.amazonaws.cn
-compute.amazonaws.com
 eu-central-1.compute.amazonaws.com
 eu-west-1.compute.amazonaws.com
 sa-east-1.compute.amazonaws.com
-us-east-1.amazonaws.com
 us-gov-west-1.compute.amazonaws.com
 us-west-1.compute.amazonaws.com
 us-west-2.compute.amazonaws.com
+us-east-1.amazonaws.com
+compute-1.amazonaws.com
 z-1.compute-1.amazonaws.com
 z-2.compute-1.amazonaws.com
+compute.amazonaws.com.cn
+cn-north-1.compute.amazonaws.com.cn
 
 // Amazon Elastic Beanstalk : https://aws.amazon.com/elasticbeanstalk/
 // Submitted by Adam Stein <astein@amazon.com>
@@ -10697,6 +10695,13 @@
 // Submitted by Thomas Orozco <thomas@aptible.com>
 on-aptible.com
 
+// Association potager.org : https://potager.org/
+// Submitted by Lunar <jardiniers@potager.org>
+potager.org
+poivron.org
+sweetpepper.org
+pimienta.org
+
 // AVM : https://avm.de
 // Submitted by Andreas Weise <a.weise@avm.de>
 myfritz.net
@@ -10705,6 +10710,14 @@
 // Submitted by Adrian <adrian@betainabox.com>
 betainabox.com
 
+// Boxfuse : https://boxfuse.com
+// Submitted by Axel Fontaine <axel@boxfuse.com>
+boxfuse.io
+
+// callidomus: https://www.callidomus.com/
+// Submitted by Marcus Popp <admin@callidomus.com>
+mycd.eu
+
 // CentralNic : http://www.centralnic.com/names/domains
 // Submitted by registry <gavin.brown@centralnic.com>
 ae.org
@@ -10759,10 +10772,18 @@
 // c.la : http://www.c.la/
 c.la
 
+// certmgr.org : https://certmgr.org
+// Submitted by B. Blechschmidt <hostmaster@certmgr.org>
+certmgr.org
+
 // Citrix : https://citrix.com
 // Submitted by Alex Stoddard <alex.stoddard@citrix.com>
 xenapponazure.com
 
+// ClearVox : http://www.clearvox.nl/
+// Submitted by Leon Rowland <leon@clearvox.nl>
+virtueeldomein.nl
+
 // cloudControl : https://www.cloudcontrol.com/
 // Submitted by Tobias Wilken <tw@cloudcontrol.com>
 cloudcontrolled.com
@@ -10792,6 +10813,14 @@
 // CHROMIUM - Disabled as per https://code.google.com/p/chromium/issues/detail?id=459802
 // *.platform.sh
 
+// Craynic, s.r.o. : http://www.craynic.com/
+// Submitted by Ales Krajnik <ales.krajnik@craynic.com>
+realm.cz
+
+// Cryptonomic : https://cryptonomic.net/
+// Submitted by Andrew Cady <public-suffix-list@cryptonomic.net>
+*.cryptonomic.net
+
 // Cupcake : https://cupcake.io/
 // Submitted by Jonathan Rudenberg <jonathan@cupcake.io>
 cupcake.is
@@ -10833,6 +10862,11 @@
 // Submitted by Richard Harper <richard@duckdns.org>
 duckdns.org
 
+// dy.fi : http://dy.fi/
+// Submitted by Heikki Hannikainen <hessu@hes.iki.fi>
+dy.fi
+tunk.org
+
 // DynDNS.com : http://www.dyndns.com/services/dns/dyndns/
 dyndns-at-home.com
 dyndns-at-work.com
@@ -11118,6 +11152,10 @@
 // Submitted by Dominik Menke <dom@digineo.de> 2016-01-18
 dynv6.net
 
+// E4YOU spol. s.r.o. : https://e4you.cz/
+// Submitted by Vladimir Dudr <info@e4you.cz>
+e4.cz
+
 // EU.org https://eu.org/
 // Submitted by Pierre Beyssac <hostmaster@eu.org>
 eu.org
@@ -11177,6 +11215,13 @@
 uk.eu.org
 us.eu.org
 
+// Evennode : http://www.evennode.com/
+// Submitted by Michal Kralik <support@evennode.com>
+eu-1.evennode.com
+eu-2.evennode.com
+us-1.evennode.com
+us-2.evennode.com
+
 // Facebook, Inc.
 // Submitted by Peter Ruibal <public-suffix@fb.com>
 apps.fbsbx.com
@@ -11189,6 +11234,10 @@
 a.prod.fastly.net
 global.prod.fastly.net
 
+// Featherhead : https://featherhead.xyz/
+// Submitted by Simon Menke <simon@featherhead.xyz>
+fhapp.xyz
+
 // Firebase, Inc.
 // Submitted by Chris Raynor <chris@firebase.com>
 firebaseapp.com
@@ -11197,6 +11246,15 @@
 // Submitted by Jonathan Rudenberg <jonathan@flynn.io>
 flynnhub.com
 
+// Freebox : http://www.freebox.fr
+// Submitted by Romain Fliedel <rfliedel@freebox.fr>
+freebox-os.com
+freeboxos.com
+fbx-os.fr
+fbxos.fr
+freebox-os.fr
+freeboxos.fr
+
 // GDS : https://www.gov.uk/service-manual/operations/operating-servicegovuk-subdomains
 // Submitted by David Illsley <david.illsley@digital.cabinet-office.gov.uk>
 service.gov.uk
@@ -11308,6 +11366,14 @@
 // Hashbang : https://hashbang.sh
 hashbang.sh
 
+// Hasura : https://hasura.io
+// Submitted by Shahidh K Muhammed <shahidh@hasura.io>
+hasura-app.io
+
+// Hepforge : https://www.hepforge.org
+// Submitted by David Grellscheid <admin@hepforge.org>
+hepforge.org
+
 // Heroku : https://www.heroku.com/
 // Submitted by Tom Maher <tmaher@heroku.com>
 herokuapp.com
@@ -11321,6 +11387,15 @@
 biz.at
 info.at
 
+// Magento Commerce
+// Submitted by Damien Tournoud <dtournoud@magento.cloud>
+*.magentosite.cloud
+
+// Meteor Development Group : https://www.meteor.com/hosting
+// Submitted by Pierre Carrier <pierre@meteor.com>
+meteorapp.com
+eu.meteorapp.com
+
 // Michau Enterprises Limited : http://www.co.pl/
 co.pl
 
@@ -11351,6 +11426,94 @@
 nsupdate.info
 nerdpol.ovh
 
+// No-IP.com : https://noip.com/
+// Submitted by Deven Reza <publicsuffixlist@noip.com>
+blogsyte.com
+brasilia.me
+cable-modem.org
+ciscofreak.com
+collegefan.org
+couchpotatofries.org
+damnserver.com
+ddns.me
+ditchyourip.com
+dnsfor.me
+dnsiskinky.com
+dvrcam.info
+dynns.com
+eating-organic.net
+fantasyleague.cc
+geekgalaxy.com
+golffan.us
+health-carereform.com
+homesecuritymac.com
+homesecuritypc.com
+hopto.me
+ilovecollege.info
+loginto.me
+mlbfan.org
+mmafan.biz
+myactivedirectory.com
+mydissent.net
+myeffect.net
+mymediapc.net
+mypsx.net
+mysecuritycamera.com
+mysecuritycamera.net
+mysecuritycamera.org
+net-freaks.com
+nflfan.org
+nhlfan.net
+no-ip.ca
+no-ip.co.uk
+no-ip.net
+noip.us
+onthewifi.com
+pgafan.net
+point2this.com
+pointto.us
+privatizehealthinsurance.net
+quicksytes.com
+read-books.org
+securitytactics.com
+serveexchange.com
+servehumour.com
+servep2p.com
+servesarcasm.com
+stufftoread.com
+ufcfan.org
+unusualperson.com
+workisboring.com
+3utilities.com
+bounceme.net
+ddns.net
+ddnsking.com
+gotdns.ch
+hopto.org
+myftp.biz
+myftp.org
+myvnc.com
+no-ip.biz
+no-ip.info
+no-ip.org
+noip.me
+redirectme.net
+servebeer.com
+serveblog.net
+servecounterstrike.com
+serveftp.com
+servegame.com
+servehalflife.com
+servehttp.com
+serveirc.com
+serveminecraft.net
+servemp3.com
+servepics.com
+servequake.com
+sytes.net
+webhop.me
+zapto.org
+
 // NYC.mn : http://www.information.nyc.mn
 // Submitted by Matthew Brown <mattbrown@nyc.mn>
 nyc.mn
@@ -11375,6 +11538,10 @@
 // Submitted by Charly Coste <changaco@changaco.oy.lc>
 oy.lc
 
+// Pagefog : https://pagefog.com/
+// Submitted by Derek Myers <derek@pagefog.com>
+pgfog.com
+
 // Pagefront : https://www.pagefronthq.com/
 // Submitted by Jason Kriss <jason@pagefronthq.com>
 pagefrontapp.com
@@ -11429,18 +11596,37 @@
 // Submitted by Asheesh Laroia <asheesh@sandstorm.io>
 sandcats.io
 
+// SBE network solutions GmbH : https://www.sbe.de/
+// Submitted by Norman Meilick <nm@sbe.de>
+logoip.de
+logoip.com
+
 // Service Online LLC : http://drs.ua/
 // Submitted by Serhii Bulakh <support@drs.ua>
 biz.ua
 co.ua
 pp.ua
 
+// Shopblocks : http://www.shopblocks.com/
+// Submitted by Alex Bowers <alex@shopblocks.com>
+myshopblocks.com
+
 // SinaAppEngine : http://sae.sina.com.cn/
 // Submitted by SinaAppEngine <saesupport@sinacloud.com>
 sinaapp.com
 vipsinaapp.com
 1kapp.com
 
+// Skyhat : http://www.skyhat.io
+// Submitted by Shante Adam <shante@skyhat.io>
+bounty-full.com
+alpha.bounty-full.com
+beta.bounty-full.com
+
+// SpaceKit : https://www.spacekit.io/
+// Submitted by Reza Akhavan <spacekit.io@gmail.com>
+spacekit.io
+
 // Synology, Inc. : https://www.synology.com/
 // Submitted by Rony Weng <ronyweng@synology.com>
 diskstation.me
@@ -11464,11 +11650,15 @@
 med.pl
 sopot.pl
 
-// TownNews.com domains : http://www.townnews.com
+// TownNews.com : http://www.townnews.com
 // Submitted by Dustin Ward <dward@townnews.com>
 bloxcms.com
 townnews-staging.com
 
+// TuxFamily : http://tuxfamily.org
+// Submitted by TuxFamily administrators <adm@staff.tuxfamily.org>
+tuxfamily.org
+
 // UDR Limited : http://www.udr.hk.com
 // Submitted by registry <hostmaster@udr.hk.com>
 hk.com
diff --git a/net/base/registry_controlled_domains/effective_tld_names.gperf b/net/base/registry_controlled_domains/effective_tld_names.gperf
index e2901fc..587d03e 100644
--- a/net/base/registry_controlled_domains/effective_tld_names.gperf
+++ b/net/base/registry_controlled_domains/effective_tld_names.gperf
@@ -18,6 +18,7 @@
 2.bg, 0
 2000.hu, 0
 3.bg, 0
+3utilities.com, 4
 4.bg, 0
 4u.com, 4
 5.bg, 0
@@ -215,6 +216,7 @@
 allfinanz, 0
 allstate, 0
 ally, 0
+alpha.bounty-full.com, 4
 alsace, 0
 alstahaug.no, 0
 alstom, 0
@@ -555,6 +557,7 @@
 beauxarts.museum, 0
 bedzin.pl, 0
 beeldengeluid.museum, 0
+beep.pl, 4
 beer, 0
 beiarn.no, 0
 bel.tr, 0
@@ -578,6 +581,7 @@
 best, 0
 bestbuy, 0
 bet, 0
+beta.bounty-full.com, 4
 betainabox.com, 4
 better-than.tv, 4
 bf, 0
@@ -727,6 +731,7 @@
 blogspot.tw, 4
 blogspot.ug, 4
 blogspot.vn, 4
+blogsyte.com, 4
 bloomberg, 0
 bloxcms.com, 4
 blue, 0
@@ -770,8 +775,11 @@
 botanicalgarden.museum, 0
 botanicgarden.museum, 0
 botany.museum, 0
+bounceme.net, 4
+bounty-full.com, 4
 boutique, 0
 box, 0
+boxfuse.io, 4
 bozen.it, 0
 br, 0
 br.com, 4
@@ -780,6 +788,7 @@
 brand.se, 0
 brandywinevalley.museum, 0
 brasil.museum, 0
+brasilia.me, 4
 bremanger.no, 0
 brescia.it, 0
 bridgestone, 0
@@ -850,6 +859,7 @@
 ca.us, 0
 caa.aero, 0
 cab, 0
+cable-modem.org, 4
 cadaques.museum, 0
 cafe, 0
 cagliari.it, 0
@@ -985,6 +995,7 @@
 ceo, 0
 cern, 0
 certification.aero, 0
+certmgr.org, 4
 cesena-forli.it, 0
 cesenaforli.it, 0
 cf, 0
@@ -1076,6 +1087,7 @@
 circle, 0
 circus.museum, 0
 cisco, 0
+ciscofreak.com, 4
 citadel, 0
 citi, 0
 citic, 0
@@ -1118,7 +1130,7 @@
 cm, 0
 cmw.ru, 0
 cn, 0
-cn-north-1.compute.amazonaws.cn, 4
+cn-north-1.compute.amazonaws.com.cn, 4
 cn.com, 4
 cn.eu.org, 4
 cn.it, 0
@@ -1130,7 +1142,6 @@
 co.ag, 0
 co.ao, 0
 co.at, 0
-co.ba, 0
 co.bb, 0
 co.bi, 0
 co.bw, 0
@@ -1199,6 +1210,7 @@
 coldwar.museum, 0
 collection.museum, 0
 college, 0
+collegefan.org, 4
 cologne, 0
 colonialwilliamsburg.museum, 0
 coloradoplateau.museum, 0
@@ -1346,8 +1358,8 @@
 company, 0
 compare, 0
 compute-1.amazonaws.com, 4
-compute.amazonaws.cn, 4
 compute.amazonaws.com, 4
+compute.amazonaws.com.cn, 4
 compute.estate, 6
 computer, 0
 computer.museum, 0
@@ -1385,6 +1397,7 @@
 corvette.museum, 0
 cosenza.it, 0
 costume.museum, 0
+couchpotatofries.org, 4
 council.aero, 0
 country, 0
 countryestate.museum, 0
@@ -1413,6 +1426,7 @@
 crs, 0
 cruise, 0
 cruises, 0
+cryptonomic.net, 6
 cs.it, 0
 csc, 0
 ct.it, 0
@@ -1455,6 +1469,7 @@
 daiwa.hiroshima.jp, 0
 dali.museum, 0
 dallas.museum, 0
+damnserver.com, 4
 dance, 0
 daplie.me, 4
 database.museum, 0
@@ -1469,6 +1484,9 @@
 dazaifu.fukuoka.jp, 0
 dc.us, 0
 dclk, 0
+ddns.me, 4
+ddns.net, 4
+ddnsking.com, 4
 ddr.museum, 0
 dds, 0
 de, 0
@@ -1518,6 +1536,7 @@
 discovery.museum, 0
 dish, 0
 diskstation.me, 4
+ditchyourip.com, 4
 divtasvuodna.no, 0
 divttasvuotna.no, 0
 diy, 0
@@ -1537,7 +1556,9 @@
 dnsdojo.com, 4
 dnsdojo.net, 4
 dnsdojo.org, 4
+dnsfor.me, 4
 dnshome.de, 4
+dnsiskinky.com, 4
 do, 0
 docs, 0
 dodge, 0
@@ -1587,8 +1608,10 @@
 durban, 0
 durham.museum, 0
 dvag, 0
+dvrcam.info, 4
 dvrdns.org, 4
 dwg, 0
+dy.fi, 4
 dyn-o-saur.com, 4
 dynalias.com, 4
 dynalias.net, 4
@@ -1613,6 +1636,7 @@
 dyndns.org, 4
 dyndns.tv, 4
 dyndns.ws, 4
+dynns.com, 4
 dynv6.net, 4
 dyroy.no, 0
 dz, 0
@@ -1621,10 +1645,12 @@
 e.se, 0
 e12.ve, 0
 e164.arpa, 0
+e4.cz, 4
 earth, 0
 eastafrica.museum, 0
 eastcoast.museum, 0
 eat, 0
+eating-organic.net, 4
 ebetsu.hokkaido.jp, 0
 ebina.kanagawa.jp, 0
 ebino.miyazaki.jp, 0
@@ -1856,10 +1882,13 @@
 etne.no, 0
 etnedal.no, 0
 eu, 0
+eu-1.evennode.com, 4
+eu-2.evennode.com, 4
 eu-central-1.compute.amazonaws.com, 4
 eu-west-1.compute.amazonaws.com, 4
 eu.com, 4
 eu.int, 0
+eu.meteorapp.com, 4
 eu.org, 4
 eun.eg, 0
 eurovision, 0
@@ -1894,6 +1923,7 @@
 familyds.org, 4
 fan, 0
 fans, 0
+fantasyleague.cc, 4
 far.br, 0
 fareast.ru, 0
 farm, 0
@@ -1906,6 +1936,8 @@
 fashion, 0
 fast, 0
 fauske.no, 0
+fbx-os.fr, 4
+fbxos.fr, 4
 fc.it, 0
 fe.it, 0
 fed.us, 0
@@ -1921,6 +1953,7 @@
 fetsund.no, 0
 fg.it, 0
 fh.se, 0
+fhapp.xyz, 4
 fhs.no, 0
 fhsk.se, 0
 fhv.se, 0
@@ -2036,6 +2069,10 @@
 franziskaner.museum, 0
 fredrikstad.no, 0
 free, 0
+freebox-os.com, 4
+freebox-os.fr, 4
+freeboxos.com, 4
+freeboxos.fr, 4
 freemasonry.museum, 0
 frei.no, 0
 freiburg.museum, 0
@@ -2229,6 +2266,7 @@
 ge.it, 0
 gea, 0
 geek.nz, 0
+geekgalaxy.com, 4
 geelvinck.museum, 0
 geisei.kochi.jp, 0
 gemological.museum, 0
@@ -2335,6 +2373,7 @@
 gold, 0
 goldpoint, 0
 golf, 0
+golffan.us, 4
 gon.pk, 0
 gonohe.aomori.jp, 0
 goo, 0
@@ -2354,6 +2393,7 @@
 gosen.niigata.jp, 0
 goshiki.hyogo.jp, 0
 got, 0
+gotdns.ch, 4
 gotdns.com, 4
 gotdns.org, 4
 gotemba.shizuoka.jp, 0
@@ -2641,6 +2681,7 @@
 hashima.gifu.jp, 0
 hashimoto.wakayama.jp, 0
 hasuda.saitama.jp, 0
+hasura-app.io, 4
 hasvik.no, 0
 hatogaya.saitama.jp, 0
 hatoyama.saitama.jp, 0
@@ -2658,6 +2699,7 @@
 hdfcbank, 0
 he.cn, 0
 health, 0
+health-carereform.com, 4
 health.museum, 0
 health.nz, 0
 health.vn, 0
@@ -2673,6 +2715,7 @@
 hemne.no, 0
 hemnes.no, 0
 hemsedal.no, 0
+hepforge.org, 4
 herad.no, 0
 here, 0
 here-for-more.info, 4
@@ -2809,6 +2852,8 @@
 homelinux.net, 4
 homelinux.org, 4
 homes, 0
+homesecuritymac.com, 4
+homesecuritypc.com, 4
 homesense, 0
 homeunix.com, 4
 homeunix.net, 4
@@ -2822,6 +2867,8 @@
 honjo.akita.jp, 0
 honjo.saitama.jp, 0
 honjyo.akita.jp, 0
+hopto.me, 4
+hopto.org, 4
 hornindal.no, 0
 horokanai.hokkaido.jp, 0
 horology.museum, 0
@@ -2937,6 +2984,7 @@
 il.us, 0
 ilawa.pl, 0
 illustration.museum, 0
+ilovecollege.info, 4
 im, 0
 im.it, 0
 imabari.ehime.jp, 0
@@ -3523,7 +3571,6 @@
 kerryhotels, 0
 kerrylogistics, 0
 kerryproperties, 0
-kesennuma.miyagi.jp, 0
 ketrzyn.pl, 0
 kfh, 0
 kg, 0
@@ -3657,7 +3704,6 @@
 kopervik.no, 0
 koriyama.fukushima.jp, 0
 koryo.nara.jp, 0
-kosa.kumamoto.jp, 0
 kosai.shizuoka.jp, 0
 kosaka.akita.jp, 0
 kosei.shiga.jp, 0
@@ -3971,7 +4017,10 @@
 lodi.it, 0
 lodingen.no, 0
 loft, 0
+loginto.me, 4
 logistics.aero, 0
+logoip.com, 4
+logoip.de, 4
 lol, 0
 lom.it, 0
 lom.no, 0
@@ -4046,6 +4095,7 @@
 maebashi.gunma.jp, 0
 magadan.ru, 0
 magazine.aero, 0
+magentosite.cloud, 6
 maibara.shiga.jp, 0
 maif, 0
 mail.pl, 0
@@ -4186,6 +4236,7 @@
 merseine.nu, 4
 mesaverde.museum, 0
 messina.it, 0
+meteorapp.com, 4
 metlife, 0
 mex.com, 4
 mg, 0
@@ -4375,9 +4426,11 @@
 mk.ua, 0
 ml, 0
 mlb, 0
+mlbfan.org, 4
 mls, 0
 mm, 2
 mma, 0
+mmafan.biz, 4
 mn, 0
 mn.it, 0
 mn.us, 0
@@ -4523,15 +4576,28 @@
 my, 0
 my.eu.org, 4
 my.id, 0
+myactivedirectory.com, 4
+mycd.eu, 4
+mydissent.net, 4
 mydrobo.com, 4
 myds.me, 4
+myeffect.net, 4
 myfritz.net, 4
+myftp.biz, 4
+myftp.org, 4
 mykolaiv.ua, 0
+mymediapc.net, 4
 myoko.niigata.jp, 0
 mypep.link, 4
 mypets.ws, 4
 myphotos.cc, 4
+mypsx.net, 4
+mysecuritycamera.com, 4
+mysecuritycamera.net, 4
+mysecuritycamera.org, 4
+myshopblocks.com, 4
 mytis.ru, 0
+myvnc.com, 4
 mz, 2
 mzansimagic, 0
 n.bg, 0
@@ -4698,6 +4764,7 @@
 nesseby.no, 0
 nesset.no, 0
 net, 0
+net-freaks.com, 4
 net.ac, 0
 net.ae, 0
 net.af, 0
@@ -4845,6 +4912,7 @@
 nf, 0
 nf.ca, 0
 nfl, 0
+nflfan.org, 4
 nfshost.com, 4
 ng, 0
 ng.eu.org, 4
@@ -4855,6 +4923,7 @@
 ngrok.io, 4
 nh.us, 0
 nhk, 0
+nhlfan.net, 4
 nhs.uk, 0
 ni, 0
 nic.in, 0
@@ -4919,6 +4988,12 @@
 nm.us, 0
 nnov.ru, 0
 no, 0
+no-ip.biz, 4
+no-ip.ca, 4
+no-ip.co.uk, 4
+no-ip.info, 4
+no-ip.net, 4
+no-ip.org, 4
 no.com, 4
 no.eu.org, 4
 no.it, 0
@@ -4929,6 +5004,8 @@
 nogata.fukuoka.jp, 0
 nogi.tochigi.jp, 0
 noheji.aomori.jp, 0
+noip.me, 4
+noip.us, 4
 nokia, 0
 nom.ad, 0
 nom.ag, 0
@@ -5155,6 +5232,7 @@
 onojo.fukuoka.jp, 0
 onomichi.hiroshima.jp, 0
 ontario.museum, 0
+onthewifi.com, 4
 onyourside, 0
 ookuwa.nagano.jp, 0
 ooo, 0
@@ -5477,6 +5555,8 @@
 pfizer, 0
 pg, 2
 pg.it, 0
+pgafan.net, 4
+pgfog.com, 4
 ph, 0
 pharmacien.fr, 0
 pharmaciens.km, 0
@@ -5504,6 +5584,7 @@
 pila.pl, 0
 pilot.aero, 0
 pilots.museum, 0
+pimienta.org, 4
 pin, 0
 pinb.gov.pl, 0
 ping, 0
@@ -5545,6 +5626,9 @@
 podzone.net, 4
 podzone.org, 4
 pohl, 0
+point2this.com, 4
+pointto.us, 4
+poivron.org, 4
 poker, 0
 pokrovsk.su, 0
 pol.dz, 0
@@ -5567,6 +5651,7 @@
 portlligat.museum, 0
 post, 0
 posts-and-telecommunications.museum, 0
+potager.org, 4
 potenza.it, 0
 powiat.pl, 0
 poznan.pl, 4
@@ -5604,6 +5689,7 @@
 priv.me, 0
 priv.no, 0
 priv.pl, 0
+privatizehealthinsurance.net, 4
 pro, 0
 pro.az, 0
 pro.br, 0
@@ -5674,6 +5760,7 @@
 quebec, 0
 quebec.museum, 0
 quest, 0
+quicksytes.com, 4
 qvc, 0
 r.bg, 0
 r.cdn77.net, 4
@@ -5707,9 +5794,11 @@
 re.it, 0
 re.kr, 0
 read, 0
+read-books.org, 4
 readmyblog.org, 4
 realestate, 0
 realestate.pl, 0
+realm.cz, 4
 realtor, 0
 realty, 0
 rebun.hokkaido.jp, 0
@@ -5723,6 +5812,7 @@
 recreation.aero, 0
 red, 0
 red.sv, 0
+redirectme.net, 4
 redstone, 0
 redumbrella, 0
 reg.dk, 4
@@ -5824,7 +5914,6 @@
 royken.no, 0
 royrvik.no, 0
 rs, 0
-rs.ba, 0
 rsc.cdn77.org, 4
 rsvp, 0
 ru, 0
@@ -6056,6 +6145,7 @@
 sec.ps, 0
 secure, 0
 security, 0
+securitytactics.com, 4
 seek, 0
 seihi.nagasaki.jp, 0
 seika.kyoto.jp, 0
@@ -6091,9 +6181,25 @@
 servebbs.com, 4
 servebbs.net, 4
 servebbs.org, 4
+servebeer.com, 4
+serveblog.net, 4
+servecounterstrike.com, 4
+serveexchange.com, 4
+serveftp.com, 4
 serveftp.net, 4
 serveftp.org, 4
+servegame.com, 4
 servegame.org, 4
+servehalflife.com, 4
+servehttp.com, 4
+servehumour.com, 4
+serveirc.com, 4
+serveminecraft.net, 4
+servemp3.com, 4
+servep2p.com, 4
+servepics.com, 4
+servequake.com, 4
+servesarcasm.com, 4
 service.gov.uk, 4
 services, 0
 services.aero, 0
@@ -6353,6 +6459,7 @@
 space, 0
 space-to-rent.com, 4
 space.museum, 0
+spacekit.io, 4
 spb.ru, 0
 spb.su, 0
 spiegel, 0
@@ -6430,6 +6537,7 @@
 study, 0
 stuff-4-sale.org, 4
 stuff-4-sale.us, 4
+stufftoread.com, 4
 stuttgart.museum, 0
 stv.ru, 0
 style, 0
@@ -6481,6 +6589,7 @@
 svizzera.museum, 0
 swatch, 0
 sweden.museum, 0
+sweetpepper.org, 4
 swidnica.pl, 0
 swiebodzin.pl, 0
 swiftcover, 0
@@ -6495,6 +6604,7 @@
 symantec, 0
 synology.me, 4
 systems, 0
+sytes.net, 4
 syzran.ru, 0
 sz, 0
 szczecin.pl, 0
@@ -6906,6 +7016,7 @@
 tula.ru, 0
 tula.su, 0
 tunes, 0
+tunk.org, 4
 tur.ar, 0
 tur.br, 0
 turek.pl, 0
@@ -6916,6 +7027,7 @@
 tushu, 0
 tuva.ru, 0
 tuva.su, 0
+tuxfamily.org, 4
 tv, 0
 tv.bb, 0
 tv.bo, 0
@@ -6960,6 +7072,7 @@
 ueda.nagano.jp, 0
 ueno.gunma.jp, 0
 uenohara.yamanashi.jp, 0
+ufcfan.org, 4
 ug, 0
 ug.gov.pl, 0
 ugim.gov.pl, 0
@@ -6986,7 +7099,6 @@
 umi.fukuoka.jp, 0
 umig.gov.pl, 0
 unazuki.toyama.jp, 0
-unbi.ba, 0
 undersea.museum, 0
 unicom, 0
 union.aero, 0
@@ -6996,7 +7108,7 @@
 unjarga.no, 0
 unnan.shimane.jp, 0
 uno, 0
-unsa.ba, 0
+unusualperson.com, 4
 unzen.nagasaki.jp, 0
 uol, 0
 uonuma.niigata.jp, 0
@@ -7017,6 +7129,8 @@
 uruma.okinawa.jp, 0
 uryu.hokkaido.jp, 0
 us, 0
+us-1.evennode.com, 4
+us-2.evennode.com, 4
 us-east-1.amazonaws.com, 4
 us-gov-west-1.compute.amazonaws.com, 4
 us-west-1.compute.amazonaws.com, 4
@@ -7162,6 +7276,7 @@
 virgin, 0
 virginia.museum, 0
 virtual.museum, 0
+virtueeldomein.nl, 4
 virtuel.museum, 0
 visa, 0
 vision, 0
@@ -7263,6 +7378,7 @@
 weber, 0
 webhop.biz, 4
 webhop.info, 4
+webhop.me, 4
 webhop.net, 4
 webhop.org, 4
 website, 0
@@ -7306,6 +7422,7 @@
 woodside, 0
 work, 0
 workinggroup.aero, 0
+workisboring.com, 4
 works, 0
 works.aero, 0
 workshop.museum, 0
@@ -7889,6 +8006,7 @@
 zaporizhzhe.ua, 0
 zaporizhzhia.ua, 0
 zappos, 0
+zapto.org, 4
 zara, 0
 zarow.pl, 0
 zentsuji.kagawa.jp, 0
diff --git a/net/cert/internal/cert_issuer_source.h b/net/cert/internal/cert_issuer_source.h
index 61580a8..1ffc3b3a 100644
--- a/net/cert/internal/cert_issuer_source.h
+++ b/net/cert/internal/cert_issuer_source.h
@@ -11,11 +11,10 @@
 #include "base/callback.h"
 #include "net/base/net_export.h"
 #include "net/cert/internal/completion_status.h"
+#include "net/cert/internal/parsed_certificate.h"
 
 namespace net {
 
-class ParsedCertificate;
-
 // Interface for looking up issuers of a certificate during path building.
 // Provides a synchronous and asynchronous method for retrieving issuers, so the
 // path builder can try to complete synchronously first. The caller is expected
@@ -58,9 +57,8 @@
   // Matches are appended to |issuers|. Any existing contents of |issuers| will
   // not be modified. If the implementation does not support synchronous
   // lookups, or if there are no matches, |issuers| is not modified.
-  virtual void SyncGetIssuersOf(
-      const ParsedCertificate* cert,
-      std::vector<scoped_refptr<ParsedCertificate>>* issuers) = 0;
+  virtual void SyncGetIssuersOf(const ParsedCertificate* cert,
+                                ParsedCertificateList* issuers) = 0;
 
   // Finds certificates whose Subject matches |cert|'s Issuer.
   // If an async callback will be made |*out_req| is filled with a Request
diff --git a/net/cert/internal/cert_issuer_source_aia.cc b/net/cert/internal/cert_issuer_source_aia.cc
index 4dacc340..5ee96a0 100644
--- a/net/cert/internal/cert_issuer_source_aia.cc
+++ b/net/cert/internal/cert_issuer_source_aia.cc
@@ -6,7 +6,6 @@
 
 #include "base/bind.h"
 #include "net/cert/cert_net_fetcher.h"
-#include "net/cert/internal/parsed_certificate.h"
 #include "url/gurl.h"
 
 namespace net {
@@ -37,7 +36,7 @@
   CertIssuerSource::IssuerCallback issuers_callback_;
   std::vector<std::unique_ptr<CertNetFetcher::Request>> cert_fetcher_requests_;
   size_t pending_requests_ = 0;
-  std::vector<scoped_refptr<ParsedCertificate>> results_;
+  ParsedCertificateList results_;
   size_t current_result_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(AiaRequest);
@@ -109,9 +108,8 @@
 
 CertIssuerSourceAia::~CertIssuerSourceAia() = default;
 
-void CertIssuerSourceAia::SyncGetIssuersOf(
-    const ParsedCertificate* cert,
-    std::vector<scoped_refptr<ParsedCertificate>>* issuers) {
+void CertIssuerSourceAia::SyncGetIssuersOf(const ParsedCertificate* cert,
+                                           ParsedCertificateList* issuers) {
   // CertIssuerSourceAia never returns synchronous results.
 }
 
diff --git a/net/cert/internal/cert_issuer_source_aia.h b/net/cert/internal/cert_issuer_source_aia.h
index e0c7fe7..afeeda5 100644
--- a/net/cert/internal/cert_issuer_source_aia.h
+++ b/net/cert/internal/cert_issuer_source_aia.h
@@ -22,9 +22,8 @@
   ~CertIssuerSourceAia() override;
 
   // CertIssuerSource implementation:
-  void SyncGetIssuersOf(
-      const ParsedCertificate* cert,
-      std::vector<scoped_refptr<ParsedCertificate>>* issuers) override;
+  void SyncGetIssuersOf(const ParsedCertificate* cert,
+                        ParsedCertificateList* issuers) override;
   void AsyncGetIssuersOf(const ParsedCertificate* cert,
                          const IssuerCallback& issuers_callback,
                          std::unique_ptr<Request>* out_req) override;
diff --git a/net/cert/internal/cert_issuer_source_aia_unittest.cc b/net/cert/internal/cert_issuer_source_aia_unittest.cc
index 455cf66..2132080 100644
--- a/net/cert/internal/cert_issuer_source_aia_unittest.cc
+++ b/net/cert/internal/cert_issuer_source_aia_unittest.cc
@@ -166,7 +166,7 @@
 
   StrictMock<MockCertNetFetcherImpl> mock_fetcher;
   CertIssuerSourceAia aia_source(&mock_fetcher);
-  std::vector<scoped_refptr<ParsedCertificate>> issuers;
+  ParsedCertificateList issuers;
   aia_source.SyncGetIssuersOf(cert.get(), &issuers);
   EXPECT_EQ(0U, issuers.size());
 }
diff --git a/net/cert/internal/cert_issuer_source_static.cc b/net/cert/internal/cert_issuer_source_static.cc
index c7685f436..d8a42a3 100644
--- a/net/cert/internal/cert_issuer_source_static.cc
+++ b/net/cert/internal/cert_issuer_source_static.cc
@@ -4,8 +4,6 @@
 
 #include "net/cert/internal/cert_issuer_source_static.h"
 
-#include "net/cert/internal/parsed_certificate.h"
-
 namespace net {
 
 CertIssuerSourceStatic::CertIssuerSourceStatic() = default;
@@ -16,9 +14,8 @@
       cert->normalized_subject().AsStringPiece(), std::move(cert)));
 }
 
-void CertIssuerSourceStatic::SyncGetIssuersOf(
-    const ParsedCertificate* cert,
-    std::vector<scoped_refptr<ParsedCertificate>>* issuers) {
+void CertIssuerSourceStatic::SyncGetIssuersOf(const ParsedCertificate* cert,
+                                              ParsedCertificateList* issuers) {
   auto range =
       intermediates_.equal_range(cert->normalized_issuer().AsStringPiece());
   for (auto it = range.first; it != range.second; ++it)
diff --git a/net/cert/internal/cert_issuer_source_static.h b/net/cert/internal/cert_issuer_source_static.h
index af67268c2..f7151e80 100644
--- a/net/cert/internal/cert_issuer_source_static.h
+++ b/net/cert/internal/cert_issuer_source_static.h
@@ -23,9 +23,8 @@
   void AddCert(scoped_refptr<ParsedCertificate> cert);
 
   // CertIssuerSource implementation:
-  void SyncGetIssuersOf(
-      const ParsedCertificate* cert,
-      std::vector<scoped_refptr<ParsedCertificate>>* issuers) override;
+  void SyncGetIssuersOf(const ParsedCertificate* cert,
+                        ParsedCertificateList* issuers) override;
   void AsyncGetIssuersOf(const ParsedCertificate* cert,
                          const IssuerCallback& issuers_callback,
                          std::unique_ptr<Request>* out_req) override;
diff --git a/net/cert/internal/cert_issuer_source_static_unittest.cc b/net/cert/internal/cert_issuer_source_static_unittest.cc
index 148f362..d59744c 100644
--- a/net/cert/internal/cert_issuer_source_static_unittest.cc
+++ b/net/cert/internal/cert_issuer_source_static_unittest.cc
@@ -78,7 +78,7 @@
   CertIssuerSourceStatic source;
   source.AddCert(root_);
 
-  std::vector<scoped_refptr<ParsedCertificate>> issuers;
+  ParsedCertificateList issuers;
   source.SyncGetIssuersOf(c1_.get(), &issuers);
   ASSERT_EQ(0U, issuers.size());
 }
@@ -87,7 +87,7 @@
   CertIssuerSourceStatic source;
   AddAllCerts(&source);
 
-  std::vector<scoped_refptr<ParsedCertificate>> issuers;
+  ParsedCertificateList issuers;
   source.SyncGetIssuersOf(i1_1_.get(), &issuers);
   ASSERT_EQ(1U, issuers.size());
   EXPECT_TRUE(issuers[0] == root_);
@@ -102,7 +102,7 @@
   CertIssuerSourceStatic source;
   AddAllCerts(&source);
 
-  std::vector<scoped_refptr<ParsedCertificate>> issuers;
+  ParsedCertificateList issuers;
   source.SyncGetIssuersOf(c1_.get(), &issuers);
 
   ASSERT_EQ(2U, issuers.size());
@@ -120,7 +120,7 @@
   CertIssuerSourceStatic source;
   AddAllCerts(&source);
 
-  std::vector<scoped_refptr<ParsedCertificate>> issuers;
+  ParsedCertificateList issuers;
   source.SyncGetIssuersOf(root_.get(), &issuers);
 
   ASSERT_EQ(1U, issuers.size());
diff --git a/net/cert/internal/parsed_certificate.cc b/net/cert/internal/parsed_certificate.cc
index e8e08c4e..a3e5cc3 100644
--- a/net/cert/internal/parsed_certificate.cc
+++ b/net/cert/internal/parsed_certificate.cc
@@ -162,7 +162,7 @@
     size_t length,
     DataSource source,
     const ParseCertificateOptions& options,
-    std::vector<scoped_refptr<ParsedCertificate>>* chain) {
+    ParsedCertificateList* chain) {
   scoped_refptr<ParsedCertificate> cert(
       CreateFromCertificateData(data, length, source, options));
   if (!cert)
diff --git a/net/cert/internal/parsed_certificate.h b/net/cert/internal/parsed_certificate.h
index 8237752..a4c6c3b 100644
--- a/net/cert/internal/parsed_certificate.h
+++ b/net/cert/internal/parsed_certificate.h
@@ -18,8 +18,11 @@
 
 struct GeneralNames;
 class NameConstraints;
+class ParsedCertificate;
 class SignatureAlgorithm;
 
+using ParsedCertificateList = std::vector<scoped_refptr<ParsedCertificate>>;
+
 // Represents an X.509 certificate, including Certificate, TBSCertificate, and
 // standard extensions.
 // Creating a ParsedCertificate does not completely parse and validate the
diff --git a/net/cert/internal/path_builder.cc b/net/cert/internal/path_builder.cc
new file mode 100644
index 0000000..863d850
--- /dev/null
+++ b/net/cert/internal/path_builder.cc
@@ -0,0 +1,628 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/path_builder.h"
+
+#include <set>
+#include <unordered_set>
+
+#include "base/callback_helpers.h"
+#include "base/memory/ptr_util.h"
+#include "net/base/net_errors.h"
+#include "net/cert/internal/cert_issuer_source.h"
+#include "net/cert/internal/parse_certificate.h"
+#include "net/cert/internal/parse_name.h"  // For CertDebugString.
+#include "net/cert/internal/signature_policy.h"
+#include "net/cert/internal/trust_store.h"
+#include "net/cert/internal/verify_certificate_chain.h"
+#include "net/cert/internal/verify_name_match.h"
+#include "net/der/parser.h"
+#include "net/der/tag.h"
+
+namespace net {
+
+namespace {
+
+using CertIssuerSources = std::vector<CertIssuerSource*>;
+
+// TODO(mattm): decide how much debug logging to keep.
+std::string CertDebugString(const ParsedCertificate* cert) {
+  RDNSequence subject, issuer;
+  std::string subject_str, issuer_str;
+  if (!ParseName(cert->tbs().subject_tlv, &subject) ||
+      !ConvertToRFC2253(subject, &subject_str))
+    subject_str = "???";
+  if (!ParseName(cert->tbs().issuer_tlv, &issuer) ||
+      !ConvertToRFC2253(issuer, &issuer_str))
+    issuer_str = "???";
+
+  return subject_str + "(" + issuer_str + ")";
+}
+
+// CertIssuersIter iterates through the intermediates from |cert_issuer_sources|
+// which may be issuers of |cert|.
+class CertIssuersIter {
+ public:
+  // Constructs the CertIssuersIter. |*cert_issuer_sources| must be valid for
+  // the lifetime of the CertIssuersIter.
+  CertIssuersIter(scoped_refptr<ParsedCertificate> cert,
+                  CertIssuerSources* cert_issuer_sources,
+                  const TrustStore& trust_store);
+
+  // Gets the next candidate issuer. If an issuer is ready synchronously, SYNC
+  // is returned and the cert is stored in |*out_cert|.  If an issuer is not
+  // ready, ASYNC is returned and |callback| will be called once |*out_cert| has
+  // been set. If |callback| is null, always completes synchronously.
+  //
+  // In either case, if all issuers have been exhausted, |*out_cert| is cleared.
+  CompletionStatus GetNextIssuer(scoped_refptr<ParsedCertificate>* out_cert,
+                                 const base::Closure& callback);
+
+  // Returns the |cert| for which issuers are being retrieved.
+  const ParsedCertificate* cert() const { return cert_.get(); }
+  scoped_refptr<ParsedCertificate> reference_cert() const { return cert_; }
+
+ private:
+  void GotAsyncCerts(CertIssuerSource::Request* request);
+
+  scoped_refptr<ParsedCertificate> cert_;
+  CertIssuerSources* cert_issuer_sources_;
+
+  // The list of issuers for |cert_|. This is added to incrementally (first
+  // synchronous results, then possibly multiple times as asynchronous results
+  // arrive.) The issuers may be re-sorted each time new issuers are added, but
+  // only the results from |cur_| onwards should be sorted, since the earlier
+  // results were already returned.
+  // Elements should not be removed from |issuers_| once added, since
+  // |present_issuers_| will point to data owned by the certs.
+  ParsedCertificateList issuers_;
+  // The index of the next cert in |issuers_| to return.
+  size_t cur_ = 0;
+  // Set of DER-encoded values for the certs in |issuers_|. Used to prevent
+  // duplicates. This is based on the full DER of the cert to allow different
+  // versions of the same certificate to be tried in different candidate paths.
+  // This points to data owned by |issuers_|.
+  std::unordered_set<base::StringPiece, base::StringPieceHash> present_issuers_;
+
+  // Tracks whether asynchronous requests have been made yet.
+  bool did_async_query_ = false;
+  // If asynchronous requests were made, how many of them are still outstanding?
+  size_t pending_async_results_;
+  // Owns the Request objects for any asynchronous requests so that they will be
+  // cancelled if CertIssuersIter is destroyed.
+  std::vector<std::unique_ptr<CertIssuerSource::Request>>
+      pending_async_requests_;
+
+  // When GetNextIssuer was called and returned asynchronously, |*out_cert_| is
+  // where the result will be stored, and |callback_| will be run when the
+  // result is ready.
+  scoped_refptr<ParsedCertificate>* out_cert_;
+  base::Closure callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(CertIssuersIter);
+};
+
+CertIssuersIter::CertIssuersIter(scoped_refptr<ParsedCertificate> in_cert,
+                                 CertIssuerSources* cert_issuer_sources,
+                                 const TrustStore& trust_store)
+    : cert_(in_cert), cert_issuer_sources_(cert_issuer_sources) {
+  DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created";
+  trust_store.FindTrustAnchorsByNormalizedName(in_cert->normalized_issuer(),
+                                               &issuers_);
+  // Insert matching roots into |present_issuers_| in case they also are
+  // returned by a CertIssuerSource. It is assumed
+  // FindTrustAnchorsByNormalizedName does not itself return dupes.
+  for (const auto& root : issuers_)
+    present_issuers_.insert(root->der_cert().AsStringPiece());
+
+  for (auto* cert_issuer_source : *cert_issuer_sources_) {
+    ParsedCertificateList new_issuers;
+    cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers);
+    for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) {
+      if (present_issuers_.find(issuer->der_cert().AsStringPiece()) !=
+          present_issuers_.end())
+        continue;
+      present_issuers_.insert(issuer->der_cert().AsStringPiece());
+      issuers_.push_back(std::move(issuer));
+    }
+  }
+  // TODO(mattm): sort by notbefore, etc (eg if cert issuer matches a trust
+  // anchor subject (or is a trust anchor), that should be sorted higher too.
+  // See big list of possible sorting hints in RFC 4158.)
+  // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that
+  // is done)
+}
+
+CompletionStatus CertIssuersIter::GetNextIssuer(
+    scoped_refptr<ParsedCertificate>* out_cert,
+    const base::Closure& callback) {
+  // Should not be called again while already waiting for an async result.
+  DCHECK(callback_.is_null());
+
+  if (cur_ < issuers_.size()) {
+    DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+             << "): returning item " << cur_ << " of " << issuers_.size();
+    // Still have issuers that haven't been returned yet, return one of them.
+    // A reference to the returned issuer is retained, since |present_issuers_|
+    // points to data owned by it.
+    *out_cert = issuers_[cur_++];
+    return CompletionStatus::SYNC;
+  }
+  if (did_async_query_) {
+    if (pending_async_results_ == 0) {
+      DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+               << ") Reached the end of all available issuers.";
+      // Reached the end of all available issuers.
+      *out_cert = nullptr;
+      return CompletionStatus::SYNC;
+    }
+
+    DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+             << ") Still waiting for async results from other "
+                "CertIssuerSources.";
+    // Still waiting for async results from other CertIssuerSources.
+    out_cert_ = out_cert;
+    callback_ = callback;
+    return CompletionStatus::ASYNC;
+  }
+  // Reached the end of synchronously gathered issuers.
+
+  if (callback.is_null()) {
+    // Synchronous-only mode, don't try to query async sources.
+    *out_cert = nullptr;
+    return CompletionStatus::SYNC;
+  }
+
+  // Now issue request(s) for async ones (AIA, etc).
+  did_async_query_ = true;
+  pending_async_results_ = 0;
+  for (auto* cert_issuer_source : *cert_issuer_sources_) {
+    std::unique_ptr<CertIssuerSource::Request> request;
+    cert_issuer_source->AsyncGetIssuersOf(
+        cert(),
+        base::Bind(&CertIssuersIter::GotAsyncCerts, base::Unretained(this)),
+        &request);
+    if (request) {
+      DVLOG(1) << "AsyncGetIssuersOf(" << CertDebugString(cert())
+               << ") pending...";
+      pending_async_results_++;
+      pending_async_requests_.push_back(std::move(request));
+    }
+  }
+
+  if (pending_async_results_ == 0) {
+    DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+             << ") No cert sources have async results.";
+    // No cert sources have async results.
+    *out_cert = nullptr;
+    return CompletionStatus::SYNC;
+  }
+
+  DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+           << ") issued AsyncGetIssuersOf call(s) (n=" << pending_async_results_
+           << ")";
+  out_cert_ = out_cert;
+  callback_ = callback;
+  return CompletionStatus::ASYNC;
+}
+
+void CertIssuersIter::GotAsyncCerts(CertIssuerSource::Request* request) {
+  DVLOG(1) << "CertIssuersIter::GotAsyncCerts(" << CertDebugString(cert())
+           << ")";
+  while (true) {
+    scoped_refptr<ParsedCertificate> cert;
+    CompletionStatus status = request->GetNext(&cert);
+    if (!cert) {
+      if (status == CompletionStatus::SYNC) {
+        // Request is exhausted, no more results pending from that
+        // CertIssuerSource.
+        DCHECK_GT(pending_async_results_, 0U);
+        pending_async_results_--;
+      }
+      break;
+    }
+    DCHECK_EQ(status, CompletionStatus::SYNC);
+    if (present_issuers_.find(cert->der_cert().AsStringPiece()) !=
+        present_issuers_.end())
+      continue;
+    present_issuers_.insert(cert->der_cert().AsStringPiece());
+    issuers_.push_back(std::move(cert));
+  }
+
+  // TODO(mattm): re-sort remaining elements of issuers_ (remaining elements may
+  // be more than the ones just inserted, depending on |cur_| value).
+
+  // Notify that more results are available, if necessary.
+  if (!callback_.is_null()) {
+    if (cur_ < issuers_.size()) {
+      DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+               << "): async returning item " << cur_ << " of "
+               << issuers_.size();
+      *out_cert_ = std::move(issuers_[cur_++]);
+      base::ResetAndReturn(&callback_).Run();
+    } else if (pending_async_results_ == 0) {
+      DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+               << "): async returning empty result";
+      *out_cert_ = nullptr;
+      base::ResetAndReturn(&callback_).Run();
+    } else {
+      DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
+               << "): empty result, but other async results "
+                  "pending, waiting..";
+    }
+  }
+}
+
+// CertIssuerIterPath tracks which certs are present in the path and prevents
+// paths from being built which repeat any certs (including different versions
+// of the same cert, based on Subject+SubjectAltName+SPKI).
+class CertIssuerIterPath {
+ public:
+  // Returns true if |cert| is already present in the path.
+  bool IsPresent(const ParsedCertificate* cert) const {
+    return present_certs_.find(GetKey(cert)) != present_certs_.end();
+  }
+
+  // Appends |cert_issuers_iter| to the path. The cert referred to by
+  // |cert_issuers_iter| must not be present in the path already.
+  void Append(std::unique_ptr<CertIssuersIter> cert_issuers_iter) {
+    bool added =
+        present_certs_.insert(GetKey(cert_issuers_iter->cert())).second;
+    DCHECK(added);
+    cur_path_.push_back(std::move(cert_issuers_iter));
+  }
+
+  // Pops the last CertIssuersIter off the path.
+  void Pop() {
+    size_t num_erased = present_certs_.erase(GetKey(cur_path_.back()->cert()));
+    DCHECK_EQ(num_erased, 1U);
+    cur_path_.pop_back();
+  }
+
+  // Copies the ParsedCertificate elements of the current path to |*out_path|.
+  void CopyPath(ParsedCertificateList* out_path) {
+    out_path->clear();
+    for (const auto& node : cur_path_)
+      out_path->push_back(node->reference_cert());
+  }
+
+  // Returns true if the path is empty.
+  bool Empty() const { return cur_path_.empty(); }
+
+  // Returns the last CertIssuersIter in the path.
+  CertIssuersIter* back() { return cur_path_.back().get(); }
+
+  std::string PathDebugString() {
+    std::string s;
+    for (const auto& node : cur_path_) {
+      if (!s.empty())
+        s += " <- ";
+      s += CertDebugString(node->cert());
+    }
+    return s;
+  }
+
+ private:
+  using Key =
+      std::tuple<base::StringPiece, base::StringPiece, base::StringPiece>;
+
+  static Key GetKey(const ParsedCertificate* cert) {
+    // TODO(mattm): ideally this would use a normalized version of
+    // SubjectAltName, but it's not that important just for LoopChecker.
+    //
+    // Note that subject_alt_names_extension().value will be empty if the cert
+    // had no SubjectAltName extension, so there is no need for a condition on
+    // has_subject_alt_names().
+    return Key(cert->normalized_subject().AsStringPiece(),
+               cert->subject_alt_names_extension().value.AsStringPiece(),
+               cert->tbs().spki_tlv.AsStringPiece());
+  }
+
+  std::vector<std::unique_ptr<CertIssuersIter>> cur_path_;
+
+  // This refers to data owned by |cur_path_|.
+  // TODO(mattm): use unordered_set. Requires making a hash function for Key.
+  std::set<Key> present_certs_;
+};
+
+}  // namespace
+
+// CertPathIter generates possible paths from |cert| to a trust anchor in
+// |trust_store|, using intermediates from the |cert_issuer_source| objects if
+// necessary.
+class CertPathIter {
+ public:
+  CertPathIter(scoped_refptr<ParsedCertificate> cert,
+               const TrustStore* trust_store);
+
+  // Adds a CertIssuerSource to provide intermediates for use in path building.
+  // The |*cert_issuer_source| must remain valid for the lifetime of the
+  // CertPathIter.
+  void AddCertIssuerSource(CertIssuerSource* cert_issuer_source);
+
+  // Gets the next candidate path. If a path is ready synchronously, SYNC is
+  // returned and the path is stored in |*path|.  If a path is not ready,
+  // ASYNC is returned and |callback| will be called once |*path| has been set.
+  // In either case, if all paths have been exhausted, |*path| is cleared.
+  CompletionStatus GetNextPath(ParsedCertificateList* path,
+                               const base::Closure& callback);
+
+ private:
+  enum State {
+    STATE_NONE,
+    STATE_GET_NEXT_ISSUER,
+    STATE_GET_NEXT_ISSUER_COMPLETE,
+    STATE_RETURN_A_PATH,
+    STATE_BACKTRACK,
+  };
+
+  CompletionStatus DoLoop(bool allow_async);
+
+  CompletionStatus DoGetNextIssuer(bool allow_async);
+  CompletionStatus DoGetNextIssuerComplete();
+  CompletionStatus DoBackTrack();
+
+  void HandleGotNextIssuer(void);
+
+  // Stores the next candidate issuer certificate, until it is used during the
+  // STATE_GET_NEXT_ISSUER_COMPLETE step.
+  scoped_refptr<ParsedCertificate> next_cert_;
+  // The current path being explored, made up of CertIssuerIters. Each node
+  // keeps track of the state of searching for issuers of that cert, so that
+  // when backtracking it can resume the search where it left off.
+  CertIssuerIterPath cur_path_;
+  // The CertIssuerSources for retrieving candidate issuers.
+  CertIssuerSources cert_issuer_sources_;
+  // The TrustStore for checking if a path ends in a trust anchor.
+  const TrustStore* trust_store_;
+  // The output variable for storing the next candidate path, which the client
+  // passes in to GetNextPath. Only used for a single path output.
+  ParsedCertificateList* out_path_;
+  // The callback to be called if an async lookup generated a candidate path.
+  base::Closure callback_;
+  // Current state of the state machine.
+  State next_state_;
+
+  DISALLOW_COPY_AND_ASSIGN(CertPathIter);
+};
+
+CertPathIter::CertPathIter(scoped_refptr<ParsedCertificate> cert,
+                           const TrustStore* trust_store)
+    : next_cert_(std::move(cert)),
+      trust_store_(trust_store),
+      next_state_(STATE_GET_NEXT_ISSUER_COMPLETE) {}
+
+void CertPathIter::AddCertIssuerSource(CertIssuerSource* cert_issuer_source) {
+  cert_issuer_sources_.push_back(cert_issuer_source);
+}
+
+CompletionStatus CertPathIter::GetNextPath(ParsedCertificateList* path,
+                                           const base::Closure& callback) {
+  out_path_ = path;
+  out_path_->clear();
+  CompletionStatus rv = DoLoop(!callback.is_null());
+  if (rv == CompletionStatus::ASYNC) {
+    callback_ = callback;
+  } else {
+    // Clear the reference to the output parameter as a precaution.
+    out_path_ = nullptr;
+  }
+  return rv;
+}
+
+CompletionStatus CertPathIter::DoLoop(bool allow_async) {
+  CompletionStatus result = CompletionStatus::SYNC;
+  do {
+    State state = next_state_;
+    next_state_ = STATE_NONE;
+    switch (state) {
+      case STATE_NONE:
+        NOTREACHED();
+        break;
+      case STATE_GET_NEXT_ISSUER:
+        result = DoGetNextIssuer(allow_async);
+        break;
+      case STATE_GET_NEXT_ISSUER_COMPLETE:
+        result = DoGetNextIssuerComplete();
+        break;
+      case STATE_RETURN_A_PATH:
+        // If the returned path did not verify, keep looking for other paths
+        // (the trust root is not part of cur_path_, so don't need to
+        // backtrack).
+        next_state_ = STATE_GET_NEXT_ISSUER;
+        result = CompletionStatus::SYNC;
+        break;
+      case STATE_BACKTRACK:
+        result = DoBackTrack();
+        break;
+    }
+  } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE &&
+           next_state_ != STATE_RETURN_A_PATH);
+
+  return result;
+}
+
+CompletionStatus CertPathIter::DoGetNextIssuer(bool allow_async) {
+  next_state_ = STATE_GET_NEXT_ISSUER_COMPLETE;
+  CompletionStatus rv = cur_path_.back()->GetNextIssuer(
+      &next_cert_, allow_async ? base::Bind(&CertPathIter::HandleGotNextIssuer,
+                                            base::Unretained(this))
+                               : base::Closure());
+  return rv;
+}
+
+CompletionStatus CertPathIter::DoGetNextIssuerComplete() {
+  if (next_cert_) {
+    // Skip this cert if it is already in the chain.
+    if (cur_path_.IsPresent(next_cert_.get())) {
+      next_state_ = STATE_GET_NEXT_ISSUER;
+      return CompletionStatus::SYNC;
+    }
+    // If the cert matches a trust root, this is a (possibly) complete path.
+    // Signal readiness. Don't add it to cur_path_, since that would cause an
+    // unnecessary lookup of issuers of the trust root.
+    if (trust_store_->IsTrustedCertificate(next_cert_.get())) {
+      DVLOG(1) << "CertPathIter IsTrustedCertificate("
+               << CertDebugString(next_cert_.get()) << ") = true";
+      next_state_ = STATE_RETURN_A_PATH;
+      cur_path_.CopyPath(out_path_);
+      out_path_->push_back(std::move(next_cert_));
+      next_cert_ = nullptr;
+      return CompletionStatus::SYNC;
+    }
+
+    cur_path_.Append(base::WrapUnique(new CertIssuersIter(
+        std::move(next_cert_), &cert_issuer_sources_, *trust_store_)));
+    next_cert_ = nullptr;
+    DVLOG(1) << "CertPathIter cur_path_ = " << cur_path_.PathDebugString();
+    // Continue descending the tree.
+    next_state_ = STATE_GET_NEXT_ISSUER;
+  } else {
+    // TODO(mattm): should also include such paths in CertPathBuilder::Result,
+    // maybe with a flag to enable it. Or use a visitor pattern so the caller
+    // can decide what to do with any failed paths.
+    // No more issuers for current chain, go back up and see if there are any
+    // more for the previous cert.
+    next_state_ = STATE_BACKTRACK;
+  }
+  return CompletionStatus::SYNC;
+}
+
+CompletionStatus CertPathIter::DoBackTrack() {
+  DVLOG(1) << "CertPathIter backtracking...";
+  cur_path_.Pop();
+  if (cur_path_.Empty()) {
+    // Exhausted all paths.
+    next_state_ = STATE_NONE;
+  } else {
+    // Continue exploring issuers of the previous path.
+    next_state_ = STATE_GET_NEXT_ISSUER;
+  }
+  return CompletionStatus::SYNC;
+}
+
+void CertPathIter::HandleGotNextIssuer(void) {
+  DCHECK(!callback_.is_null());
+  CompletionStatus rv = DoLoop(true /* allow_async */);
+  if (rv == CompletionStatus::SYNC) {
+    // Clear the reference to the output parameter as a precaution.
+    out_path_ = nullptr;
+    base::ResetAndReturn(&callback_).Run();
+  }
+}
+
+CertPathBuilder::ResultPath::ResultPath() = default;
+CertPathBuilder::ResultPath::~ResultPath() = default;
+CertPathBuilder::Result::Result() = default;
+CertPathBuilder::Result::~Result() = default;
+
+CertPathBuilder::CertPathBuilder(scoped_refptr<ParsedCertificate> cert,
+                                 const TrustStore* trust_store,
+                                 const SignaturePolicy* signature_policy,
+                                 const der::GeneralizedTime& time,
+                                 Result* result)
+    : cert_path_iter_(new CertPathIter(std::move(cert), trust_store)),
+      trust_store_(trust_store),
+      signature_policy_(signature_policy),
+      time_(time),
+      next_state_(STATE_NONE),
+      out_result_(result) {}
+
+CertPathBuilder::~CertPathBuilder() {}
+
+void CertPathBuilder::AddCertIssuerSource(
+    CertIssuerSource* cert_issuer_source) {
+  cert_path_iter_->AddCertIssuerSource(cert_issuer_source);
+}
+
+CompletionStatus CertPathBuilder::Run(const base::Closure& callback) {
+  DCHECK_EQ(STATE_NONE, next_state_);
+  next_state_ = STATE_GET_NEXT_PATH;
+  CompletionStatus rv = DoLoop(!callback.is_null());
+
+  if (rv == CompletionStatus::ASYNC)
+    callback_ = callback;
+
+  return rv;
+}
+
+CompletionStatus CertPathBuilder::DoLoop(bool allow_async) {
+  CompletionStatus result = CompletionStatus::SYNC;
+
+  do {
+    State state = next_state_;
+    next_state_ = STATE_NONE;
+    switch (state) {
+      case STATE_NONE:
+        NOTREACHED();
+        break;
+      case STATE_GET_NEXT_PATH:
+        result = DoGetNextPath(allow_async);
+        break;
+      case STATE_GET_NEXT_PATH_COMPLETE:
+        result = DoGetNextPathComplete();
+        break;
+    }
+  } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE);
+
+  return result;
+}
+
+CompletionStatus CertPathBuilder::DoGetNextPath(bool allow_async) {
+  next_state_ = STATE_GET_NEXT_PATH_COMPLETE;
+  CompletionStatus rv = cert_path_iter_->GetNextPath(
+      &next_path_, allow_async ? base::Bind(&CertPathBuilder::HandleGotNextPath,
+                                            base::Unretained(this))
+                               : base::Closure());
+  return rv;
+}
+
+void CertPathBuilder::HandleGotNextPath() {
+  DCHECK(!callback_.is_null());
+  CompletionStatus rv = DoLoop(true /* allow_async */);
+  if (rv == CompletionStatus::SYNC)
+    base::ResetAndReturn(&callback_).Run();
+}
+
+CompletionStatus CertPathBuilder::DoGetNextPathComplete() {
+  if (next_path_.empty()) {
+    // No more paths to check, signal completion.
+    next_state_ = STATE_NONE;
+    return CompletionStatus::SYNC;
+  }
+
+  bool verify_result = VerifyCertificateChainAssumingTrustedRoot(
+      next_path_, *trust_store_, signature_policy_, time_);
+  DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = "
+           << verify_result;
+  AddResultPath(next_path_, verify_result);
+
+  if (verify_result) {
+    // Found a valid path, return immediately.
+    // TODO(mattm): add debug/test mode that tries all possible paths.
+    next_state_ = STATE_NONE;
+    return CompletionStatus::SYNC;
+  }
+
+  // Path did not verify. Try more paths. If there are no more paths, the result
+  // will be returned next time DoGetNextPathComplete is called with next_path_
+  // empty.
+  next_state_ = STATE_GET_NEXT_PATH;
+  return CompletionStatus::SYNC;
+}
+
+void CertPathBuilder::AddResultPath(const ParsedCertificateList& path,
+                                    bool is_success) {
+  std::unique_ptr<ResultPath> result_path(new ResultPath());
+  // TODO(mattm): better error reporting.
+  result_path->error = is_success ? OK : ERR_CERT_AUTHORITY_INVALID;
+  // TODO(mattm): set best_result_index based on number or severity of errors.
+  if (result_path->error == OK)
+    out_result_->best_result_index = out_result_->paths.size();
+  // TODO(mattm): add flag to only return a single path or all attempted paths?
+  result_path->path = path;
+  out_result_->paths.push_back(std::move(result_path));
+}
+
+}  // namespace net
diff --git a/net/cert/internal/path_builder.h b/net/cert/internal/path_builder.h
new file mode 100644
index 0000000..f08ad127
--- /dev/null
+++ b/net/cert/internal/path_builder.h
@@ -0,0 +1,172 @@
+// 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 NET_CERT_INTERNAL_PATH_BUILDER_H_
+#define NET_CERT_INTERNAL_PATH_BUILDER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_export.h"
+#include "net/cert/internal/completion_status.h"
+#include "net/cert/internal/parsed_certificate.h"
+#include "net/der/input.h"
+#include "net/der/parse_values.h"
+
+namespace net {
+
+namespace der {
+struct GeneralizedTime;
+}
+
+class CertPathIter;
+class CertIssuerSource;
+class TrustStore;
+class SignaturePolicy;
+
+// Checks whether a certificate is trusted by building candidate paths to trust
+// anchors and verifying those paths according to RFC 5280. Each instance of
+// CertPathBuilder is used for a single verification.
+//
+// WARNING: This implementation is currently experimental.  Consult an OWNER
+// before using it.
+class NET_EXPORT CertPathBuilder {
+ public:
+  // Represents a single candidate path that was built.
+  struct NET_EXPORT ResultPath {
+    ResultPath();
+    ~ResultPath();
+
+    // Returns true if this path was successfully verified.
+    bool is_success() const { return error == OK; }
+
+    // The candidate path, in forward direction.
+    //   * path[0] is the target certificate.
+    //   * path[i+1] is a candidate issuer of path[i]. The subject matches
+    //   path[i]'s issuer, but nothing else is guaranteed unless is_success() is
+    //   true.
+    //   * path[N-1] will be a trust anchor if is_success() is true, otherwise
+    //   it may or may not be a trust anchor.
+    ParsedCertificateList path;
+
+    // A net error code result of attempting to verify this path.
+    // TODO(mattm): may want to have an independent result enum, which caller
+    // can map to a net error if they want.
+    int error = ERR_UNEXPECTED;
+  };
+
+  // Provides the overall result of path building. This includes the paths that
+  // were attempted.
+  struct NET_EXPORT Result {
+    Result();
+    ~Result();
+
+    // Returns true if there was a valid path.
+    bool is_success() const { return error() == OK; }
+
+    // Returns the net error code of the overall best result.
+    int error() const {
+      if (paths.empty())
+        return ERR_CERT_AUTHORITY_INVALID;
+      return paths[best_result_index]->error;
+    }
+
+    // List of paths that were attempted and the result for each.
+    std::vector<std::unique_ptr<ResultPath>> paths;
+
+    // Index into |paths|. Before use, |paths.empty()| must be checked.
+    // NOTE: currently the definition of "best" is fairly limited. Successful is
+    // better than unsuccessful, but otherwise nothing is guaranteed.
+    size_t best_result_index = 0;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Result);
+  };
+
+  // TODO(mattm): allow caller specified hook/callback to extend path
+  // verification.
+  //
+  // Creates a CertPathBuilder that attempts to find a path from |cert| to a
+  // trust anchor in |trust_store|, which satisfies |signature_policy| and is
+  // valid at |time|.  Details of attempted path(s) are stored in |*result|.
+  //
+  // The caller must keep |trust_store|, |signature_policy|, and |*result| valid
+  // for the lifetime of the CertPathBuilder.
+  CertPathBuilder(scoped_refptr<ParsedCertificate> cert,
+                  const TrustStore* trust_store,
+                  const SignaturePolicy* signature_policy,
+                  const der::GeneralizedTime& time,
+                  Result* result);
+  ~CertPathBuilder();
+
+  // Adds a CertIssuerSource to provide intermediates for use in path building.
+  // Multiple sources may be added. Must not be called after Run is called.
+  // The |*cert_issuer_source| must remain valid for the lifetime of the
+  // CertPathBuilder.
+  //
+  // (If no issuer sources are added, the target certificate will only verify if
+  // it is a trust anchor or is directly signed by a trust anchor.)
+  void AddCertIssuerSource(CertIssuerSource* cert_issuer_source);
+
+  // Begins verification of the target certificate.
+  //
+  // If the return value is SYNC then the verification is complete and the
+  // |result| value can be inspected for the status, and |callback| will not be
+  // called.
+  // If the return value is ASYNC, the |callback| will be called asynchronously
+  // once the verification is complete. |result| should not be examined or
+  // modified until the |callback| is run.
+  //
+  // If |callback| is null, verification always completes synchronously, even if
+  // it fails to find a valid path and one could have been found asynchronously.
+  //
+  // The CertPathBuilder may be deleted while an ASYNC verification is pending,
+  // in which case the verification is cancelled, |callback| will not be called,
+  // and the output Result will be in an undefined state.
+  // It is safe to delete the CertPathBuilder during the |callback|.
+  // Run must not be called more than once on each CertPathBuilder instance.
+  CompletionStatus Run(const base::Closure& callback);
+
+ private:
+  enum State {
+    STATE_NONE,
+    STATE_GET_NEXT_PATH,
+    STATE_GET_NEXT_PATH_COMPLETE,
+  };
+
+  CompletionStatus DoLoop(bool allow_async);
+
+  CompletionStatus DoGetNextPath(bool allow_async);
+  void HandleGotNextPath();
+  CompletionStatus DoGetNextPathComplete();
+
+  void AddResultPath(const ParsedCertificateList& path, bool is_success);
+
+  base::Closure callback_;
+
+  std::unique_ptr<CertPathIter> cert_path_iter_;
+  const TrustStore* trust_store_;
+  const SignaturePolicy* signature_policy_;
+  const der::GeneralizedTime time_;
+
+  // Stores the next complete path to attempt verification on. This is filled in
+  // by |cert_path_iter_| during the STATE_GET_NEXT_PATH step, and thus should
+  // only be accessed during the STATE_GET_NEXT_PATH_COMPLETE step.
+  // (Will be empty if all paths have been tried, otherwise will be a candidate
+  // path starting with the target cert and ending with a trust anchor.)
+  ParsedCertificateList next_path_;
+  State next_state_;
+
+  Result* out_result_;
+
+  DISALLOW_COPY_AND_ASSIGN(CertPathBuilder);
+};
+
+}  // namespace net
+
+#endif  // NET_CERT_INTERNAL_PATH_BUILDER_H_
diff --git a/net/cert/internal/path_builder_pkits_unittest.cc b/net/cert/internal/path_builder_pkits_unittest.cc
new file mode 100644
index 0000000..a046d1cf
--- /dev/null
+++ b/net/cert/internal/path_builder_pkits_unittest.cc
@@ -0,0 +1,227 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/path_builder.h"
+
+#include "net/base/net_errors.h"
+#include "net/cert/internal/cert_issuer_source_static.h"
+#include "net/cert/internal/parse_certificate.h"
+#include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/signature_policy.h"
+#include "net/cert/internal/trust_store.h"
+#include "net/cert/internal/verify_certificate_chain.h"
+#include "net/der/input.h"
+
+// Disable tests that require DSA signatures (DSA signatures are intentionally
+// unsupported). Custom versions of the DSA tests are defined below which expect
+// verification to fail.
+#define Section1ValidDSASignaturesTest4 DISABLED_Section1ValidDSASignaturesTest4
+#define Section1ValidDSAParameterInheritanceTest5 \
+  DISABLED_Section1ValidDSAParameterInheritanceTest5
+
+// Disable tests that require name constraints with name types that are
+// intentionally unsupported. Custom versions of the tests are defined below
+// which expect verification to fail.
+#define Section13ValidRFC822nameConstraintsTest21 \
+  DISABLED_Section13ValidRFC822nameConstraintsTest21
+#define Section13ValidRFC822nameConstraintsTest23 \
+  DISABLED_Section13ValidRFC822nameConstraintsTest23
+#define Section13ValidRFC822nameConstraintsTest25 \
+  DISABLED_Section13ValidRFC822nameConstraintsTest25
+#define Section13ValidDNandRFC822nameConstraintsTest27 \
+  DISABLED_Section13ValidDNandRFC822nameConstraintsTest27
+#define Section13ValidURInameConstraintsTest34 \
+  DISABLED_Section13ValidURInameConstraintsTest34
+#define Section13ValidURInameConstraintsTest36 \
+  DISABLED_Section13ValidURInameConstraintsTest36
+
+// TODO(mattm): these require CRL support:
+#define Section7InvalidkeyUsageCriticalcRLSignFalseTest4 \
+  DISABLED_Section7InvalidkeyUsageCriticalcRLSignFalseTest4
+#define Section7InvalidkeyUsageNotCriticalcRLSignFalseTest5 \
+  DISABLED_Section7InvalidkeyUsageNotCriticalcRLSignFalseTest5
+
+#include "net/cert/internal/nist_pkits_unittest.h"
+
+namespace net {
+
+namespace {
+
+class PathBuilderPkitsTestDelegate {
+ public:
+  static bool Verify(std::vector<std::string> cert_ders,
+                     std::vector<std::string> crl_ders) {
+    if (cert_ders.empty()) {
+      ADD_FAILURE() << "cert_ders is empty";
+      return false;
+    }
+    ParsedCertificateList certs;
+    for (const std::string& der : cert_ders) {
+      certs.push_back(ParsedCertificate::CreateFromCertificateCopy(der, {}));
+      if (!certs.back()) {
+        ADD_FAILURE() << "ParsedCertificate::CreateFromCertificateCopy failed";
+        return false;
+      }
+    }
+    // First entry in the PKITS chain is the trust anchor.
+    // TODO(mattm): test with all possible trust anchors in the trust store?
+    TrustStore trust_store;
+    trust_store.AddTrustedCertificate(certs[0]);
+
+    // TODO(mattm): test with other irrelevant certs in cert_issuer_sources?
+    CertIssuerSourceStatic cert_issuer_source;
+    for (size_t i = 1; i < cert_ders.size() - 1; ++i)
+      cert_issuer_source.AddCert(certs[i]);
+
+    scoped_refptr<ParsedCertificate> target_cert(certs.back());
+
+    SimpleSignaturePolicy signature_policy(1024);
+
+    // Run all tests at the time the PKITS was published.
+    der::GeneralizedTime time = {2011, 4, 15, 0, 0, 0};
+
+    CertPathBuilder::Result result;
+    CertPathBuilder path_builder(std::move(target_cert), &trust_store,
+                                 &signature_policy, time, &result);
+    path_builder.AddCertIssuerSource(&cert_issuer_source);
+
+    CompletionStatus rv = path_builder.Run(base::Closure());
+    EXPECT_EQ(CompletionStatus::SYNC, rv);
+
+    return result.is_success();
+  }
+};
+
+}  // namespace
+
+class PkitsTest01SignatureVerificationCustomPathBuilderFoo
+    : public PkitsTest<PathBuilderPkitsTestDelegate> {};
+
+// Modified version of 4.1.4 Valid DSA Signatures Test4
+TEST_F(PkitsTest01SignatureVerificationCustomPathBuilderFoo,
+       Section1ValidDSASignaturesTest4Custom) {
+  const char* const certs[] = {"TrustAnchorRootCertificate", "DSACACert",
+                               "ValidDSASignaturesTest4EE"};
+  const char* const crls[] = {"TrustAnchorRootCRL", "DSACACRL"};
+  // DSA signatures are intentionally unsupported.
+  ASSERT_FALSE(this->Verify(certs, crls));
+}
+
+// Modified version of 4.1.5 Valid DSA Parameter Inheritance Test5
+TEST_F(PkitsTest01SignatureVerificationCustomPathBuilderFoo,
+       Section1ValidDSAParameterInheritanceTest5Custom) {
+  const char* const certs[] = {"TrustAnchorRootCertificate", "DSACACert",
+                               "DSAParametersInheritedCACert",
+                               "ValidDSAParameterInheritanceTest5EE"};
+  const char* const crls[] = {"TrustAnchorRootCRL", "DSACACRL",
+                              "DSAParametersInheritedCACRL"};
+  // DSA signatures are intentionally unsupported.
+  ASSERT_FALSE(this->Verify(certs, crls));
+}
+
+class PkitsTest13SignatureVerificationCustomPathBuilderFoo
+    : public PkitsTest<PathBuilderPkitsTestDelegate> {};
+
+// Modified version of 4.13.21 Valid RFC822 nameConstraints Test21
+TEST_F(PkitsTest13SignatureVerificationCustomPathBuilderFoo,
+       Section13ValidRFC822nameConstraintsTest21Custom) {
+  const char* const certs[] = {"TrustAnchorRootCertificate",
+                               "nameConstraintsRFC822CA1Cert",
+                               "ValidRFC822nameConstraintsTest21EE"};
+  const char* const crls[] = {"TrustAnchorRootCRL",
+                              "nameConstraintsRFC822CA1CRL"};
+  // Name constraints on rfc822Names are not supported.
+  ASSERT_FALSE(this->Verify(certs, crls));
+}
+
+// Modified version of 4.13.23 Valid RFC822 nameConstraints Test23
+TEST_F(PkitsTest13SignatureVerificationCustomPathBuilderFoo,
+       Section13ValidRFC822nameConstraintsTest23Custom) {
+  const char* const certs[] = {"TrustAnchorRootCertificate",
+                               "nameConstraintsRFC822CA2Cert",
+                               "ValidRFC822nameConstraintsTest23EE"};
+  const char* const crls[] = {"TrustAnchorRootCRL",
+                              "nameConstraintsRFC822CA2CRL"};
+  // Name constraints on rfc822Names are not supported.
+  ASSERT_FALSE(this->Verify(certs, crls));
+}
+
+// Modified version of 4.13.25 Valid RFC822 nameConstraints Test25
+TEST_F(PkitsTest13SignatureVerificationCustomPathBuilderFoo,
+       Section13ValidRFC822nameConstraintsTest25Custom) {
+  const char* const certs[] = {"TrustAnchorRootCertificate",
+                               "nameConstraintsRFC822CA3Cert",
+                               "ValidRFC822nameConstraintsTest25EE"};
+  const char* const crls[] = {"TrustAnchorRootCRL",
+                              "nameConstraintsRFC822CA3CRL"};
+  // Name constraints on rfc822Names are not supported.
+  ASSERT_FALSE(this->Verify(certs, crls));
+}
+
+// Modified version of 4.13.27 Valid DN and RFC822 nameConstraints Test27
+TEST_F(PkitsTest13SignatureVerificationCustomPathBuilderFoo,
+       Section13ValidDNandRFC822nameConstraintsTest27Custom) {
+  const char* const certs[] = {"TrustAnchorRootCertificate",
+                               "nameConstraintsDN1CACert",
+                               "nameConstraintsDN1subCA3Cert",
+                               "ValidDNandRFC822nameConstraintsTest27EE"};
+  const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsDN1CACRL",
+                              "nameConstraintsDN1subCA3CRL"};
+  // Name constraints on rfc822Names are not supported.
+  ASSERT_FALSE(this->Verify(certs, crls));
+}
+
+// Modified version of 4.13.34 Valid URI nameConstraints Test34
+TEST_F(PkitsTest13SignatureVerificationCustomPathBuilderFoo,
+       Section13ValidURInameConstraintsTest34Custom) {
+  const char* const certs[] = {"TrustAnchorRootCertificate",
+                               "nameConstraintsURI1CACert",
+                               "ValidURInameConstraintsTest34EE"};
+  const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsURI1CACRL"};
+  // Name constraints on uniformResourceIdentifiers are not supported.
+  ASSERT_FALSE(this->Verify(certs, crls));
+}
+
+// Modified version of 4.13.36 Valid URI nameConstraints Test36
+TEST_F(PkitsTest13SignatureVerificationCustomPathBuilderFoo,
+       Section13ValidURInameConstraintsTest36Custom) {
+  const char* const certs[] = {"TrustAnchorRootCertificate",
+                               "nameConstraintsURI2CACert",
+                               "ValidURInameConstraintsTest36EE"};
+  const char* const crls[] = {"TrustAnchorRootCRL", "nameConstraintsURI2CACRL"};
+  // Name constraints on uniformResourceIdentifiers are not supported.
+  ASSERT_FALSE(this->Verify(certs, crls));
+}
+
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+                              PkitsTest01SignatureVerification,
+                              PathBuilderPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+                              PkitsTest02ValidityPeriods,
+                              PathBuilderPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+                              PkitsTest03VerifyingNameChaining,
+                              PathBuilderPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+                              PkitsTest06VerifyingBasicConstraints,
+                              PathBuilderPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+                              PkitsTest07KeyUsage,
+                              PathBuilderPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+                              PkitsTest13NameConstraints,
+                              PathBuilderPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+                              PkitsTest16PrivateCertificateExtensions,
+                              PathBuilderPkitsTestDelegate);
+
+// TODO(mattm): CRL support: PkitsTest04BasicCertificateRevocationTests,
+// PkitsTest05VerifyingPathswithSelfIssuedCertificates,
+// PkitsTest14DistributionPoints, PkitsTest15DeltaCRLs
+
+// TODO(mattm): Certificate Policies support: PkitsTest08CertificatePolicies,
+// PkitsTest09RequireExplicitPolicy PkitsTest10PolicyMappings,
+// PkitsTest11InhibitPolicyMapping, PkitsTest12InhibitAnyPolicy
+
+}  // namespace net
diff --git a/net/cert/internal/path_builder_unittest.cc b/net/cert/internal/path_builder_unittest.cc
new file mode 100644
index 0000000..dfdf25b
--- /dev/null
+++ b/net/cert/internal/path_builder_unittest.cc
@@ -0,0 +1,1108 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/path_builder.h"
+
+#include "base/base_paths.h"
+#include "base/cancelable_callback.h"
+#include "base/files/file_util.h"
+#include "base/location.h"
+#include "base/path_service.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "net/cert/internal/cert_issuer_source_static.h"
+#include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/signature_policy.h"
+#include "net/cert/internal/test_helpers.h"
+#include "net/cert/internal/trust_store.h"
+#include "net/cert/internal/verify_certificate_chain.h"
+#include "net/cert/pem_tokenizer.h"
+#include "net/der/input.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/test_certificate_data.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::SaveArg;
+using ::testing::StrictMock;
+using ::testing::SetArgPointee;
+using ::testing::Return;
+
+// AsyncCertIssuerSourceStatic always returns its certs asynchronously.
+class AsyncCertIssuerSourceStatic : public CertIssuerSource {
+ public:
+  class StaticAsyncRequest : public Request {
+   public:
+    StaticAsyncRequest(const IssuerCallback& issuers_callback,
+                       ParsedCertificateList&& issuers)
+        : cancelable_closure_(base::Bind(&StaticAsyncRequest::RunCallback,
+                                         base::Unretained(this))),
+          issuers_callback_(issuers_callback) {
+      issuers_.swap(issuers);
+      issuers_iter_ = issuers_.begin();
+    }
+    ~StaticAsyncRequest() override {}
+
+    CompletionStatus GetNext(
+        scoped_refptr<ParsedCertificate>* out_cert) override {
+      if (issuers_iter_ == issuers_.end())
+        *out_cert = nullptr;
+      else
+        *out_cert = std::move(*issuers_iter_++);
+      return CompletionStatus::SYNC;
+    }
+
+    base::Closure callback() { return cancelable_closure_.callback(); }
+
+   private:
+    void RunCallback() { issuers_callback_.Run(this); }
+
+    base::CancelableClosure cancelable_closure_;
+    IssuerCallback issuers_callback_;
+    ParsedCertificateList issuers_;
+    ParsedCertificateList::iterator issuers_iter_;
+
+    DISALLOW_COPY_AND_ASSIGN(StaticAsyncRequest);
+  };
+
+  ~AsyncCertIssuerSourceStatic() override {}
+
+  void AddCert(scoped_refptr<ParsedCertificate> cert) {
+    static_cert_issuer_source_.AddCert(std::move(cert));
+  }
+
+  void SyncGetIssuersOf(const ParsedCertificate* cert,
+                        ParsedCertificateList* issuers) override {}
+  void AsyncGetIssuersOf(const ParsedCertificate* cert,
+                         const IssuerCallback& issuers_callback,
+                         std::unique_ptr<Request>* out_req) override {
+    num_async_gets_++;
+    ParsedCertificateList issuers;
+    static_cert_issuer_source_.SyncGetIssuersOf(cert, &issuers);
+    std::unique_ptr<StaticAsyncRequest> req(
+        new StaticAsyncRequest(issuers_callback, std::move(issuers)));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, req->callback());
+    *out_req = std::move(req);
+  }
+  int num_async_gets() const { return num_async_gets_; }
+
+ private:
+  CertIssuerSourceStatic static_cert_issuer_source_;
+
+  int num_async_gets_ = 0;
+};
+
+// Reads a data file from the unit-test data.
+std::string ReadTestFileToString(const std::string& file_name) {
+  // Compute the full path, relative to the src/ directory.
+  base::FilePath src_root;
+  PathService::Get(base::DIR_SOURCE_ROOT, &src_root);
+  base::FilePath filepath = src_root.AppendASCII(file_name);
+
+  // Read the full contents of the file.
+  std::string file_data;
+  if (!base::ReadFileToString(filepath, &file_data)) {
+    ADD_FAILURE() << "Couldn't read file: " << filepath.value();
+    return std::string();
+  }
+
+  return file_data;
+}
+
+// Reads a verify_certificate_chain_unittest-style test case from |file_name|.
+// Test cases are comprised of a certificate chain, trust store, a timestamp to
+// validate at, and the expected result of verification (though the expected
+// result is ignored here).
+void ReadVerifyCertChainTestFromFile(const std::string& file_name,
+                                     std::vector<std::string>* chain,
+                                     scoped_refptr<ParsedCertificate>* root,
+                                     der::GeneralizedTime* time) {
+  chain->clear();
+
+  std::string file_data = ReadTestFileToString(file_name);
+
+  std::vector<std::string> pem_headers;
+
+  const char kCertificateHeader[] = "CERTIFICATE";
+  const char kTrustedCertificateHeader[] = "TRUSTED_CERTIFICATE";
+  const char kTimeHeader[] = "TIME";
+
+  pem_headers.push_back(kCertificateHeader);
+  pem_headers.push_back(kTrustedCertificateHeader);
+  pem_headers.push_back(kTimeHeader);
+
+  bool has_time = false;
+
+  PEMTokenizer pem_tokenizer(file_data, pem_headers);
+  while (pem_tokenizer.GetNext()) {
+    const std::string& block_type = pem_tokenizer.block_type();
+    const std::string& block_data = pem_tokenizer.data();
+
+    if (block_type == kCertificateHeader) {
+      chain->push_back(block_data);
+    } else if (block_type == kTrustedCertificateHeader) {
+      *root = ParsedCertificate::CreateFromCertificateCopy(block_data, {});
+      ASSERT_TRUE(*root);
+    } else if (block_type == kTimeHeader) {
+      ASSERT_FALSE(has_time) << "Duplicate " << kTimeHeader;
+      has_time = true;
+      ASSERT_TRUE(der::ParseUTCTime(der::Input(&block_data), time));
+    }
+  }
+
+  ASSERT_TRUE(has_time);
+}
+
+::testing::AssertionResult ReadTestPem(const std::string& file_name,
+                                       const std::string& block_name,
+                                       std::string* result) {
+  const PemBlockMapping mappings[] = {
+      {block_name.c_str(), result},
+  };
+
+  return ReadTestDataFromPemFile(file_name, mappings);
+}
+
+::testing::AssertionResult ReadTestCert(
+    const std::string& file_name,
+    scoped_refptr<ParsedCertificate>* result) {
+  std::string der;
+  ::testing::AssertionResult r = ReadTestPem(
+      "net/data/ssl/certificates/" + file_name, "CERTIFICATE", &der);
+  if (!r)
+    return r;
+  *result = ParsedCertificate::CreateFromCertificateCopy(der, {});
+  if (!*result)
+    return ::testing::AssertionFailure() << "CreateFromCertificateCopy failed";
+  return ::testing::AssertionSuccess();
+}
+
+// Run the path builder, and wait for async completion if necessary. The return
+// value signifies whether the path builder completed synchronously or
+// asynchronously, not that RunPathBuilder itself is asynchronous.
+CompletionStatus RunPathBuilder(CertPathBuilder* path_builder) {
+  TestClosure callback;
+  CompletionStatus rv = path_builder->Run(callback.closure());
+
+  if (rv == CompletionStatus::ASYNC) {
+    DVLOG(1) << "waiting for async completion...";
+    callback.WaitForResult();
+    DVLOG(1) << "async completed.";
+  }
+  return rv;
+}
+
+class PathBuilderMultiRootTest : public ::testing::Test {
+ public:
+  PathBuilderMultiRootTest() : signature_policy_(1024) {}
+
+  void SetUp() override {
+    ASSERT_TRUE(ReadTestCert("multi-root-A-by-B.pem", &a_by_b_));
+    ASSERT_TRUE(ReadTestCert("multi-root-B-by-C.pem", &b_by_c_));
+    ASSERT_TRUE(ReadTestCert("multi-root-B-by-F.pem", &b_by_f_));
+    ASSERT_TRUE(ReadTestCert("multi-root-C-by-D.pem", &c_by_d_));
+    ASSERT_TRUE(ReadTestCert("multi-root-C-by-E.pem", &c_by_e_));
+    ASSERT_TRUE(ReadTestCert("multi-root-D-by-D.pem", &d_by_d_));
+    ASSERT_TRUE(ReadTestCert("multi-root-E-by-E.pem", &e_by_e_));
+    ASSERT_TRUE(ReadTestCert("multi-root-F-by-E.pem", &f_by_e_));
+  }
+
+ protected:
+  scoped_refptr<ParsedCertificate> a_by_b_, b_by_c_, b_by_f_, c_by_d_, c_by_e_,
+      d_by_d_, e_by_e_, f_by_e_;
+
+  SimpleSignaturePolicy signature_policy_;
+  der::GeneralizedTime time_ = {2016, 4, 11, 0, 0, 0};
+};
+
+// If the target cert is a trust anchor, it should verify and should not include
+// anything else in the path.
+TEST_F(PathBuilderMultiRootTest, TargetIsTrustAnchor) {
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(a_by_b_);
+  trust_store.AddTrustedCertificate(b_by_f_);
+
+  CertPathBuilder::Result result;
+  CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
+                               &result);
+
+  EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+  EXPECT_EQ(OK, result.error());
+  EXPECT_EQ(1U, result.paths[result.best_result_index]->path.size());
+  EXPECT_EQ(a_by_b_, result.paths[result.best_result_index]->path[0]);
+}
+
+// If the target cert is directly issued by a trust anchor, it should verify
+// without any intermediate certs being provided.
+TEST_F(PathBuilderMultiRootTest, TargetDirectlySignedByTrustAnchor) {
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(b_by_f_);
+
+  CertPathBuilder::Result result;
+  CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
+                               &result);
+
+  EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+  EXPECT_EQ(OK, result.error());
+  EXPECT_EQ(2U, result.paths[result.best_result_index]->path.size());
+  EXPECT_EQ(a_by_b_, result.paths[result.best_result_index]->path[0]);
+  EXPECT_EQ(b_by_f_, result.paths[result.best_result_index]->path[1]);
+}
+
+// Test that async cert queries are not made if the path can be successfully
+// built with synchronously available certs.
+TEST_F(PathBuilderMultiRootTest, TriesSyncFirst) {
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(e_by_e_);
+
+  CertIssuerSourceStatic sync_certs;
+  sync_certs.AddCert(b_by_f_);
+  sync_certs.AddCert(f_by_e_);
+
+  AsyncCertIssuerSourceStatic async_certs;
+  async_certs.AddCert(b_by_c_);
+  async_certs.AddCert(c_by_e_);
+
+  CertPathBuilder::Result result;
+  CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
+                               &result);
+  path_builder.AddCertIssuerSource(&async_certs);
+  path_builder.AddCertIssuerSource(&sync_certs);
+
+  EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+  EXPECT_EQ(OK, result.error());
+  EXPECT_EQ(0, async_certs.num_async_gets());
+}
+
+// Test that async cert queries are not made if no callback is provided.
+TEST_F(PathBuilderMultiRootTest, SychronousOnlyMode) {
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(e_by_e_);
+
+  CertIssuerSourceStatic sync_certs;
+  sync_certs.AddCert(f_by_e_);
+
+  AsyncCertIssuerSourceStatic async_certs;
+  async_certs.AddCert(b_by_f_);
+
+  CertPathBuilder::Result result;
+  CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
+                               &result);
+  path_builder.AddCertIssuerSource(&async_certs);
+  path_builder.AddCertIssuerSource(&sync_certs);
+
+  EXPECT_EQ(CompletionStatus::SYNC, path_builder.Run(base::Closure()));
+
+  EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.error());
+  EXPECT_EQ(0, async_certs.num_async_gets());
+}
+
+// If async queries are needed, all async sources will be queried
+// simultaneously.
+TEST_F(PathBuilderMultiRootTest, TestAsyncSimultaneous) {
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(e_by_e_);
+
+  CertIssuerSourceStatic sync_certs;
+  sync_certs.AddCert(b_by_c_);
+  sync_certs.AddCert(b_by_f_);
+
+  AsyncCertIssuerSourceStatic async_certs1;
+  async_certs1.AddCert(c_by_e_);
+
+  AsyncCertIssuerSourceStatic async_certs2;
+  async_certs2.AddCert(f_by_e_);
+
+  CertPathBuilder::Result result;
+  CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
+                               &result);
+  path_builder.AddCertIssuerSource(&async_certs1);
+  path_builder.AddCertIssuerSource(&async_certs2);
+  path_builder.AddCertIssuerSource(&sync_certs);
+
+  EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder));
+
+  EXPECT_EQ(OK, result.error());
+  EXPECT_EQ(1, async_certs1.num_async_gets());
+  EXPECT_EQ(1, async_certs2.num_async_gets());
+}
+
+// Test that PathBuilder does not generate longer paths than necessary if one of
+// the supplied certs is itself a trust anchor.
+TEST_F(PathBuilderMultiRootTest, TestLongChain) {
+  // Both D(D) and C(D) are trusted roots.
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(d_by_d_);
+  trust_store.AddTrustedCertificate(c_by_d_);
+
+  // Certs B(C), and C(D) are all supplied.
+  CertIssuerSourceStatic sync_certs;
+  sync_certs.AddCert(b_by_c_);
+  sync_certs.AddCert(c_by_d_);
+
+  CertPathBuilder::Result result;
+  CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
+                               &result);
+  path_builder.AddCertIssuerSource(&sync_certs);
+
+  EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+  EXPECT_EQ(OK, result.error());
+
+  // The result path should be A(B) <- B(C) <- C(D)
+  // not the longer but also valid A(B) <- B(C) <- C(D) <- D(D)
+  EXPECT_EQ(3U, result.paths[result.best_result_index]->path.size());
+}
+
+// Test that PathBuilder will backtrack and try a different path if the first
+// one doesn't work out.
+TEST_F(PathBuilderMultiRootTest, TestBacktracking) {
+  // Only D(D) is a trusted root.
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(d_by_d_);
+
+  // Certs B(F) and F(E) are supplied synchronously, thus the path
+  // A(B) <- B(F) <- F(E) should be built first, though it won't verify.
+  CertIssuerSourceStatic sync_certs;
+  sync_certs.AddCert(b_by_f_);
+  sync_certs.AddCert(f_by_e_);
+
+  // Certs B(C), and C(D) are supplied asynchronously, so the path
+  // A(B) <- B(C) <- C(D) <- D(D) should be tried second.
+  AsyncCertIssuerSourceStatic async_certs;
+  async_certs.AddCert(b_by_c_);
+  async_certs.AddCert(c_by_d_);
+
+  CertPathBuilder::Result result;
+  CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_,
+                               &result);
+  path_builder.AddCertIssuerSource(&sync_certs);
+  path_builder.AddCertIssuerSource(&async_certs);
+
+  EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder));
+
+  EXPECT_EQ(OK, result.error());
+
+  // The result path should be A(B) <- B(C) <- C(D) <- D(D)
+  ASSERT_EQ(4U, result.paths[result.best_result_index]->path.size());
+  EXPECT_EQ(a_by_b_, result.paths[result.best_result_index]->path[0]);
+  EXPECT_EQ(b_by_c_, result.paths[result.best_result_index]->path[1]);
+  EXPECT_EQ(c_by_d_, result.paths[result.best_result_index]->path[2]);
+  EXPECT_EQ(d_by_d_, result.paths[result.best_result_index]->path[3]);
+}
+
+// Test that whichever order CertIssuerSource returns the issuers, the path
+// building still succeeds.
+TEST_F(PathBuilderMultiRootTest, TestCertIssuerOrdering) {
+  // Only D(D) is a trusted root.
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(d_by_d_);
+
+  for (bool reverse_order : {false, true}) {
+    SCOPED_TRACE(reverse_order);
+    std::vector<scoped_refptr<ParsedCertificate>> certs = {
+        b_by_c_, b_by_f_, f_by_e_, c_by_d_, c_by_e_};
+    CertIssuerSourceStatic sync_certs;
+    if (reverse_order) {
+      for (auto it = certs.rbegin(); it != certs.rend(); ++it)
+        sync_certs.AddCert(*it);
+    } else {
+      for (const auto& cert : certs)
+        sync_certs.AddCert(cert);
+    }
+
+    CertPathBuilder::Result result;
+    CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_,
+                                 time_, &result);
+    path_builder.AddCertIssuerSource(&sync_certs);
+
+    EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+    EXPECT_EQ(OK, result.error());
+
+    // The result path should be A(B) <- B(C) <- C(D) <- D(D)
+    ASSERT_EQ(4U, result.paths[result.best_result_index]->path.size());
+    EXPECT_EQ(a_by_b_, result.paths[result.best_result_index]->path[0]);
+    EXPECT_EQ(b_by_c_, result.paths[result.best_result_index]->path[1]);
+    EXPECT_EQ(c_by_d_, result.paths[result.best_result_index]->path[2]);
+    EXPECT_EQ(d_by_d_, result.paths[result.best_result_index]->path[3]);
+  }
+}
+
+class PathBuilderKeyRolloverTest : public ::testing::Test {
+ public:
+  PathBuilderKeyRolloverTest() : signature_policy_(1024) {}
+
+  void SetUp() override {
+    std::vector<std::string> path;
+
+    ReadVerifyCertChainTestFromFile(
+        "net/data/verify_certificate_chain_unittest/key-rollover-oldchain.pem",
+        &path, &oldroot_, &time_);
+    ASSERT_EQ(2U, path.size());
+    target_ = ParsedCertificate::CreateFromCertificateCopy(path[0], {});
+    oldintermediate_ =
+        ParsedCertificate::CreateFromCertificateCopy(path[1], {});
+    ASSERT_TRUE(target_);
+    ASSERT_TRUE(oldintermediate_);
+
+    ReadVerifyCertChainTestFromFile(
+        "net/data/verify_certificate_chain_unittest/"
+        "key-rollover-longrolloverchain.pem",
+        &path, &oldroot_, &time_);
+    ASSERT_EQ(4U, path.size());
+    newintermediate_ =
+        ParsedCertificate::CreateFromCertificateCopy(path[1], {});
+    newroot_ = ParsedCertificate::CreateFromCertificateCopy(path[2], {});
+    newrootrollover_ =
+        ParsedCertificate::CreateFromCertificateCopy(path[3], {});
+    ASSERT_TRUE(newintermediate_);
+    ASSERT_TRUE(newroot_);
+    ASSERT_TRUE(newrootrollover_);
+  }
+
+ protected:
+  //    oldroot-------->newrootrollover  newroot
+  //       |                      |        |
+  //       v                      v        v
+  // oldintermediate           newintermediate
+  //       |                          |
+  //       +------------+-------------+
+  //                    |
+  //                    v
+  //                  target
+  scoped_refptr<ParsedCertificate> target_;
+  scoped_refptr<ParsedCertificate> oldintermediate_;
+  scoped_refptr<ParsedCertificate> newintermediate_;
+  scoped_refptr<ParsedCertificate> oldroot_;
+  scoped_refptr<ParsedCertificate> newroot_;
+  scoped_refptr<ParsedCertificate> newrootrollover_;
+
+  SimpleSignaturePolicy signature_policy_;
+  der::GeneralizedTime time_;
+};
+
+// Tests that if only the old root cert is trusted, the path builder can build a
+// path through the new intermediate and rollover cert to the old root.
+TEST_F(PathBuilderKeyRolloverTest, TestRolloverOnlyOldRootTrusted) {
+  // Only oldroot is trusted.
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(oldroot_);
+
+  // Old intermediate cert is not provided, so the pathbuilder will need to go
+  // through the rollover cert.
+  CertIssuerSourceStatic sync_certs;
+  sync_certs.AddCert(newintermediate_);
+  sync_certs.AddCert(newrootrollover_);
+
+  CertPathBuilder::Result result;
+  CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+                               &result);
+  path_builder.AddCertIssuerSource(&sync_certs);
+
+  EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+  EXPECT_EQ(OK, result.error());
+
+  // Path builder will first attempt: target <- newintermediate <- oldroot
+  // but it will fail since newintermediate is signed by newroot.
+  ASSERT_EQ(2U, result.paths.size());
+  EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.paths[0]->error);
+  ASSERT_EQ(3U, result.paths[0]->path.size());
+  EXPECT_EQ(target_, result.paths[0]->path[0]);
+  EXPECT_EQ(newintermediate_, result.paths[0]->path[1]);
+  EXPECT_EQ(oldroot_, result.paths[0]->path[2]);
+
+  // Path builder will next attempt:
+  // target <- newintermediate <- newrootrollover <- oldroot
+  // which will succeed.
+  EXPECT_EQ(1U, result.best_result_index);
+  EXPECT_EQ(OK, result.paths[1]->error);
+  ASSERT_EQ(4U, result.paths[1]->path.size());
+  EXPECT_EQ(target_, result.paths[1]->path[0]);
+  EXPECT_EQ(newintermediate_, result.paths[1]->path[1]);
+  EXPECT_EQ(newrootrollover_, result.paths[1]->path[2]);
+  EXPECT_EQ(oldroot_, result.paths[1]->path[3]);
+}
+
+// Tests that if both old and new roots are trusted it can build a path through
+// either.
+// TODO(mattm): Once prioritization is implemented, it should test that it
+// always builds the path through the new intermediate and new root.
+TEST_F(PathBuilderKeyRolloverTest, TestRolloverBothRootsTrusted) {
+  // Both oldroot and newroot are trusted.
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(oldroot_);
+  trust_store.AddTrustedCertificate(newroot_);
+
+  // Both old and new intermediates + rollover cert are provided.
+  CertIssuerSourceStatic sync_certs;
+  sync_certs.AddCert(oldintermediate_);
+  sync_certs.AddCert(newintermediate_);
+  sync_certs.AddCert(newrootrollover_);
+
+  CertPathBuilder::Result result;
+  CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+                               &result);
+  path_builder.AddCertIssuerSource(&sync_certs);
+
+  EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+  EXPECT_EQ(OK, result.error());
+
+  // Path builder willattempt one of:
+  // target <- oldintermediate <- oldroot
+  // target <- newintermediate <- newroot
+  // either will succeed.
+  ASSERT_EQ(1U, result.paths.size());
+  EXPECT_EQ(OK, result.paths[0]->error);
+  ASSERT_EQ(3U, result.paths[0]->path.size());
+  EXPECT_EQ(target_, result.paths[0]->path[0]);
+  if (result.paths[0]->path[1] != newintermediate_) {
+    DVLOG(1) << "USED OLD";
+    EXPECT_EQ(oldintermediate_, result.paths[0]->path[1]);
+    EXPECT_EQ(oldroot_, result.paths[0]->path[2]);
+  } else {
+    DVLOG(1) << "USED NEW";
+    EXPECT_EQ(newintermediate_, result.paths[0]->path[1]);
+    EXPECT_EQ(newroot_, result.paths[0]->path[2]);
+  }
+}
+
+// Tests that multiple trust root matches on a single path will be considered.
+// Both roots have the same subject but different keys. Only one of them will
+// verify.
+TEST_F(PathBuilderKeyRolloverTest, TestMultipleRootMatchesOnlyOneWorks) {
+  // Both newroot and oldroot are trusted.
+  TrustStore trust_store;
+  // Note: The test assumes newroot will be tried before oldroot.
+  // Currently this depends on the order the roots are added.
+  trust_store.AddTrustedCertificate(newroot_);
+  trust_store.AddTrustedCertificate(oldroot_);
+
+  // Only oldintermediate is supplied, so the path with newroot should fail,
+  // oldroot should succeed.
+  CertIssuerSourceStatic sync_certs;
+  sync_certs.AddCert(oldintermediate_);
+
+  CertPathBuilder::Result result;
+  CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+                               &result);
+  path_builder.AddCertIssuerSource(&sync_certs);
+
+  EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+  EXPECT_EQ(OK, result.error());
+  ASSERT_EQ(2U, result.paths.size());
+
+  // Path builder will first attempt: target <- oldintermediate <- newroot
+  // but it will fail since oldintermediate is signed by oldroot.
+  EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.paths[0]->error);
+  ASSERT_EQ(3U, result.paths[0]->path.size());
+  EXPECT_EQ(target_, result.paths[0]->path[0]);
+  EXPECT_EQ(oldintermediate_, result.paths[0]->path[1]);
+  EXPECT_EQ(newroot_, result.paths[0]->path[2]);
+
+  // Path builder will next attempt:
+  // target <- old intermediate <- oldroot
+  // which should succeed.
+  EXPECT_EQ(OK, result.paths[1]->error);
+  ASSERT_EQ(3U, result.paths[1]->path.size());
+  EXPECT_EQ(target_, result.paths[1]->path[0]);
+  EXPECT_EQ(oldintermediate_, result.paths[1]->path[1]);
+  EXPECT_EQ(oldroot_, result.paths[1]->path[2]);
+}
+
+// Tests that the path builder doesn't build longer than necessary paths.
+TEST_F(PathBuilderKeyRolloverTest, TestRolloverLongChain) {
+  // Only oldroot is trusted.
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(oldroot_);
+
+  // New intermediate and new root are provided synchronously.
+  CertIssuerSourceStatic sync_certs;
+  sync_certs.AddCert(newintermediate_);
+  sync_certs.AddCert(newroot_);
+
+  // Rollover cert is only provided asynchronously. This will force the
+  // pathbuilder to first try building a longer than necessary path.
+  AsyncCertIssuerSourceStatic async_certs;
+  async_certs.AddCert(newrootrollover_);
+
+  CertPathBuilder::Result result;
+  CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+                               &result);
+  path_builder.AddCertIssuerSource(&sync_certs);
+  path_builder.AddCertIssuerSource(&async_certs);
+
+  EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder));
+
+  EXPECT_EQ(OK, result.error());
+  ASSERT_EQ(3U, result.paths.size());
+
+  // Path builder will first attempt: target <- newintermediate <- oldroot
+  // but it will fail since newintermediate is signed by newroot.
+  EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.paths[0]->error);
+  ASSERT_EQ(3U, result.paths[0]->path.size());
+  EXPECT_EQ(target_, result.paths[0]->path[0]);
+  EXPECT_EQ(newintermediate_, result.paths[0]->path[1]);
+  EXPECT_EQ(oldroot_, result.paths[0]->path[2]);
+
+  // Path builder will next attempt:
+  // target <- newintermediate <- newroot <- oldroot
+  // but it will fail since newroot is self-signed.
+  EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.paths[1]->error);
+  ASSERT_EQ(4U, result.paths[1]->path.size());
+  EXPECT_EQ(target_, result.paths[1]->path[0]);
+  EXPECT_EQ(newintermediate_, result.paths[1]->path[1]);
+  EXPECT_EQ(newroot_, result.paths[1]->path[2]);
+  EXPECT_EQ(oldroot_, result.paths[1]->path[3]);
+
+  // Path builder will skip:
+  // target <- newintermediate <- newroot <- newrootrollover <- ...
+  // Since newroot and newrootrollover have the same Name+SAN+SPKI.
+
+  // Finally path builder will use:
+  // target <- newintermediate <- newrootrollover <- oldroot
+  EXPECT_EQ(2U, result.best_result_index);
+  EXPECT_EQ(OK, result.paths[2]->error);
+  ASSERT_EQ(4U, result.paths[2]->path.size());
+  EXPECT_EQ(target_, result.paths[2]->path[0]);
+  EXPECT_EQ(newintermediate_, result.paths[2]->path[1]);
+  EXPECT_EQ(newrootrollover_, result.paths[2]->path[2]);
+  EXPECT_EQ(oldroot_, result.paths[2]->path[3]);
+}
+
+// If the target cert is a trust root, that alone is a valid path.
+TEST_F(PathBuilderKeyRolloverTest, TestEndEntityIsTrustRoot) {
+  // Trust newintermediate.
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(newintermediate_);
+
+  CertPathBuilder::Result result;
+  // Newintermediate is also the target cert.
+  CertPathBuilder path_builder(newintermediate_, &trust_store,
+                               &signature_policy_, time_, &result);
+
+  EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+  EXPECT_EQ(OK, result.error());
+
+  ASSERT_EQ(1U, result.paths.size());
+  EXPECT_EQ(OK, result.paths[0]->error);
+  ASSERT_EQ(1U, result.paths[0]->path.size());
+  EXPECT_EQ(newintermediate_, result.paths[0]->path[0]);
+}
+
+// If target has same Name+SAN+SPKI as a necessary intermediate, test if a path
+// can still be built.
+// Since LoopChecker will prevent the intermediate from being included, this
+// currently does NOT verify. This case shouldn't occur in the web PKI.
+TEST_F(PathBuilderKeyRolloverTest,
+       TestEndEntityHasSameNameAndSpkiAsIntermediate) {
+  // Trust oldroot.
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(oldroot_);
+
+  // New root rollover is provided synchronously.
+  CertIssuerSourceStatic sync_certs;
+  sync_certs.AddCert(newrootrollover_);
+
+  CertPathBuilder::Result result;
+  // Newroot is the target cert.
+  CertPathBuilder path_builder(newroot_, &trust_store, &signature_policy_,
+                               time_, &result);
+  path_builder.AddCertIssuerSource(&sync_certs);
+
+  EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+  // This could actually be OK, but CertPathBuilder does not build the
+  // newroot <- newrootrollover <- oldroot path.
+  EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.error());
+}
+
+// If target has same Name+SAN+SPKI as the trust root, test that a (trivial)
+// path can still be built.
+TEST_F(PathBuilderKeyRolloverTest,
+       TestEndEntityHasSameNameAndSpkiAsTrustAnchor) {
+  // Trust newrootrollover.
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(newrootrollover_);
+
+  CertPathBuilder::Result result;
+  // Newroot is the target cert.
+  CertPathBuilder path_builder(newroot_, &trust_store, &signature_policy_,
+                               time_, &result);
+
+  EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+  EXPECT_EQ(OK, result.error());
+
+  ASSERT_FALSE(result.paths.empty());
+  const CertPathBuilder::ResultPath* best_result =
+      result.paths[result.best_result_index].get();
+
+  // Newroot has same name+SPKI as newrootrollover, thus the path is valid and
+  // only contains newroot.
+  EXPECT_EQ(OK, best_result->error);
+  ASSERT_EQ(1U, best_result->path.size());
+  EXPECT_EQ(newroot_, best_result->path[0]);
+}
+
+// Test that PathBuilder will not try the same path twice if multiple
+// CertIssuerSources provide the same certificate.
+TEST_F(PathBuilderKeyRolloverTest, TestDuplicateIntermediates) {
+  // Create a separate copy of oldintermediate.
+  scoped_refptr<ParsedCertificate> oldintermediate_dupe(
+      ParsedCertificate::CreateFromCertificateCopy(
+          oldintermediate_->der_cert().AsStringPiece(), {}));
+
+  // Only newroot is a trusted root.
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(newroot_);
+
+  // The oldintermediate is supplied synchronously by |sync_certs1| and
+  // another copy of oldintermediate is supplied synchronously by |sync_certs2|.
+  // The path target <- oldintermediate <- newroot  should be built first,
+  // though it won't verify. It should not be attempted again even though
+  // oldintermediate was supplied twice.
+  CertIssuerSourceStatic sync_certs1;
+  sync_certs1.AddCert(oldintermediate_);
+  CertIssuerSourceStatic sync_certs2;
+  sync_certs2.AddCert(oldintermediate_dupe);
+
+  // The newintermediate is supplied asynchronously, so the path
+  // target <- newintermediate <- newroot should be tried second.
+  AsyncCertIssuerSourceStatic async_certs;
+  async_certs.AddCert(newintermediate_);
+
+  CertPathBuilder::Result result;
+  CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+                               &result);
+  path_builder.AddCertIssuerSource(&sync_certs1);
+  path_builder.AddCertIssuerSource(&sync_certs2);
+  path_builder.AddCertIssuerSource(&async_certs);
+
+  EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder));
+
+  EXPECT_EQ(OK, result.error());
+  ASSERT_EQ(2U, result.paths.size());
+
+  // Path builder will first attempt: target <- oldintermediate <- newroot
+  // but it will fail since oldintermediate is signed by oldroot.
+  EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.paths[0]->error);
+  ASSERT_EQ(3U, result.paths[0]->path.size());
+  EXPECT_EQ(target_, result.paths[0]->path[0]);
+  // Compare the DER instead of ParsedCertificate pointer, don't care which copy
+  // of oldintermediate was used in the path.
+  EXPECT_EQ(oldintermediate_->der_cert(), result.paths[0]->path[1]->der_cert());
+  EXPECT_EQ(newroot_, result.paths[0]->path[2]);
+
+  // Path builder will next attempt: target <- newintermediate <- newroot
+  // which will succeed.
+  EXPECT_EQ(1U, result.best_result_index);
+  EXPECT_EQ(OK, result.paths[1]->error);
+  ASSERT_EQ(3U, result.paths[1]->path.size());
+  EXPECT_EQ(target_, result.paths[1]->path[0]);
+  EXPECT_EQ(newintermediate_, result.paths[1]->path[1]);
+  EXPECT_EQ(newroot_, result.paths[1]->path[2]);
+}
+
+// Test that PathBuilder will not try the same path twice if the same cert is
+// presented via a CertIssuerSources and a TrustAnchor.
+TEST_F(PathBuilderKeyRolloverTest, TestDuplicateIntermediateAndRoot) {
+  // Create a separate copy of newroot.
+  scoped_refptr<ParsedCertificate> newroot_dupe(
+      ParsedCertificate::CreateFromCertificateCopy(
+          newroot_->der_cert().AsStringPiece(), {}));
+
+  // Only newroot is a trusted root.
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(newroot_);
+
+  // The oldintermediate and newroot are supplied synchronously by |sync_certs|.
+  CertIssuerSourceStatic sync_certs;
+  sync_certs.AddCert(oldintermediate_);
+  sync_certs.AddCert(newroot_dupe);
+
+  CertPathBuilder::Result result;
+  CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+                               &result);
+  path_builder.AddCertIssuerSource(&sync_certs);
+
+  EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder));
+
+  EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.error());
+  ASSERT_EQ(1U, result.paths.size());
+
+  // Path builder attempt: target <- oldintermediate <- newroot
+  // but it will fail since oldintermediate is signed by oldroot.
+  EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.paths[0]->error);
+  ASSERT_EQ(3U, result.paths[0]->path.size());
+  EXPECT_EQ(target_, result.paths[0]->path[0]);
+  EXPECT_EQ(oldintermediate_, result.paths[0]->path[1]);
+  // Compare the DER instead of ParsedCertificate pointer, don't care which copy
+  // of newroot was used in the path.
+  EXPECT_EQ(newroot_->der_cert(), result.paths[0]->path[2]->der_cert());
+}
+
+class MockCertIssuerSourceRequest : public CertIssuerSource::Request {
+ public:
+  MOCK_METHOD1(GetNext, CompletionStatus(scoped_refptr<ParsedCertificate>*));
+};
+
+class MockCertIssuerSource : public CertIssuerSource {
+ public:
+  MOCK_METHOD2(SyncGetIssuersOf,
+               void(const ParsedCertificate*, ParsedCertificateList*));
+  MOCK_METHOD3(AsyncGetIssuersOf,
+               void(const ParsedCertificate*,
+                    const IssuerCallback&,
+                    std::unique_ptr<Request>*));
+};
+
+// Helper class to pass the Request to the PathBuilder when it calls
+// AsyncGetIssuersOf. (GoogleMock has a ByMove helper, but it apparently can
+// only be used with Return, not SetArgPointee.)
+class CertIssuerSourceRequestMover {
+ public:
+  CertIssuerSourceRequestMover(std::unique_ptr<CertIssuerSource::Request> req)
+      : request_(std::move(req)) {}
+  void MoveIt(const ParsedCertificate* cert,
+              const CertIssuerSource::IssuerCallback& issuers_callback,
+              std::unique_ptr<CertIssuerSource::Request>* out_req) {
+    *out_req = std::move(request_);
+  }
+
+ private:
+  std::unique_ptr<CertIssuerSource::Request> request_;
+};
+
+// Test that a single CertIssuerSource returning multiple async batches of
+// issuers is handled correctly. Due to the StrictMocks, it also tests that path
+// builder does not request issuers of certs that it shouldn't.
+TEST_F(PathBuilderKeyRolloverTest, TestMultipleAsyncCallbacksFromSingleSource) {
+  StrictMock<MockCertIssuerSource> cert_issuer_source;
+
+  // Only newroot is a trusted root.
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(newroot_);
+
+  CertPathBuilder::Result result;
+  CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+                               &result);
+  path_builder.AddCertIssuerSource(&cert_issuer_source);
+
+  CertIssuerSource::IssuerCallback target_issuers_callback;
+  // Create the mock CertIssuerSource::Request...
+  std::unique_ptr<StrictMock<MockCertIssuerSourceRequest>>
+      target_issuers_req_owner(new StrictMock<MockCertIssuerSourceRequest>());
+  // Keep a raw pointer to the Request...
+  StrictMock<MockCertIssuerSourceRequest>* target_issuers_req =
+      target_issuers_req_owner.get();
+  // Setup helper class to pass ownership of the Request to the PathBuilder when
+  // it calls AsyncGetIssuersOf.
+  CertIssuerSourceRequestMover req_mover(std::move(target_issuers_req_owner));
+  {
+    ::testing::InSequence s;
+    EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(target_.get(), _));
+    EXPECT_CALL(cert_issuer_source, AsyncGetIssuersOf(target_.get(), _, _))
+        .WillOnce(
+            DoAll(SaveArg<1>(&target_issuers_callback),
+                  Invoke(&req_mover, &CertIssuerSourceRequestMover::MoveIt)));
+  }
+
+  TestClosure callback;
+  CompletionStatus rv = path_builder.Run(callback.closure());
+  ASSERT_EQ(CompletionStatus::ASYNC, rv);
+
+  ASSERT_FALSE(target_issuers_callback.is_null());
+
+  ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source);
+
+  // First async batch: return oldintermediate_.
+  EXPECT_CALL(*target_issuers_req, GetNext(_))
+      .WillOnce(DoAll(SetArgPointee<0>(oldintermediate_),
+                      Return(CompletionStatus::SYNC)))
+      .WillOnce(
+          DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC)));
+  {
+    ::testing::InSequence s;
+    // oldintermediate_ does not create a valid path, so both sync and async
+    // lookups are expected.
+    EXPECT_CALL(cert_issuer_source,
+                SyncGetIssuersOf(oldintermediate_.get(), _));
+    EXPECT_CALL(cert_issuer_source,
+                AsyncGetIssuersOf(oldintermediate_.get(), _, _));
+  }
+  target_issuers_callback.Run(target_issuers_req);
+  ::testing::Mock::VerifyAndClearExpectations(target_issuers_req);
+  ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source);
+
+  // Second async batch: return newintermediate_.
+  EXPECT_CALL(*target_issuers_req, GetNext(_))
+      .WillOnce(DoAll(SetArgPointee<0>(newintermediate_),
+                      Return(CompletionStatus::SYNC)))
+      .WillOnce(
+          DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC)));
+  // newroot_ is in the trust store, so this path will be completed
+  // synchronously. AsyncGetIssuersOf will not be called on newintermediate_.
+  EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(newintermediate_.get(), _));
+  target_issuers_callback.Run(target_issuers_req);
+  // Note that VerifyAndClearExpectations(target_issuers_req) is not called
+  // here. PathBuilder could have destroyed it already, so just let the
+  // expectations get checked by the destructor.
+  ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source);
+
+  // Ensure pathbuilder finished and filled result.
+  callback.WaitForResult();
+
+  EXPECT_EQ(OK, result.error());
+  ASSERT_EQ(2U, result.paths.size());
+
+  // Path builder first attempts: target <- oldintermediate <- newroot
+  // but it will fail since oldintermediate is signed by oldroot.
+  EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.paths[0]->error);
+  ASSERT_EQ(3U, result.paths[0]->path.size());
+  EXPECT_EQ(target_, result.paths[0]->path[0]);
+  EXPECT_EQ(oldintermediate_, result.paths[0]->path[1]);
+  EXPECT_EQ(newroot_, result.paths[0]->path[2]);
+
+  // After the second batch of async results, path builder will attempt:
+  // target <- newintermediate <- newroot which will succeed.
+  EXPECT_EQ(OK, result.paths[1]->error);
+  ASSERT_EQ(3U, result.paths[1]->path.size());
+  EXPECT_EQ(target_, result.paths[1]->path[0]);
+  EXPECT_EQ(newintermediate_, result.paths[1]->path[1]);
+  EXPECT_EQ(newroot_, result.paths[1]->path[2]);
+}
+
+// Test that PathBuilder will not try the same path twice if CertIssuerSources
+// asynchronously provide the same certificate multiple times.
+TEST_F(PathBuilderKeyRolloverTest, TestDuplicateAsyncIntermediates) {
+  StrictMock<MockCertIssuerSource> cert_issuer_source;
+
+  // Only newroot is a trusted root.
+  TrustStore trust_store;
+  trust_store.AddTrustedCertificate(newroot_);
+
+  CertPathBuilder::Result result;
+  CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_,
+                               &result);
+  path_builder.AddCertIssuerSource(&cert_issuer_source);
+
+  CertIssuerSource::IssuerCallback target_issuers_callback;
+  // Create the mock CertIssuerSource::Request...
+  std::unique_ptr<StrictMock<MockCertIssuerSourceRequest>>
+      target_issuers_req_owner(new StrictMock<MockCertIssuerSourceRequest>());
+  // Keep a raw pointer to the Request...
+  StrictMock<MockCertIssuerSourceRequest>* target_issuers_req =
+      target_issuers_req_owner.get();
+  // Setup helper class to pass ownership of the Request to the PathBuilder when
+  // it calls AsyncGetIssuersOf.
+  CertIssuerSourceRequestMover req_mover(std::move(target_issuers_req_owner));
+  {
+    ::testing::InSequence s;
+    EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(target_.get(), _));
+    EXPECT_CALL(cert_issuer_source, AsyncGetIssuersOf(target_.get(), _, _))
+        .WillOnce(
+            DoAll(SaveArg<1>(&target_issuers_callback),
+                  Invoke(&req_mover, &CertIssuerSourceRequestMover::MoveIt)));
+  }
+
+  TestClosure callback;
+  CompletionStatus rv = path_builder.Run(callback.closure());
+  ASSERT_EQ(CompletionStatus::ASYNC, rv);
+
+  ASSERT_FALSE(target_issuers_callback.is_null());
+
+  ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source);
+
+  // First async batch: return oldintermediate_.
+  EXPECT_CALL(*target_issuers_req, GetNext(_))
+      .WillOnce(DoAll(SetArgPointee<0>(oldintermediate_),
+                      Return(CompletionStatus::SYNC)))
+      .WillOnce(
+          DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC)));
+  {
+    ::testing::InSequence s;
+    // oldintermediate_ does not create a valid path, so both sync and async
+    // lookups are expected.
+    EXPECT_CALL(cert_issuer_source,
+                SyncGetIssuersOf(oldintermediate_.get(), _));
+    EXPECT_CALL(cert_issuer_source,
+                AsyncGetIssuersOf(oldintermediate_.get(), _, _));
+  }
+  target_issuers_callback.Run(target_issuers_req);
+  ::testing::Mock::VerifyAndClearExpectations(target_issuers_req);
+  ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source);
+
+  // Second async batch: return a different copy of oldintermediate_ again.
+  scoped_refptr<ParsedCertificate> oldintermediate_dupe(
+      ParsedCertificate::CreateFromCertificateCopy(
+          oldintermediate_->der_cert().AsStringPiece(), {}));
+  EXPECT_CALL(*target_issuers_req, GetNext(_))
+      .WillOnce(DoAll(SetArgPointee<0>(oldintermediate_dupe),
+                      Return(CompletionStatus::SYNC)))
+      .WillOnce(
+          DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC)));
+  target_issuers_callback.Run(target_issuers_req);
+  // oldintermediate was already processed above, it should not generate any
+  // more requests.
+  ::testing::Mock::VerifyAndClearExpectations(target_issuers_req);
+  ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source);
+
+  // Third async batch: return newintermediate_.
+  EXPECT_CALL(*target_issuers_req, GetNext(_))
+      .WillOnce(DoAll(SetArgPointee<0>(newintermediate_),
+                      Return(CompletionStatus::SYNC)))
+      .WillOnce(
+          DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC)));
+  // newroot_ is in the trust store, so this path will be completed
+  // synchronously. AsyncGetIssuersOf will not be called on newintermediate_.
+  EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(newintermediate_.get(), _));
+  target_issuers_callback.Run(target_issuers_req);
+  // Note that VerifyAndClearExpectations(target_issuers_req) is not called
+  // here. PathBuilder could have destroyed it already, so just let the
+  // expectations get checked by the destructor.
+  ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source);
+
+  // Ensure pathbuilder finished and filled result.
+  callback.WaitForResult();
+
+  EXPECT_EQ(OK, result.error());
+  ASSERT_EQ(2U, result.paths.size());
+
+  // Path builder first attempts: target <- oldintermediate <- newroot
+  // but it will fail since oldintermediate is signed by oldroot.
+  EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, result.paths[0]->error);
+  ASSERT_EQ(3U, result.paths[0]->path.size());
+  EXPECT_EQ(target_, result.paths[0]->path[0]);
+  EXPECT_EQ(oldintermediate_, result.paths[0]->path[1]);
+  EXPECT_EQ(newroot_, result.paths[0]->path[2]);
+
+  // The second async result does not generate any path.
+
+  // After the third batch of async results, path builder will attempt:
+  // target <- newintermediate <- newroot which will succeed.
+  EXPECT_EQ(OK, result.paths[1]->error);
+  ASSERT_EQ(3U, result.paths[1]->path.size());
+  EXPECT_EQ(target_, result.paths[1]->path[0]);
+  EXPECT_EQ(newintermediate_, result.paths[1]->path[1]);
+  EXPECT_EQ(newroot_, result.paths[1]->path[2]);
+}
+
+}  // namespace
+
+}  // namespace net
diff --git a/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc b/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc
new file mode 100644
index 0000000..e08ea30
--- /dev/null
+++ b/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc
@@ -0,0 +1,56 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/internal/path_builder.h"
+
+#include "net/cert/internal/cert_issuer_source_static.h"
+#include "net/cert/internal/signature_policy.h"
+#include "net/cert/internal/trust_store.h"
+#include "net/cert/internal/verify_certificate_chain_typed_unittest.h"
+
+namespace net {
+
+namespace {
+
+class PathBuilderDelegate {
+ public:
+  static void Verify(const ParsedCertificateList& chain,
+                     const ParsedCertificateList& roots,
+                     const der::GeneralizedTime& time,
+                     bool expected_result) {
+    SimpleSignaturePolicy signature_policy(1024);
+    ASSERT_FALSE(chain.empty());
+
+    TrustStore trust_store;
+    for (const auto& root : roots)
+      trust_store.AddTrustedCertificate(root);
+
+    CertIssuerSourceStatic intermediate_cert_issuer_source;
+    for (size_t i = 1; i < chain.size(); ++i)
+      intermediate_cert_issuer_source.AddCert(chain[i]);
+
+    CertPathBuilder::Result result;
+    // First cert in the |chain| is the target.
+    CertPathBuilder path_builder(chain.front(), &trust_store, &signature_policy,
+                                 time, &result);
+    path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source);
+
+    CompletionStatus rv = path_builder.Run(base::Closure());
+    EXPECT_EQ(CompletionStatus::SYNC, rv);
+
+    EXPECT_EQ(expected_result, result.is_success());
+  }
+};
+
+}  // namespace
+
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+                              VerifyCertificateChainSingleRootTest,
+                              PathBuilderDelegate);
+
+INSTANTIATE_TYPED_TEST_CASE_P(PathBuilder,
+                              VerifyCertificateChainNonSingleRootTest,
+                              PathBuilderDelegate);
+
+}  // namespace net
diff --git a/net/cert/internal/trust_store.cc b/net/cert/internal/trust_store.cc
index 892698ba5..d46933b 100644
--- a/net/cert/internal/trust_store.cc
+++ b/net/cert/internal/trust_store.cc
@@ -4,8 +4,6 @@
 
 #include "net/cert/internal/trust_store.h"
 
-#include "net/cert/internal/parsed_certificate.h"
-
 namespace net {
 
 TrustStore::TrustStore() {}
@@ -24,7 +22,7 @@
 
 void TrustStore::FindTrustAnchorsByNormalizedName(
     const der::Input& normalized_name,
-    std::vector<scoped_refptr<ParsedCertificate>>* matches) const {
+    ParsedCertificateList* matches) const {
   auto range = anchors_.equal_range(normalized_name.AsStringPiece());
   for (auto it = range.first; it != range.second; ++it)
     matches->push_back(it->second);
@@ -33,9 +31,13 @@
 bool TrustStore::IsTrustedCertificate(const ParsedCertificate* cert) const {
   auto range = anchors_.equal_range(cert->normalized_subject().AsStringPiece());
   for (auto it = range.first; it != range.second; ++it) {
-    // First compare the ParsedCertificate pointers as an optimization, fall
-    // back to comparing full DER encoding.
-    if (it->second == cert || it->second->der_cert() == cert->der_cert())
+    // First compare the ParsedCertificate pointers as an optimization.
+    if (it->second == cert ||
+        // Trust check is based on Name+SPKI match. This could match the same
+        // certificate stored in a different ParsedCertificate object, or a
+        // different cert that has the same Name+SPKI.
+        (it->second->normalized_subject() == cert->normalized_subject() &&
+         it->second->tbs().spki_tlv == cert->tbs().spki_tlv))
       return true;
   }
   return false;
diff --git a/net/cert/internal/trust_store.h b/net/cert/internal/trust_store.h
index 611af1c..0afbf9a 100644
--- a/net/cert/internal/trust_store.h
+++ b/net/cert/internal/trust_store.h
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/strings/string_piece.h"
 #include "net/base/net_export.h"
+#include "net/cert/internal/parsed_certificate.h"
 
 namespace net {
 
@@ -18,8 +19,6 @@
 class Input;
 }
 
-class ParsedCertificate;
-
 // A very simple implementation of a TrustStore, which contains a set of
 // trusted certificates.
 // TODO(mattm): convert this into an interface, provide implementations that
@@ -36,9 +35,8 @@
   void AddTrustedCertificate(scoped_refptr<ParsedCertificate> anchor);
 
   // Returns the trust anchors that match |name| in |*matches|, if any.
-  void FindTrustAnchorsByNormalizedName(
-      const der::Input& normalized_name,
-      std::vector<scoped_refptr<ParsedCertificate>>* matches) const;
+  void FindTrustAnchorsByNormalizedName(const der::Input& normalized_name,
+                                        ParsedCertificateList* matches) const;
 
   // Returns true if |cert| matches a certificate in the TrustStore.
   bool IsTrustedCertificate(const ParsedCertificate* cert) const
diff --git a/net/cert/internal/verify_certificate_chain.cc b/net/cert/internal/verify_certificate_chain.cc
index 73bd6f13..baef57a 100644
--- a/net/cert/internal/verify_certificate_chain.cc
+++ b/net/cert/internal/verify_certificate_chain.cc
@@ -9,7 +9,6 @@
 #include "base/logging.h"
 #include "net/cert/internal/name_constraints.h"
 #include "net/cert/internal/parse_certificate.h"
-#include "net/cert/internal/parsed_certificate.h"
 #include "net/cert/internal/signature_algorithm.h"
 #include "net/cert/internal/signature_policy.h"
 #include "net/cert/internal/trust_store.h"
@@ -336,9 +335,6 @@
 
 }  // namespace
 
-// TODO(eroman): Move this into existing anonymous namespace.
-namespace {
-
 // This implementation is structured to mimic the description of certificate
 // path verification given by RFC 5280 section 6.1.
 //
@@ -346,7 +342,7 @@
 // the chain. This root certificate is assumed to be trusted, and neither its
 // signature nor issuer name are verified. (It needn't be self-signed).
 bool VerifyCertificateChainAssumingTrustedRoot(
-    const std::vector<scoped_refptr<ParsedCertificate>>& certs,
+    const ParsedCertificateList& certs,
     // The trust store is only used for assertions.
     const TrustStore& trust_store,
     const SignaturePolicy* signature_policy,
@@ -450,56 +446,4 @@
   return true;
 }
 
-// TODO(eroman): This function is a temporary hack in the absence of full
-// path building. It may insert 1 certificate at the root of the
-// chain to ensure that the path's root certificate is a trust anchor.
-//
-// Beyond this no other verification is done on the chain. The caller is
-// responsible for verifying the subsequent chain's correctness.
-WARN_UNUSED_RESULT bool BuildSimplePathToTrustAnchor(
-    const TrustStore& trust_store,
-    std::vector<scoped_refptr<ParsedCertificate>>* certs) {
-  if (certs->empty())
-    return false;
-
-  // Check if the current root certificate is trusted. If it is then no
-  // extra work is needed.
-  if (trust_store.IsTrustedCertificate(certs->back().get()))
-    return true;
-
-  std::vector<scoped_refptr<ParsedCertificate>> trust_anchors;
-  trust_store.FindTrustAnchorsByNormalizedName(
-      certs->back()->normalized_issuer(), &trust_anchors);
-  if (trust_anchors.empty())
-    return false;
-  // TODO(mattm): this only tries the first match, even if there are multiple.
-  certs->push_back(std::move(trust_anchors[0]));
-  return true;
-}
-
-}  // namespace
-
-bool VerifyCertificateChain(
-    const std::vector<scoped_refptr<ParsedCertificate>>& cert_chain,
-    const TrustStore& trust_store,
-    const SignaturePolicy* signature_policy,
-    const der::GeneralizedTime& time,
-    std::vector<scoped_refptr<ParsedCertificate>>* trusted_chain_out) {
-  if (cert_chain.empty())
-    return false;
-
-  std::vector<scoped_refptr<ParsedCertificate>> full_chain = cert_chain;
-
-  // Modify the certificate chain so that its root is a trusted certificate.
-  if (!BuildSimplePathToTrustAnchor(trust_store, &full_chain))
-    return false;
-
-  // Verify the chain.
-  bool success = VerifyCertificateChainAssumingTrustedRoot(
-      full_chain, trust_store, signature_policy, time);
-  if (success && trusted_chain_out != nullptr)
-    *trusted_chain_out = std::move(full_chain);
-  return success;
-}
-
 }  // namespace net
diff --git a/net/cert/internal/verify_certificate_chain.h b/net/cert/internal/verify_certificate_chain.h
index 291c843..5dc6275 100644
--- a/net/cert/internal/verify_certificate_chain.h
+++ b/net/cert/internal/verify_certificate_chain.h
@@ -10,6 +10,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "net/base/net_export.h"
+#include "net/cert/internal/parsed_certificate.h"
 #include "net/der/input.h"
 
 namespace net {
@@ -18,12 +19,12 @@
 struct GeneralizedTime;
 }
 
-class ParsedCertificate;
 class SignaturePolicy;
 class TrustStore;
 
-// VerifyCertificateChain() verifies a certificate path (chain) based on the
-// rules in RFC 5280.
+// VerifyCertificateChainAssumingTrustedRoot() verifies a certificate path
+// (chain) based on the rules in RFC 5280. The caller is responsible for
+// building the path and ensuring the chain ends in a trusted root certificate.
 //
 // WARNING: This implementation is in progress, and is currently incomplete.
 // Consult an OWNER before using it.
@@ -38,11 +39,11 @@
 //
 //      * cert_chain[0] is the target certificate to verify.
 //      * cert_chain[i+1] holds the certificate that issued cert_chain[i].
-//      * cert_chain[N-1] must be the trust anchor, or have been directly
-//        issued by a trust anchor.
+//      * cert_chain[N-1] must be the trust anchor.
 //
 //   trust_store:
-//     Contains the set of trusted public keys (and their names).
+//     Contains the set of trusted public keys (and their names). This is only
+//     used to DCHECK that the final cert is a trust anchor.
 //
 //   signature_policy:
 //     The policy to use when verifying signatures (what hash algorithms are
@@ -51,28 +52,17 @@
 //   time:
 //     The UTC time to use for expiration checks.
 //
-//   trusted_chain_out:
-//     The vector to populate with the verified trusted certificate chain.
-//      * trusted_chain_out[0] is the target certificate verified.
-//      * trusted_chain_out[i+1] holds the certificate that issued
-//        trusted_chain_out[i].
-//      * trusted_chain_out[N-1] is the trust anchor.
-//     If a nullptr is passed, this parameter is ignored.
-//     If the target certificate can not be verified, this parameter is
-//     ignored.
-//
 // ---------
 // Outputs
 // ---------
 //
 //   Returns true if the target certificate can be verified.
-NET_EXPORT bool VerifyCertificateChain(
-    const std::vector<scoped_refptr<ParsedCertificate>>& cert_chain,
+NET_EXPORT bool VerifyCertificateChainAssumingTrustedRoot(
+    const ParsedCertificateList& certs,
+    // The trust store is only used for assertions.
     const TrustStore& trust_store,
     const SignaturePolicy* signature_policy,
-    const der::GeneralizedTime& time,
-    std::vector<scoped_refptr<ParsedCertificate>>* trusted_chain_out)
-    WARN_UNUSED_RESULT;
+    const der::GeneralizedTime& time) WARN_UNUSED_RESULT;
 
 }  // namespace net
 
diff --git a/net/cert/internal/verify_certificate_chain_pkits_unittest.cc b/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
index 4c543f4..33a1156 100644
--- a/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
+++ b/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
@@ -52,35 +52,30 @@
       ADD_FAILURE() << "cert_ders is empty";
       return false;
     }
-    // First entry in the PKITS chain is the trust anchor.
-    TrustStore trust_store;
-    scoped_refptr<ParsedCertificate> anchor(
-        ParsedCertificate::CreateFromCertificateCopy(cert_ders[0], {}));
-    EXPECT_TRUE(anchor);
-    if (anchor)
-      trust_store.AddTrustedCertificate(std::move(anchor));
 
     // PKITS lists chains from trust anchor to target, VerifyCertificateChain
     // takes them starting with the target and not including the trust anchor.
     std::vector<scoped_refptr<net::ParsedCertificate>> input_chain;
-    for (size_t i = cert_ders.size() - 1; i > 0; --i) {
+    for (auto i = cert_ders.rbegin(); i != cert_ders.rend(); ++i) {
       if (!net::ParsedCertificate::CreateAndAddToVector(
-              reinterpret_cast<const uint8_t*>(cert_ders[i].data()),
-              cert_ders[i].size(),
+              reinterpret_cast<const uint8_t*>(i->data()), i->size(),
               net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE, {},
               &input_chain)) {
-        ADD_FAILURE() << "cert " << i << " failed to parse";
+        ADD_FAILURE() << "cert failed to parse";
         return false;
       }
     }
 
+    TrustStore trust_store;
+    trust_store.AddTrustedCertificate(input_chain.back());
+
     SimpleSignaturePolicy signature_policy(1024);
 
     // Run all tests at the time the PKITS was published.
     der::GeneralizedTime time = {2011, 4, 15, 0, 0, 0};
 
-    return VerifyCertificateChain(input_chain, trust_store, &signature_policy,
-                                  time, nullptr);
+    return VerifyCertificateChainAssumingTrustedRoot(input_chain, trust_store,
+                                                     &signature_policy, time);
   }
 };
 
diff --git a/net/cert/internal/verify_certificate_chain_typed_unittest.h b/net/cert/internal/verify_certificate_chain_typed_unittest.h
new file mode 100644
index 0000000..1ddd464
--- /dev/null
+++ b/net/cert/internal/verify_certificate_chain_typed_unittest.h
@@ -0,0 +1,305 @@
+// 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 NET_CERT_INTERNAL_VERIFY_CERTIFICATE_CHAIN_TYPED_UNITTEST_H_
+#define NET_CERT_INTERNAL_VERIFY_CERTIFICATE_CHAIN_TYPED_UNITTEST_H_
+
+#include "base/base_paths.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "net/cert/internal/parsed_certificate.h"
+#include "net/cert/internal/test_helpers.h"
+#include "net/cert/pem_tokenizer.h"
+#include "net/der/input.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+template <typename TestDelegate>
+class VerifyCertificateChainTest : public ::testing::Test {
+ public:
+  void RunTest(const char* file_name) {
+    ParsedCertificateList chain;
+    ParsedCertificateList roots;
+    der::GeneralizedTime time;
+    bool expected_result;
+
+    ReadTestFromFile(file_name, &chain, &roots, &time, &expected_result);
+
+    TestDelegate::Verify(chain, roots, time, expected_result);
+  }
+
+ private:
+  // Reads a data file from the unit-test data.
+  std::string ReadTestFileToString(const std::string& file_name) {
+    // Compute the full path, relative to the src/ directory.
+    base::FilePath src_root;
+    PathService::Get(base::DIR_SOURCE_ROOT, &src_root);
+    base::FilePath filepath = src_root.AppendASCII(
+        std::string("net/data/verify_certificate_chain_unittest/") + file_name);
+
+    // Read the full contents of the file.
+    std::string file_data;
+    if (!base::ReadFileToString(filepath, &file_data)) {
+      ADD_FAILURE() << "Couldn't read file: " << filepath.value();
+      return std::string();
+    }
+
+    return file_data;
+  }
+
+  // Reads a test case from |file_name|. Test cases are comprised of a
+  // certificate chain, trust store, a timestamp to validate at, and the
+  // expected result of verification.
+  void ReadTestFromFile(const std::string& file_name,
+                        ParsedCertificateList* chain,
+                        ParsedCertificateList* roots,
+                        der::GeneralizedTime* time,
+                        bool* verify_result) {
+    chain->clear();
+    roots->clear();
+
+    std::string file_data = ReadTestFileToString(file_name);
+
+    std::vector<std::string> pem_headers;
+
+    const char kCertificateHeader[] = "CERTIFICATE";
+    const char kTrustedCertificateHeader[] = "TRUSTED_CERTIFICATE";
+    const char kTimeHeader[] = "TIME";
+    const char kResultHeader[] = "VERIFY_RESULT";
+
+    pem_headers.push_back(kCertificateHeader);
+    pem_headers.push_back(kTrustedCertificateHeader);
+    pem_headers.push_back(kTimeHeader);
+    pem_headers.push_back(kResultHeader);
+
+    bool has_time = false;
+    bool has_result = false;
+
+    PEMTokenizer pem_tokenizer(file_data, pem_headers);
+    while (pem_tokenizer.GetNext()) {
+      const std::string& block_type = pem_tokenizer.block_type();
+      const std::string& block_data = pem_tokenizer.data();
+
+      if (block_type == kCertificateHeader) {
+        ASSERT_TRUE(net::ParsedCertificate::CreateAndAddToVector(
+            reinterpret_cast<const uint8_t*>(block_data.data()),
+            block_data.size(),
+            net::ParsedCertificate::DataSource::INTERNAL_COPY, {}, chain));
+      } else if (block_type == kTrustedCertificateHeader) {
+        ASSERT_TRUE(net::ParsedCertificate::CreateAndAddToVector(
+            reinterpret_cast<const uint8_t*>(block_data.data()),
+            block_data.size(),
+            net::ParsedCertificate::DataSource::INTERNAL_COPY, {}, roots));
+      } else if (block_type == kTimeHeader) {
+        ASSERT_FALSE(has_time) << "Duplicate " << kTimeHeader;
+        has_time = true;
+        ASSERT_TRUE(der::ParseUTCTime(der::Input(&block_data), time));
+      } else if (block_type == kResultHeader) {
+        ASSERT_FALSE(has_result) << "Duplicate " << kResultHeader;
+        ASSERT_TRUE(block_data == "SUCCESS" || block_data == "FAIL")
+            << "Unrecognized result: " << block_data;
+        has_result = true;
+        *verify_result = block_data == "SUCCESS";
+      }
+    }
+
+    ASSERT_TRUE(has_time);
+    ASSERT_TRUE(has_result);
+  }
+};
+
+// Tests that have only one root. These can be tested without requiring any
+// path-building ability.
+template <typename TestDelegate>
+class VerifyCertificateChainSingleRootTest
+    : public VerifyCertificateChainTest<TestDelegate> {};
+
+TYPED_TEST_CASE_P(VerifyCertificateChainSingleRootTest);
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, TargetAndIntermediary) {
+  this->RunTest("target-and-intermediary.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+             IntermediaryLacksBasicConstraints) {
+  this->RunTest("intermediary-lacks-basic-constraints.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+             IntermediaryBasicConstraintsCaFalse) {
+  this->RunTest("intermediary-basic-constraints-ca-false.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+             IntermediaryBasicConstraintsNotCritical) {
+  this->RunTest("intermediary-basic-constraints-not-critical.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+             IntermediaryLacksSigningKeyUsage) {
+  this->RunTest("intermediary-lacks-signing-key-usage.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+             IntermediaryUnknownCriticalExtension) {
+  this->RunTest("intermediary-unknown-critical-extension.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+             IntermediaryUnknownNonCriticalExtension) {
+  this->RunTest("intermediary-unknown-non-critical-extension.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+             ViolatesBasicConstraintsPathlen0) {
+  this->RunTest("violates-basic-constraints-pathlen-0.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+             BasicConstraintsPathlen0SelfIssued) {
+  this->RunTest("basic-constraints-pathlen-0-self-issued.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, TargetSignedWithMd5) {
+  this->RunTest("target-signed-with-md5.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, IntermediarySignedWithMd5) {
+  this->RunTest("intermediary-signed-with-md5.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, TargetWrongSignature) {
+  this->RunTest("target-wrong-signature.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, TargetSignedBy512bitRsa) {
+  this->RunTest("target-signed-by-512bit-rsa.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, TargetSignedUsingEcdsa) {
+  this->RunTest("target-signed-using-ecdsa.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, ExpiredIntermediary) {
+  this->RunTest("expired-intermediary.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, ExpiredTarget) {
+  this->RunTest("expired-target.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, ExpiredTargetNotBefore) {
+  this->RunTest("expired-target-notBefore.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, ExpiredRoot) {
+  this->RunTest("expired-root.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, TargetNotEndEntity) {
+  this->RunTest("target-not-end-entity.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+             TargetHasKeyCertSignButNotCa) {
+  this->RunTest("target-has-keycertsign-but-not-ca.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, TargetHasPathlenButNotCa) {
+  this->RunTest("target-has-pathlen-but-not-ca.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+             TargetUnknownCriticalExtension) {
+  this->RunTest("target-unknown-critical-extension.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+             IssuerAndSubjectNotByteForByteEqual) {
+  this->RunTest("issuer-and-subject-not-byte-for-byte-equal.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+             IssuerAndSubjectNotByteForByteEqualAnchor) {
+  this->RunTest("issuer-and-subject-not-byte-for-byte-equal-anchor.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, ViolatesPathlen1Root) {
+  this->RunTest("violates-pathlen-1-root.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, NonSelfSignedRoot) {
+  this->RunTest("non-self-signed-root.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, KeyRolloverOldChain) {
+  this->RunTest("key-rollover-oldchain.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, KeyRolloverRolloverChain) {
+  this->RunTest("key-rollover-rolloverchain.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest,
+             KeyRolloverLongRolloverChain) {
+  this->RunTest("key-rollover-longrolloverchain.pem");
+}
+
+TYPED_TEST_P(VerifyCertificateChainSingleRootTest, KeyRolloverNewChain) {
+  this->RunTest("key-rollover-newchain.pem");
+}
+
+// TODO(eroman): Add test that invalidate validity dates where the day or month
+// ordinal not in range, like "March 39, 2016" are rejected.
+
+REGISTER_TYPED_TEST_CASE_P(VerifyCertificateChainSingleRootTest,
+                           TargetAndIntermediary,
+                           IntermediaryLacksBasicConstraints,
+                           IntermediaryBasicConstraintsCaFalse,
+                           IntermediaryBasicConstraintsNotCritical,
+                           IntermediaryLacksSigningKeyUsage,
+                           IntermediaryUnknownCriticalExtension,
+                           IntermediaryUnknownNonCriticalExtension,
+                           ViolatesBasicConstraintsPathlen0,
+                           BasicConstraintsPathlen0SelfIssued,
+                           TargetSignedWithMd5,
+                           IntermediarySignedWithMd5,
+                           TargetWrongSignature,
+                           TargetSignedBy512bitRsa,
+                           TargetSignedUsingEcdsa,
+                           ExpiredIntermediary,
+                           ExpiredTarget,
+                           ExpiredTargetNotBefore,
+                           ExpiredRoot,
+                           TargetNotEndEntity,
+                           TargetHasKeyCertSignButNotCa,
+                           TargetHasPathlenButNotCa,
+                           TargetUnknownCriticalExtension,
+                           IssuerAndSubjectNotByteForByteEqual,
+                           IssuerAndSubjectNotByteForByteEqualAnchor,
+                           ViolatesPathlen1Root,
+                           NonSelfSignedRoot,
+                           KeyRolloverOldChain,
+                           KeyRolloverRolloverChain,
+                           KeyRolloverLongRolloverChain,
+                           KeyRolloverNewChain);
+
+// Tests that have zero roots or more than one root.
+template <typename TestDelegate>
+class VerifyCertificateChainNonSingleRootTest
+    : public VerifyCertificateChainTest<TestDelegate> {};
+
+TYPED_TEST_CASE_P(VerifyCertificateChainNonSingleRootTest);
+
+TYPED_TEST_P(VerifyCertificateChainNonSingleRootTest, UnknownRoot) {
+  this->RunTest("unknown-root.pem");
+}
+
+REGISTER_TYPED_TEST_CASE_P(VerifyCertificateChainNonSingleRootTest,
+                           UnknownRoot);
+
+}  // namespace net
+
+#endif  // NET_CERT_INTERNAL_VERIFY_CERTIFICATE_CHAIN_TYPED_UNITTEST_H_
diff --git a/net/cert/internal/verify_certificate_chain_unittest.cc b/net/cert/internal/verify_certificate_chain_unittest.cc
index 9103f12f..b857296 100644
--- a/net/cert/internal/verify_certificate_chain_unittest.cc
+++ b/net/cert/internal/verify_certificate_chain_unittest.cc
@@ -4,254 +4,41 @@
 
 #include "net/cert/internal/verify_certificate_chain.h"
 
-#include "base/base_paths.h"
-#include "base/files/file_util.h"
-#include "base/path_service.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "net/cert/internal/parsed_certificate.h"
 #include "net/cert/internal/signature_policy.h"
-#include "net/cert/internal/test_helpers.h"
 #include "net/cert/internal/trust_store.h"
-#include "net/cert/pem_tokenizer.h"
-#include "net/der/input.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#include "net/cert/internal/verify_certificate_chain_typed_unittest.h"
 
 namespace net {
 
 namespace {
 
-// Reads a data file from the unit-test data.
-std::string ReadTestFileToString(const std::string& file_name) {
-  // Compute the full path, relative to the src/ directory.
-  base::FilePath src_root;
-  PathService::Get(base::DIR_SOURCE_ROOT, &src_root);
-  base::FilePath filepath = src_root.AppendASCII(
-      std::string("net/data/verify_certificate_chain_unittest/") + file_name);
+class VerifyCertificateChainAssumingTrustedRootDelegate {
+ public:
+  static void Verify(const ParsedCertificateList& chain,
+                     const ParsedCertificateList& roots,
+                     const der::GeneralizedTime& time,
+                     bool expected_result) {
+    TrustStore trust_store;
+    ASSERT_EQ(1U, roots.size());
+    trust_store.AddTrustedCertificate(roots[0]);
 
-  // Read the full contents of the file.
-  std::string file_data;
-  if (!base::ReadFileToString(filepath, &file_data)) {
-    ADD_FAILURE() << "Couldn't read file: " << filepath.value();
-    return std::string();
+    ParsedCertificateList full_chain(chain);
+    full_chain.push_back(roots[0]);
+
+    SimpleSignaturePolicy signature_policy(1024);
+
+    bool result = VerifyCertificateChainAssumingTrustedRoot(
+        full_chain, trust_store, &signature_policy, time);
+
+    ASSERT_EQ(expected_result, result);
   }
-
-  return file_data;
-}
-
-// Reads a test case from |file_name|. Test cases are comprised of a
-// certificate chain, trust store, a timestamp to validate at, and the
-// expected result of verification.
-void ReadTestFromFile(const std::string& file_name,
-                      std::vector<std::string>* chain,
-                      TrustStore* trust_store,
-                      der::GeneralizedTime* time,
-                      bool* verify_result) {
-  chain->clear();
-  trust_store->Clear();
-
-  std::string file_data = ReadTestFileToString(file_name);
-
-  std::vector<std::string> pem_headers;
-
-  const char kCertificateHeader[] = "CERTIFICATE";
-  const char kTrustedCertificateHeader[] = "TRUSTED_CERTIFICATE";
-  const char kTimeHeader[] = "TIME";
-  const char kResultHeader[] = "VERIFY_RESULT";
-
-  pem_headers.push_back(kCertificateHeader);
-  pem_headers.push_back(kTrustedCertificateHeader);
-  pem_headers.push_back(kTimeHeader);
-  pem_headers.push_back(kResultHeader);
-
-  bool has_time = false;
-  bool has_result = false;
-
-  PEMTokenizer pem_tokenizer(file_data, pem_headers);
-  while (pem_tokenizer.GetNext()) {
-    const std::string& block_type = pem_tokenizer.block_type();
-    const std::string& block_data = pem_tokenizer.data();
-
-    if (block_type == kCertificateHeader) {
-      chain->push_back(block_data);
-    } else if (block_type == kTrustedCertificateHeader) {
-      scoped_refptr<ParsedCertificate> cert(
-          ParsedCertificate::CreateFromCertificateCopy(block_data, {}));
-      ASSERT_TRUE(cert);
-      trust_store->AddTrustedCertificate(std::move(cert));
-    } else if (block_type == kTimeHeader) {
-      ASSERT_FALSE(has_time) << "Duplicate " << kTimeHeader;
-      has_time = true;
-      ASSERT_TRUE(der::ParseUTCTime(der::Input(&block_data), time));
-    } else if (block_type == kResultHeader) {
-      ASSERT_FALSE(has_result) << "Duplicate " << kResultHeader;
-      ASSERT_TRUE(block_data == "SUCCESS" || block_data == "FAIL")
-          << "Unrecognized result: " << block_data;
-      has_result = true;
-      *verify_result = block_data == "SUCCESS";
-    }
-  }
-
-  ASSERT_TRUE(has_time);
-  ASSERT_TRUE(has_result);
-}
-
-void RunTest(const char* file_name) {
-  std::vector<std::string> chain;
-  TrustStore trust_store;
-  der::GeneralizedTime time;
-  bool expected_result;
-
-  ReadTestFromFile(file_name, &chain, &trust_store, &time, &expected_result);
-
-  std::vector<scoped_refptr<net::ParsedCertificate>> input_chain;
-  for (const auto& cert_der : chain) {
-    ASSERT_TRUE(net::ParsedCertificate::CreateAndAddToVector(
-        reinterpret_cast<const uint8_t*>(cert_der.data()), cert_der.size(),
-        net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE, {},
-        &input_chain));
-  }
-
-  SimpleSignaturePolicy signature_policy(1024);
-
-  std::vector<scoped_refptr<ParsedCertificate>> trusted_chain;
-  bool result = VerifyCertificateChain(input_chain, trust_store,
-                                       &signature_policy, time, &trusted_chain);
-  if (result) {
-    ASSERT_EQ(trusted_chain.size(), input_chain.size() + 1);
-    ASSERT_TRUE(std::equal(input_chain.begin(), input_chain.end(),
-                           trusted_chain.begin()));
-    ASSERT_TRUE(trust_store.IsTrustedCertificate(trusted_chain.back().get()));
-  } else {
-    ASSERT_EQ(trusted_chain.size(), 0u);
-  }
-
-  ASSERT_EQ(expected_result, result);
-}
-
-TEST(VerifyCertificateChainTest, TargetAndIntermediary) {
-  RunTest("target-and-intermediary.pem");
-}
-
-TEST(VerifyCertificateChainTest, UnknownRoot) {
-  RunTest("unknown-root.pem");
-}
-
-TEST(VerifyCertificateChainTest, IntermediaryLacksBasicConstraints) {
-  RunTest("intermediary-lacks-basic-constraints.pem");
-}
-
-TEST(VerifyCertificateChainTest, IntermediaryBasicConstraintsCaFalse) {
-  RunTest("intermediary-basic-constraints-ca-false.pem");
-}
-
-TEST(VerifyCertificateChainTest, IntermediaryBasicConstraintsNotCritical) {
-  RunTest("intermediary-basic-constraints-not-critical.pem");
-}
-
-TEST(VerifyCertificateChainTest, IntermediaryLacksSigningKeyUsage) {
-  RunTest("intermediary-lacks-signing-key-usage.pem");
-}
-
-TEST(VerifyCertificateChainTest, IntermediaryUnknownCriticalExtension) {
-  RunTest("intermediary-unknown-critical-extension.pem");
-}
-
-TEST(VerifyCertificateChainTest, IntermediaryUnknownNonCriticalExtension) {
-  RunTest("intermediary-unknown-non-critical-extension.pem");
-}
-
-TEST(VerifyCertificateChainTest, ViolatesBasicConstraintsPathlen0) {
-  RunTest("violates-basic-constraints-pathlen-0.pem");
-}
-
-TEST(VerifyCertificateChainTest, BasicConstraintsPathlen0SelfIssued) {
-  RunTest("basic-constraints-pathlen-0-self-issued.pem");
-}
-
-TEST(VerifyCertificateChainTest, TargetSignedWithMd5) {
-  RunTest("target-signed-with-md5.pem");
-}
-
-TEST(VerifyCertificateChainTest, IntermediarySignedWithMd5) {
-  RunTest("intermediary-signed-with-md5.pem");
-}
-
-TEST(VerifyCertificateChainTest, TargetWrongSignature) {
-  RunTest("target-wrong-signature.pem");
-}
-
-TEST(VerifyCertificateChainTest, TargetSignedBy512bitRsa) {
-  RunTest("target-signed-by-512bit-rsa.pem");
-}
-
-TEST(VerifyCertificateChainTest, TargetSignedUsingEcdsa) {
-  RunTest("target-signed-using-ecdsa.pem");
-}
-
-TEST(VerifyCertificateChainTest, ExpiredIntermediary) {
-  RunTest("expired-intermediary.pem");
-}
-
-TEST(VerifyCertificateChainTest, ExpiredTarget) {
-  RunTest("expired-target.pem");
-}
-
-TEST(VerifyCertificateChainTest, ExpiredTargetNotBefore) {
-  RunTest("expired-target-notBefore.pem");
-}
-
-TEST(VerifyCertificateChainTest, ExpiredRoot) {
-  RunTest("expired-root.pem");
-}
-
-TEST(VerifyCertificateChainTest, TargetNotEndEntity) {
-  RunTest("target-not-end-entity.pem");
-}
-
-TEST(VerifyCertificateChainTest, TargetHasKeyCertSignButNotCa) {
-  RunTest("target-has-keycertsign-but-not-ca.pem");
-}
-
-TEST(VerifyCertificateChainTest, TargetHasPathlenButNotCa) {
-  RunTest("target-has-pathlen-but-not-ca.pem");
-}
-
-TEST(VerifyCertificateChainTest, TargetUnknownCriticalExtension) {
-  RunTest("target-unknown-critical-extension.pem");
-}
-
-TEST(VerifyCertificateChainTest, IssuerAndSubjectNotByteForByteEqual) {
-  RunTest("issuer-and-subject-not-byte-for-byte-equal.pem");
-}
-
-TEST(VerifyCertificateChainTest, IssuerAndSubjectNotByteForByteEqualAnchor) {
-  RunTest("issuer-and-subject-not-byte-for-byte-equal-anchor.pem");
-}
-
-TEST(VerifyCertificateChainTest, ViolatesPathlen1Root) {
-  RunTest("violates-pathlen-1-root.pem");
-}
-
-TEST(VerifyCertificateChainTest, NonSelfSignedRoot) {
-  RunTest("non-self-signed-root.pem");
-}
-
-// Tests that verifying a chain with no certificates fails.
-TEST(VerifyCertificateChainTest, EmptyChainIsInvalid) {
-  TrustStore trust_store;
-  der::GeneralizedTime time;
-  std::vector<scoped_refptr<ParsedCertificate>> chain;
-  SimpleSignaturePolicy signature_policy(2048);
-
-  ASSERT_FALSE(VerifyCertificateChain(chain, trust_store, &signature_policy,
-                                      time, nullptr));
-}
-
-// TODO(eroman): Add test that invalidate validity dates where the day or month
-// ordinal not in range, like "March 39, 2016" are rejected.
+};
 
 }  // namespace
 
+INSTANTIATE_TYPED_TEST_CASE_P(
+    VerifyCertificateChainAssumingTrustedRoot,
+    VerifyCertificateChainSingleRootTest,
+    VerifyCertificateChainAssumingTrustedRootDelegate);
+
 }  // namespace net
diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc
index 407c9ff2..2469f28 100644
--- a/net/cookies/canonical_cookie.cc
+++ b/net/cookies/canonical_cookie.cc
@@ -480,9 +480,9 @@
     const std::string& name) {
   const char kSecurePrefix[] = "__Secure-";
   const char kHostPrefix[] = "__Host-";
-  if (name.find(kSecurePrefix) == 0)
+  if (base::StartsWith(name, kSecurePrefix, base::CompareCase::SENSITIVE))
     return CanonicalCookie::COOKIE_PREFIX_SECURE;
-  if (name.find(kHostPrefix) == 0)
+  if (base::StartsWith(name, kHostPrefix, base::CompareCase::SENSITIVE))
     return CanonicalCookie::COOKIE_PREFIX_HOST;
   return CanonicalCookie::COOKIE_PREFIX_NONE;
 }
diff --git a/net/data/fuzzer_dictionaries/net_dns_hosts_parse_fuzzer.dict b/net/data/fuzzer_dictionaries/net_dns_hosts_parse_fuzzer.dict
new file mode 100644
index 0000000..dd72cefb
--- /dev/null
+++ b/net/data/fuzzer_dictionaries/net_dns_hosts_parse_fuzzer.dict
@@ -0,0 +1,843 @@
+# 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.
+
+# Fuzzer dictionary targetting DNS responses.
+
+# Some 16-bit big-endian values. Useful in a number of fields. Includes
+# A, AAAA, and CNAME IDs, low values for record counts, and multiples of
+# lengths of A and AAAA data fields.
+"\x00\x00"
+"\x00\x01"
+"\x00\x02"
+"\x00\x03"
+"\x00\x04"
+"\x00\x05"
+"\x00\x08"
+"\x00\x0C"
+"\x00\x10"
+"\x00\x1C"
+"\x00\x20"
+"\x00\x30"
+
+# Some encoded domain names.
+"\x03foo\x00"
+"\x03foo\x03com\x00"
+"\x01a\x03foo\x03com\x00"
+"\x03bar\x00"
+
+# Message headers (Without message ID field).
+"\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00"
+# Truncated message, requiring TCP fallback.
+"\x83\x80\x00\x01\x00\x01\x00\x00\x00\x00"
+# Varying number of answers
+"\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
+"\x81\x80\x00\x01\x00\x02\x00\x00\x00\x00"
+"\x81\x80\x00\x01\x00\x10\x00\x00\x00\x00"
+
+# A, AAAA, and CNAME request suffixes - appear after domain name.
+"\x00\x01\x00\x01"
+"\x00\x1c\x00\x01"
+"\x00\x05\x00\x01"
+
+# A, AAAA, and CNAME requests for foo and foo.com.
+"\x03foo\x00\x00\x01\x00\x01"
+"\x03foo\x00\x00\x1c\x00\x01"
+"\x03foo\x00\x00\x05\x00\x01"
+"\x03foo\x03com\x00\x00\x01\x00\x01"
+"\x03foo\x03com\x00\x00\x1c\x00\x01"
+"\x03foo\x03com\x00\x00\x05\x00\x01"
+
+# All of the answers below are missing the name field, which should appear
+# first.
+
+# A answer suffixes, two different IP and TTLs.
+"\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x01\x02\x03\x04"
+"\x00\x01\x00\x01\x00\x00\x00\xFF\x00\x04\x02\x03\x04\x05"
+
+# AAAA answer suffixes, two different IPs and TTLs.
+"\x00\x1C\x00\x01\x00\x00\x00\x00\x00\x08\x01\x02\x03\x04\x05\x06\x07\x08"
+"\x00\x1C\x00\x01\x00\x00\x00\xFF\x00\x08\x02\x03\x04\x05\x06\x07\x08\x09"
+
+# CDATA answer suffixes, first two truncated as well.
+"\x00\x05\x00\x01\x00\x00\x00\xFF"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05\x03foo\x00"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05\x03bar\x00"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x09\x03foo\x03com\x00"
+
+
+# This part has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_dns_hosts_parse_fuzzer binary, RFC 1034 and RFC 1035.
+"all"
+"QNAME=ISI.EDU.,"
+"pointing"
+"C.ISI.EDU,"
+"C.ISI.EDU."
+"C.ISI.EDU)"
+"52.0.0.10.IN-ADDR.ARPA."
+"[RFC-799]"
+"XX.LCS.MIT.EDU,"
+"XX.LCS.MIT.EDU."
+"CPU"
+"C.ISI.EDU:"
+"A.B.C.D"
+"ARPA"
+"*.X.COM"
+"IN-ADDR.ARPA"
+"0"
+"\"*.X\","
+"resources"
+"supported"
+"string"
+"returning"
+"AXFR"
+"YALE.ARPA."
+"B.C.D,"
+"list"
+"large"
+"CNAME,"
+"ASCII"
+"M."
+"YALE.EDU."
+"direct"
+"IN,"
+"[RFC-1035]."
+"\"A\""
+"\"IN-ADDR.ARPA\"."
+"HINFO"
+"RFC-1031,"
+"QCLASS=IN,"
+"Z."
+"QCLASS=IN."
+"ARPANET"
+"QNAME=65.0.6.26.IN-ADDR.ARPA.,QCLASS=IN,QTYPE=PTR"
+"section"
+"51.0.0.10.IN-ADDR.ARPA."
+"|(VAXA.ISI.EDU,VENERA.ISI.EDU,"
+"DEC-2060"
+"version"
+"[RFC-1031]."
+"TTL"
+"[RFC-742]"
+"QTYPE=NS"
+"FTP"
+"hash"
+"QTYPE=CNAME,"
+"RFC-793,"
+"address"
+"SNAME,"
+"["
+"\"NAME/FINGER\","
+"SRI-NIC.ARPA."
+"SRI-NIC.ARPA,"
+"MB"
+"SRI-NIC.ARPA:"
+"QTYPE=CNAME"
+"NOT"
+"MX"
+"[RFC-821]"
+"useful"
+"select"
+"SRI-NIC.ARPA"
+"use"
+"SNAME"
+"from"
+"to"
+"positive"
+"(QCLASS)"
+"[RFC-1032]."
+"(DNS),"
+"TELNET,"
+"call"
+"B.X,"
+"memory"
+"type"
+"[RFC-973]"
+"RFC-822."
+"QNAME=SIR-NIC.ARPA,"
+"MILNET"
+"TOPS20"
+"[IEN-116,"
+"PTR)."
+"HOSTS.TXT,"
+"COMSAT,"
+"EXPIRE."
+"must"
+"EVEN"
+"|(C.ISI.EDU,SRI-NIC.ARPA"
+"QNAME=USC-ISIC.ARPA.,"
+"this"
+"CNAME."
+"work"
+"EDU,"
+"EDU."
+"EDU"
+"following"
+"root"
+"[RFC-1010]"
+"F."
+"J.,"
+"type."
+"high"
+"[RFC-953]"
+"US"
+"allowed"
+"serial"
+"IEN-116,"
+"[RFC-1032]"
+"[RFC-1033]."
+"write"
+"NOSC"
+"VENERA.ISI.EDU.|"
+"Z.X"
+"A"
+"QTYPE,"
+"[RFC-810]"
+"QTYPE."
+"may"
+"after"
+"RFC-1032,"
+"such"
+"data"
+"\"A"
+"a"
+"UDP"
+"short"
+"(CNAME)"
+"[RFC-1002]"
+"UDEL.EDU."
+"SRI,"
+"RFC-953."
+"RFC-953,"
+"TELNET)."
+"(HOSTS.TXT)"
+"ISI.EDU"
+"MIL"
+"[RFC-952]"
+"RFC-830,"
+"pointer"
+"its"
+"STYPE"
+"before"
+"HAS"
+"RR"
+"HOSTMASTER.SRI-NIC.ARPA."
+"65.0.6.26.IN-ADDR.ARPA,"
+"65.0.6.26.IN-ADDR.ARPA."
+"RD"
+"NAMES"
+"YALE"
+"QNAME=BRL.MIL,"
+"RA,"
+"ACM,"
+"QCLASS"
+"ARPA."
+"not"
+"(QTYPE),"
+"OPCODE=SQUERY,RESPONSE"
+"name"
+"RFC,"
+"mode"
+"RFC-799,"
+"ICS.UCI"
+"RESOLVERS"
+"A.X.COM"
+"SOME"
+"CNAME"
+"UDEL"
+"(QNAME),"
+"E."
+"space"
+"L."
+"MINIMUM"
+"RDATA"
+"supports"
+"REFRESH,"
+"HOSTMASTER@SRI-NIC.ARPA."
+"This"
+"SLIST:"
+"free"
+"RFC"
+"base"
+"RFC-952"
+"received."
+"SLIST."
+"SLIST,"
+"DATA."
+"thread"
+"YALE-BULLDOG.ARPA."
+"could"
+"QCLASS,"
+"times"
+"length"
+"HOSTMASTER@SRI-NIC.ARPA"
+"MIT.EDU"
+"already"
+"CONFIGURED"
+"number"
+"one"
+"RFC-"
+"Start"
+"ISI"
+"RFC."
+"RFC-1001,"
+"open"
+"CSNET"
+"size"
+"\""
+"X."
+"A.ISI.EDU"
+"TTL)"
+"\"HOSTNAME"
+"unknown"
+"top"
+"SERVERS"
+"too"
+"RFC-953]."
+"QTYPE"
+"BBN"
+"that"
+"completed"
+"XX"
+"*.A.X.COM"
+"QTYPE=MX,"
+"MX."
+"RD."
+"K."
+"target"
+"16"
+"Z.X),"
+"LCS.MIT.EDU"
+"[RFC-1031]"
+"and"
+"[RFC-805]"
+"[RFC-811]"
+"(RCODE)"
+"have"
+"need"
+"RESPONSE,"
+"null"
+"any"
+"contents"
+"|(SRI-NIC.ARPA,"
+"SOMEONE"
+"RESOURCE"
+"73.0.0.26.IN-ADDR.ARPA."
+"DARPA"
+"ACC.ARPA."
+"RFC-812,"
+"-"
+"mechanism"
+"internal"
+"take"
+"which"
+"MIL."
+"MIL,"
+"="
+"UCI"
+"RFC-742,"
+"multiple"
+"TCP/IP"
+"USC-ISIC.ARPA."
+"QNAME=USC-ISIC.ARPA,"
+"The"
+"]"
+"class"
+"D."
+"RFC-1010,"
+"D,"
+"RFC-805,"
+"AA,"
+"VAXA.ISI.EDU."
+"QNAME=ISI.EDU,"
+"MG)."
+"\"DOD"
+"QNAME=SRI-NIC.ARPA,"
+"text"
+"labels"
+"VENERA"
+"RFC-1033,"
+"INCORRECTLY"
+"[RFC-"
+"Z"
+"[RFC-952,"
+"RECORDS"
+"implementation"
+"true"
+"cache"
+"[RFC-768]"
+"XX.LCS.MIT.EDU"
+"only"
+"PVM@ISI.EDU."
+"RETRY,"
+"get"
+"PVM@ISI.EDU"
+"ACHILLES"
+"LOUIE.UDEL.EDU."
+"IN-ADDR"
+"resource"
+"A.ISI"
+"THIS"
+"NIC"
+"(via"
+"Zones"
+"RFC-920,"
+"J."
+"RFC-920."
+"common"
+"set"
+"configured"
+"QNAME=SRI-NIC.ARPA.,"
+"this,"
+"are"
+"RFC-883]."
+"A.ISI.EDU."
+"A.ISI.EDU)"
+"INTRODUCTION"
+"TCP"
+"MIT"
+"PC"
+"unable"
+"probably"
+"C.D,"
+"103.0.3.26.IN-ADDR.ARPA."
+"available"
+"C"
+"parent"
+"RFC-830]."
+"REFRESH"
+"UNIX"
+"CH)."
+"key"
+"52.0.0.10.IN-ADDR.ARPA"
+"P."
+"AND"
+"RFC-1002,"
+"OPCODE=SQUERY"
+"ROME.UCI"
+"LCS"
+"PDP-11/70"
+"ISI.EDU,"
+"ISI.EDU."
+"MAILB"
+"[RFC-974]"
+"CONCEPTS"
+"[RFC-920]"
+"SOA,"
+"RCODE=NE"
+"DNS."
+"DNS,"
+"poll"
+"UMN-REI-UC.ARPA."
+"SNAME."
+"[RFC-883]"
+"RFC-974,"
+"RFC-1002"
+"create"
+"S.,"
+"."
+"[RFC-830]"
+"expected"
+"empty"
+"RA"
+"CH"
+"(RD)"
+"VENERA.ISI.EDU."
+"SRI"
+"A.B.X,"
+"NAME"
+"value"
+"while"
+"error"
+"loop"
+"\"NICNAME/WHOIS\","
+"is"
+"CACHE"
+"FACILITIES"
+"in"
+"|(XX.LCS.MIT.EDU,"
+"SOA"
+"binary"
+"[RFC-819]"
+")"
+"SRI-NIC"
+"V."
+"\"A\"."
+"QNAME."
+"QNAME,"
+"units"
+"(NE)."
+"used"
+"IP"
+"\"."
+"IN"
+"ID"
+"IF"
+"task"
+"SCENARIO"
+"RFC-883,"
+"HOSTS.TXT"
+"Names"
+"RFC-811,"
+"the"
+"If"
+"being"
+"EXPIRE"
+"RFC-882,"
+"|ACHILLES.MIT.EDU)"
+"XX.COM."
+"(RDATA)"
+"source"
+"CSNET."
+"build"
+"ACHILLES.MIT.EDU."
+"format"
+"read"
+"(AA)"
+"ISIC.ARPA,"
+"SERIAL"
+"VAXA.ISI"
+"found,"
+"SLIST"
+"sorting"
+"OPCODE=SQUERY,"
+"OF"
+"AUTHORITY"
+"OS"
+"AA"
+"DOMAIN"
+"because"
+"SRI-NIC.ARPA.|"
+"some"
+"back"
+"growth"
+"USC-ISIC.ARPA,"
+"RFC-821,"
+"happens"
+"for"
+"W."
+"RFC-883"
+"X.COM"
+"avoid"
+"does"
+"allocate"
+"COM"
+"assuming"
+"BRL"
+"PTR"
+"[RFC-793]"
+"be"
+"QCLASS=*"
+"MIT.EDU."
+"by"
+"C."
+"on"
+"SCLASS"
+"of"
+"FTP)"
+"FTP,"
+"UK"
+"or"
+"ACC"
+"SBELT."
+"SBELT,"
+"No"
+"(SBELT)"
+"A.X.COM."
+"A.X.COM,"
+"REFERENCES"
+"USC-ISIC.ARPA"
+"[RFC-1001]"
+"RESPONSE"
+"transfer"
+"support"
+"*"
+"NE"
+"long"
+"QTYPE=*"
+"start"
+"C.ISI.EDU"
+"TTL,"
+"RD,"
+"\"4.3.2.1.IN-ADDR.ARPA\"."
+"NS"
+"was"
+"RR."
+"RR,"
+"QTYPE=A"
+"MEMO"
+"but"
+"QNAME"
+"[RFC-1001,"
+"DNS"
+"line"
+"trying"
+"with"
+"TCP/UDP"
+"count"
+"SBELT"
+"(NIC)"
+"up"
+"classes:"
+"RFC-768,"
+"[IEN-116]"
+"VAXA"
+"NETBIOS"
+"called"
+"delete"
+"CIC"
+"USC-"
+"RETRY"
+"RFC-810,"
+"RECORDS,"
+"an"
+"To"
+"as"
+"at"
+"file"
+"[RFC-812]"
+"physical"
+"X.COM,"
+"no"
+"[RFC-882,"
+"when"
+"A,"
+"virtual"
+"RFC-952,"
+"RFC-952."
+"valid"
+"test"
+"you"
+"IP/TCP"
+"STATUS"
+"requested"
+"[RFC-974"
+"SPACE"
+"QNAME=SIR-NIC.ARPA.,"
+"RFC-819,"
+"variable"
+"[RFC-882]"
+"BIBLIOGRAPHY"
+"[RFC-1033]"
+"US."
+"\"MILNET"
+"As"
+"RFC-973,"
+"RFC-882"
+"QTYPE=MX"
+"4.0.10.18.IN-ADDR.ARPA."
+"FOO.F.ISI.ARPA,"
+"Assuming"
+"[RFC-1034],"
+"[RFC-1034]."
+"UNIX\""
+"IMPLEMENTATION"
+"EGP."
+"ANCOUNT"
+"@"
+"P"
+"TXT-DATA"
+"RMAILBX"
+"|QTYPE=A,"
+"QDCOUNT"
+"[RFC-1010]."
+"EMAILBX"
+"IN-"
+"OPCODE=IQUERY,"
+"MX)"
+"ID=997"
+"\"VENERA.ISI.EDU\";"
+"OPCODE"
+"MILNET-GW.ISI.EDU."
+"52.0.2.10.IN-ADDR.ARPA."
+"objects"
+"MD"
+"MG"
+"MF"
+"MR"
+"QNAME=10.IN-ADDR.ARPA."
+"S."
+"GGP"
+"few"
+"QTYPE=PTR,"
+"MD,"
+"F"
+"[RFC-974]."
+"MGMNAME"
+"GW.LCS.MIT.EDU."
+"GW.LCS.MIT.EDU,"
+"V"
+"\\DDD"
+"ALL"
+"10.IN-ADDR.ARPA."
+"closing"
+"EXCHANGE."
+"MADNAME."
+"$ORIGIN"
+"HIS"
+"26.IN-ADDR.ARPA."
+"(MD)"
+"QTYPES"
+"PROTOCOL"
+"26.IN-ADDR.ARPA"
+"NSCOUNT"
+"(MR)"
+"PREFERENCE"
+"<BIT"
+"$INCLUDE."
+"MR)"
+"VAXA.ISI.EDU"
+"77.0.0.10.IN-ADDR.ARPA."
+"\"IBM-PC"
+"$INCLUDE"
+"SERVER"
+"18.IN-ADDR.ARPA."
+"ADDRESS"
+"Check"
+"static"
+"GW.ISI.EDU."
+"(QNAME)."
+"GW.ISI.EDU,"
+"F.ISI.ARPA,"
+"F.ISI.ARPA."
+"time."
+"PTRDNAME"
+"HOSTMASTER@SRI-"
+"(STATUS)"
+"(MINFO)"
+"(MG)"
+"QCLASS."
+"(HS)"
+"X,"
+"MNAME"
+"QNAME=VENERA.ISI.EDU"
+"MASTER"
+"(IN)"
+"KNOWS."
+"RNAME"
+"|QR|"
+"VAXA.ISI.EDU,"
+"R"
+"1)"
+"ARCOUNT"
+"RCODE"
+"NEWNAME"
+"CLASS"
+"begin"
+"(MF)."
+"Common"
+"<RDATA>"
+"QR"
+"average"
+"QNAME=6.0.0.10.IN-ADDR.ARPA,"
+"WKS"
+"SYSTEM,"
+"MADNAME"
+"ARPANET,"
+"MINFO"
+"DEFINITIONS"
+"failed"
+"[RFC-1034]"
+"(QCLASS),"
+"SPECIFICATION"
+"X"
+"THE"
+"MILNET."
+"MILNET-"
+"bytes"
+"(MX)"
+"NSDNAME"
+"10.IN-ADDR.ARPA"
+"|AA|TC|RD|RA|"
+"QTYPE=A,"
+"corruption"
+"FOO.F.ISI.ARPA"
+"(QUERY)"
+"MF,"
+"FOO"
+"CURLEY"
+"X.Y,"
+"AXFR,"
+"S"
+"MAILA"
+"exceeds"
+"ISI.EDU:"
+"103.0.0.26.IN-ADDR.ARPA."
+"MOE"
+"[RFC-822]."
+"CHAOS"
+"NAMEDROPPERS@SRI-NIC.ARPA"
+"SOA."
+"RESOLVER"
+"A.X,"
+"EXCHANGE"
+"SMTP"
+"QCLASS=*,"
+"CS"
+"$ORIGIN,"
+"B.X"
+"(MB,"
+"TYPE"
+"Size"
+"parse"
+"ADDR.ARPA"
+"(SMTP)."
+"key."
+"MAP>"
+"OWN"
+"VENERA.ISI.EDU"
+"DDD."
+"MB."
+"NS,"
+"I"
+"OPCODE=RESPONSE,"
+"ARPA,"
+"WITHIN"
+"tables"
+"unsigned"
+"LARRY"
+"D"
+"\\X"
+"WHICH"
+"(IQUERY)"
+"QCLASS=IN"
+"discarded"
+"6.0.0.10.IN-ADDR.ARPA."
+"MAIL"
+"QTYPE=MAILB"
+"HS"
+"SUPPORT"
+"STOOGES"
+"X.Y"
+"/"
+"(SLIST)."
+"O"
+"OS,"
+"OFFSET"
+"FILES"
+"RR),"
+"$INCLUDE,"
+"guard"
+"[<TTL>]"
+"CRLF"
+"Error"
+"ERRORS-TO:"
+"22.0.2.10.IN-ADDR.ARPA."
+"default"
+"MESSAGES"
+"signed"
+"<SUBSYS>ISI-MAILBOXES.TXT"
+"MULTICS.MIT.EDU."
+"NULL"
+"application"
+"TXT"
+"TC"
+"PROTOCOL=TCP"
+"UDP."
+"UDP,"
+"F.ISI.ARPA"
+"(EXPERIMENTAL)"
+"RDLENGTH"
+"NIC.ARPA"
+
diff --git a/net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict b/net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict
new file mode 100644
index 0000000..eb26765b
--- /dev/null
+++ b/net/data/fuzzer_dictionaries/net_dns_record_fuzzer.dict
@@ -0,0 +1,843 @@
+# 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.
+
+# Fuzzer dictionary targetting DNS responses.
+
+# Some 16-bit big-endian values. Useful in a number of fields. Includes
+# A, AAAA, and CNAME IDs, low values for record counts, and multiples of
+# lengths of A and AAAA data fields.
+"\x00\x00"
+"\x00\x01"
+"\x00\x02"
+"\x00\x03"
+"\x00\x04"
+"\x00\x05"
+"\x00\x08"
+"\x00\x0C"
+"\x00\x10"
+"\x00\x1C"
+"\x00\x20"
+"\x00\x30"
+
+# Some encoded domain names.
+"\x03foo\x00"
+"\x03foo\x03com\x00"
+"\x01a\x03foo\x03com\x00"
+"\x03bar\x00"
+
+# Message headers (Without message ID field).
+"\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00"
+# Truncated message, requiring TCP fallback.
+"\x83\x80\x00\x01\x00\x01\x00\x00\x00\x00"
+# Varying number of answers
+"\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
+"\x81\x80\x00\x01\x00\x02\x00\x00\x00\x00"
+"\x81\x80\x00\x01\x00\x10\x00\x00\x00\x00"
+
+# A, AAAA, and CNAME request suffixes - appear after domain name.
+"\x00\x01\x00\x01"
+"\x00\x1c\x00\x01"
+"\x00\x05\x00\x01"
+
+# A, AAAA, and CNAME requests for foo and foo.com.
+"\x03foo\x00\x00\x01\x00\x01"
+"\x03foo\x00\x00\x1c\x00\x01"
+"\x03foo\x00\x00\x05\x00\x01"
+"\x03foo\x03com\x00\x00\x01\x00\x01"
+"\x03foo\x03com\x00\x00\x1c\x00\x01"
+"\x03foo\x03com\x00\x00\x05\x00\x01"
+
+# All of the answers below are missing the name field, which should appear
+# first.
+
+# A answer suffixes, two different IP and TTLs.
+"\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x01\x02\x03\x04"
+"\x00\x01\x00\x01\x00\x00\x00\xFF\x00\x04\x02\x03\x04\x05"
+
+# AAAA answer suffixes, two different IPs and TTLs.
+"\x00\x1C\x00\x01\x00\x00\x00\x00\x00\x08\x01\x02\x03\x04\x05\x06\x07\x08"
+"\x00\x1C\x00\x01\x00\x00\x00\xFF\x00\x08\x02\x03\x04\x05\x06\x07\x08\x09"
+
+# CDATA answer suffixes, first two truncated as well.
+"\x00\x05\x00\x01\x00\x00\x00\xFF"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05\x03foo\x00"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05\x03bar\x00"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x09\x03foo\x03com\x00"
+
+
+# This part has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_dns_record_fuzzer binary, RFC 1034 and RFC 1035.
+"all"
+"QNAME=ISI.EDU.,"
+"pointing"
+"C.ISI.EDU,"
+"C.ISI.EDU."
+"C.ISI.EDU)"
+"52.0.0.10.IN-ADDR.ARPA."
+"[RFC-799]"
+"XX.LCS.MIT.EDU,"
+"XX.LCS.MIT.EDU."
+"CPU"
+"C.ISI.EDU:"
+"A.B.C.D"
+"ARPA"
+"*.X.COM"
+"IN-ADDR.ARPA"
+"0"
+"\"*.X\","
+"resources"
+"supported"
+"string"
+"returning"
+"AXFR"
+"YALE.ARPA."
+"B.C.D,"
+"list"
+"large"
+"CNAME,"
+"ASCII"
+"M."
+"YALE.EDU."
+"direct"
+"IN,"
+"[RFC-1035]."
+"\"A\""
+"\"IN-ADDR.ARPA\"."
+"HINFO"
+"RFC-1031,"
+"QCLASS=IN,"
+"Z."
+"QCLASS=IN."
+"ARPANET"
+"QNAME=65.0.6.26.IN-ADDR.ARPA.,QCLASS=IN,QTYPE=PTR"
+"section"
+"51.0.0.10.IN-ADDR.ARPA."
+"|(VAXA.ISI.EDU,VENERA.ISI.EDU,"
+"DEC-2060"
+"version"
+"[RFC-1031]."
+"TTL"
+"[RFC-742]"
+"QTYPE=NS"
+"FTP"
+"hash"
+"QTYPE=CNAME,"
+"RFC-793,"
+"address"
+"SNAME,"
+"["
+"\"NAME/FINGER\","
+"SRI-NIC.ARPA."
+"SRI-NIC.ARPA,"
+"MB"
+"SRI-NIC.ARPA:"
+"QTYPE=CNAME"
+"NOT"
+"MX"
+"[RFC-821]"
+"useful"
+"select"
+"SRI-NIC.ARPA"
+"use"
+"SNAME"
+"from"
+"to"
+"positive"
+"(QCLASS)"
+"[RFC-1032]."
+"(DNS),"
+"TELNET,"
+"call"
+"B.X,"
+"memory"
+"type"
+"[RFC-973]"
+"RFC-822."
+"QNAME=SIR-NIC.ARPA,"
+"MILNET"
+"TOPS20"
+"[IEN-116,"
+"PTR)."
+"HOSTS.TXT,"
+"COMSAT,"
+"EXPIRE."
+"must"
+"EVEN"
+"|(C.ISI.EDU,SRI-NIC.ARPA"
+"QNAME=USC-ISIC.ARPA.,"
+"this"
+"CNAME."
+"work"
+"EDU,"
+"EDU."
+"EDU"
+"following"
+"root"
+"[RFC-1010]"
+"F."
+"J.,"
+"type."
+"high"
+"[RFC-953]"
+"US"
+"allowed"
+"serial"
+"IEN-116,"
+"[RFC-1032]"
+"[RFC-1033]."
+"write"
+"NOSC"
+"VENERA.ISI.EDU.|"
+"Z.X"
+"A"
+"QTYPE,"
+"[RFC-810]"
+"QTYPE."
+"may"
+"after"
+"RFC-1032,"
+"such"
+"data"
+"\"A"
+"a"
+"UDP"
+"short"
+"(CNAME)"
+"[RFC-1002]"
+"UDEL.EDU."
+"SRI,"
+"RFC-953."
+"RFC-953,"
+"TELNET)."
+"(HOSTS.TXT)"
+"ISI.EDU"
+"MIL"
+"[RFC-952]"
+"RFC-830,"
+"pointer"
+"its"
+"STYPE"
+"before"
+"HAS"
+"RR"
+"HOSTMASTER.SRI-NIC.ARPA."
+"65.0.6.26.IN-ADDR.ARPA,"
+"65.0.6.26.IN-ADDR.ARPA."
+"RD"
+"NAMES"
+"YALE"
+"QNAME=BRL.MIL,"
+"RA,"
+"ACM,"
+"QCLASS"
+"ARPA."
+"not"
+"(QTYPE),"
+"OPCODE=SQUERY,RESPONSE"
+"name"
+"RFC,"
+"mode"
+"RFC-799,"
+"ICS.UCI"
+"RESOLVERS"
+"A.X.COM"
+"SOME"
+"CNAME"
+"UDEL"
+"(QNAME),"
+"E."
+"space"
+"L."
+"MINIMUM"
+"RDATA"
+"supports"
+"REFRESH,"
+"HOSTMASTER@SRI-NIC.ARPA."
+"This"
+"SLIST:"
+"free"
+"RFC"
+"base"
+"RFC-952"
+"received."
+"SLIST."
+"SLIST,"
+"DATA."
+"thread"
+"YALE-BULLDOG.ARPA."
+"could"
+"QCLASS,"
+"times"
+"length"
+"HOSTMASTER@SRI-NIC.ARPA"
+"MIT.EDU"
+"already"
+"CONFIGURED"
+"number"
+"one"
+"RFC-"
+"Start"
+"ISI"
+"RFC."
+"RFC-1001,"
+"open"
+"CSNET"
+"size"
+"\""
+"X."
+"A.ISI.EDU"
+"TTL)"
+"\"HOSTNAME"
+"unknown"
+"top"
+"SERVERS"
+"too"
+"RFC-953]."
+"QTYPE"
+"BBN"
+"that"
+"completed"
+"XX"
+"*.A.X.COM"
+"QTYPE=MX,"
+"MX."
+"RD."
+"K."
+"target"
+"16"
+"Z.X),"
+"LCS.MIT.EDU"
+"[RFC-1031]"
+"and"
+"[RFC-805]"
+"[RFC-811]"
+"(RCODE)"
+"have"
+"need"
+"RESPONSE,"
+"null"
+"any"
+"contents"
+"|(SRI-NIC.ARPA,"
+"SOMEONE"
+"RESOURCE"
+"73.0.0.26.IN-ADDR.ARPA."
+"DARPA"
+"ACC.ARPA."
+"RFC-812,"
+"-"
+"mechanism"
+"internal"
+"take"
+"which"
+"MIL."
+"MIL,"
+"="
+"UCI"
+"RFC-742,"
+"multiple"
+"TCP/IP"
+"USC-ISIC.ARPA."
+"QNAME=USC-ISIC.ARPA,"
+"The"
+"]"
+"class"
+"D."
+"RFC-1010,"
+"D,"
+"RFC-805,"
+"AA,"
+"VAXA.ISI.EDU."
+"QNAME=ISI.EDU,"
+"MG)."
+"\"DOD"
+"QNAME=SRI-NIC.ARPA,"
+"text"
+"labels"
+"VENERA"
+"RFC-1033,"
+"INCORRECTLY"
+"[RFC-"
+"Z"
+"[RFC-952,"
+"RECORDS"
+"implementation"
+"true"
+"cache"
+"[RFC-768]"
+"XX.LCS.MIT.EDU"
+"only"
+"PVM@ISI.EDU."
+"RETRY,"
+"get"
+"PVM@ISI.EDU"
+"ACHILLES"
+"LOUIE.UDEL.EDU."
+"IN-ADDR"
+"resource"
+"A.ISI"
+"THIS"
+"NIC"
+"(via"
+"Zones"
+"RFC-920,"
+"J."
+"RFC-920."
+"common"
+"set"
+"configured"
+"QNAME=SRI-NIC.ARPA.,"
+"this,"
+"are"
+"RFC-883]."
+"A.ISI.EDU."
+"A.ISI.EDU)"
+"INTRODUCTION"
+"TCP"
+"MIT"
+"PC"
+"unable"
+"probably"
+"C.D,"
+"103.0.3.26.IN-ADDR.ARPA."
+"available"
+"C"
+"parent"
+"RFC-830]."
+"REFRESH"
+"UNIX"
+"CH)."
+"key"
+"52.0.0.10.IN-ADDR.ARPA"
+"P."
+"AND"
+"RFC-1002,"
+"OPCODE=SQUERY"
+"ROME.UCI"
+"LCS"
+"PDP-11/70"
+"ISI.EDU,"
+"ISI.EDU."
+"MAILB"
+"[RFC-974]"
+"CONCEPTS"
+"[RFC-920]"
+"SOA,"
+"RCODE=NE"
+"DNS."
+"DNS,"
+"poll"
+"UMN-REI-UC.ARPA."
+"SNAME."
+"[RFC-883]"
+"RFC-974,"
+"RFC-1002"
+"create"
+"S.,"
+"."
+"[RFC-830]"
+"expected"
+"empty"
+"RA"
+"CH"
+"(RD)"
+"VENERA.ISI.EDU."
+"SRI"
+"A.B.X,"
+"NAME"
+"value"
+"while"
+"error"
+"loop"
+"\"NICNAME/WHOIS\","
+"is"
+"CACHE"
+"FACILITIES"
+"in"
+"|(XX.LCS.MIT.EDU,"
+"SOA"
+"binary"
+"[RFC-819]"
+")"
+"SRI-NIC"
+"V."
+"\"A\"."
+"QNAME."
+"QNAME,"
+"units"
+"(NE)."
+"used"
+"IP"
+"\"."
+"IN"
+"ID"
+"IF"
+"task"
+"SCENARIO"
+"RFC-883,"
+"HOSTS.TXT"
+"Names"
+"RFC-811,"
+"the"
+"If"
+"being"
+"EXPIRE"
+"RFC-882,"
+"|ACHILLES.MIT.EDU)"
+"XX.COM."
+"(RDATA)"
+"source"
+"CSNET."
+"build"
+"ACHILLES.MIT.EDU."
+"format"
+"read"
+"(AA)"
+"ISIC.ARPA,"
+"SERIAL"
+"VAXA.ISI"
+"found,"
+"SLIST"
+"sorting"
+"OPCODE=SQUERY,"
+"OF"
+"AUTHORITY"
+"OS"
+"AA"
+"DOMAIN"
+"because"
+"SRI-NIC.ARPA.|"
+"some"
+"back"
+"growth"
+"USC-ISIC.ARPA,"
+"RFC-821,"
+"happens"
+"for"
+"W."
+"RFC-883"
+"X.COM"
+"avoid"
+"does"
+"allocate"
+"COM"
+"assuming"
+"BRL"
+"PTR"
+"[RFC-793]"
+"be"
+"QCLASS=*"
+"MIT.EDU."
+"by"
+"C."
+"on"
+"SCLASS"
+"of"
+"FTP)"
+"FTP,"
+"UK"
+"or"
+"ACC"
+"SBELT."
+"SBELT,"
+"No"
+"(SBELT)"
+"A.X.COM."
+"A.X.COM,"
+"REFERENCES"
+"USC-ISIC.ARPA"
+"[RFC-1001]"
+"RESPONSE"
+"transfer"
+"support"
+"*"
+"NE"
+"long"
+"QTYPE=*"
+"start"
+"C.ISI.EDU"
+"TTL,"
+"RD,"
+"\"4.3.2.1.IN-ADDR.ARPA\"."
+"NS"
+"was"
+"RR."
+"RR,"
+"QTYPE=A"
+"MEMO"
+"but"
+"QNAME"
+"[RFC-1001,"
+"DNS"
+"line"
+"trying"
+"with"
+"TCP/UDP"
+"count"
+"SBELT"
+"(NIC)"
+"up"
+"classes:"
+"RFC-768,"
+"[IEN-116]"
+"VAXA"
+"NETBIOS"
+"called"
+"delete"
+"CIC"
+"USC-"
+"RETRY"
+"RFC-810,"
+"RECORDS,"
+"an"
+"To"
+"as"
+"at"
+"file"
+"[RFC-812]"
+"physical"
+"X.COM,"
+"no"
+"[RFC-882,"
+"when"
+"A,"
+"virtual"
+"RFC-952,"
+"RFC-952."
+"valid"
+"test"
+"you"
+"IP/TCP"
+"STATUS"
+"requested"
+"[RFC-974"
+"SPACE"
+"QNAME=SIR-NIC.ARPA.,"
+"RFC-819,"
+"variable"
+"[RFC-882]"
+"BIBLIOGRAPHY"
+"[RFC-1033]"
+"US."
+"\"MILNET"
+"As"
+"RFC-973,"
+"RFC-882"
+"QTYPE=MX"
+"4.0.10.18.IN-ADDR.ARPA."
+"FOO.F.ISI.ARPA,"
+"Assuming"
+"[RFC-1034],"
+"[RFC-1034]."
+"UNIX\""
+"IMPLEMENTATION"
+"EGP."
+"ANCOUNT"
+"@"
+"P"
+"TXT-DATA"
+"RMAILBX"
+"|QTYPE=A,"
+"QDCOUNT"
+"[RFC-1010]."
+"EMAILBX"
+"IN-"
+"OPCODE=IQUERY,"
+"MX)"
+"ID=997"
+"\"VENERA.ISI.EDU\";"
+"OPCODE"
+"MILNET-GW.ISI.EDU."
+"52.0.2.10.IN-ADDR.ARPA."
+"objects"
+"MD"
+"MG"
+"MF"
+"MR"
+"QNAME=10.IN-ADDR.ARPA."
+"S."
+"GGP"
+"few"
+"QTYPE=PTR,"
+"MD,"
+"F"
+"[RFC-974]."
+"MGMNAME"
+"GW.LCS.MIT.EDU."
+"GW.LCS.MIT.EDU,"
+"V"
+"\\DDD"
+"ALL"
+"10.IN-ADDR.ARPA."
+"closing"
+"EXCHANGE."
+"MADNAME."
+"$ORIGIN"
+"HIS"
+"26.IN-ADDR.ARPA."
+"(MD)"
+"QTYPES"
+"PROTOCOL"
+"26.IN-ADDR.ARPA"
+"NSCOUNT"
+"(MR)"
+"PREFERENCE"
+"<BIT"
+"$INCLUDE."
+"MR)"
+"VAXA.ISI.EDU"
+"77.0.0.10.IN-ADDR.ARPA."
+"\"IBM-PC"
+"$INCLUDE"
+"SERVER"
+"18.IN-ADDR.ARPA."
+"ADDRESS"
+"Check"
+"static"
+"GW.ISI.EDU."
+"(QNAME)."
+"GW.ISI.EDU,"
+"F.ISI.ARPA,"
+"F.ISI.ARPA."
+"time."
+"PTRDNAME"
+"HOSTMASTER@SRI-"
+"(STATUS)"
+"(MINFO)"
+"(MG)"
+"QCLASS."
+"(HS)"
+"X,"
+"MNAME"
+"QNAME=VENERA.ISI.EDU"
+"MASTER"
+"(IN)"
+"KNOWS."
+"RNAME"
+"|QR|"
+"VAXA.ISI.EDU,"
+"R"
+"1)"
+"ARCOUNT"
+"RCODE"
+"NEWNAME"
+"CLASS"
+"begin"
+"(MF)."
+"Common"
+"<RDATA>"
+"QR"
+"average"
+"QNAME=6.0.0.10.IN-ADDR.ARPA,"
+"WKS"
+"SYSTEM,"
+"MADNAME"
+"ARPANET,"
+"MINFO"
+"DEFINITIONS"
+"failed"
+"[RFC-1034]"
+"(QCLASS),"
+"SPECIFICATION"
+"X"
+"THE"
+"MILNET."
+"MILNET-"
+"bytes"
+"(MX)"
+"NSDNAME"
+"10.IN-ADDR.ARPA"
+"|AA|TC|RD|RA|"
+"QTYPE=A,"
+"corruption"
+"FOO.F.ISI.ARPA"
+"(QUERY)"
+"MF,"
+"FOO"
+"CURLEY"
+"X.Y,"
+"AXFR,"
+"S"
+"MAILA"
+"exceeds"
+"ISI.EDU:"
+"103.0.0.26.IN-ADDR.ARPA."
+"MOE"
+"[RFC-822]."
+"CHAOS"
+"NAMEDROPPERS@SRI-NIC.ARPA"
+"SOA."
+"RESOLVER"
+"A.X,"
+"EXCHANGE"
+"SMTP"
+"QCLASS=*,"
+"CS"
+"$ORIGIN,"
+"B.X"
+"(MB,"
+"TYPE"
+"Size"
+"parse"
+"ADDR.ARPA"
+"(SMTP)."
+"key."
+"MAP>"
+"OWN"
+"VENERA.ISI.EDU"
+"DDD."
+"MB."
+"NS,"
+"I"
+"OPCODE=RESPONSE,"
+"ARPA,"
+"WITHIN"
+"tables"
+"unsigned"
+"LARRY"
+"D"
+"\\X"
+"WHICH"
+"(IQUERY)"
+"QCLASS=IN"
+"discarded"
+"6.0.0.10.IN-ADDR.ARPA."
+"MAIL"
+"QTYPE=MAILB"
+"HS"
+"SUPPORT"
+"STOOGES"
+"X.Y"
+"/"
+"(SLIST)."
+"O"
+"OS,"
+"OFFSET"
+"FILES"
+"RR),"
+"$INCLUDE,"
+"guard"
+"[<TTL>]"
+"CRLF"
+"Error"
+"ERRORS-TO:"
+"22.0.2.10.IN-ADDR.ARPA."
+"default"
+"MESSAGES"
+"signed"
+"<SUBSYS>ISI-MAILBOXES.TXT"
+"MULTICS.MIT.EDU."
+"NULL"
+"application"
+"TXT"
+"TC"
+"PROTOCOL=TCP"
+"UDP."
+"UDP,"
+"F.ISI.ARPA"
+"(EXPERIMENTAL)"
+"RDLENGTH"
+"NIC.ARPA"
+
diff --git a/net/data/fuzzer_dictionaries/net_get_domain_and_registry_fuzzer.dict b/net/data/fuzzer_dictionaries/net_get_domain_and_registry_fuzzer.dict
new file mode 100644
index 0000000..b5c58a5
--- /dev/null
+++ b/net/data/fuzzer_dictionaries/net_get_domain_and_registry_fuzzer.dict
@@ -0,0 +1,848 @@
+# 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.
+
+# Fuzzer dictionary targetting DNS responses.
+
+# Some 16-bit big-endian values. Useful in a number of fields. Includes
+# A, AAAA, and CNAME IDs, low values for record counts, and multiples of
+# lengths of A and AAAA data fields.
+"\x00\x00"
+"\x00\x01"
+"\x00\x02"
+"\x00\x03"
+"\x00\x04"
+"\x00\x05"
+"\x00\x08"
+"\x00\x0C"
+"\x00\x10"
+"\x00\x1C"
+"\x00\x20"
+"\x00\x30"
+
+# Some encoded domain names.
+"\x03foo\x00"
+"\x03foo\x03com\x00"
+"\x01a\x03foo\x03com\x00"
+"\x03bar\x00"
+
+# Message headers (Without message ID field).
+"\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00"
+# Truncated message, requiring TCP fallback.
+"\x83\x80\x00\x01\x00\x01\x00\x00\x00\x00"
+# Varying number of answers
+"\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
+"\x81\x80\x00\x01\x00\x02\x00\x00\x00\x00"
+"\x81\x80\x00\x01\x00\x10\x00\x00\x00\x00"
+
+# A, AAAA, and CNAME request suffixes - appear after domain name.
+"\x00\x01\x00\x01"
+"\x00\x1c\x00\x01"
+"\x00\x05\x00\x01"
+
+# A, AAAA, and CNAME requests for foo and foo.com.
+"\x03foo\x00\x00\x01\x00\x01"
+"\x03foo\x00\x00\x1c\x00\x01"
+"\x03foo\x00\x00\x05\x00\x01"
+"\x03foo\x03com\x00\x00\x01\x00\x01"
+"\x03foo\x03com\x00\x00\x1c\x00\x01"
+"\x03foo\x03com\x00\x00\x05\x00\x01"
+
+# All of the answers below are missing the name field, which should appear
+# first.
+
+# A answer suffixes, two different IP and TTLs.
+"\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x01\x02\x03\x04"
+"\x00\x01\x00\x01\x00\x00\x00\xFF\x00\x04\x02\x03\x04\x05"
+
+# AAAA answer suffixes, two different IPs and TTLs.
+"\x00\x1C\x00\x01\x00\x00\x00\x00\x00\x08\x01\x02\x03\x04\x05\x06\x07\x08"
+"\x00\x1C\x00\x01\x00\x00\x00\xFF\x00\x08\x02\x03\x04\x05\x06\x07\x08\x09"
+
+# CDATA answer suffixes, first two truncated as well.
+"\x00\x05\x00\x01\x00\x00\x00\xFF"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05\x03foo\x00"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05\x03bar\x00"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x09\x03foo\x03com\x00"
+
+
+# This part has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_get_domain_and_registry_fuzzer binary, RFC 1034 and RFC 1035.
+"all"
+"QNAME=ISI.EDU.,"
+"pointing"
+"C.ISI.EDU,"
+"C.ISI.EDU."
+"C.ISI.EDU)"
+"52.0.0.10.IN-ADDR.ARPA."
+"[RFC-799]"
+"XX.LCS.MIT.EDU,"
+"XX.LCS.MIT.EDU."
+"CPU"
+"C.ISI.EDU:"
+"A.B.C.D"
+"ARPA"
+"*.X.COM"
+"IN-ADDR.ARPA"
+"to"
+"\"*.X\","
+"resources"
+"supported"
+"string"
+"returning"
+"AXFR"
+"YALE.ARPA."
+"B.C.D,"
+"list"
+"large"
+"CNAME,"
+"ASCII"
+"M."
+"YALE.EDU."
+"direct"
+"IN,"
+"[RFC-1035]."
+"\"A\""
+"\"IN-ADDR.ARPA\"."
+"HINFO"
+"RFC-1031,"
+"QCLASS=IN,"
+"Z."
+"QCLASS=IN."
+"ARPANET"
+"QNAME=65.0.6.26.IN-ADDR.ARPA.,QCLASS=IN,QTYPE=PTR"
+"section"
+"51.0.0.10.IN-ADDR.ARPA."
+"|(VAXA.ISI.EDU,VENERA.ISI.EDU,"
+"DEC-2060"
+"version"
+"[RFC-1031]."
+"TTL"
+"[RFC-742]"
+"QTYPE=NS"
+"FTP"
+"hash"
+"QTYPE=CNAME,"
+"RFC-793,"
+"address"
+"SNAME,"
+"["
+"\"NAME/FINGER\","
+"SRI-NIC.ARPA."
+"SRI-NIC.ARPA,"
+"MB"
+"SRI-NIC.ARPA:"
+"QTYPE=CNAME"
+"NOT"
+"MX"
+"[RFC-821]"
+"useful"
+"select"
+"SRI-NIC.ARPA"
+"use"
+"SNAME"
+"from"
+"0"
+"positive"
+"(QCLASS)"
+"[RFC-1032]."
+"(DNS),"
+"TELNET,"
+"call"
+"B.X,"
+"memory"
+"type"
+"[RFC-973]"
+"RFC-822."
+"QNAME=SIR-NIC.ARPA,"
+"MILNET"
+"TOPS20"
+"[IEN-116,"
+"PTR)."
+"HOSTS.TXT,"
+"COMSAT,"
+"EXPIRE."
+"must"
+"EVEN"
+"|(C.ISI.EDU,SRI-NIC.ARPA"
+"QNAME=USC-ISIC.ARPA.,"
+"this"
+"CNAME."
+"work"
+"EDU,"
+"EDU."
+"EDU"
+"following"
+"root"
+"[RFC-1010]"
+"F."
+"J.,"
+"type."
+"high"
+"[RFC-953]"
+"US"
+"allowed"
+"serial"
+"IEN-116,"
+"[RFC-1032]"
+"end"
+"[RFC-1033]."
+"write"
+"NOSC"
+"VENERA.ISI.EDU.|"
+"Z.X"
+"A"
+"QTYPE,"
+"[RFC-810]"
+"QTYPE."
+"may"
+"after"
+"RFC-1032,"
+"such"
+"data"
+"\"A"
+"a"
+"UDP"
+"short"
+"(CNAME)"
+"[RFC-1002]"
+"UDEL.EDU."
+"SRI,"
+"RFC-953."
+"RFC-953,"
+"TELNET)."
+"(HOSTS.TXT)"
+"ISI.EDU"
+"MIL"
+"[RFC-952]"
+"RFC-830,"
+"pointer"
+"its"
+"STYPE"
+"before"
+"HAS"
+"RR"
+"HOSTMASTER.SRI-NIC.ARPA."
+"65.0.6.26.IN-ADDR.ARPA,"
+"65.0.6.26.IN-ADDR.ARPA."
+"RD"
+"NAMES"
+"YALE"
+"QNAME=BRL.MIL,"
+"RA,"
+"ACM,"
+"QCLASS"
+"ARPA."
+"not"
+"(QTYPE),"
+"OPCODE=SQUERY,RESPONSE"
+"name"
+"RFC,"
+"mode"
+"RFC-799,"
+"ICS.UCI"
+"RESOLVERS"
+"A.X.COM"
+"SOME"
+"CNAME"
+"UDEL"
+"(QNAME),"
+"E."
+"space"
+"L."
+"MINIMUM"
+"RDATA"
+"supports"
+"REFRESH,"
+"HOSTMASTER@SRI-NIC.ARPA."
+"This"
+"SLIST:"
+"free"
+"RFC"
+"base"
+"RFC-952"
+"received."
+"SLIST."
+"SLIST,"
+"DATA."
+"thread"
+"YALE-BULLDOG.ARPA."
+"could"
+"QCLASS,"
+"times"
+"length"
+"HOSTMASTER@SRI-NIC.ARPA"
+"MIT.EDU"
+"already"
+"CONFIGURED"
+"number"
+"one"
+"RFC-"
+"Start"
+"ISI"
+"RFC."
+"RFC-1001,"
+"open"
+"CSNET"
+"size"
+"\""
+"X."
+"A.ISI.EDU"
+"TTL)"
+"\"HOSTNAME"
+"unknown"
+"top"
+"SERVERS"
+"2"
+"too"
+"RFC-953]."
+"QTYPE"
+"BBN"
+"that"
+"completed"
+"XX"
+"*.A.X.COM"
+"QTYPE=MX,"
+"MX."
+"RD."
+"K."
+"target"
+"16"
+"Z.X),"
+"LCS.MIT.EDU"
+"[RFC-1031]"
+"and"
+"[RFC-805]"
+"[RFC-811]"
+"(RCODE)"
+"have"
+"need"
+"RESPONSE,"
+"null"
+"any"
+"contents"
+"|(SRI-NIC.ARPA,"
+"SOMEONE"
+"RESOURCE"
+"73.0.0.26.IN-ADDR.ARPA."
+"DARPA"
+"ACC.ARPA."
+"RFC-812,"
+"-"
+"mechanism"
+"internal"
+"take"
+"which"
+"MIL."
+"MIL,"
+"="
+"UCI"
+"RFC-742,"
+"multiple"
+"TCP/IP"
+"USC-ISIC.ARPA."
+"QNAME=USC-ISIC.ARPA,"
+"The"
+"]"
+"class"
+"D."
+"RFC-1010,"
+"D,"
+"RFC-805,"
+"AA,"
+"VAXA.ISI.EDU."
+"QNAME=ISI.EDU,"
+"MG)."
+"\"DOD"
+"QNAME=SRI-NIC.ARPA,"
+"text"
+"labels"
+"VENERA"
+"RFC-1033,"
+"INCORRECTLY"
+"[RFC-"
+"Z"
+"[RFC-952,"
+"RECORDS"
+"implementation"
+"with"
+"cache"
+"[RFC-768]"
+"XX.LCS.MIT.EDU"
+"only"
+"PVM@ISI.EDU."
+"RETRY,"
+"get"
+"PVM@ISI.EDU"
+"ACHILLES"
+"LOUIE.UDEL.EDU."
+"IN-ADDR"
+"resource"
+"A.ISI"
+"THIS"
+"NIC"
+"(via"
+"Zones"
+"RFC-920,"
+"J."
+"RFC-920."
+"common"
+"set"
+"configured"
+"QNAME=SRI-NIC.ARPA.,"
+"this,"
+"are"
+"RFC-883]."
+"A.ISI.EDU."
+"A.ISI.EDU)"
+"INTRODUCTION"
+"TCP"
+"MIT"
+"PC"
+"3"
+"unable"
+"probably"
+"C.D,"
+"103.0.3.26.IN-ADDR.ARPA."
+"available"
+"C"
+"parent"
+"RFC-830]."
+"REFRESH"
+"UNIX"
+"CH)."
+"key"
+"52.0.0.10.IN-ADDR.ARPA"
+"P."
+"AND"
+"RFC-1002,"
+"OPCODE=SQUERY"
+"ROME.UCI"
+"LCS"
+"PDP-11/70"
+"ISI.EDU,"
+"ISI.EDU."
+"MAILB"
+"[RFC-974]"
+"CONCEPTS"
+"[RFC-920]"
+"SOA,"
+"RCODE=NE"
+"DNS."
+"DNS,"
+"poll"
+"UMN-REI-UC.ARPA."
+"SNAME."
+"[RFC-883]"
+"RFC-974,"
+"RFC-1002"
+"create"
+"S.,"
+"."
+"[RFC-830]"
+"expected"
+"empty"
+"RA"
+"CH"
+"(RD)"
+"VENERA.ISI.EDU."
+"SRI"
+"A.B.X,"
+"NAME"
+"value"
+"while"
+"error"
+"loop"
+"\"NICNAME/WHOIS\","
+"is"
+"CACHE"
+"FACILITIES"
+"in"
+"|(XX.LCS.MIT.EDU,"
+"SOA"
+"binary"
+"[RFC-819]"
+")"
+"SRI-NIC"
+"V."
+"\"A\"."
+"QNAME."
+"QNAME,"
+"units"
+"(NE)."
+"used"
+"IP"
+"\"."
+"IN"
+"ID"
+"IF"
+"task"
+"SCENARIO"
+"RFC-883,"
+"HOSTS.TXT"
+"Names"
+"RFC-811,"
+"the"
+"If"
+"being"
+"EXPIRE"
+"RFC-882,"
+"|ACHILLES.MIT.EDU)"
+"XX.COM."
+"(RDATA)"
+"source"
+"CSNET."
+"build"
+"ACHILLES.MIT.EDU."
+"format"
+"read"
+"(AA)"
+"ISIC.ARPA,"
+"SERIAL"
+"VAXA.ISI"
+"found,"
+"SLIST"
+"sorting"
+"OPCODE=SQUERY,"
+"OF"
+"AUTHORITY"
+"OS"
+"AA"
+"DOMAIN"
+"because"
+"SRI-NIC.ARPA.|"
+"some"
+"back"
+"growth"
+"USC-ISIC.ARPA,"
+"RFC-821,"
+"happens"
+"for"
+"W."
+"RFC-883"
+"X.COM"
+"avoid"
+"does"
+"allocate"
+"COM"
+"assuming"
+"BRL"
+"PTR"
+"[RFC-793]"
+"be"
+"QCLASS=*"
+"MIT.EDU."
+"by"
+"C."
+"on"
+"SCLASS"
+"of"
+"FTP)"
+"FTP,"
+"UK"
+"or"
+"ACC"
+"SBELT."
+"SBELT,"
+"No"
+"(SBELT)"
+"A.X.COM."
+"A.X.COM,"
+"REFERENCES"
+"USC-ISIC.ARPA"
+"[RFC-1001]"
+"RESPONSE"
+"transfer"
+"support"
+"*"
+"NE"
+"long"
+"QTYPE=*"
+"start"
+"C.ISI.EDU"
+"TTL,"
+"RD,"
+"\"4.3.2.1.IN-ADDR.ARPA\"."
+"NS"
+"was"
+"RR."
+"RR,"
+"QTYPE=A"
+"MEMO"
+"but"
+"QNAME"
+"[RFC-1001,"
+"DNS"
+"line"
+"trying"
+"true"
+"TCP/UDP"
+"count"
+"SBELT"
+"(NIC)"
+"up"
+"classes:"
+"RFC-768,"
+"[IEN-116]"
+"VAXA"
+"NETBIOS"
+"called"
+"delete"
+"CIC"
+"USC-"
+"RETRY"
+"RFC-810,"
+"RECORDS,"
+"an"
+"To"
+"as"
+"at"
+"file"
+"[RFC-812]"
+"physical"
+"X.COM,"
+"no"
+"[RFC-882,"
+"when"
+"A,"
+"virtual"
+"RFC-952,"
+"RFC-952."
+"valid"
+"5"
+"test"
+"you"
+"IP/TCP"
+"STATUS"
+"requested"
+"[RFC-974"
+"SPACE"
+"QNAME=SIR-NIC.ARPA.,"
+"RFC-819,"
+"variable"
+"[RFC-882]"
+"BIBLIOGRAPHY"
+"[RFC-1033]"
+"US."
+"\"MILNET"
+"As"
+"RFC-973,"
+"RFC-882"
+"QTYPE=MX"
+"4.0.10.18.IN-ADDR.ARPA."
+"FOO.F.ISI.ARPA,"
+"Assuming"
+"[RFC-1034],"
+"[RFC-1034]."
+"UNIX\""
+"IMPLEMENTATION"
+"EGP."
+"ANCOUNT"
+"@"
+"P"
+"TXT-DATA"
+"RMAILBX"
+"|QTYPE=A,"
+"QDCOUNT"
+"[RFC-1010]."
+"EMAILBX"
+"IN-"
+"OPCODE=IQUERY,"
+"MX)"
+"ID=997"
+"\"VENERA.ISI.EDU\";"
+"OPCODE"
+"MILNET-GW.ISI.EDU."
+"52.0.2.10.IN-ADDR.ARPA."
+"objects"
+"MD"
+"MG"
+"MF"
+"MR"
+"QNAME=10.IN-ADDR.ARPA."
+"OFFSET"
+"S."
+"GGP"
+"few"
+"QTYPE=PTR,"
+"MD,"
+"F"
+"[RFC-974]."
+"MGMNAME"
+"GW.LCS.MIT.EDU."
+"GW.LCS.MIT.EDU,"
+"V"
+"\\DDD"
+"ALL"
+"10.IN-ADDR.ARPA."
+"closing"
+"EXCHANGE."
+"MADNAME."
+"$ORIGIN"
+"HIS"
+"26.IN-ADDR.ARPA."
+"(MD)"
+"QTYPES"
+"PROTOCOL"
+"26.IN-ADDR.ARPA"
+"NSCOUNT"
+"(MR)"
+"PREFERENCE"
+"<BIT"
+"$INCLUDE."
+"MR)"
+"VAXA.ISI.EDU"
+"77.0.0.10.IN-ADDR.ARPA."
+"\"IBM-PC"
+"$INCLUDE"
+"SERVER"
+"18.IN-ADDR.ARPA."
+"ADDRESS"
+"Check"
+"static"
+"GW.ISI.EDU."
+"(QNAME)."
+"GW.ISI.EDU,"
+"F.ISI.ARPA,"
+"F.ISI.ARPA."
+"time."
+"PTRDNAME"
+"HOSTMASTER@SRI-"
+"(STATUS)"
+"(MINFO)"
+"(MG)"
+"QCLASS."
+"(HS)"
+"X,"
+"MNAME"
+"QNAME=VENERA.ISI.EDU"
+"MASTER"
+"(IN)"
+"KNOWS."
+"RNAME"
+"|QR|"
+"VAXA.ISI.EDU,"
+"R"
+"1)"
+"ARCOUNT"
+"RCODE"
+"NEWNAME"
+"CLASS"
+"begin"
+"(MF)."
+"Common"
+"<RDATA>"
+"QR"
+"average"
+"QNAME=6.0.0.10.IN-ADDR.ARPA,"
+"WKS"
+"SYSTEM,"
+"MADNAME"
+"ARPANET,"
+"MINFO"
+"DEFINITIONS"
+"failed"
+"[RFC-1034]"
+"(QCLASS),"
+"SPECIFICATION"
+"X"
+"THE"
+"MILNET."
+"MILNET-"
+"bytes"
+"(MX)"
+"NSDNAME"
+"10.IN-ADDR.ARPA"
+"|AA|TC|RD|RA|"
+"QTYPE=A,"
+"corruption"
+"FOO.F.ISI.ARPA"
+"(QUERY)"
+"MF,"
+"FOO"
+"CURLEY"
+"X.Y,"
+"AXFR,"
+"S"
+"MAILA"
+"exceeds"
+"ISI.EDU:"
+"103.0.0.26.IN-ADDR.ARPA."
+"MOE"
+"[RFC-822]."
+"CHAOS"
+"NAMEDROPPERS@SRI-NIC.ARPA"
+"SOA."
+"RESOLVER"
+"A.X,"
+"EXCHANGE"
+"SMTP"
+"QCLASS=*,"
+"CS"
+"$ORIGIN,"
+"B.X"
+"(MB,"
+"TYPE"
+"Size"
+"parse"
+"ADDR.ARPA"
+"(SMTP)."
+"key."
+"MAP>"
+"OWN"
+"VENERA.ISI.EDU"
+"DDD."
+"MB."
+"NS,"
+"I"
+"OPCODE=RESPONSE,"
+"ARPA,"
+"WITHIN"
+"tables"
+"unsigned"
+"LARRY"
+"D"
+"\\X"
+"WHICH"
+"(IQUERY)"
+"QCLASS=IN"
+"discarded"
+"6.0.0.10.IN-ADDR.ARPA."
+"MAIL"
+"QTYPE=MAILB"
+"HS"
+"SUPPORT"
+"STOOGES"
+"X.Y"
+"/"
+"(SLIST)."
+"O"
+"OS,"
+"offset"
+"FILES"
+"RR),"
+"$INCLUDE,"
+"guard"
+"[<TTL>]"
+"CRLF"
+"Error"
+"ERRORS-TO:"
+"22.0.2.10.IN-ADDR.ARPA."
+"default"
+"MESSAGES"
+"signed"
+"<SUBSYS>ISI-MAILBOXES.TXT"
+"MULTICS.MIT.EDU."
+"NULL"
+"application"
+"TXT"
+"TC"
+"PROTOCOL=TCP"
+"UDP."
+"UDP,"
+"F.ISI.ARPA"
+"(EXPERIMENTAL)"
+"RDLENGTH"
+"NIC.ARPA"
+
diff --git a/net/data/fuzzer_dictionaries/net_host_resolver_impl_fuzzer.dict b/net/data/fuzzer_dictionaries/net_host_resolver_impl_fuzzer.dict
new file mode 100644
index 0000000..3e7f1d89
--- /dev/null
+++ b/net/data/fuzzer_dictionaries/net_host_resolver_impl_fuzzer.dict
@@ -0,0 +1,1397 @@
+# 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.
+
+# Fuzzer dictionary targetting DNS responses.
+
+# Some 16-bit big-endian values. Useful in a number of fields. Includes
+# A, AAAA, and CNAME IDs, low values for record counts, and multiples of
+# lengths of A and AAAA data fields.
+"\x00\x00"
+"\x00\x01"
+"\x00\x02"
+"\x00\x03"
+"\x00\x04"
+"\x00\x05"
+"\x00\x08"
+"\x00\x0C"
+"\x00\x10"
+"\x00\x1C"
+"\x00\x20"
+"\x00\x30"
+
+# Some encoded domain names.
+"\x03foo\x00"
+"\x03foo\x03com\x00"
+"\x01a\x03foo\x03com\x00"
+"\x03bar\x00"
+
+# Message headers (Without message ID field).
+"\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00"
+# Truncated message, requiring TCP fallback.
+"\x83\x80\x00\x01\x00\x01\x00\x00\x00\x00"
+# Varying number of answers
+"\x81\x80\x00\x01\x00\x00\x00\x00\x00\x00"
+"\x81\x80\x00\x01\x00\x02\x00\x00\x00\x00"
+"\x81\x80\x00\x01\x00\x10\x00\x00\x00\x00"
+
+# A, AAAA, and CNAME request suffixes - appear after domain name.
+"\x00\x01\x00\x01"
+"\x00\x1c\x00\x01"
+"\x00\x05\x00\x01"
+
+# A, AAAA, and CNAME requests for foo and foo.com.
+"\x03foo\x00\x00\x01\x00\x01"
+"\x03foo\x00\x00\x1c\x00\x01"
+"\x03foo\x00\x00\x05\x00\x01"
+"\x03foo\x03com\x00\x00\x01\x00\x01"
+"\x03foo\x03com\x00\x00\x1c\x00\x01"
+"\x03foo\x03com\x00\x00\x05\x00\x01"
+
+# All of the answers below are missing the name field, which should appear
+# first.
+
+# A answer suffixes, two different IP and TTLs.
+"\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04\x01\x02\x03\x04"
+"\x00\x01\x00\x01\x00\x00\x00\xFF\x00\x04\x02\x03\x04\x05"
+
+# AAAA answer suffixes, two different IPs and TTLs.
+"\x00\x1C\x00\x01\x00\x00\x00\x00\x00\x08\x01\x02\x03\x04\x05\x06\x07\x08"
+"\x00\x1C\x00\x01\x00\x00\x00\xFF\x00\x08\x02\x03\x04\x05\x06\x07\x08\x09"
+
+# CDATA answer suffixes, first two truncated as well.
+"\x00\x05\x00\x01\x00\x00\x00\xFF"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05\x03foo\x00"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x05\x03bar\x00"
+"\x00\x05\x00\x01\x00\x00\x00\xFF\x00\x09\x03foo\x03com\x00"
+
+
+# This part has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_host_resolver_impl_fuzzer binary, RFC 1034 and RFC 1035.
+"EXPIRE"
+"all"
+"code"
+"QNAME=ISI.EDU.,"
+"chain"
+"C.ISI.EDU,"
+"C.ISI.EDU."
+"results"
+"existing"
+"INTRODUCTION"
+"52.0.0.10.IN-ADDR.ARPA."
+"QCLASS"
+"[RFC-799]"
+"follow"
+"XX.LCS.MIT.EDU."
+"(which"
+"C.ISI.EDU:"
+"content"
+"A.B.X,"
+"pointing"
+"zone"
+"A.B.C.D"
+"CPU"
+"(RCODE)"
+"send"
+"IN-ADDR.ARPA"
+"0"
+"Host"
+"program"
+"under"
+"\"*.X\","
+"exit."
+"resources"
+"TOPS20"
+"labels"
+"string"
+"advantage"
+"returning"
+"very"
+"none"
+"C.ISI.EDU)"
+"AXFR"
+"YALE.ARPA."
+"difference"
+"Experimental"
+"entire"
+"did"
+"supports"
+"list"
+"large"
+"CNAME,"
+"-1"
+"delegate"
+"small"
+"ASCII"
+"C."
+"M."
+"YALE.EDU."
+"direct"
+"past"
+"likely"
+"\"A\""
+"\"IN-ADDR.ARPA\"."
+"XX.LCS.MIT.EDU,"
+"HINFO"
+"RFC-1031,"
+"IN,"
+"particular,"
+"Z."
+"errors"
+"appear"
+"ARPANET"
+"QNAME=65.0.6.26.IN-ADDR.ARPA.,QCLASS=IN,QTYPE=PTR"
+"QCLASS=*"
+"section"
+"51.0.0.10.IN-ADDR.ARPA."
+"children"
+"current"
+"DEC-2060"
+"waiting"
+"version"
+"above"
+"TTL"
+"[RFC-742]"
+"shared"
+"method"
+"QTYPE=NS"
+"FTP"
+"*.A.X.COM"
+"hash"
+"EDU."
+"exchange"
+"QTYPE=CNAME,"
+"never"
+"[RFC-"
+"here"
+"\"HOSTNAME"
+"RFC-793,"
+"address"
+"SNAME,"
+"path"
+"Distribution"
+"\"NAME/FINGER\","
+"change"
+"search"
+"SRI-NIC.ARPA."
+"[RFC-952,"
+"SRI-NIC.ARPA,"
+"MB"
+"receive"
+"changed"
+"SRI-NIC.ARPA:"
+"prior"
+"amount"
+"QTYPE=CNAME"
+"RFC-822."
+"here."
+"published"
+"NOT"
+"Serial"
+"J.,"
+"error,"
+"MX"
+"error."
+"composed"
+"named"
+"via"
+"useful"
+"addresses"
+"case."
+"ARPA"
+"When"
+"private"
+"*.X.COM"
+"total"
+"gateway"
+"select"
+"Status"
+"SRI-NIC.ARPA"
+"use"
+"SNAME"
+"from"
+"would"
+"to"
+"positive"
+"contains"
+"(QCLASS)"
+"two"
+"[RFC-1032]."
+"(DNS),"
+"TELNET,"
+"call"
+"B.X,"
+"memory"
+"type"
+"until"
+"used."
+"more"
+"sort"
+"QNAME=SIR-NIC.ARPA,"
+"MILNET"
+"name."
+"Domain"
+"[IEN-116,"
+"PTR)."
+"HOSTS.TXT,"
+"COMSAT,"
+"EXPIRE."
+"known"
+"cases"
+"must"
+"EVEN"
+"account"
+"include"
+"QCLASS=IN."
+"QNAME=USC-ISIC.ARPA.,"
+"this"
+"CNAME."
+"work"
+"EDU,"
+"can"
+"evolved"
+"EDU"
+"following"
+"original"
+"root"
+"example"
+"F."
+"history"
+"type."
+"stream"
+"Organizations"
+"process"
+"pieces"
+"high"
+"minimum"
+"[RFC-953]"
+"numbers"
+"want"
+"allowed"
+"serial"
+"keep"
+"IEN-116,"
+"returned"
+"class."
+"information"
+"class,"
+"end"
+"goal"
+"[RFC-1033]."
+"divided"
+"holds"
+"write"
+"located"
+"NOSC"
+"VENERA.ISI.EDU.|"
+"plus"
+"Z.X"
+"A"
+"map"
+"[RFC-810]"
+"QTYPE."
+"may"
+"after"
+"Request"
+"containing"
+"RFC-1032,"
+"date"
+"such"
+"[RFC-1035]."
+"data"
+"response"
+"types"
+"\"A"
+"a"
+"FTP,"
+"All"
+"short"
+"attempt"
+"IF"
+"After"
+"UDEL.EDU."
+"SRI,"
+")"
+"RFC-953,"
+"so"
+"TELNET)."
+"MIT.EDU"
+"order"
+"(HOSTS.TXT)"
+"ACHILLES"
+"ISI.EDU"
+"MIL"
+"over"
+"move"
+"vary"
+"Z.X),"
+"RFC-830,"
+"through"
+"V."
+"during"
+"still"
+"pointer"
+"its"
+"STYPE"
+"before"
+"25"
+"style"
+"HAS"
+"group"
+"RR"
+"HOSTMASTER.SRI-NIC.ARPA."
+"65.0.6.26.IN-ADDR.ARPA,"
+"fix"
+"65.0.6.26.IN-ADDR.ARPA."
+"28"
+"actually"
+"RD"
+"NAMES"
+"YALE"
+"policy"
+"mail"
+"QNAME=BRL.MIL,"
+"it."
+"them"
+"good"
+"return"
+"greater"
+"combination"
+"B.C.D,"
+"matches"
+"RA,"
+"ACM,"
+"9"
+"ARPA."
+"they"
+"half"
+"not"
+"However,"
+"parsing"
+"[RFC-973]"
+"instructions"
+"OPCODE=SQUERY,RESPONSE"
+"term"
+"name"
+"RFC,"
+"always"
+"Authority"
+"THIS"
+"RFC."
+"mode"
+"timeout"
+"RFC-799,"
+"found"
+"|"
+"mean"
+"RESOLVERS"
+"status"
+"domain"
+"From"
+"Network"
+"QTYPE,"
+"series"
+"SOME"
+"idea"
+"related"
+"CNAME"
+"UDEL"
+"happen"
+"beyond"
+"RFC-882"
+"special"
+"out"
+"try"
+"E."
+"space"
+"open"
+"since"
+"stub"
+"L."
+"MINIMUM"
+"RFC-768,"
+"RDATA"
+"get"
+"cause"
+"REFRESH,"
+"HOSTMASTER@SRI-NIC.ARPA."
+"SERVERS"
+"This"
+"SLIST:"
+"free"
+"RFC"
+"reason"
+"base"
+"put"
+"byte"
+"RFC-952"
+"received."
+"generate"
+"SLIST,"
+"RFC-883,"
+"definition"
+"DATA."
+"thread"
+"YALE-BULLDOG.ARPA."
+"could"
+"transition"
+"QCLASS,"
+"times"
+"MIT"
+"length"
+"place"
+"ICS.UCI"
+"HOSTMASTER@SRI-NIC.ARPA"
+"first"
+"origin"
+"already"
+"RD."
+"CONFIGURED"
+"number"
+"one"
+"RFC-"
+"Start"
+"ISI"
+"RFC-953."
+"construct"
+"another"
+"owner"
+"message"
+"QTYPE=*"
+"Local"
+"CSNET"
+"size"
+"doesn't"
+"given"
+"\""
+"X."
+"A.ISI.EDU"
+"service"
+"set,"
+"introduction"
+"unknown"
+"top"
+"system"
+"least"
+"parallel"
+"their"
+"intermediate"
+"master"
+"listed"
+"passed"
+"QTYPE"
+"ignored."
+"scheme"
+"Data"
+"store"
+"gives"
+"BBN"
+"that"
+"completed"
+"UDP"
+"XX"
+"part"
+"too"
+"RFC-953]."
+"(CNAME)"
+"translation"
+"copy"
+"than"
+"population"
+"wide"
+"Set"
+"K."
+"target"
+"DNS,"
+"16"
+"was"
+"require"
+"second"
+"matter"
+"See"
+"classes"
+"were"
+"[RFC-1031]"
+"result"
+"and"
+"Information"
+"[RFC-805]"
+"QNAME"
+"[RFC-811]"
+"[RFC-1032]"
+"say"
+"have"
+"need"
+"Mail"
+"1"
+"null"
+"RETRY"
+"any"
+"contents"
+"|(SRI-NIC.ARPA,"
+"SOMEONE"
+"RESOURCE"
+"73.0.0.26.IN-ADDR.ARPA."
+"min"
+"DARPA"
+"database."
+"responsible"
+"able"
+"RFC-812,"
+"mechanism"
+"client"
+"also"
+"(AA)"
+"contact"
+"take"
+"which"
+"MIL."
+"MIL,"
+"="
+"UCI"
+"added"
+"multiple"
+"Name"
+"USC-ISIC.ARPA."
+"QCLASS=IN,"
+"track"
+"object"
+"most"
+"detect"
+"connected"
+"services"
+"The"
+"]"
+"model"
+"domain."
+"D."
+"RFC-1010,"
+"D,"
+"[RFC-1010]"
+"RFC-805,"
+"AA,"
+"sometimes"
+"Some"
+"VAXA.ISI.EDU."
+"QNAME=ISI.EDU,"
+"MG)."
+"error"
+"If"
+"fact"
+"QNAME=SRI-NIC.ARPA,"
+"particularly"
+"text"
+"supported"
+"terminate"
+"VENERA"
+"attempts"
+"relation"
+"RFC-1033,"
+"Under"
+"|(VAXA.ISI.EDU,VENERA.ISI.EDU,"
+"USC-ISIC.ARPA,"
+"find"
+"cache."
+"Z"
+"based"
+"advanced"
+"RECORDS"
+"implementation"
+"("
+"cache"
+"[RFC-768]"
+"outside"
+"should"
+"XX.LCS.MIT.EDU"
+"only"
+"PVM@ISI.EDU."
+"RETRY,"
+"local"
+"do"
+"[RFC-1031]."
+"means"
+"there"
+"While"
+"cannot"
+"new"
+"2"
+"LOUIE.UDEL.EDU."
+"IN-ADDR"
+"processes"
+"resource"
+"A.ISI"
+"cached"
+"NIC"
+"generally"
+"(via"
+"ROME.UCI"
+"Zones"
+"RFC-920,"
+"J."
+"RFC-920."
+"common"
+"mapped"
+"including"
+"where"
+"valid"
+"set"
+"For"
+"configured"
+"we"
+"QNAME=SRI-NIC.ARPA.,"
+"up"
+"relative"
+"depends"
+"individual"
+"are"
+"RFC-883]."
+"close"
+"A.ISI.EDU."
+"said"
+"A.ISI.EDU)"
+"purpose"
+"TCP"
+"label"
+"PC"
+"3"
+"unable"
+"between"
+"probably"
+"boundary"
+"C.D,"
+"numerous"
+"across"
+"available"
+"C"
+"terms"
+"ability"
+"parent"
+"RFC-830]."
+"LCS.MIT.EDU"
+"negotiated"
+"REFRESH"
+"UNIX"
+"CH)."
+"key"
+"March"
+"configuration"
+"come"
+"classes."
+"AND"
+"both"
+"RFC-1002,"
+"OPCODE=SQUERY"
+"last"
+"LCS"
+"deals"
+"PDP-11/70"
+"equal"
+"against"
+"ISI.EDU."
+"MAILB"
+"[RFC-974]"
+"opcode"
+"RFC-742,"
+"C.ISI.EDU"
+"expression"
+"can't"
+"load"
+"among"
+"[RFC-920]"
+"point"
+"simple"
+"had"
+"period"
+"header"
+"[IEN-116]"
+"DNS."
+"52.0.0.10.IN-ADDR.ARPA"
+"table"
+"poll"
+"UMN-REI-UC.ARPA."
+"["
+"[RFC-883]"
+"RFC-974,"
+"RFC-1002"
+"addition"
+"P."
+"create"
+"S.,"
+"political"
+"copies"
+"been"
+"."
+"Early"
+"Introduction"
+"describes"
+"expected"
+"empty"
+"RA"
+"SLIST."
+"CH"
+"(RD)"
+"VENERA.ISI.EDU."
+"with"
+"SRI"
+"PVM@ISI.EDU"
+"[RFC-821]"
+"Using"
+"an"
+"case"
+"exception"
+"has"
+"NAME"
+"these"
+"appearance"
+"value"
+"will"
+"while"
+"replaced"
+"many"
+"loop"
+"SOA,"
+"RFC-1001,"
+"\"NICNAME/WHOIS\","
+"is"
+"CACHE"
+"it"
+"encountered"
+"FACILITIES"
+"in"
+"|(XX.LCS.MIT.EDU,"
+"RESPONSE,"
+"if"
+"SOA"
+"binary"
+"different"
+"perhaps"
+"[RFC-819]"
+"perform"
+"make"
+"hostname"
+"same"
+"orders"
+"QNAME."
+"QNAME,"
+"parts"
+"widely"
+"of:"
+"several"
+"Types"
+"(NE)."
+"development"
+"fairly"
+"used"
+"Institute"
+"IP"
+"\"."
+"CONCEPTS"
+"effect"
+"user"
+"IN"
+"infinite"
+"frequently"
+"ID"
+"recent"
+"task"
+"SCENARIO"
+"database"
+"makes"
+"depending"
+"well"
+"It"
+"HOSTS.TXT"
+"without"
+"thought"
+"edge"
+"Names"
+"RFC-811,"
+"In"
+"organization"
+"the"
+"ACC.ARPA."
+"left"
+"United"
+"protocol"
+"less"
+"being"
+"-"
+"rest"
+"A,"
+"Access"
+"CSNET."
+"stored"
+"RFC-882,"
+"Internet"
+"followed"
+"(QTYPE),"
+"previous"
+"RFC-952,"
+"|ACHILLES.MIT.EDU)"
+"majority"
+"XX.COM."
+"|(C.ISI.EDU,SRI-NIC.ARPA"
+"character"
+"capabilities"
+"(RDATA)"
+"source"
+"add"
+"internal"
+"TTL)"
+"4"
+"Although"
+"RCODE=NE"
+"5"
+"save"
+"administrative"
+"remaining"
+"match"
+"build"
+"around"
+"ACHILLES.MIT.EDU."
+"format"
+"read"
+"Of"
+"possible"
+"required."
+"alias"
+"ISIC.ARPA,"
+"integer"
+"bit"
+"VAXA.ISI"
+"found,"
+"desire"
+"SLIST"
+"sorting"
+"OPCODE=SQUERY,"
+"OF"
+"AUTHORITY"
+"server"
+"specific"
+"popular"
+"output"
+"OS"
+"Before"
+"STATUS"
+"DOMAIN"
+"because"
+"old"
+"often"
+"deal"
+"sequence"
+"RFC-821,"
+"SRI-NIC.ARPA.|"
+"Since"
+"some"
+"System"
+"growth"
+"equivalent"
+"examples"
+"loaded"
+"INCORRECTLY"
+"unless"
+"reasons"
+"TCP/IP"
+"happens"
+"ignore"
+"for"
+"W."
+"RFC-883"
+"X.COM"
+"avoid"
+"QTYPE=MX"
+"does"
+"allocate"
+"COM"
+"assuming"
+"BRL"
+"PTR"
+"[RFC-793]"
+"refer"
+"be"
+"example,"
+"MIT.EDU."
+"broken"
+"host"
+"become"
+"by"
+"SRI-NIC"
+"on"
+"about"
+"actual"
+"socket"
+"SCLASS"
+"RFC-810,"
+"of"
+"FTP)"
+"US"
+"compatible"
+"extensions"
+"\"A\"."
+"UK"
+"referred"
+"or"
+"ACC"
+"SBELT."
+"SBELT,"
+"No"
+"(SBELT)"
+"into"
+"within"
+"A.X.COM."
+"Two"
+"A.X.COM,"
+"negative"
+"included"
+"REFERENCES"
+"determine"
+"USC-ISIC.ARPA"
+"file."
+"[RFC-1001]"
+"[RFC-830]"
+"RESPONSE"
+"fast"
+"additional"
+"[RFC-812]"
+"transfer"
+"support"
+"*"
+"question"
+"NE"
+"long"
+"class"
+"start"
+"SERIAL"
+"TTL,"
+"User"
+"A.X.COM"
+"forward"
+"RD,"
+"\"4.3.2.1.IN-ADDR.ARPA\"."
+"NS"
+"sections"
+"function"
+"RR."
+"RR,"
+"QTYPE=A"
+"complete"
+"form"
+"MEMO"
+"but"
+"back"
+"failure"
+"link"
+"DNS"
+"SNAME."
+"encoded"
+"line"
+"trying"
+"true"
+"TCP/UDP"
+"[RFC-1033]"
+"count"
+"SBELT"
+"made"
+"[RFC-952]"
+"algorithm"
+"used,"
+"(NIC)"
+"official"
+"this,"
+"classes:"
+"experimental"
+"ISI.EDU,"
+"limit"
+"critical"
+"VAXA"
+"distribution"
+"NETBIOS"
+"similar"
+"called"
+"[RFC-1001,"
+"delete"
+"CIC"
+"USC-"
+"units"
+"ad"
+"RECORDS,"
+"defined"
+"request"
+"specified"
+"influence"
+"general"
+"To"
+"as"
+"exist"
+"at"
+"file"
+"MX."
+"check"
+"physical"
+"X.COM,"
+"functions"
+"QNAME=USC-ISIC.ARPA,"
+"no"
+"[RFC-882,"
+"when"
+"QTYPE=MX,"
+"virtual"
+"details."
+"field"
+"RFC-952."
+"other"
+"role"
+"test"
+"you"
+"(QNAME),"
+"IP/TCP"
+"formats"
+"AA"
+"requested"
+"[RFC-974"
+"SPACE"
+"QNAME=SIR-NIC.ARPA.,"
+"RFC-819,"
+"important"
+"variable"
+"[RFC-882]"
+"[RFC-1002]"
+"structure"
+"\"DOD"
+"BIBLIOGRAPHY"
+"lead"
+"using"
+"US."
+"\"MILNET"
+"103.0.3.26.IN-ADDR.ARPA."
+"together"
+"An"
+"As"
+"RFC-973,"
+"time"
+"failures"
+"starting"
+"having"
+"V"
+"FOO.F.ISI.ARPA,"
+"Assuming"
+"[RFC-1034]."
+"calculate"
+"IMPLEMENTATION"
+"Not"
+"ANCOUNT"
+"Secondary"
+"@"
+"ALL"
+"P"
+"TXT-DATA"
+"namespaces"
+"entries"
+"RMAILBX"
+"prevent"
+"QDCOUNT"
+"[RFC-1010]."
+"EMAILBX"
+"IN-"
+"OPCODE=IQUERY,"
+"MX)"
+"implemented"
+"port"
+"Available"
+"ID=997"
+"[RFC-1034],"
+"\"VENERA.ISI.EDU\";"
+"OPCODE"
+"MILNET-GW.ISI.EDU."
+";"
+"body"
+"52.0.2.10.IN-ADDR.ARPA."
+"reported"
+"objects"
+"strong"
+"UNIX\""
+"MD"
+"MF"
+"QNAME=10.IN-ADDR.ARPA."
+"serialize"
+"<SUBSYS>ISI-MAILBOXES.TXT"
+"X,"
+"Too"
+"77.0.0.10.IN-ADDR.ARPA."
+"spawned"
+"exception."
+"permitted"
+"RDLENGTH"
+"few"
+"duplicate"
+"QTYPE=PTR,"
+"CURLEY"
+"MD,"
+"F"
+"[RFC-974]."
+"MGMNAME"
+"validity"
+"GW.LCS.MIT.EDU,"
+"Time"
+"(back"
+"\\DDD"
+"10.IN-ADDR.ARPA."
+"closing"
+"requested,"
+"reserved"
+"EXCHANGE."
+"HIS"
+"reject"
+"ensure"
+"(MD)"
+"QTYPES"
+"PROTOCOL"
+"description"
+"26.IN-ADDR.ARPA"
+"NSCOUNT"
+"(MR)"
+"derived"
+"Foreign"
+"OWN"
+"26.IN-ADDR.ARPA."
+"TC"
+"map."
+"cases."
+"PREFERENCE"
+"don't"
+"VENERA.ISI.EDU"
+"held"
+"X"
+"below:"
+"$INCLUDE."
+"forms"
+"MR)"
+"VAXA.ISI.EDU"
+"main"
+"pending"
+"timestamp"
+"Ignoring"
+"MADNAME."
+"\\"
+"$ORIGIN"
+"\"IBM-PC"
+"document"
+"$INCLUDE"
+"SERVER"
+"ADDRESS"
+"identifier"
+"Check"
+"reduce"
+"static"
+"expect"
+"MASTER"
+"GW.ISI.EDU."
+"(QNAME)."
+"is:"
+"GW.ISI.EDU,"
+"F.ISI.ARPA,"
+"F.ISI.ARPA."
+"time."
+"PTRDNAME"
+"HOSTMASTER@SRI-"
+"(STATUS)"
+"possibility"
+"|QTYPE=A,"
+"(MINFO)"
+"initialize"
+"beginning"
+"compression"
+"(MG)"
+"created"
+"QCLASS."
+"encoding"
+"(HS)"
+"MNAME"
+"ports"
+"QNAME=VENERA.ISI.EDU"
+"(IN)"
+"Response"
+"KNOWS."
+"|QR|"
+"VAXA.ISI.EDU,"
+"Reserved"
+"14"
+"1)"
+"SOA."
+"ARCOUNT"
+"Other"
+"RCODE"
+"NEWNAME"
+"22.0.2.10.IN-ADDR.ARPA."
+"With"
+"CLASS"
+"begin"
+"(MF)."
+"Common"
+"<RDATA>"
+"Responses"
+"EGP."
+"average"
+"R"
+"QNAME=6.0.0.10.IN-ADDR.ARPA,"
+"WKS"
+"SYSTEM,"
+"ARPANET,"
+"MINFO"
+"participate"
+"DEFINITIONS"
+"failed"
+"[RFC-1034]"
+"mixture"
+"SPECIFICATION"
+"THE"
+"MILNET."
+"MILNET-"
+"<BIT"
+"bytes"
+"(MX)"
+"10.IN-ADDR.ARPA"
+"4.0.10.18.IN-ADDR.ARPA."
+"FOO.F.ISI.ARPA"
+"(QUERY)"
+"maximum"
+"existence"
+"|AA|TC|RD|RA|"
+"MADNAME"
+"subject"
+"QTYPE=A,"
+"FILES"
+"reading"
+"0."
+"corruption"
+"0,"
+"Sending"
+"MF,"
+"connection."
+"Server"
+"entries."
+"suggested"
+"reverse"
+"AXFR,"
+"according"
+"connection"
+"MAILA"
+"(QCLASS),"
+"exceeds"
+"ISI.EDU:"
+"103.0.0.26.IN-ADDR.ARPA."
+"[RFC-822]."
+"NAMEDROPPERS@SRI-NIC.ARPA"
+"RESOLVER"
+"respect"
+"throughout"
+"S"
+"FOO"
+"define"
+"enable"
+"EXCHANGE"
+"SMTP"
+"MG"
+"QCLASS=*,"
+"CS"
+"$ORIGIN,"
+"(MB,"
+"TYPE"
+"Any"
+"Size"
+"rename"
+"almost"
+"parse"
+"ADDR.ARPA"
+"(SMTP)."
+"key."
+"MAP>"
+"expired"
+"member"
+"Address"
+"DDD."
+"MB."
+"NS,"
+"I"
+"MR"
+"read,"
+"OPCODE=RESPONSE,"
+"person"
+"entry"
+"WITHIN"
+"LARRY"
+"front"
+"tables"
+"loading"
+"unsigned"
+"aspects"
+"D"
+"CHAOS"
+"WHICH"
+"(IQUERY)"
+"QCLASS=IN"
+"6.0.0.10.IN-ADDR.ARPA."
+"S."
+"QTYPE=MAILB"
+"HS"
+"SUPPORT"
+"A.X,"
+"STOOGES"
+"discarded"
+"done."
+"literals"
+"X.Y"
+"However"
+"/"
+"(SLIST)."
+"X.Y,"
+"integer."
+"ARPA,"
+"who"
+"18.IN-ADDR.ARPA."
+"B.X"
+"expansion"
+"OS,"
+"offset"
+"F.ISI.ARPA"
+"GGP"
+"O"
+"Communications"
+"RR),"
+"location"
+"MOE"
+"range"
+"value."
+"Message"
+"block"
+"$INCLUDE,"
+"guard"
+"[<TTL>]"
+"QR"
+"CRLF"
+"Error"
+"ERRORS-TO:"
+"he"
+"default"
+"MESSAGES"
+"signed"
+"storing"
+"MULTICS.MIT.EDU."
+"New"
+"NULL"
+"application"
+"OFFSET"
+"holding"
+"TXT"
+"NSDNAME"
+"PROTOCOL=TCP"
+"UDP."
+"UDP,"
+"RNAME"
+"GW.LCS.MIT.EDU."
+"(EXPERIMENTAL)"
+"\\X"
+"MAIL"
+"NIC.ARPA"
+
diff --git a/net/data/fuzzer_dictionaries/net_http_proxy_client_socket_fuzzer.dict b/net/data/fuzzer_dictionaries/net_http_proxy_client_socket_fuzzer.dict
new file mode 100644
index 0000000..4028d26e
--- /dev/null
+++ b/net/data/fuzzer_dictionaries/net_http_proxy_client_socket_fuzzer.dict
@@ -0,0 +1,1088 @@
+# 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.
+
+# Fuzzer dictionary targetting HTTP/1.x responses.
+
+# Entries that are generally useful in headers
+":"
+"\x0A"
+"\x0D"
+"0"
+"50"
+"500"
+# Horizontal whitespace. Matters mostly in status line.
+" "
+"\x09"
+# Header continuation
+"\x0D\x0A\x09"
+# Used in a lot of individual headers
+";"
+"="
+","
+"\""
+"-"
+
+# Status line components
+"HTTP"
+"/1.1"
+"/1.0"
+# More interesting status codes.  Leading space so can be inserted into
+# other status lines.
+" 100"
+" 200"
+" 206"
+" 301"
+" 302"
+" 303"
+" 304"
+" 307"
+" 308"
+" 401"
+" 403"
+" 404"
+" 500"
+" 501"
+" 403"
+
+# Full status lines (Some with relevant following headers)
+"HTTP/1.1 200 OK\x0A\x0A"
+"HTTP/1.1 100 Continue\x0A\x0A"
+"HTTP/1.1 401 Unauthorized\x0AWWW-Authenticate: Basic realm=\"Middle-Earth\"\x0A\xA0"
+"HTTP/1.1 407 Proxy Authentication Required\x0AProxy-Authenticate: Digest realm=\"Middle-Earth\", nonce=\"aaaaaaaaaa\"\x0A\x0A"
+"HTTP/1.0 301 Moved Permanently\x0ALocation: /a\x0A\x0A"
+"HTTP/1.1 302 Found\x0ALocation: http://lost/\x0A\x0A"
+
+# Proxy authentication headers. Note that fuzzers don't support NTLM or
+# negotiate.
+"WWW-Authenticate:"
+"Proxy-Authenticate:"
+"Basic"
+"Digest"
+"realm"
+"nonce"
+
+"Connection:"
+"Proxy-Connection:"
+"Keep-Alive"
+"Close"
+"Upgrade"
+"\x0AConnection: Keep-Alive"
+"\x0AConnection: Close"
+"\x0AProxy-Connection: Keep-Alive"
+"\x0AProxy-Connection: Close"
+
+"Content-Length:"
+"Transfer-Encoding:"
+"chunked"
+"\x0AContent-Length: 0"
+"\x0AContent-Length: 500"
+"\x0ATransfer-Encoding: chunked\x0A\x0A5\x0A12345\x0A0\x0A\x0A"
+
+"Location:"
+"\x0ALocation: http://foo/"
+"\x0ALocation: http://bar/"
+"\x0ALocation: https://foo/"
+"\x0ALocation: https://bar/"
+
+"Accept-Ranges:"
+"bytes"
+"\x0AAccept-Ranges: bytes"
+
+"Content-Range:"
+
+"Age:"
+"\x0AAge: 0"
+"\x0AAge: 3153600000"
+
+"Cache-Control:"
+"max-age"
+"no-cache"
+"no-store"
+"must-revalidate"
+"\x0ACache-Control: max-age=3153600000"
+"\x0ACache-Control: max-age=0"
+"\x0ACache-Control: no-cache"
+"\x0ACache-Control: no-store"
+"\x0ACache-Control: must-revalidate"
+
+"Content-Disposition:"
+"attachment"
+"filename"
+
+"Content-Encoding:"
+"gzip"
+"deflate"
+"sdch"
+"br"
+"\x0AContent-Encoding: gzip"
+"\x0AContent-Encoding: deflate"
+"\x0AContent-Encoding: sdch"
+"\x0AContent-Encoding: br"
+
+"Date:"
+"Fri, 01 Apr, 2050 14:14:14 GMT"
+"Mon, 28 Mar, 2016 04:04:04 GMT"
+"\x0ADate: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0ADate: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Last-Modified:"
+"\x0ALast-Modified: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0ALast-Modified: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Expires:"
+"\x0AExpires: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0AExpires: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Set-Cookie:"
+"Expires"
+"Max-Age"
+"Domain"
+"Path"
+"Secure"
+"HttpOnly"
+"Priority"
+"Low"
+"Medium"
+"High"
+"SameSite"
+"Strict"
+"Lax"
+"\x0ASet-Cookie: foo=bar"
+"\x0ASet-Cookie: foo2=bar2;HttpOnly;Priority=Low;SameSite=Strict;Path=/"
+"\x0ASet-Cookie: foo=chicken;SameSite=Lax"
+
+"Strict-Transport-Security:"
+"includeSubDomains"
+
+"Vary:"
+"\x0AVary: Cookie"
+"\x0AVary: Age"
+
+"ETag:"
+"\x0AETag: jumboshrimp"
+
+
+# This part has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_http_proxy_client_socket_fuzzer binary and RFC 2616.
+"all"
+"code"
+"maximum"
+"Transfer-Encoding"
+"D.,"
+"results"
+"follow"
+"(LZW)."
+"provided."
+"(which"
+"ISDN"
+"\"TE\""
+"LF>"
+"FORCE"
+"calculate"
+"\"IETF"
+"UNIX,"
+"ARPA"
+"\"OPTIONAL\""
+"environment"
+"Host"
+"program"
+"USENET"
+"TEXT"
+"Not"
+"Nov"
+"include"
+"resources"
+"CONNECT"
+"digit"
+"supported"
+"string"
+"returning"
+"ALL"
+"HTTP/1.1;"
+"SP,"
+"SP."
+"entries"
+"HTTP/1.1,"
+"HTTP/1.1."
+"difference"
+"(URI):"
+"--"
+"[CRLF]"
+"EXPRESS"
+"list"
+"HTTP/1.0\","
+"(RFC"
+"large"
+"ONLY"
+"Tag"
+"(LWS"
+"enclosing"
+"\"SHOULD\","
+"(URL)\","
+"\"A\"..\"Z\">"
+"unexpected"
+"GET)"
+"\"HEAD\""
+"direct"
+"Failed"
+"second"
+"Version"
+"\"A\""
+"allowed."
+"pass"
+"GET,"
+"tag."
+"implemented"
+"\"HTTP/1.0\""
+"INFRINGE"
+"errors"
+"ISO-8859-4,"
+"appear"
+"opaque"
+"section"
+"CPU"
+"current"
+"waiting"
+"version"
+"above"
+"TTL"
+"shared"
+"CRLF)"
+"public"
+"FTP"
+"NNTP."
+"WWW-"
+"never"
+"equals"
+"\"HTTP/1.1"
+"reported"
+"objects"
+"address"
+"active"
+"path"
+"["
+"\"POST\""
+"HTTP."
+"change"
+"MA"
+"\"AS"
+"broken"
+"BACK)"
+"NOT"
+"NNTP"
+"named"
+"useful"
+"secure"
+"family"
+"case."
+"detected."
+"\"HTTP\""
+"private"
+"CERN/3.0"
+"CTE"
+"(CTE)"
+"Too"
+"CTL"
+"PUT,"
+"user-agent"
+"PUT)"
+"byte"
+"select"
+"use"
+"TASK"
+"from"
+"exception."
+"working"
+"to"
+"value."
+"WARRANTIES"
+"two"
+"URI;"
+"User-Agent"
+"few"
+"--THIS_STRING_SEPARATES"
+"POST,"
+"call"
+"6"
+"MUST,"
+"scope"
+"type"
+"authorization"
+"more"
+"ISO-8859-9,"
+"(GMT),"
+"(TE)"
+"name."
+"initial"
+"Required"
+"RFC-850"
+"warn"
+"bytes,"
+"Found"
+"cases"
+"MHTML"
+"name:"
+"must"
+"parse"
+"lowercase"
+"MHTML,"
+"RIGHTS"
+"this"
+"NTP"
+"work"
+"--THIS_STRING_SEPARATES--"
+"Syntax"
+"paragraph"
+"can"
+"tracing"
+"following"
+"\"I"
+"closing"
+"modifier"
+"root"
+"example"
+"requested,"
+"J.,"
+"control"
+"type."
+"reserved"
+"links"
+"process"
+"attribute"
+"allowed"
+"high"
+"currency"
+"numbers"
+"want"
+"type:"
+"native"
+"LF"
+"class,"
+"end"
+"Missing"
+"HTTP-"
+"HTTP,"
+"charset"
+"1"
+"line."
+"2*N"
+"H."
+"1XX"
+"WARRANTIES,"
+"HTTP:"
+"A"
+"badly"
+"HEAD"
+"may"
+"insecure"
+"after"
+"variant"
+"different"
+"wrong"
+"[SP"
+"ANSI,"
+"date"
+"such"
+"data"
+"parallel"
+"repeat"
+"a"
+"FTP,"
+"All"
+"short"
+"\"GET\""
+"Y."
+"UA"
+"(2**N),"
+"element"
+"so"
+"cases."
+"File"
+"(LWS)"
+"\"DEFLATE"
+"order"
+"\"SHOULD"
+"don't"
+"MIC"
+"move"
+"vary"
+"satisfied"
+"CD-ROM,"
+"ended"
+"HTTP-WG."
+"LINK,"
+"pointer"
+"its"
+"digest"
+"before"
+"HTML"
+"(OK)"
+"using:"
+"MAY,"
+"fix"
+"ISO-3166"
+"actually"
+"407"
+"(GNU"
+"\"HTTP/1.1\","
+"P.,"
+"401"
+"MERCHANTABILITY"
+"DNS."
+"into"
+"\"HTTP"
+"it."
+"it,"
+"return"
+"combination"
+"URL"
+"URI"
+"number"
+"Bad"
+"not"
+"However,"
+"SSL"
+"name"
+"always"
+"decimal"
+"expectation."
+"did"
+"ISO-639"
+"]URI,"
+"found"
+"trailer"
+"mean"
+"breakdown"
+"domain"
+"From"
+"UTC"
+"(via"
+"(URI)"
+"UNLINK"
+"used"
+"expect"
+"exceeded"
+"(MIC)"
+"event"
+"out"
+"is:"
+"by"
+"E."
+"space"
+"\"MUST/MAY/SHOULD\""
+"REQUIRED"
+"ALPHA"
+"HTTP/2.4"
+"4DIGIT"
+"increase"
+"L."
+"time."
+"PATCH,"
+"supports"
+"2DIGIT"
+"K.,"
+"(A,"
+"This"
+"free"
+"\"B\""
+"RFC"
+"base"
+"proxy"
+"IMPLIED,"
+"POST"
+"received."
+"generate"
+"text/plain"
+"ISO-8859-7,"
+"\"HTTP/1.1\""
+"Partial"
+"could"
+"transition"
+"DISCLAIMS"
+"times"
+"filter"
+"HTML\","
+"length"
+"HEAD."
+"HEAD,"
+"S.,"
+"first"
+"origin"
+"\"E\""
+"already"
+"UPALPHA"
+"3DIGIT"
+"*"
+"Cache"
+"Please"
+"token."
+"one"
+"CHAR"
+"ISI"
+"another"
+"FITNESS"
+"message"
+"CSS1,"
+"open"
+"size"
+"doesn't"
+"\""
+"script"
+"unknown"
+"top"
+"header)"
+"system"
+"construct"
+"image/gif"
+"2"
+"ignored."
+"listed"
+"Date"
+"LOALPHA"
+"scheme"
+"final"
+"store"
+"too"
+"M."
+"Success"
+"that"
+"completed"
+"OPTIONAL;"
+"task"
+"tokens"
+"R"
+"pragma"
+"(IANA"
+"WAIS"
+"F.,"
+"than"
+"(A"
+"K."
+"target"
+"16"
+"require"
+"Only"
+"WWW-Authenticate"
+"HTTP/2.13,"
+"headers"
+"See"
+"GMT."
+"HTTP/2.0,"
+"were"
+"1)"
+"IS\""
+"stale"
+"1*8ALPHA"
+"are"
+"and"
+"IRC/6.9,"
+"false"
+"URL)."
+"turned"
+"ANSI"
+"B"
+"(IANA)"
+"(LWS)."
+"have"
+"MIME,"
+"need"
+"HTTP/1.1.)"
+"null"
+"any"
+"contents"
+"conversion"
+"data)"
+"(LZ77)"
+"(MIME"
+"mechanism"
+"internal"
+"(C)"
+"take"
+"which"
+"With"
+"UCI"
+"HTTP/0.9,"
+"content-"
+"200"
+"begin"
+"headers)"
+"unless"
+"TCP/IP"
+"Content-Disposition"
+"206"
+"buffer"
+"object"
+"\"MUST\","
+"regular"
+"letter"
+"entry"
+"The"
+"]"
+"the"
+"D."
+"(STD"
+"incompatible"
+"L.,"
+"(URL)"
+"left"
+"+"
+"\"MIME"
+"Note:"
+"particularly"
+"WA"
+"text"
+"labels"
+"\"C\""
+"Authentication"
+"Unrecognized"
+"CRLF."
+"PARTICULAR"
+"CRLF,"
+"SP"
+"find"
+"MUST"
+"true,"
+"cache."
+"upgrade"
+"cache)"
+"implementation"
+"("
+"[RFC"
+"cache"
+"3"
+"should"
+"failed"
+"only"
+"unable"
+"LDAP)"
+"USA"
+"US-ASCII"
+"(UA)"
+"get"
+"E.,"
+"HEREIN"
+"\"HTTP\"."
+"cannot"
+"new"
+"THE"
+"BNF"
+"DIGIT,"
+"closure"
+"PUT"
+"0)"
+"resource"
+"A.,"
+"W."
+"Content-Type:"
+"ISO-8859."
+"calling"
+"J."
+"INCLUDING"
+"common"
+"INTERNET"
+"release"
+"ISI/RR-98-463,"
+"\"CONNECT\""
+"where"
+"set"
+"IANA"
+"For"
+"\"F\""
+"configured"
+"C"
+"this,"
+"multipart"
+"close"
+"end."
+"detect"
+"GET"
+"WWW\","
+"1*DIGIT"
+"BUT"
+"MIT"
+"outside"
+"Proxy-Authorization"
+"closed"
+"between"
+"probably"
+"boundary"
+"reading"
+"\"SHALL"
+"\"RECOMMENDED\","
+"available"
+"we"
+"FOR"
+"missing"
+"importance"
+"screen"
+"connection."
+"ISO-8859-1"
+"UNIX"
+"STD"
+"key"
+"(MIME)"
+"P."
+"\"HTTP/1.1\"."
+"HTTP/1.0),"
+"AND"
+"received"
+"WWW"
+"TRACE"
+"\"MAY\","
+"many"
+"*TEXT"
+"Unsupported"
+"Rules"
+"connection"
+"Unicode"
+"*OCTET"
+"exceeds"
+"(URN)"
+"safely"
+"finds"
+"can't"
+"WARRANTY"
+"ISO-8859-8,"
+"Content-Length"
+"consume"
+"stream"
+"simple"
+"header"
+"DNS)"
+"colon"
+"adding"
+"spans"
+"1*HEX"
+"table"
+"allocated"
+"BCP"
+"application/pdf"
+"LWS:"
+"\"REQUIRED\","
+"Wed,"
+"C."
+"C,"
+"Proxy-Authenticate"
+"encryption"
+"create"
+"(MHTML)\","
+"been"
+"."
+"HTTP/12.3."
+"\"OPTIONS\""
+"\"PUT\""
+"context."
+"LWS,"
+"basic"
+"expected"
+"prototype"
+"GMT,"
+"empty"
+">"
+"URL."
+"PNG,\""
+"\"D\""
+"CA"
+"HEX"
+"N"
+"0*3DIGIT"
+"\"W/\""
+"CR"
+"\"DELETE\""
+"unnecessarily"
+"case"
+"exception"
+"save"
+"(HTTP)"
+"value"
+"Assigned"
+"while"
+"\"GZIP"
+"\"SHALL\","
+"error"
+"\"GMT\""
+"\"TRACE\""
+"resident"
+"is"
+"thus"
+"it"
+"encountered"
+"Content"
+"MIME"
+"in"
+"SIGCOMM"
+"You"
+"if"
+"result"
+"binary"
+"containing"
+"\"A"
+")"
+"CREATE"
+"expired"
+"1DIGIT"
+"same"
+"OPTIONS"
+"read"
+"BNF,"
+"unrecognized"
+"units"
+"UST"
+"status"
+"\"%"
+"extended"
+"http"
+"context"
+"I"
+"IP"
+"(O)."
+"allocation"
+"running"
+"*LWS"
+"user"
+"SMTP"
+"stack"
+"tracking"
+"IETF"
+"CR."
+"failing"
+"ANY"
+"patterns"
+"M.,"
+"Names"
+"In"
+"position"
+"model"
+"audio"
+"If"
+"US-ASCII."
+"MAY"
+"THAT"
+"being"
+"(OK)."
+"actions"
+"invalid"
+"HTTP/1.0)"
+"CRC."
+"previous"
+"tables"
+"TO"
+"<US-ASCII"
+"character"
+"source"
+"ISO-8859-2,"
+"valid"
+"location"
+"HTTP/1.0"
+"HTTP/1.1"
+"size,"
+"has"
+"match"
+"build"
+"URI."
+"tests"
+"format"
+"transfer-encoding"
+"H.,"
+"T"
+"using"
+"LIMITED"
+"OK"
+"success"
+"text/html"
+"ISO-8859-5,"
+"B,"
+"signal"
+"MIME:"
+"(HTCPCP/1.0)\","
+"server"
+"discarded"
+"true"
+"OF"
+"output"
+"page"
+"S."
+"right"
+"old"
+"sequence"
+"uppercase"
+"B.,"
+"some"
+"back"
+"HT"
+"Last-Modified"
+"growth"
+"equivalent"
+"specified"
+"multiple"
+"H.F.,"
+"HTTP/1.0."
+"(BNF)"
+"happens"
+"ignore"
+"PUT."
+"INDEX."
+"trace"
+"for"
+"avoid"
+"CR,"
+"does"
+"Authorization"
+"assuming"
+"be"
+"run"
+"GET."
+"deleted"
+"302"
+"X3.4-1986"
+"<URL:"
+"O"
+"ISO-8859-1."
+"last-modified"
+"host"
+"HTTP/1.0,"
+"LWS>"
+"INFORMATION"
+"X3.4-1986,"
+"properties"
+"ALPHA,"
+"Location"
+"on"
+"DIGIT"
+"ENGINEERING"
+"actual"
+"extension"
+"of"
+"R.,"
+"\"UTF-8,"
+"*<TEXT,"
+"OR"
+"range"
+"3ALPHA"
+"URI,"
+"positive"
+"Message"
+"DELETE"
+"content-type"
+"or"
+"UC"
+"No"
+"ISO-"
+"image"
+"ACM"
+"HEX\""
+"URL,"
+"because"
+"ISO-8859-6,"
+"T.,"
+"operator"
+"T/TCP"
+"mark"
+"file."
+"area"
+"GET\""
+"transfer"
+"support"
+"there"
+"long"
+"class"
+"start"
+"HT."
+"forward"
+"was"
+"function"
+"HT,"
+"N."
+"HTTP/1.1\","
+"memory"
+"OCTET"
+"but"
+"failure"
+"TE:"
+"IMPLIED"
+"CRLF"
+"DNS"
+"Error"
+"\"ZLIB"
+"line"
+"trying"
+"with"
+"GMT"
+"count"
+"algorithm"
+"default"
+"B."
+"ISO-8859-1,"
+"up"
+"ISO-8859-1)"
+"SHOULD"
+"PURPOSE."
+"limit"
+"used."
+"WILL"
+"DEL"
+"define"
+"called"
+"delete"
+"DELETE,"
+"storing"
+"USE"
+"image/jpeg"
+"defined"
+"LWS"
+"combining"
+"unsafe"
+"an"
+"To"
+"as"
+"warning"
+"exist"
+"at"
+"file"
+"NOT\""
+"NOT,"
+"W3C/MIT"
+"ISO-8859-1:1987."
+"SHTTP/1.3,"
+"no"
+"when"
+"A,"
+"virtual"
+"A."
+"details."
+"application"
+"other"
+"OPTIONAL"
+"Proxy"
+"LF,"
+"test"
+"MD5"
+"you"
+"TE"
+"ISO-8859-3,"
+"requested"
+"elements"
+"C)"
+"symbol"
+"T."
+"code)"
+"variable"
+"SOCIETY"
+"\"MUST"
+"TCP"
+"ISO-10646\","
+"NOT\","
+"R."
+"lead"
+"audio/basic"
+"IANA."
+"\"WAIS"
+"persistent"
+"Its"
+"As"
+"time"
+"failures"
+"\"ISO-8859-1\""
+"once"
+
diff --git a/net/data/fuzzer_dictionaries/net_http_stream_parser_fuzzer.dict b/net/data/fuzzer_dictionaries/net_http_stream_parser_fuzzer.dict
new file mode 100644
index 0000000..cba14dc
--- /dev/null
+++ b/net/data/fuzzer_dictionaries/net_http_stream_parser_fuzzer.dict
@@ -0,0 +1,1039 @@
+# 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.
+
+# Fuzzer dictionary targetting HTTP/1.x responses.
+
+# Entries that are generally useful in headers
+":"
+"\x0A"
+"\x0D"
+"0"
+"50"
+"500"
+# Horizontal whitespace. Matters mostly in status line.
+" "
+"\x09"
+# Header continuation
+"\x0D\x0A\x09"
+# Used in a lot of individual headers
+";"
+"="
+","
+"\""
+"-"
+
+# Status line components
+"HTTP"
+"/1.1"
+"/1.0"
+# More interesting status codes.  Leading space so can be inserted into
+# other status lines.
+" 100"
+" 200"
+" 206"
+" 301"
+" 302"
+" 303"
+" 304"
+" 307"
+" 308"
+" 401"
+" 403"
+" 404"
+" 500"
+" 501"
+" 403"
+
+# Full status lines (Some with relevant following headers)
+"HTTP/1.1 200 OK\x0A\x0A"
+"HTTP/1.1 100 Continue\x0A\x0A"
+"HTTP/1.1 401 Unauthorized\x0AWWW-Authenticate: Basic realm=\"Middle-Earth\"\x0A\xA0"
+"HTTP/1.1 407 Proxy Authentication Required\x0AProxy-Authenticate: Digest realm=\"Middle-Earth\", nonce=\"aaaaaaaaaa\"\x0A\x0A"
+"HTTP/1.0 301 Moved Permanently\x0ALocation: /a\x0A\x0A"
+"HTTP/1.1 302 Found\x0ALocation: http://lost/\x0A\x0A"
+
+# Proxy authentication headers. Note that fuzzers don't support NTLM or
+# negotiate.
+"WWW-Authenticate:"
+"Proxy-Authenticate:"
+"Basic"
+"Digest"
+"realm"
+"nonce"
+
+"Connection:"
+"Proxy-Connection:"
+"Keep-Alive"
+"Close"
+"Upgrade"
+"\x0AConnection: Keep-Alive"
+"\x0AConnection: Close"
+"\x0AProxy-Connection: Keep-Alive"
+"\x0AProxy-Connection: Close"
+
+"Content-Length:"
+"Transfer-Encoding:"
+"chunked"
+"\x0AContent-Length: 0"
+"\x0AContent-Length: 500"
+"\x0ATransfer-Encoding: chunked\x0A\x0A5\x0A12345\x0A0\x0A\x0A"
+
+"Location:"
+"\x0ALocation: http://foo/"
+"\x0ALocation: http://bar/"
+"\x0ALocation: https://foo/"
+"\x0ALocation: https://bar/"
+
+"Accept-Ranges:"
+"bytes"
+"\x0AAccept-Ranges: bytes"
+
+"Content-Range:"
+
+"Age:"
+"\x0AAge: 0"
+"\x0AAge: 3153600000"
+
+"Cache-Control:"
+"max-age"
+"no-cache"
+"no-store"
+"must-revalidate"
+"\x0ACache-Control: max-age=3153600000"
+"\x0ACache-Control: max-age=0"
+"\x0ACache-Control: no-cache"
+"\x0ACache-Control: no-store"
+"\x0ACache-Control: must-revalidate"
+
+"Content-Disposition:"
+"attachment"
+"filename"
+
+"Content-Encoding:"
+"gzip"
+"deflate"
+"sdch"
+"br"
+"\x0AContent-Encoding: gzip"
+"\x0AContent-Encoding: deflate"
+"\x0AContent-Encoding: sdch"
+"\x0AContent-Encoding: br"
+
+"Date:"
+"Fri, 01 Apr, 2050 14:14:14 GMT"
+"Mon, 28 Mar, 2016 04:04:04 GMT"
+"\x0ADate: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0ADate: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Last-Modified:"
+"\x0ALast-Modified: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0ALast-Modified: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Expires:"
+"\x0AExpires: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0AExpires: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Set-Cookie:"
+"Expires"
+"Max-Age"
+"Domain"
+"Path"
+"Secure"
+"HttpOnly"
+"Priority"
+"Low"
+"Medium"
+"High"
+"SameSite"
+"Strict"
+"Lax"
+"\x0ASet-Cookie: foo=bar"
+"\x0ASet-Cookie: foo2=bar2;HttpOnly;Priority=Low;SameSite=Strict;Path=/"
+"\x0ASet-Cookie: foo=chicken;SameSite=Lax"
+
+"Strict-Transport-Security:"
+"includeSubDomains"
+
+"Vary:"
+"\x0AVary: Cookie"
+"\x0AVary: Age"
+
+"ETag:"
+"\x0AETag: jumboshrimp"
+
+
+# This part has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_http_stream_parser_fuzzer binary and RFC 2616.
+"all"
+"code"
+"maximum"
+"Transfer-Encoding"
+"D.,"
+"results"
+"follow"
+"(LZW)."
+"provided."
+"(which"
+"ISDN"
+"\"TE\""
+"LF>"
+"FORCE"
+"calculate"
+"\"IETF"
+"UNIX,"
+"ARPA"
+"\"OPTIONAL\""
+"environment"
+"ENGINEERING"
+"program"
+"USENET"
+"TEXT"
+"Not"
+"Nov"
+"include"
+"resources"
+"(STD"
+"labels"
+"string"
+"returning"
+"HTTP/1.1;"
+"SP,"
+"SP."
+"entries"
+"HTTP/1.1,"
+"HTTP/1.1."
+"difference"
+"(URI):"
+"did"
+"[CRLF]"
+"EXPRESS"
+"list"
+"HTTP/1.0\","
+"(RFC"
+"large"
+"ONLY"
+"Tag"
+"(LWS"
+"(URL)\","
+"\"A\"..\"Z\">"
+"unexpected"
+"GET)"
+"direct"
+"Failed"
+"second"
+"Version"
+"\"A\""
+"allowed."
+"GET,"
+"tag."
+"implemented"
+"\"HTTP/1.0\""
+"errors"
+"ISO-8859-4,"
+"appear"
+"incompatible"
+"section"
+"CPU"
+"current"
+"waiting"
+"version"
+"above"
+"TTL"
+"new"
+"CRLF)"
+"public"
+"FTP"
+"NNTP."
+"WWW-"
+"never"
+"equals"
+"\"HTTP/1.1"
+"reported"
+"objects"
+"address"
+"active"
+"\"HEAD\""
+"["
+"\"POST\""
+"HTTP."
+"change"
+"MA"
+"\"AS"
+"last-modified"
+"BACK)"
+"NOT"
+"NNTP"
+"named"
+"useful"
+"secure"
+"case."
+"detected."
+"\"HTTP\""
+"private"
+"CERN/3.0"
+"CTE"
+"(CTE)"
+"Too"
+"CTL"
+"PUT,"
+"user-agent"
+"PUT)"
+"POST"
+"select"
+"use"
+"TASK"
+"from"
+"exception."
+"working"
+"to"
+"positive"
+"two"
+"URI;"
+"properties"
+"few"
+"--THIS_STRING_SEPARATES"
+"POST,"
+"call"
+"memory"
+"MUST,"
+"scope"
+"type"
+"authorization"
+"more"
+"ISO-8859-9,"
+"(GMT),"
+"(TE)"
+"name."
+"LF,"
+"RFC-850"
+"warn"
+"bytes,"
+"Found"
+"cases"
+"MHTML"
+"name:"
+"must"
+"Content"
+"ALL"
+"MHTML,"
+"RIGHTS"
+"this"
+"NTP"
+"work"
+"--THIS_STRING_SEPARATES--"
+"Syntax"
+"can"
+"of"
+"following"
+"\"I"
+"closing"
+"root"
+"example"
+"requested,"
+"J.,"
+"type."
+"reserved"
+"stream"
+"process"
+"attribute"
+"allowed"
+"high"
+"currency"
+"numbers"
+"want"
+"type:"
+"native"
+"LF"
+"class,"
+"end"
+"Missing"
+"HTTP-"
+"HTTP,"
+"links"
+"1"
+"line."
+"2*N"
+"H."
+"1XX"
+"WARRANTIES,"
+"HTTP:"
+"A"
+"badly"
+"HEAD"
+"may"
+"insecure"
+"after"
+"containing"
+"tracking"
+"wrong"
+"[SP"
+"ANSI,"
+"date"
+"such"
+"data"
+"parallel"
+"repeat"
+"a"
+"FTP,"
+"All"
+"short"
+"Y."
+"UA"
+"(2**N),"
+"element"
+"so"
+"cases."
+"File"
+"(LWS)"
+"\"DEFLATE"
+"order"
+"charset"
+"\"SHOULD"
+"don't"
+"MIC"
+"move"
+"vary"
+"satisfied"
+"CD-ROM,"
+"HTTP-WG."
+"LINK,"
+"pointer"
+"its"
+"digest"
+"before"
+"HTML"
+"(OK)"
+"Rules"
+"MAY,"
+"fix"
+"ISO-3166"
+"actually"
+"407"
+"(GNU"
+"\"HTTP/1.1\","
+"P.,"
+"401"
+"MERCHANTABILITY"
+"DNS."
+"into"
+"\"HTTP"
+"it."
+"it,"
+"return"
+"URL"
+"URI"
+"number"
+"Bad"
+"not"
+"However,"
+"SSL"
+"name"
+"always"
+"expectation."
+"--"
+"ISO-639"
+"]URI,"
+"found"
+"trailer"
+"mean"
+"breakdown"
+"From"
+"UTC"
+"(via"
+"(URI)"
+"UNLINK"
+"expect"
+"exceeded"
+"(MIC)"
+"event"
+"out"
+"is:"
+"E."
+"space"
+"\"MUST/MAY/SHOULD\""
+"REQUIRED"
+"ALPHA"
+"HTTP/2.4"
+"4DIGIT"
+"increase"
+"L."
+"time."
+"PATCH,"
+"supports"
+"2DIGIT"
+"K.,"
+"(A,"
+"This"
+"free"
+"\"B\""
+"RFC"
+"base"
+"IMPLIED,"
+"byte"
+"received."
+"generate"
+"text/plain"
+"ISO-8859-7,"
+"\"HTTP/1.1\""
+"Partial"
+"could"
+"transition"
+"DISCLAIMS"
+"times"
+"filter"
+"HTML\","
+"length"
+"HEAD."
+"HEAD,"
+"S.,"
+"first"
+"origin"
+"\"E\""
+"already"
+"UPALPHA"
+"3DIGIT"
+"Cache"
+"Please"
+"token."
+"one"
+"CHAR"
+"ISI"
+"another"
+"FITNESS"
+"message"
+"CSS1,"
+"open"
+"size"
+"doesn't"
+"\""
+"script"
+"unknown"
+"top"
+"header)"
+"system"
+"construct"
+"image/gif"
+"2"
+"ignored."
+"listed"
+"Date"
+"LOALPHA"
+"scheme"
+"store"
+"too"
+"M."
+"Success"
+"that"
+"completed"
+"OPTIONAL;"
+"R"
+"pragma"
+"(IANA"
+"WAIS"
+"F.,"
+"than"
+"K."
+"target"
+"Content-Type:"
+"require"
+"Only"
+"HTTP/2.13,"
+"headers"
+"See"
+"GMT."
+"HTTP/2.0,"
+"were"
+"1)"
+"IS\""
+"1*8ALPHA"
+"are"
+"and"
+"IRC/6.9,"
+"false"
+"turned"
+"ANSI"
+"B"
+"(IANA)"
+"tables"
+"have"
+"MIME,"
+"need"
+"HTTP/1.1.)"
+"null"
+"any"
+"contents"
+"data)"
+"(LZ77)"
+"(MIME"
+"mechanism"
+"internal"
+"(C)"
+"take"
+"which"
+"With"
+"UCI"
+"HTTP/0.9,"
+"content-"
+"200"
+"begin"
+"multiple"
+"TCP/IP"
+"Content-Disposition"
+"206"
+"buffer"
+"object"
+"\"MUST\","
+"regular"
+"entry"
+"The"
+"]"
+"model"
+"D."
+"US-ASCII"
+"L.,"
+"(URL)"
+"If"
+"+"
+"\"MIME"
+"Note:"
+"particularly"
+"WA"
+"text"
+"supported"
+"\"C\""
+"Unrecognized"
+"CRLF."
+"CRLF,"
+"SP"
+"find"
+"MUST"
+"true,"
+"cache."
+"upgrade"
+"cache)"
+"implementation"
+"("
+"[RFC"
+"cache"
+"outside"
+"should"
+"failed"
+"only"
+"URL)."
+"LDAP)"
+"USA"
+"WARRANTIES"
+"(UA)"
+"get"
+"there"
+"HEREIN"
+"\"HTTP\"."
+"cannot"
+"shared"
+"THE"
+"BNF"
+"DIGIT,"
+"closure"
+"PUT"
+"reading"
+"resource"
+"A.,"
+"W."
+"16"
+"ISO-8859."
+"calling"
+"J."
+"INCLUDING"
+"common"
+"INTERNET"
+"release"
+"ISI/RR-98-463,"
+"\"CONNECT\""
+"where"
+"set"
+"IANA"
+"For"
+"\"F\""
+"configured"
+"C"
+"this,"
+"multipart"
+"close"
+"E.,"
+"end."
+"detect"
+"GET"
+"WWW\","
+"1*DIGIT"
+"BUT"
+"MIT"
+"3"
+"unable"
+"between"
+"probably"
+"boundary"
+"0)"
+"\"SHALL"
+"\"RECOMMENDED\","
+"available"
+"we"
+"FOR"
+"missing"
+"importance"
+"screen"
+"connection."
+"PARTICULAR"
+"UNIX"
+"STD"
+"ISO-8859-1"
+"key"
+"(MIME)"
+"P."
+"\"HTTP/1.1\"."
+"HTTP/1.0),"
+"AND"
+"received"
+"WWW"
+"TRACE"
+"\"MAY\","
+"many"
+"*TEXT"
+"Unsupported"
+"using:"
+"connection"
+"Unicode"
+"*OCTET"
+"exceeds"
+"(URN)"
+"safely"
+"ANY"
+"can't"
+"WARRANTY"
+"ISO-8859-8,"
+"Content-Length"
+"consume"
+"simple"
+"header"
+"DNS)"
+"colon"
+"\"GET\""
+"spans"
+"1*HEX"
+"table"
+"allocated"
+"BCP"
+"application/pdf"
+"LWS:"
+"save"
+"\"REQUIRED\","
+"Wed,"
+"C."
+"C,"
+"encryption"
+"create"
+"(MHTML)\","
+"been"
+"."
+"HTTP/12.3."
+"\"PUT\""
+"context."
+"LWS,"
+"basic"
+"expected"
+"prototype"
+"GMT,"
+"empty"
+"define"
+"PNG,\""
+"\"D\""
+"with"
+"CA"
+"HEX"
+"N"
+"0*3DIGIT"
+"\"W/\""
+"CR"
+"\"DELETE\""
+"unnecessarily"
+"case"
+"exception"
+"(A"
+"(HTTP)"
+"value"
+"INFRINGE"
+"while"
+"\"GZIP"
+"\"SHALL\","
+"error"
+"\"GMT\""
+"(LWS)."
+"resident"
+"is"
+"thus"
+"it"
+"encountered"
+"parse"
+"MIME"
+"in"
+"SIGCOMM"
+"You"
+"if"
+"result"
+"binary"
+"different"
+"\"A"
+")"
+"CREATE"
+"expired"
+"1DIGIT"
+"same"
+"OPTIONS"
+"transfer-encoding"
+"BNF,"
+"unrecognized"
+"units"
+"UST"
+"status"
+"\"%"
+"used"
+"http"
+"context"
+"I"
+"IP"
+"(O)."
+"allocation"
+"running"
+"*LWS"
+"user"
+"SMTP"
+"\"SHOULD\","
+"stack"
+"task"
+"CR."
+"failing"
+"IETF"
+"M.,"
+"Names"
+"In"
+"position"
+"the"
+"audio"
+"left"
+"US-ASCII."
+"MAY"
+"THAT"
+"being"
+"(OK)."
+"actions"
+"invalid"
+"HTTP/1.0)"
+"CRC."
+"previous"
+"adding"
+"TO"
+"<US-ASCII"
+"source"
+"ISO-8859-2,"
+"\"OPTIONS\""
+"location"
+"HTTP/1.0"
+"HTTP/1.1"
+"size,"
+"has"
+"match"
+"build"
+"URI."
+"tests"
+"format"
+"read"
+"H.,"
+"T"
+"using"
+"LIMITED"
+"OK"
+"text/html"
+"success"
+"ISO-8859-5,"
+"B,"
+"signal"
+"MIME:"
+"(HTCPCP/1.0)\","
+"server"
+"ignore"
+"OF"
+"output"
+"page"
+"S."
+"because"
+"old"
+"sequence"
+"HT."
+"B.,"
+"some"
+"back"
+"HT"
+"Last-Modified"
+"growth"
+"DEL"
+"specified"
+"unless"
+"H.F.,"
+"HTTP/1.0."
+"(BNF)"
+"happens"
+"discarded"
+"PUT."
+"INDEX."
+"trace"
+"for"
+"avoid"
+"CR,"
+"does"
+"CONNECT"
+"assuming"
+"be"
+"run"
+"GET."
+"deleted"
+"equivalent"
+"X3.4-1986"
+"<URL:"
+"O"
+"ISO-8859-1."
+"broken"
+"host"
+"HTTP/1.0,"
+"LWS>"
+"INFORMATION"
+"X3.4-1986,"
+"by"
+"ALPHA,"
+"Location"
+"on"
+"DIGIT"
+"actual"
+"extension"
+"tracing"
+"R.,"
+"\"UTF-8,"
+"*<TEXT,"
+"OR"
+"range"
+"3ALPHA"
+"URI,"
+"value."
+"Message"
+"DELETE"
+"content-type"
+"or"
+"UC"
+"No"
+"ISO-"
+"image"
+"ACM"
+"HEX\""
+"URL,"
+"ISO-8859-6,"
+"T.,"
+"operator"
+"T/TCP"
+"file."
+"GET\""
+"transfer"
+"support"
+"*"
+"long"
+"class"
+"start"
+"forward"
+"was"
+"function"
+"HT,"
+"N."
+"HTTP/1.1\","
+"OCTET"
+"but"
+"failure"
+"TE:"
+"IMPLIED"
+"CRLF"
+"DNS"
+"Error"
+"\"ZLIB"
+"line"
+"trying"
+"true"
+"GMT"
+"count"
+"default"
+"B."
+"ISO-8859-1,"
+"up"
+"ISO-8859-1)"
+"SHOULD"
+"PURPOSE."
+"used."
+"WILL"
+">"
+"called"
+"delete"
+"DELETE,"
+"storing"
+"USE"
+"image/jpeg"
+"defined"
+"LWS"
+"URL."
+"unsafe"
+"an"
+"To"
+"as"
+"warning"
+"exist"
+"at"
+"file"
+"NOT\""
+"NOT,"
+"W3C/MIT"
+"ISO-8859-1:1987."
+"SHTTP/1.3,"
+"no"
+"when"
+"A,"
+"virtual"
+"A."
+"details."
+"application"
+"valid"
+"OPTIONAL"
+"\"TRACE\""
+"test"
+"MD5"
+"you"
+"TE"
+"ISO-8859-3,"
+"requested"
+"elements"
+"C)"
+"symbol"
+"T."
+"code)"
+"variable"
+"SOCIETY"
+"\"MUST"
+"TCP"
+"ISO-10646\","
+"NOT\","
+"R."
+"audio/basic"
+"IANA."
+"\"WAIS"
+"persistent"
+"Its"
+"As"
+"time"
+"failures"
+"\"ISO-8859-1\""
+"once"
+
diff --git a/net/data/fuzzer_dictionaries/net_mime_sniffer_fuzzer.dict b/net/data/fuzzer_dictionaries/net_mime_sniffer_fuzzer.dict
new file mode 100644
index 0000000..ec42dd9
--- /dev/null
+++ b/net/data/fuzzer_dictionaries/net_mime_sniffer_fuzzer.dict
@@ -0,0 +1,299 @@
+# 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.
+
+# This file has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_mime_sniffer_fuzzer binary and RFC 2045.
+"all"
+"BASE64"
+"US-ASCII."
+"LESS"
+"being"
+"text"
+"supported"
+"\"C\""
+"TAB)"
+"X.400"
+"invalid"
+"EQUAL"
+"CRLF."
+"CRLF,"
+"A."
+"data"
+"its"
+"to"
+"before"
+"TO"
+"implementation"
+"true"
+"US-ASCII,"
+"0"
+"only"
+"internal"
+"TAB"
+"(US-ASCII)"
+"FORMATTING"
+"(A"
+"TILDE,"
+"US-ASCII"
+"(STD"
+"\"F\")"
+"V"
+"string"
+"get"
+"EXPRESSLY"
+"H"
+"L"
+"P"
+"T"
+"CONTENT-TYPE"
+"CONTENT-TRANSFER-"
+"not"
+"X"
+"D"
+"BNF"
+"ENCODING:"
+"name"
+"ON"
+"d"
+"success"
+"MAY"
+"\"=0D=0A\"."
+"bytes"
+"(RFC"
+"default"
+"ONLY"
+"RFC."
+"THE"
+"section"
+"\"0123456789ABCDEF\"."
+"ASCII"
+"*(CRLF"
+"A"
+"set"
+"NO)"
+"[RFC-821])"
+"\"=0D=0A\""
+"\"=0C\","
+"M."
+"some"
+"direct"
+"sign"
+"TEXT,"
+"\"A\""
+"are"
+"allowed."
+"\"X-\")"
+"MIME."
+"\"X-\","
+"event"
+"THAN,"
+"MUST"
+"for"
+"space"
+"+"
+"1*DIGIT"
+"/"
+"THAN"
+"may"
+"3"
+"version"
+"HISTORICAL"
+"MIME,"
+"probably"
+"CRLF)"
+"REQUIRES"
+"corruption"
+"IMPLEMENTORS:"
+"available"
+"be"
+"C"
+"G"
+"7BIT\""
+"This"
+"NO"
+"K"
+"NJ"
+"O"
+"(EXCLAMATION"
+"RFC"
+"1)"
+"[ATK],"
+"base"
+"STD"
+"ISO-8859-1"
+"W"
+"application/octet-stream"
+"\"=3D\"."
+"["
+"CA"
+"by"
+"AND"
+"on"
+"c"
+"NOTE:"
+"g"
+"of"
+"could"
+"POINT"
+"S"
+"times"
+"s"
+"MANDATORY"
+"NOT"
+"UA"
+"or"
+"CR,"
+"STRONGLY"
+"TAB,"
+"already"
+"useful"
+"*(SPACE"
+"No"
+"(MIME)"
+"number"
+"one"
+"CHAR"
+"RFC,"
+"\"=0D\""
+"because"
+"[RFC-821]),"
+"S."
+"EBCDIC."
+"[RFC-821]."
+"(SMTP)"
+"IMPORTANT:"
+"\"=0A=0D\""
+"use"
+"from"
+"USA"
+"&"
+"IETF"
+"transfer"
+"top"
+"(US-ASCII"
+"IANA"
+"long"
+"\"=0D\","
+"few"
+"2"
+"E"
+"expected"
+"type"
+">"
+"\"D\""
+"B"
+"N."
+"received"
+"[RFC-1741],"
+"completed"
+"J"
+"LF)"
+"SMTP.)"
+"but"
+"back"
+"warn"
+"R"
+"SIGN)"
+"CRLF"
+"EBCDIC"
+"BETWEEN"
+"CR"
+"line"
+"Z"
+"with"
+"unnecessarily"
+"must"
+"count"
+"(HT)"
+"GREATER"
+"16"
+"this"
+"was"
+"work"
+"value"
+"ISO-8859-1,"
+"while"
+"following"
+"IANA.>"
+"called"
+"(US-"
+"and"
+"(PEM)"
+"type."
+"UNIX"
+"RELATIONSHIP"
+"ENCODING"
+"\"E\""
+"attribute"
+"is"
+"allowed"
+"thus"
+"lost."
+"Virtual"
+"an"
+"high"
+"as"
+"MIME"
+"at"
+"have"
+"in"
+"need"
+"any"
+"contents"
+"native"
+"LF"
+"binary"
+"F"
+"\"X-\""
+"7BIT"
+"TX"
+"no"
+")"
+"FORBIDDEN"
+"2(DIGIT"
+"format"
+"when"
+"length"
+"mechanism"
+"j"
+"RESTRICTIONS:"
+"application"
+"that"
+"valid"
+"which"
+"="
+"LWSP"
+"profile"
+"ISO"
+"begin"
+"used"
+"multiple"
+"SPACE"
+"I"
+"SMTP"
+"after"
+"M"
+"\"B\""
+"Q"
+"U"
+"[X400]"
+"Y"
+"such"
+"The"
+"N"
+"]"
+"\"=0A\","
+"a"
+"short"
+"WARNING"
+"ALWAYS"
+"SPACE,"
+"NOTE"
+"As"
+"does"
+"<A"
+"the"
+"avoid"
+"If"
+
diff --git a/net/data/fuzzer_dictionaries/net_parse_data_url_fuzzer.dict b/net/data/fuzzer_dictionaries/net_parse_data_url_fuzzer.dict
new file mode 100644
index 0000000..1668f4c
--- /dev/null
+++ b/net/data/fuzzer_dictionaries/net_parse_data_url_fuzzer.dict
@@ -0,0 +1,449 @@
+# 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.
+
+# This file has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_parse_data_url_fuzzer binary and RFC 3986.
+"all"
+"DNS"
+"text"
+"labels"
+"DQUOTE"
+"\"%D3%81%87%A4%95%81@%C2%85%81%83%88\"."
+"[RFC2234]"
+"F.,"
+"FORCE"
+"SOCIETY"
+"\"%\""
+"with"
+"cache"
+"WINS,"
+"D.1."
+"0"
+"only"
+"HTML"
+"SPONSORED"
+"[RFC1630]."
+"D.,"
+"[RFC1123]"
+"US-ASCII"
+"(STD"
+"[RFC1808],"
+"string"
+"get"
+"=="
+"H"
+"HEREIN"
+"[BCP35]"
+"SP)"
+"SCTP)"
+"(NUL)"
+"THE"
+"(URI):"
+"REPRESENTS"
+"[RFC2732]."
+"resource"
+"A.,"
+"EXPRESS"
+"list"
+"(%2E),"
+"WILL"
+"HE/SHE"
+"J."
+"INCLUDING"
+"common"
+"segment."
+"[RFC2732]"
+"(URL)\","
+"set"
+"HTTP"
+"IANA"
+"INFORMATION"
+"(%41-%5A"
+"[RFC2518]"
+"M."
+"direct"
+"sign"
+"Only"
+"Version"
+"are"
+"allowed."
+"\"X\""
+"HTTP,"
+"(SP)."
+"2DIGIT"
+"section"
+"BUT"
+"\"UTF-8,"
+"3"
+"version"
+"[RFC1034]"
+"probably"
+"[UCS],"
+"metadata"
+"Y.,"
+"C"
+"WWW\""
+"parent"
+"0X"
+"W3C/IETF"
+"S"
+"key"
+"address"
+"INPUT"
+"["
+"P."
+"WWW:"
+"AND"
+"received"
+"WWW"
+"[BCP35]."
+"MA"
+"\"AS"
+"[RFC2718]."
+"(IDNA)\","
+"implementation"
+"TCP"
+"NOT"
+"(URN)"
+"ANY"
+"[RFC1808]"
+"WARRANTY"
+"useful"
+"[RFC1737]."
+"[STD63],"
+"\"HTTP\""
+"(MIME)"
+"TELNET"
+"[RFC1630]"
+"S."
+"D.2."
+"B.,"
+"[RFC2234]."
+"[RFC2234],"
+"BCP"
+"select"
+"[STD63];"
+"use"
+"LATIN"
+"from"
+"C."
+"to"
+"WARRANTIES"
+"(MHTML)\","
+"ENGINEERING"
+"URI;"
+"."
+"few"
+"(DNS)."
+"expected"
+"USENET"
+"type"
+"empty"
+"XML"
+"URL?\","
+"W3C/MIT"
+"F"
+"CA"
+"STD:"
+"SMTP"
+"[RFC2141],"
+"N"
+"A),"
+"flag"
+"NOTE:"
+"CR"
+"MHTML"
+"BY"
+"must"
+"ANY),"
+"ALL"
+"[STD63]"
+"RIGHTS"
+"this"
+"SP"
+"[BCP19]"
+"value"
+"INFRINGE"
+"while"
+"KATAKANA"
+"resources"
+"error"
+"following"
+"example"
+"loop"
+"J.,"
+"2E:"
+"type."
+"L."
+"have"
+"%61-%7A),"
+"is"
+"allowed"
+"thus"
+"URI,"
+"parse"
+"STEP"
+"MIME"
+"UTF-8"
+"in"
+"[RFC0952]."
+"native"
+"FOR"
+"binary"
+"ISO/IEC"
+"\"A"
+"(%5F),"
+")"
+"algorithm."
+"returning"
+"\"A\","
+"[RFC2141]"
+"BUFFER"
+"ABNF"
+"[RFC2557]."
+"I."
+"WARRANTIES,"
+"URN"
+"EBCDIC"
+"A"
+"LF"
+"used"
+"http"
+"I"
+"IP"
+"IS"
+"after"
+"L"
+"Q"
+"'A'"
+"running"
+"HEXDIG"
+"such"
+"EBCDIC,"
+"data"
+"TASK"
+"a"
+"task"
+"P"
+"[ASCII]."
+"M.,"
+"Names"
+"flag."
+"the"
+"If"
+"[RFC3490]"
+"US-ASCII."
+"2C:"
+"THAT"
+"being"
+"when"
+"E.,"
+"(%2D),"
+"\"URL:\""
+"mechanism"
+"WITH"
+"its"
+"before"
+"tables"
+"[UCS]"
+"TO"
+"BNF"
+"platform"
+"internal"
+"P.,"
+"ORGANIZATION"
+"\"HTTP"
+"URI."
+"it,"
+"D"
+"format"
+"URL"
+"S.,"
+"(0"
+"URI\""
+"URI"
+"K."
+"URI:"
+"T"
+"D.W."
+"not"
+"R."
+"LIMITED"
+"\"%3A\")"
+"name"
+"OF"
+"B."
+"[RFC1736]"
+"(R),"
+"IPR"
+"[RFC1738];"
+"OUTPUT"
+"LALR"
+"OR"
+"STD"
+"[RFC3513]"
+"because"
+"bytes"
+"DNS,"
+"some"
+"back"
+"(URI)"
+"*DIGIT"
+"[RFC2046]"
+"[RFC3305]"
+"\"%7E\""
+"W3C"
+"E."
+"for"
+"space"
+"ABNF\","
+"avoid"
+"[RFC1535]."
+"/"
+"increase"
+"may"
+"time."
+"does"
+"'F'"
+"[RFC2396]"
+"be"
+"K.,"
+"DISCLAIM"
+"G"
+"(UTF-16),"
+"This"
+"M"
+"INTERNET"
+"RFC"
+"X3.4,"
+"base"
+"(T):"
+"IMPLIED,"
+"by"
+"\"URL\""
+"on"
+"DIGIT"
+"(ABNF)"
+"WEBDAV\","
+"of"
+"could"
+"R.,"
+"(ABNF:"
+"failed"
+"or"
+"1*4HEXDIG"
+"already"
+"No"
+"CAPITAL"
+"number"
+"one"
+"ISO"
+"FITNESS"
+"message"
+"open"
+"ANSI"
+"[BCP19],"
+"\"%C3%80\","
+"IETF"
+"unknown"
+"support"
+"\"URN"
+"[RFC1123]."
+"long"
+"[RFC0952]"
+"[ASCII]"
+":"
+"was"
+"[RFC3513]."
+"[RFC2718]"
+"B"
+"N."
+"that"
+"IDNA"
+"OCTET"
+"but"
+"R"
+"POSIX"
+"LETTER"
+"CONTRIBUTOR,"
+"[RFC1738]"
+"line"
+"(C)"
+"true"
+"\"URI\""
+"PARTICULAR"
+"target"
+"16"
+"default"
+"double"
+"\"URN\""
+"[RFC2557]"
+"enabled"
+"up"
+"TCP,"
+"PURPOSE."
+"MERCHANTABILITY"
+"1)"
+"IS\""
+"\"IANA"
+"called"
+"multipart"
+"and"
+"USE"
+"false"
+"(IF"
+"USA"
+"URL,"
+"an"
+"To"
+"as"
+"(%7E)"
+"at"
+"file"
+"need"
+"any"
+"\"%E3%82%A2\"."
+"physical"
+"1*HEXDIG"
+"no"
+"[RFC1737]"
+"-"
+"invalid"
+"A."
+"application"
+"valid"
+"take"
+"which"
+"test"
+"[RFC2732],"
+"you"
+"="
+"GRAVE"
+"<URI>"
+"begin"
+"[RFC2396],"
+"multiple"
+"2B:"
+"period,"
+"UDP,"
+"[RFC1535]"
+"T."
+"(UCS)\","
+"U"
+"A-F."
+"T.,"
+"The"
+"]"
+"source"
+"D."
+"persistent"
+"traditional"
+"L.,"
+"As"
+"IMPLIED"
+"(URL)"
+"ALPHA"
+"[RFC3305]."
+"H.,"
+"\"MIME"
diff --git a/net/data/fuzzer_dictionaries/net_url_request_fuzzer.dict b/net/data/fuzzer_dictionaries/net_url_request_fuzzer.dict
new file mode 100644
index 0000000..742ae16
--- /dev/null
+++ b/net/data/fuzzer_dictionaries/net_url_request_fuzzer.dict
@@ -0,0 +1,1718 @@
+# 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.
+
+# Fuzzer dictionary targetting HTTP/1.x responses.
+
+# Entries that are generally useful in headers
+":"
+"\x0A"
+"\x0D"
+"0"
+"50"
+"500"
+# Horizontal whitespace. Matters mostly in status line.
+" "
+"\x09"
+# Header continuation
+"\x0D\x0A\x09"
+# Used in a lot of individual headers
+";"
+"="
+","
+"\""
+"-"
+
+# Status line components
+"HTTP"
+"/1.1"
+"/1.0"
+# More interesting status codes.  Leading space so can be inserted into
+# other status lines.
+" 100"
+" 200"
+" 206"
+" 301"
+" 302"
+" 303"
+" 304"
+" 307"
+" 308"
+" 401"
+" 403"
+" 404"
+" 500"
+" 501"
+" 403"
+
+# Full status lines (Some with relevant following headers)
+"HTTP/1.1 200 OK\x0A\x0A"
+"HTTP/1.1 100 Continue\x0A\x0A"
+"HTTP/1.1 401 Unauthorized\x0AWWW-Authenticate: Basic realm=\"Middle-Earth\"\x0A\xA0"
+"HTTP/1.1 407 Proxy Authentication Required\x0AProxy-Authenticate: Digest realm=\"Middle-Earth\", nonce=\"aaaaaaaaaa\"\x0A\x0A"
+"HTTP/1.0 301 Moved Permanently\x0ALocation: /a\x0A\x0A"
+"HTTP/1.1 302 Found\x0ALocation: http://lost/\x0A\x0A"
+
+# Proxy authentication headers. Note that fuzzers don't support NTLM or
+# negotiate.
+"WWW-Authenticate:"
+"Proxy-Authenticate:"
+"Basic"
+"Digest"
+"realm"
+"nonce"
+
+"Connection:"
+"Proxy-Connection:"
+"Keep-Alive"
+"Close"
+"Upgrade"
+"\x0AConnection: Keep-Alive"
+"\x0AConnection: Close"
+"\x0AProxy-Connection: Keep-Alive"
+"\x0AProxy-Connection: Close"
+
+"Content-Length:"
+"Transfer-Encoding:"
+"chunked"
+"\x0AContent-Length: 0"
+"\x0AContent-Length: 500"
+"\x0ATransfer-Encoding: chunked\x0A\x0A5\x0A12345\x0A0\x0A\x0A"
+
+"Location:"
+"\x0ALocation: http://foo/"
+"\x0ALocation: http://bar/"
+"\x0ALocation: https://foo/"
+"\x0ALocation: https://bar/"
+
+"Accept-Ranges:"
+"bytes"
+"\x0AAccept-Ranges: bytes"
+
+"Content-Range:"
+
+"Age:"
+"\x0AAge: 0"
+"\x0AAge: 3153600000"
+
+"Cache-Control:"
+"max-age"
+"no-cache"
+"no-store"
+"must-revalidate"
+"\x0ACache-Control: max-age=3153600000"
+"\x0ACache-Control: max-age=0"
+"\x0ACache-Control: no-cache"
+"\x0ACache-Control: no-store"
+"\x0ACache-Control: must-revalidate"
+
+"Content-Disposition:"
+"attachment"
+"filename"
+
+"Content-Encoding:"
+"gzip"
+"deflate"
+"sdch"
+"br"
+"\x0AContent-Encoding: gzip"
+"\x0AContent-Encoding: deflate"
+"\x0AContent-Encoding: sdch"
+"\x0AContent-Encoding: br"
+
+"Date:"
+"Fri, 01 Apr, 2050 14:14:14 GMT"
+"Mon, 28 Mar, 2016 04:04:04 GMT"
+"\x0ADate: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0ADate: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Last-Modified:"
+"\x0ALast-Modified: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0ALast-Modified: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Expires:"
+"\x0AExpires: Fri, 01 Apr, 2050 14:14:14 GMT"
+"\x0AExpires: Mon, 28 Mar, 2016 04:04:04 GMT"
+
+"Set-Cookie:"
+"Expires"
+"Max-Age"
+"Domain"
+"Path"
+"Secure"
+"HttpOnly"
+"Priority"
+"Low"
+"Medium"
+"High"
+"SameSite"
+"Strict"
+"Lax"
+"\x0ASet-Cookie: foo=bar"
+"\x0ASet-Cookie: foo2=bar2;HttpOnly;Priority=Low;SameSite=Strict;Path=/"
+"\x0ASet-Cookie: foo=chicken;SameSite=Lax"
+
+"Strict-Transport-Security:"
+"includeSubDomains"
+
+"Vary:"
+"\x0AVary: Cookie"
+"\x0AVary: Age"
+
+"ETag:"
+"\x0AETag: jumboshrimp"
+
+
+# This part has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_url_request_fuzzer binary and RFC 3986.
+"all"
+"consider"
+"Transfer-Encoding"
+"D.,"
+"prefix"
+"concept"
+"CR"
+"follow"
+"RFC-850"
+"(which"
+"ISDN"
+"\"TE\""
+"increase"
+"number"
+"calculate"
+"\"IETF"
+"fixed-length"
+"\"OPTIONAL\""
+"to"
+"Host"
+"program"
+"Western"
+"under"
+"Changing"
+"(STD"
+"digit"
+"returned"
+"returning"
+"very"
+"SP,"
+"SP."
+"Validation"
+"(URI):"
+"Incomplete"
+"Origin"
+"--"
+"cause"
+"EXPRESS"
+"list"
+"large"
+"expired."
+"small"
+"(URL)\","
+"range."
+"past"
+"second"
+"Version"
+"allowed."
+"tag."
+"implemented"
+"canonical"
+"even"
+"established"
+"errors"
+"incompatible"
+"section"
+"contributed"
+"while"
+"decoding"
+"version"
+"above"
+"TTL"
+"new"
+"increasing"
+"method"
+"WWW-"
+"never"
+"equals"
+"here"
+"ranges"
+"reported"
+"compressed"
+"active"
+"path"
+"strong"
+"Index"
+"changed"
+"DISCLAIMS"
+"prior"
+"amount"
+"published"
+"NOT"
+"error,"
+"options"
+"via"
+"followed"
+"secure"
+"family"
+"\"HTTP\""
+"Unspecified"
+"replace"
+"CERN/3.0"
+"CTE"
+"(CTE)"
+"TO"
+"Too"
+"CTL"
+"PUT,"
+"total"
+"PUT)"
+"Security"
+"select"
+"languages"
+"TASK"
+"exception."
+"would"
+"contains"
+"negative"
+"User-Agent"
+"call"
+"MUST,"
+"type"
+"until"
+"authorization"
+"more"
+"ISO-8859-9,"
+"initiated"
+"composite"
+"LF,"
+"line"
+"it"
+"warn"
+"American"
+"varying"
+"known"
+"Found"
+"MHTML"
+"must"
+"parse"
+"none"
+"1999"
+"work"
+"paragraph"
+"sent"
+"evolved"
+"root"
+"example"
+"requested,"
+"history"
+"type."
+"(HTCPCP/1.0)\","
+"accept"
+"currency"
+"minimum"
+"Compromise"
+"numbers"
+"want"
+"type:"
+"times"
+"simple"
+"LF"
+"information"
+"needs"
+"end"
+"goal"
+"verify"
+"far"
+"Pragma"
+"reject"
+"A"
+"badly"
+"HEAD"
+"description"
+"number."
+"insecure"
+"after"
+"variant"
+"confirmed"
+"reflect"
+"wrong"
+"law"
+"response"
+"types"
+"a"
+"All"
+"short"
+"attempt"
+"third"
+"menu."
+")"
+"algorithms"
+"cases."
+"File"
+"\"DEFLATE"
+"order"
+"\"SHOULD"
+"help"
+"don't"
+"over"
+"vary"
+"satisfied"
+"CD-ROM,"
+"held"
+"HTTP-WG."
+"through"
+"of,"
+"existence"
+"its"
+"digest"
+"before"
+"difference"
+"20"
+"termed"
+"MAY,"
+"fix"
+"ISO-3166"
+"actually"
+"407"
+"(GNU"
+"absence"
+"\"HTTP/1.1\","
+"Sun,"
+"MERCHANTABILITY"
+"408"
+"it."
+"them"
+"good"
+"return"
+"HTTP/2.4"
+"combination"
+"URL"
+"URI"
+"Due"
+"Bad"
+"they"
+"Control"
+"always"
+"decimal"
+"refresh"
+"expectation."
+"MAY"
+"token"
+"]URI,"
+"[CRLF]"
+"found"
+"Content-Type"
+"ports"
+"trailer"
+"referred"
+"status"
+"weight"
+"series"
+"reduce"
+"(URI)"
+"expect"
+"max-age=0"
+"combining"
+"operation"
+"beyond"
+"Type"
+"event"
+"is:"
+"by"
+"E."
+"network"
+"Server:"
+"open"
+"\"MUST/MAY/SHOULD\""
+"since"
+"request/response"
+"content"
+"message."
+"PATCH,"
+"7"
+"2DIGIT"
+"available."
+"K.,"
+"linear"
+"Extension"
+"University"
+"enclosing"
+"free"
+"reason"
+"base"
+"proxy"
+"POST"
+"beginning"
+"generate"
+"text/plain"
+"definition"
+"perform"
+"Partial"
+"created"
+"UPALPHA"
+"script"
+"\"GMT\""
+"filter"
+"SSL"
+"expecting"
+"If-Modified-Since"
+"HEAD."
+"HEAD,"
+"assign"
+"user"
+"major"
+"already"
+"Copyright"
+"encoding"
+"Cache"
+"Please"
+"token."
+"TCP"
+"content-range"
+"least"
+"another"
+"FITNESS"
+"invalid."
+"\""
+"service"
+"image/gif"
+"top"
+"header)"
+"construct"
+"2"
+"ignored."
+"listed"
+"passed"
+"Delta"
+"LOALPHA"
+"scheme"
+"store"
+"too"
+"M."
+"immediate"
+"direct"
+"tokens"
+"part"
+"WAIS"
+"F.,"
+"to:"
+"distance"
+"Code"
+"target"
+"Content-Type:"
+"zero,"
+"likely"
+"WWW-Authenticate"
+"matter"
+"idle"
+"determined"
+"stale"
+"ISO-8859-8,"
+"payload"
+"ANSI"
+"B"
+"seen"
+"HTTP/1.1.)"
+"null"
+"OPTIONS"
+"contents"
+"paths"
+"data."
+"data)"
+"zero"
+"depending"
+"Acceptable"
+"responsible"
+"(MIME"
+"also"
+"internal"
+"(C)"
+"build"
+"finding"
+"With"
+"UCI"
+"Names"
+"content-"
+"added"
+"headers."
+"Content-Disposition"
+"object"
+"\"MUST\","
+"most"
+"regular"
+"ensure"
+"letter"
+"2*N"
+"services"
+"The"
+"Responses"
+"payload."
+"clear"
+"sometimes"
+"flow"
+"Client"
+"ISO-8859-3,"
+"Its"
+"incomplete"
+"\"MIME"
+"Note:"
+"particularly"
+"labels"
+"\"C\""
+"session"
+"Unrecognized"
+"find"
+"]"
+"implementation"
+"[RFC"
+"ranges."
+"BNF,"
+"user-agent"
+"failed"
+"URL)."
+"LDAP)"
+"8"
+"US-ASCII"
+"do"
+"hit"
+"stop"
+"\"HTTP\"."
+"While"
+"Set"
+"rest"
+"report"
+"during"
+"body,"
+"PUT"
+"(via"
+"public"
+"twice"
+"bad"
+"common"
+"release"
+"require"
+"set"
+"mandatory"
+"reference"
+"\"F\""
+"MIME:"
+"depends"
+"individual"
+"result"
+"J."
+"close"
+"subject"
+"said"
+"headers"
+"WWW\","
+"See"
+"BUT"
+"unable"
+"various"
+"probably"
+"0)"
+"0."
+"0,"
+"discovery"
+"available"
+"we"
+"reasons."
+"terms"
+"missing"
+"Server"
+"(MIME)"
+"OPTIONAL;"
+"AND"
+"both"
+"protect"
+"Unexpected"
+"last"
+"reverse"
+"\"MAY\","
+"*TEXT"
+"against"
+"connection"
+"became"
+"context"
+"exceeds"
+"however,"
+"mean"
+"reached."
+"finds"
+"experimental"
+"load"
+"Redirect"
+"Content-Length"
+"alternate"
+"consume"
+"point"
+"reasons"
+"had"
+"header"
+"DNS)"
+"DNS."
+"B.,"
+"(O)."
+"1.0"
+"throughout"
+"BCP"
+"["
+"application/pdf"
+"\"REQUIRED\","
+"C."
+"basis"
+"\"POST\""
+"create"
+"acceptance"
+"(MHTML)\","
+"Reason"
+"been"
+"."
+"much"
+"\"PUT\""
+"basic"
+"expected"
+"text/html;"
+"empty"
+"HTTP/1.0"
+"concerning"
+"Flow"
+"N"
+"size,"
+"\"W/\""
+"reason."
+"MA"
+"\"DELETE\""
+"unnecessarily"
+"exception"
+"handling"
+"Group,"
+"particular,"
+"technical"
+"near"
+"\"GZIP"
+"error"
+"(IANA)"
+"\"TRACE\""
+"Accept-Language"
+"played"
+"is"
+"herein"
+"encountered"
+"E-mail"
+"MIME"
+"in"
+"accepted."
+"if"
+"containing"
+"\"A"
+"lengths"
+"make"
+"format"
+"\"I"
+"unrecognized"
+"widely"
+"9"
+"several"
+"higher"
+"\"%"
+"used"
+"temporary"
+"alert"
+"action"
+"purpose"
+"characters"
+"stack"
+"recent"
+"lower"
+"task"
+"database"
+"NNTP"
+"failing"
+"person"
+"client"
+"length."
+"entry"
+"the"
+"left"
+"protocol"
+"US-ASCII."
+"THAT"
+"bandwidth"
+"inactive"
+"(TE)"
+"Internet"
+"HTTP/1.0)"
+"HTTP/1.0."
+"previous"
+"tables"
+"unique"
+"case."
+"character"
+"Trailers"
+"source"
+"ISO-8859-2,"
+"subjects"
+"WILL"
+"location"
+"0*3DIGIT"
+"input"
+"save"
+"remaining"
+"URI."
+"URI,"
+"fact,"
+"transfer-encoding"
+"possible"
+"required."
+"Assigned"
+"Length"
+"URI;"
+"integer"
+"bit"
+"Sat,"
+"desire"
+"OK"
+"success"
+"ISO-8859-5,"
+"OF"
+"signal"
+"INFRINGE"
+"H.F.,"
+"specific"
+"X3.4-1986"
+"security"
+"OR"
+"S."
+"right"
+"old"
+"often"
+"deal"
+"people"
+"successfully"
+"some"
+"back"
+"HT"
+"Last-Modified"
+"headers)"
+"DEL"
+"examples"
+"unless"
+"(BNF)"
+"TCP/IP"
+"ignore"
+"PUT."
+"INDEX."
+"headers,"
+"for"
+"track"
+"CONNECT"
+"be"
+"replaced"
+"run"
+"deleted"
+"example,"
+"<URL:"
+"O"
+"last-modified"
+"become"
+"relating"
+"permitted"
+"ALPHA,"
+"First"
+"ENGINEERING"
+"anything"
+"tracing"
+"\"UTF-8,"
+"*<TEXT,"
+"range"
+"3ALPHA"
+"extensions"
+"positive"
+"block"
+"IRC/6.9,"
+"W3C/MIT"
+"into"
+"within"
+"ACM"
+"two"
+"down"
+"file."
+"compression"
+"IETF"
+"expired"
+"support"
+"initial"
+"question"
+"long"
+"User"
+"HT."
+"forward"
+"version."
+"sections"
+"disallowed"
+"lowest"
+"HT,"
+"an"
+"form"
+"attempted"
+"registered"
+"differences"
+"URL."
+"failure"
+"server."
+"link"
+"CRLF"
+"DNS"
+"encoded"
+"Non-Authoritative"
+"true"
+"GMT"
+"reset"
+"consist"
+"versions"
+"used,"
+"maximum"
+"us"
+"used."
+"If-None-Match"
+"HTML\","
+"similar"
+"called"
+"delete"
+"DELETE,"
+"storing"
+"associated"
+"Introduction"
+"request"
+"specified"
+"influence"
+"To"
+"single"
+"warning"
+"exist"
+"New"
+"NOT,"
+"check"
+"ISO-8859-1:1987."
+"encrypt"
+"Only"
+"no"
+"May"
+"when"
+"A,"
+"invalid"
+"A."
+"MHTML,"
+"name."
+"setting"
+"role"
+"Proxy"
+"test"
+"TE"
+"pseudonym"
+"negotiation."
+"exceeded"
+"update"
+"T."
+"variable"
+"NOT\","
+"R."
+"longer"
+"algorithm"
+"IANA."
+"age"
+"packets"
+"together"
+"An"
+"As"
+"time"
+"failures"
+"requires"
+"avoid"
+"code."
+"once"
+"code"
+"partial"
+"chain"
+"TEXT"
+"results"
+"existing"
+"go"
+"(LZW)."
+"provided."
+"CPU"
+"CREATE"
+"Notice"
+"LF>"
+"\"HEAD\""
+"zone"
+"UNIX,"
+"ARPA"
+"send"
+"Standard"
+"environment"
+"USENET"
+"Not"
+"Nov"
+"include"
+"resources"
+"string"
+"advantage"
+"outside"
+"Explicit"
+"ALL"
+"HTTP/1.1;"
+"entries"
+"HTTP/1.1,"
+"HTTP/1.1."
+"entire"
+"Protocol"
+"level"
+"did"
+"button"
+"HTTP/1.0\","
+"(RFC"
+"try"
+"ONLY"
+"Tag"
+"(LWS"
+"\"SHOULD\","
+"prevent"
+"\"A\"..\"Z\">"
+"unexpected"
+"INFORMATION"
+"Failed"
+"\"A\""
+"Satisfiable"
+"port"
+"append"
+"\"HTTP/1.0\""
+"formats"
+"ISO-8859-4,"
+"appear"
+"rate"
+"opaque"
+"current"
+"waiting"
+"HTML"
+"shared"
+"CRLF)"
+"302"
+"body"
+"FTP"
+"NNTP."
+"\"SHALL"
+"following"
+"objects"
+"address"
+"1*HEX"
+"Distribution"
+"entry."
+"HTTP."
+"change"
+"cache)"
+"incoming"
+"\"AS"
+"receive"
+"larger"
+"host"
+"descended"
+"here."
+"+"
+"{"
+"makes"
+"composed"
+"named"
+"useful"
+"addresses"
+"extra"
+"detected."
+"When"
+"private"
+"session."
+"gateway"
+"Status"
+"use"
+"from"
+"stream"
+"working"
+"value."
+"next"
+"few"
+"--THIS_STRING_SEPARATES"
+"POST,"
+"memory"
+"scope"
+"means"
+"HEX\""
+"(GMT),"
+"bytes:"
+"Default"
+"Require"
+"Required"
+"DIGIT"
+"validity"
+"bytes,"
+"Connection"
+"Time"
+"cases"
+"name:"
+"behalf"
+"MD5"
+"lowercase"
+"RIGHTS"
+"this"
+"NTP"
+"--THIS_STRING_SEPARATES--"
+"Syntax"
+"values"
+"can"
+"believed"
+"making"
+"closing"
+"modifier"
+"J.,"
+"control"
+"reserved"
+"links"
+"process"
+"attribute"
+"high"
+"tag"
+"allowed"
+"Policy"
+"input,"
+"native"
+"class,"
+"Missing"
+"HTTP-"
+"HTTP,"
+"charset"
+"delay"
+"located"
+"R.,"
+"instead"
+"1XX"
+"WARRANTIES,"
+"parameter"
+"FORCE"
+"STD"
+"may"
+"Request"
+"British"
+"HEREIN"
+"Roman"
+"client's"
+"[SP"
+"ANSI,"
+"date"
+"such"
+"data"
+"HTTP/1.1\","
+"Y."
+"UA"
+"revalidate"
+"element"
+"so"
+"allow"
+"(LWS)"
+"holds"
+"move"
+"years"
+"including"
+"LINK,"
+"still"
+"pointer"
+"non-zero"
+"1"
+"negotiated"
+"Multiple"
+"line."
+"using:"
+"forms"
+"Referer"
+"P.,"
+"PNG,\""
+"cache-control"
+"policy"
+"mail"
+"\"HTTP"
+"SIGCOMM"
+"greater"
+"matches"
+"lesser"
+"not"
+"parsing"
+"matched"
+"term"
+"name"
+"establishment"
+"A.,"
+"ISO-639"
+"entirely"
+"identifier"
+"elements"
+"|"
+"successful"
+"domain"
+"From"
+"Network"
+"related"
+"UNLINK"
+"trying"
+"(LZ77)"
+"year"
+"(MIC)"
+"Parameter"
+"special"
+"out"
+"ultimately"
+"space"
+"REQUIRED"
+"416"
+"WARRANTY"
+"4DIGIT"
+"time,"
+"L."
+"time."
+"supports"
+"(A,"
+"state"
+"This"
+"derived"
+"INTERNET"
+"possibility"
+"\"B\""
+"RFC"
+"IMPLIED,"
+"byte"
+"received."
+"log"
+"ISO-8859-7,"
+"\"HTTP/1.1\""
+"language"
+"could"
+"transition"
+"programming"
+"tries"
+"keep"
+"length"
+"place"
+"S.,"
+"first"
+"origin"
+"there"
+"sent."
+"3DIGIT"
+"K."
+"one"
+"CHAR"
+"list,"
+"ISI"
+"version:"
+"message"
+"CSS1,"
+"quality"
+"size"
+"doesn't"
+"given"
+"For"
+"enabled."
+"unknown"
+"system"
+"unspecified"
+"parallel"
+"priority"
+"their"
+"attack"
+"intermediate"
+"HTTP:"
+"Date"
+"x-gzip"
+"Data"
+"Response"
+"HTTP/2.0,"
+"gives"
+"Success"
+"that"
+"completed"
+"exactly"
+"R"
+"pragma"
+"(IANA"
+"copy"
+"than"
+"History"
+"wide"
+"12"
+"14"
+"16"
+"was"
+"Universal"
+"protected"
+"servers."
+"were"
+"1)"
+"IS\""
+"SHTTP/1.3,"
+"1*8ALPHA"
+"Location"
+"and"
+"Information"
+"false"
+"1.1"
+"1.2"
+"(2**N),"
+"turned"
+"Tue,"
+"Other"
+"SP"
+"(LWS)."
+"have"
+"MIME,"
+"need"
+"Mail"
+"any"
+"Requested"
+"conversion"
+"HTTP/2.13,"
+"database."
+"After"
+"able"
+"mechanism"
+"OPTIONAL"
+"take"
+"which"
+"HTTP/0.9,"
+"201"
+"200"
+"begin"
+"multiple"
+"Name"
+"trace"
+"206"
+"buffer"
+"who"
+"connected"
+"plus"
+"HTTP/12.3."
+"\"OPTIONS\""
+"segment"
+"class"
+"D."
+"considered"
+"GET"
+"Some"
+"TE:"
+"L.,"
+"(URL)"
+"}"
+"fact"
+"Web"
+"WA"
+"violation"
+"text"
+"supported"
+"synchronous"
+"Authentication"
+"inconsistent"
+"CRLF."
+"CRLF,"
+"label"
+"Public"
+"MUST"
+"true,"
+"cache."
+"upgrade"
+"based"
+"Posting"
+"("
+"cache"
+"3"
+"should"
+"only"
+"Proxy-Authorization"
+"Byte"
+"Strong"
+"local"
+"MIC"
+"WARRANTIES"
+"(UA)"
+"<US-ASCII"
+"handle"
+"get"
+"E.,"
+"Accept-Ranges"
+"expectation"
+"(See"
+"cannot"
+"128"
+"THE"
+"conjunction"
+"BNF"
+"DIGIT,"
+"closure"
+"resource"
+"ended"
+"cached"
+"W."
+"ISO-8859."
+"calling"
+"INCLUDING"
+"contain"
+"ISI/RR-98-463,"
+"\"CONNECT\""
+"where"
+"ignored"
+"IANA"
+"exists"
+"configured"
+"C"
+"packet"
+"up"
+"relative"
+"multipart"
+"end."
+"detect"
+"has"
+"stream."
+"1*DIGIT"
+"Oct"
+"written"
+"LIMITED"
+"closed"
+"between"
+"boundary"
+"reading"
+"across"
+"\"RECOMMENDED\","
+"Body"
+"ability"
+"FOR"
+"opening"
+"importance"
+"screen"
+"connection."
+"ISO-8859-1"
+"UNIX"
+"key"
+"group"
+"configuration"
+"P."
+"valid"
+"\"HTTP/1.1\"."
+"HTTP/1.0),"
+"WWW"
+"revoked"
+"TRACE"
+"many"
+"taking"
+"(OK)"
+"equal"
+"Rules"
+"(0)"
+"Unicode"
+"*OCTET"
+"(URN)"
+"safely"
+"can't"
+"among"
+"(OK)."
+"Log"
+"period"
+"colon"
+"adding"
+"spans"
+"article"
+"table"
+"allocated"
+"LWS:"
+"Identifier"
+"Wed,"
+"USA"
+"Proxy-Authenticate"
+"encryption"
+"Jun"
+"copies"
+"But"
+"mark"
+"defined"
+"combined"
+"LWS,"
+"LWS"
+"prototype"
+">"
+"enable"
+"401"
+"content-disposition"
+"received"
+"unsafe"
+"SMTP"
+"ANY"
+"World"
+"chain."
+"case"
+"disconnected"
+"(HTTP)"
+"these"
+"Number"
+"value"
+"will"
+"Fri,"
+"\"SHALL\","
+"Any"
+"Additional"
+"resident"
+"NOT\""
+"thus"
+"it,"
+"according"
+"Content"
+"Content-Range"
+"properties"
+"Unsupported"
+"malformed"
+"PARTICULAR"
+"You"
+"binary"
+"different"
+"perhaps"
+"generic"
+"pay"
+"set."
+"00:00:00"
+"1DIGIT"
+"same"
+"parts"
+"largest"
+"units"
+"document"
+"Types"
+"residing"
+"breakdown"
+"UTC"
+"extended"
+"http"
+"I"
+"IP"
+"effect"
+"allocation"
+"running"
+"*LWS"
+"infinite"
+"frequently"
+"tracking"
+"undefined"
+"CR."
+"well"
+"It"
+"If-Range"
+"patterns"
+"without"
+"M.,"
+"CR,"
+"In"
+"position"
+"model"
+"audio"
+"If"
+"negotiation"
+"Also,"
+"Service"
+"less"
+"being"
+"generally"
+"obtain"
+"actions"
+"Access"
+"stored"
+"CRC."
+"However,"
+"application"
+"capabilities"
+"appeared"
+"add"
+"Thu,"
+"4"
+"Although"
+"HTTP/1.1"
+"usage"
+"(A"
+"match"
+"details"
+"tests"
+"aspects"
+"read"
+"Many"
+"H.,"
+"early"
+"action,"
+"T"
+"address."
+"using"
+"password"
+"loss"
+"like"
+"text/html"
+"Content-Encoding"
+"B,"
+"B."
+"\"HTTP/1.1"
+"server"
+"discarded"
+"either"
+"BACK)"
+"output"
+"Operation"
+"page"
+"\"GET\""
+"exceed"
+"because"
+"sequence"
+"uppercase"
+"Since"
+"growth"
+"Authority"
+"respect"
+"International"
+"recognition"
+"happens"
+"provided"
+"trust"
+"lead"
+"MIT"
+"highest"
+"expectation,"
+"does"
+"Authorization"
+"assuming"
+"refer"
+"GET)"
+"GET,"
+"GET."
+"equivalent"
+"Official"
+"C)"
+"ISO-8859-1."
+"broken"
+"Range"
+"HTTP/1.0,"
+"LWS>"
+"X3.4-1986,"
+"Microsoft"
+"on"
+"about"
+"actual"
+"extension"
+"of"
+"C,"
+"accepted"
+"FTP,"
+"compatible"
+"addition"
+"unidirectional"
+"Message"
+"DELETE"
+"content-type"
+"or"
+"UC"
+"final"
+"No"
+"ISO-"
+"image"
+"Two"
+"Internal"
+"times,"
+"ISO-8859-6,"
+"determine"
+"T.,"
+"operator"
+"T/TCP"
+"additional"
+"area"
+"GET\""
+"transfer"
+"*"
+"decode"
+"start"
+"describes"
+"low"
+"strict"
+"context."
+"function"
+"complete"
+"N."
+"enough"
+"OCTET"
+"but"
+"IMPLIED"
+"Error"
+"Dec"
+"with"
+"Trailer"
+"count"
+"clients."
+"made"
+"compute"
+"default"
+"GMT,"
+"ISO-8859-1,"
+"Moved"
+"this,"
+"ISO-8859-1)"
+"SHOULD"
+"PURPOSE."
+"limit"
+"GMT."
+"site"
+"problem"
+"define"
+"USE"
+"image/jpeg"
+"\"E\""
+"URL,"
+"describe"
+"general"
+"as"
+"UST"
+"at"
+"file"
+"lifetime"
+"are"
+"Accept-Encoding"
+"incorrect"
+"variety"
+"\"D\""
+"virtual"
+"details."
+"field"
+"other"
+"5"
+"Purpose"
+"you"
+"CA"
+"requested"
+"repeat"
+"HEX"
+"symbol"
+"Cache-Control"
+"Remove"
+"March"
+"important"
+"H."
+"code)"
+"included"
+"SOCIETY"
+"\"MUST"
+"ISO-10646\","
+"\"ZLIB"
+"audio/basic"
+"\"ISO-8859-1\""
+"\"WAIS"
+"persistent"
+"having"
+"directory"
+"ALPHA"
+"validation"
+"original"
+
diff --git a/net/data/fuzzer_dictionaries/net_websocket_frame_parser_fuzzer.dict b/net/data/fuzzer_dictionaries/net_websocket_frame_parser_fuzzer.dict
new file mode 100644
index 0000000..afba1606
--- /dev/null
+++ b/net/data/fuzzer_dictionaries/net_websocket_frame_parser_fuzzer.dict
@@ -0,0 +1,460 @@
+# 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.
+
+# This file has been generated with testing/libfuzzer/dictionary_generator.py
+# using net_websocket_frame_parser_fuzzer binary and RFC 6455.
+"WG"
+"all"
+"LETTER"
+"(\"MUST\","
+"Unknown"
+"supported"
+"|K|"
+"[WSAPI],"
+"[TALKING]."
+"\"UTF-8,"
+"[RFC6265]"
+"[FIPS.180-3],"
+"F.,"
+"T."
+"U+007A"
+"\"IETF"
+"implementation"
+"("
+"cache"
+"\"OPTIONAL\""
+"environment"
+"0"
+"only"
+"version"
+"G.,"
+"text"
+"G."
+"[RFC3987])."
+"string"
+"get"
+"=="
+"failed."
+"[RFC3986]."
+"(2MSL),"
+"|F|R|R|R|"
+"DIGIT)"
+"FIN"
+"(URI):"
+"SHA-1"
+"resource"
+"MAY"
+"EXAMPLE:"
+"list"
+"SYN"
+"large"
+"A.5"
+"J."
+"common"
+"RSV3:"
+"\"RECOMMENDED\","
+"ASCII"
+"(IP"
+"Y.,"
+"set"
+"HTTP"
+"IANA"
+"frame"
+"M."
+"direct"
+"this,"
+"Version"
+"are"
+"[RFC4086]"
+"GET,"
+"UTF-8-"
+"_ASCII_"
+"TLS,"
+"TLS."
+"Z)"
+"GET"
+"section"
+"[RFC3986]:"
+"TCP"
+"ABNF."
+"unable"
+"probably"
+"MUST"
+"[RFC3986],"
+"metadata"
+"available"
+"R.,"
+"C"
+"hash"
+"\"SHALL"
+"U+007E"
+"\"HTTP/1.1"
+"\"MAY\","
+"CONNECTING"
+"_ASCII"
+"key"
+"address"
+"OPTIONAL;"
+"["
+"P."
+"received"
+"NOTE:"
+"RSV1,"
+"WHATWG"
+"\"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\""
+"(IETF)"
+"IMPLEMENTATION"
+"|I|S|S|S|"
+"CLOSED"
+"NOT"
+"[RFC3629]."
+"J.,"
+"UTF-8."
+"\"REQUIRED\","
+"useful"
+"SHUT_WR"
+"(IETF)."
+"H."
+"HTTP)."
+"S."
+"ASCII)"
+"allocated"
+"poll"
+"BCP"
+"select"
+"[RFC4270])."
+"use"
+"LATIN"
+"from"
+"C."
+"certificate"
+"to"
+"\"SOCKS"
+"create"
+"S.,"
+"|N|V|V|V|"
+"[RFC2616]"
+"(IRI)"
+"call"
+"memory"
+"expected"
+"type"
+"empty"
+"with"
+"[RFC2616]."
+"OPEN"
+"[RFC4648]"
+"BNF"
+"NOT\","
+"[RFC2119]"
+"flag"
+"[RFC4270]"
+"TCP."
+"[RFC2616],"
+"\"258EAFA5-E914-47DA-"
+"CLOSING"
+"unnecessarily"
+"must"
+"high"
+"[RFC3864]."
+"ANSI"
+"this"
+"work"
+"value"
+"while"
+"\"SHALL\","
+"error"
+"following"
+"closing"
+"(NZDIGIT"
+"UTF-8"
+"type."
+"(UUID)"
+"is"
+"in"
+"thus"
+"Invalid"
+"parse"
+"key."
+"allowed"
+"Z)."
+"TLS.)"
+"failed"
+"|A|"
+"binary"
+"\"A"
+"[RFC5226]"
+")"
+"algorithm."
+"returning"
+"ISSN:"
+"U+0041"
+"write"
+"[RFC5234]"
+"I."
+"units"
+"[RFC4122]"
+"[WSAPI]"
+"URN"
+"A"
+"used"
+"XOR"
+"HTML"
+"[RFC1928]"
+"may"
+"IP"
+"after"
+"(TLS)"
+"H.,"
+"IRI"
+"running"
+"*LWS"
+"HTTPS"
+"CAPITAL"
+"SMTP"
+"such"
+"data"
+"a"
+"length:"
+"[ANSI.X3-4.1986]"
+"tracking"
+"[RFC6265]."
+"i"
+"2BX"
+"or"
+"[RFC5226]."
+"[RFC5226],"
+"M.,"
+"Names"
+"HTTP,"
+"RST"
+"the"
+"MOD"
+"If"
+"\"SHOULD"
+"being"
+"-"
+"SHA-1,"
+"E.,"
+"(IDN)"
+"ABNF)."
+"D.,"
+"mechanism"
+"[RFC4122])"
+"(GUID,"
+"RSV3"
+"its"
+"_A"
+"before"
+"U+0061"
+"[RFC2119]."
+"unsigned"
+"writing"
+"source"
+"SOCKS5"
+"P.,"
+"HTTP/1.1"
+"\"HTTP"
+"URI."
+"..."
+"format"
+"read"
+"|S|"
+"URI"
+"Bad"
+"URI:"
+"[RFC3629]"
+"not"
+"R."
+"\"IESG"
+"missing,"
+"name"
+"success"
+"C5AB0DC85B11\"."
+"signal"
+"WD-"
+"A.,"
+"API"
+"SQL"
+"page"
+"STD"
+"API),"
+"because"
+"bytes"
+"some"
+"back"
+"HYBI"
+"\"258EAFA5-"
+"RST,"
+"[RFC6066]"
+"[RFC3864]"
+"I.,"
+"RSV2,"
+"[RFC5234],"
+"for"
+"space"
+"ABNF\","
+"avoid"
+"/"
+"L."
+"time."
+"does"
+"TIME_WAIT"
+"CONNECT"
+"GUID."
+"assuming"
+"supports"
+"[RFC3986]"
+"be"
+"run"
+"This"
+"ABNF,"
+"PUB"
+"free"
+"E914-47DA-95CA-C5AB0DC85B11\""
+"RFC"
+"X3.4,"
+"base"
+"[RFC4648]),"
+"[RFC4648])."
+"[RFC6066]."
+"received."
+"by"
+"[RFC2818]."
+"on"
+"DIGIT"
+"FIN:"
+"ABNF"
+"TLS\","
+"of"
+"could"
+"&"
+"[TALKING]"
+"wrong"
+"times"
+"[RFC6202]"
+"length"
+"UI"
+"UK"
+"transfer"
+"HTTP/1.1\"."
+"[ANSI.X3-4.1986]."
+"HTTP/1.1\","
+"support"
+"[RFC5246]."
+"API\","
+"already"
+"HTTP/HTTPS"
+">="
+"E914-47DA-95CA-C5AB0DC85B11\","
+"[RFC4648])"
+"number"
+"one"
+"IDN"
+"Start"
+"NZDIGIT"
+"RFC."
+"ISO"
+"SMALL"
+"open"
+"U+0021"
+"size"
+"IETF"
+"unknown"
+"top"
+"*"
+"MASK"
+"long"
+"class"
+"start"
+"too"
+":"
+"was"
+"configured"
+"[RFC2817]."
+"TLS"
+"that"
+"completed"
+"[FIPS.180-3]"
+"but"
+"95CA-C5AB0DC85B11\""
+"BSD"
+"FIPS"
+"[RFC6454]"
+"DNS"
+"Error"
+"line"
+"trying"
+"true"
+"\"URI\""
+"target"
+"16"
+"default"
+"B."
+"up"
+"SHOULD"
+"(IESG)."
+"API."
+"called"
+"and"
+"UPGRADE"
+"false"
+"[RFC6202]."
+"[RFC2817]"
+"URI)"
+"lost."
+"[RFC2818]"
+"an"
+"To"
+"as"
+"at"
+"have"
+"need"
+"null"
+"U+005A"
+"any"
+"contents"
+"[RFC5246]"
+"\"SHOULD\","
+"no"
+"when"
+"invalid"
+"A."
+"application"
+"valid"
+"take"
+"which"
+"test"
+"you"
+"="
+"[RFC5321]"
+"requested"
+"begin"
+"multiple"
+"[RFC5234]."
+"(FIN/ACK),"
+"HTTP\","
+"[RFC3987]"
+"L-S.,"
+"\"MUST"
+"W3C"
+"\"MUST\","
+"E."
+"Common"
+"T.,"
+"The"
+"]"
+"pages"
+"D."
+"\"GET"
+"[RFC6265]),"
+"TW12"
+"IANA."
+"finished"
+"L.,"
+"As"
+"ALPHA"
+"+"
+"D.3."
+
diff --git a/net/data/http/http.dict b/net/data/http/http.dict
deleted file mode 100644
index 2e750cb8..0000000
--- a/net/data/http/http.dict
+++ /dev/null
@@ -1,163 +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.
-
-# Fuzzer dictionary targetting HTTP/1.x responses.
-
-# Entries that are generally useful in headers
-":"
-"\x0A"
-"\x0D"
-"0"
-"50"
-"500"
-# Horizontal whitespace. Matters mostly in status line.
-" "
-"\x09"
-# Header continuation
-"\x0D\x0A\x09"
-# Used in a lot of individual headers
-";"
-"="
-","
-"\""
-"-"
-
-# Status line components
-"HTTP"
-"/1.1"
-"/1.0"
-# More interesting status codes.  Leading space so can be inserted into
-# other status lines.
-" 100"
-" 200"
-" 206"
-" 301"
-" 302"
-" 303"
-" 304"
-" 307"
-" 308"
-" 401"
-" 403"
-" 404"
-" 500"
-" 501"
-" 403"
-
-# Full status lines (Some with relevant following headers)
-"HTTP/1.1 200 OK\x0A\x0A"
-"HTTP/1.1 100 Continue\x0A\x0A"
-"HTTP/1.1 401 Unauthorized\x0AWWW-Authenticate: Basic realm=\"Middle-Earth\"\x0A\xA0"
-"HTTP/1.1 407 Proxy Authentication Required\x0AProxy-Authenticate: Digest realm=\"Middle-Earth\", nonce=\"aaaaaaaaaa\"\x0A\x0A"
-"HTTP/1.0 301 Moved Permanently\x0ALocation: /a\x0A\x0A"
-"HTTP/1.1 302 Found\x0ALocation: http://lost/\x0A\x0A"
-
-# Proxy authentication headers. Note that fuzzers don't support NTLM or
-# negotiate.
-"WWW-Authenticate:"
-"Proxy-Authenticate:"
-"Basic"
-"Digest"
-"realm"
-"nonce"
-
-"Connection:"
-"Proxy-Connection:"
-"Keep-Alive"
-"Close"
-"Upgrade"
-"\x0AConnection: Keep-Alive"
-"\x0AConnection: Close"
-"\x0AProxy-Connection: Keep-Alive"
-"\x0AProxy-Connection: Close"
-
-"Content-Length:"
-"Transfer-Encoding:"
-"chunked"
-"\x0AContent-Length: 0"
-"\x0AContent-Length: 500"
-"\x0ATransfer-Encoding: chunked\x0A\x0A5\x0A12345\x0A0\x0A\x0A"
-
-"Location:"
-"\x0ALocation: http://foo/"
-"\x0ALocation: http://bar/"
-"\x0ALocation: https://foo/"
-"\x0ALocation: https://bar/"
-
-"Accept-Ranges:"
-"bytes"
-"\x0AAccept-Ranges: bytes"
-
-"Content-Range:"
-
-"Age:"
-"\x0AAge: 0"
-"\x0AAge: 3153600000"
-
-"Cache-Control:"
-"max-age"
-"no-cache"
-"no-store"
-"must-revalidate"
-"\x0ACache-Control: max-age=3153600000"
-"\x0ACache-Control: max-age=0"
-"\x0ACache-Control: no-cache"
-"\x0ACache-Control: no-store"
-"\x0ACache-Control: must-revalidate"
-
-"Content-Disposition:"
-"attachment"
-"filename"
-
-"Content-Encoding:"
-"gzip"
-"deflate"
-"sdch"
-"br"
-"\x0AContent-Encoding: gzip"
-"\x0AContent-Encoding: deflate"
-"\x0AContent-Encoding: sdch"
-"\x0AContent-Encoding: br"
-
-"Date:"
-"Fri, 01 Apr, 2050 14:14:14 GMT"
-"Mon, 28 Mar, 2016 04:04:04 GMT"
-"\x0ADate: Fri, 01 Apr, 2050 14:14:14 GMT"
-"\x0ADate: Mon, 28 Mar, 2016 04:04:04 GMT"
-
-"Last-Modified:"
-"\x0ALast-Modified: Fri, 01 Apr, 2050 14:14:14 GMT"
-"\x0ALast-Modified: Mon, 28 Mar, 2016 04:04:04 GMT"
-
-"Expires:"
-"\x0AExpires: Fri, 01 Apr, 2050 14:14:14 GMT"
-"\x0AExpires: Mon, 28 Mar, 2016 04:04:04 GMT"
-
-"Set-Cookie:"
-"Expires"
-"Max-Age"
-"Domain"
-"Path"
-"Secure"
-"HttpOnly"
-"Priority"
-"Low"
-"Medium"
-"High"
-"SameSite"
-"Strict"
-"Lax"
-"\x0ASet-Cookie: foo=bar"
-"\x0ASet-Cookie: foo2=bar2;HttpOnly;Priority=Low;SameSite=Strict;Path=/"
-"\x0ASet-Cookie: foo=chicken;SameSite=Lax"
-
-"Strict-Transport-Security:"
-"includeSubDomains"
-
-"Vary:"
-"\x0AVary: Cookie"
-"\x0AVary: Age"
-
-"ETag:"
-"\x0AETag: jumboshrimp"
diff --git a/net/data/ssl/symantec/roots/8da084fcf99ce07722f89b3205939806fa5cb811e1c813f6a108c7d336b3408e.pem b/net/data/ssl/symantec/roots/8da084fcf99ce07722f89b3205939806fa5cb811e1c813f6a108c7d336b3408e.pem
deleted file mode 100644
index 410007a..0000000
--- a/net/data/ssl/symantec/roots/8da084fcf99ce07722f89b3205939806fa5cb811e1c813f6a108c7d336b3408e.pem
+++ /dev/null
@@ -1,90 +0,0 @@
-Certificate:
-    Data:
-        Version: 3 (0x2)
-        Serial Number:
-            4a:47:00:01:00:02:e5:a0:5d:d6:3f:00:51:bf
-    Signature Algorithm: sha1WithRSAEncryption
-        Issuer: C=DE, O=TC TrustCenter GmbH, OU=TC TrustCenter Class 3 CA, CN=TC TrustCenter Class 3 CA II
-        Validity
-            Not Before: Jan 12 14:41:57 2006 GMT
-            Not After : Dec 31 22:59:59 2025 GMT
-        Subject: C=DE, O=TC TrustCenter GmbH, OU=TC TrustCenter Class 3 CA, CN=TC TrustCenter Class 3 CA II
-        Subject Public Key Info:
-            Public Key Algorithm: rsaEncryption
-                Public-Key: (2048 bit)
-                Modulus:
-                    00:b4:e0:bb:51:bb:39:5c:8b:04:c5:4c:79:1c:23:
-                    86:31:10:63:43:55:27:3f:c6:45:c7:a4:3d:ec:09:
-                    0d:1a:1e:20:c2:56:1e:de:1b:37:07:30:22:2f:6f:
-                    f1:06:f1:ab:ad:d6:c8:ab:61:a3:2f:43:c4:b0:b2:
-                    2d:fc:c3:96:69:7b:7e:8a:e4:cc:c0:39:12:90:42:
-                    60:c9:cc:35:68:ee:da:5f:90:56:5f:cd:1c:4d:5b:
-                    58:49:eb:0e:01:4f:64:fa:2c:3c:89:58:d8:2f:2e:
-                    e2:b0:68:e9:22:3b:75:89:d6:44:1a:65:f2:1b:97:
-                    26:1d:28:6d:ac:e8:bd:59:1d:2b:24:f6:d6:84:03:
-                    66:88:24:00:78:60:f1:f8:ab:fe:02:b2:6b:fb:22:
-                    fb:35:e6:16:d1:ad:f6:2e:12:e4:fa:35:6a:e5:19:
-                    b9:5d:db:3b:1e:1a:fb:d3:ff:15:14:08:d8:09:6a:
-                    ba:45:9d:14:79:60:7d:af:40:8a:07:73:b3:93:96:
-                    d3:74:34:8d:3a:37:29:de:5c:ec:f5:ee:2e:31:c2:
-                    20:dc:be:f1:4f:7f:23:52:d9:5b:e2:64:d9:9c:aa:
-                    07:08:b5:45:bd:d1:d0:31:c1:ab:54:9f:a9:d2:c3:
-                    62:60:03:f1:bb:39:4a:92:4a:3d:0a:b9:9d:c5:a0:
-                    fe:37
-                Exponent: 65537 (0x10001)
-        X509v3 extensions:
-            X509v3 Basic Constraints: critical
-                CA:TRUE
-            X509v3 Key Usage: critical
-                Certificate Sign, CRL Sign
-            X509v3 Subject Key Identifier: 
-                D4:A2:FC:9F:B3:C3:D8:03:D3:57:5C:07:A4:D0:24:A7:C0:F2:00:D4
-            X509v3 CRL Distribution Points: 
-
-                Full Name:
-                  URI:http://www.trustcenter.de/crl/v2/tc_class_3_ca_II.crl
-                  URI:ldap://www.trustcenter.de/CN=TC%20TrustCenter%20Class%203%20CA%20II,O=TC%20TrustCenter%20GmbH,OU=rootcerts,DC=trustcenter,DC=de?certificateRevocationList?base?
-
-    Signature Algorithm: sha1WithRSAEncryption
-         36:60:e4:70:f7:06:20:43:d9:23:1a:42:f2:f8:a3:b2:b9:4d:
-         8a:b4:f3:c2:9a:55:31:7c:c4:3b:67:9a:b4:df:4d:0e:8a:93:
-         4a:17:8b:1b:8d:ca:89:e1:cf:3a:1e:ac:1d:f1:9c:32:b4:8e:
-         59:76:a2:41:85:25:37:a0:13:d0:f5:7c:4e:d5:ea:96:e2:6e:
-         72:c1:bb:2a:fe:6c:6e:f8:91:98:46:fc:c9:1b:57:5b:ea:c8:
-         1a:3b:3f:b0:51:98:3c:07:da:2c:59:01:da:8b:44:e8:e1:74:
-         fd:a7:68:dd:54:ba:83:46:ec:c8:46:b5:f8:af:97:c0:3b:09:
-         1c:8f:ce:72:96:3d:33:56:70:bc:96:cb:d8:d5:7d:20:9a:83:
-         9f:1a:dc:39:f1:c5:72:a3:11:03:fd:3b:42:52:29:db:e8:01:
-         f7:9b:5e:8c:d6:8d:86:4e:19:fa:bc:1c:be:c5:21:a5:87:9e:
-         78:2e:36:db:09:71:a3:72:34:f8:6c:e3:06:09:f2:5e:56:a5:
-         d3:dd:98:fa:d4:e6:06:f4:f0:b6:20:63:4b:ea:29:bd:aa:82:
-         66:1e:fb:81:aa:a7:37:ad:13:18:e6:92:c3:81:c1:33:bb:88:
-         1e:a1:e7:e2:b4:bd:31:6c:0e:51:3d:6f:fb:96:56:80:e2:36:
-         17:d1:dc:e4
------BEGIN CERTIFICATE-----
-MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjEL
-MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV
-BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0
-Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYwMTEyMTQ0MTU3WhcNMjUxMjMxMjI1
-OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i
-SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UEAxMc
-VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJW
-Ht4bNwcwIi9v8Qbxq63WyKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+Q
-Vl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo6SI7dYnWRBpl8huXJh0obazovVkdKyT2
-1oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZuV3bOx4a+9P/FRQI2Alq
-ukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk2ZyqBwi1
-Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1Ud
-EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NX
-XAek0CSnwPIA1DCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy
-dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6
-Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz
-JTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290
-Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
-TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlN
-irTzwppVMXzEO2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8
-TtXqluJucsG7Kv5sbviRmEb8yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6
-g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9IJqDnxrcOfHFcqMRA/07QlIp2+gB
-95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal092Y+tTmBvTwtiBj
-S+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc5A==
------END CERTIFICATE-----
diff --git a/net/data/ssl/symantec/roots/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.pem b/net/data/ssl/symantec/roots/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.pem
new file mode 100644
index 0000000..c0d77069
--- /dev/null
+++ b/net/data/ssl/symantec/roots/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.pem
@@ -0,0 +1,82 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            0f:6b:55:2f:9e:bf:90:7b:0f:66:29:a9:bd:f4:d8:ce
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, O=Symantec Corporation, CN=Symantec Enterprise Mobile Root for Microsoft
+        Validity
+            Not Before: Mar 15 00:00:00 2012 GMT
+            Not After : Mar 14 23:59:59 2032 GMT
+        Subject: C=US, O=Symantec Corporation, CN=Symantec Enterprise Mobile Root for Microsoft
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:b5:3d:b0:72:ee:91:e9:a5:69:9c:11:4d:7a:f9:
+                    b3:fa:3d:f2:94:9b:23:b7:a6:03:ec:62:18:fc:85:
+                    12:22:fe:c1:71:7d:54:93:b9:91:7d:62:f6:ca:a8:
+                    38:15:65:f8:77:3d:e5:82:20:3a:d4:b5:d1:6e:8d:
+                    06:49:bd:df:82:0e:24:85:e7:ef:78:2d:18:f2:e0:
+                    0b:68:46:3e:24:10:c8:57:ee:0e:6d:71:a6:d3:b1:
+                    56:1c:d7:29:d5:b2:ea:54:05:0a:a8:3c:a1:b8:25:
+                    52:07:05:a0:df:e7:dc:ee:5c:3b:41:b5:ab:5c:33:
+                    32:d2:ce:eb:e9:96:f8:40:f4:0a:ba:33:1d:f8:56:
+                    03:09:82:f5:67:07:c4:c0:34:c1:5d:fc:45:bb:ea:
+                    3c:9a:d5:74:71:6d:d5:86:d3:c2:fc:85:bc:54:eb:
+                    a3:d5:f2:4f:d5:45:af:57:bc:f0:22:c0:8f:a2:45:
+                    c8:75:34:77:de:a1:6d:37:72:b3:73:8d:0c:6b:53:
+                    ba:59:e1:a8:3e:80:57:d2:5f:59:ee:68:75:cf:81:
+                    9c:a3:ca:45:8c:37:db:05:72:34:1c:32:02:f8:d5:
+                    f9:2c:0d:da:58:9e:c4:17:b4:9b:c9:90:c4:88:59:
+                    3f:71:91:90:44:18:be:22:8b:79:92:2e:42:b0:8b:
+                    97:5b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Subject Alternative Name: 
+                DirName:/CN=MPKI-2048-1-111
+            X509v3 Subject Key Identifier: 
+                4D:EC:DF:26:06:DC:24:10:C0:B6:99:F4:D7:39:C7:6F:19:F8:26:28
+    Signature Algorithm: sha256WithRSAEncryption
+         a9:57:59:d0:01:54:14:46:af:c7:79:54:0c:6a:2a:5b:d8:3a:
+         1d:81:e4:88:a3:31:b4:f1:f3:35:f1:46:73:5c:43:c9:fe:bc:
+         a2:6a:19:c0:bd:2f:5f:cb:38:a3:6d:6e:e8:14:5e:f2:78:7e:
+         45:7a:e1:bb:f4:2e:9b:45:eb:e0:1d:50:1c:34:5b:7f:98:8a:
+         86:0f:87:da:e4:64:26:77:fc:09:df:23:41:4f:0e:9f:fa:0e:
+         fa:44:85:f0:29:97:a4:94:e2:f4:40:2d:91:1c:76:f4:a8:60:
+         de:71:a6:b0:05:e2:4f:69:d9:19:0b:89:3a:e0:fa:ab:2b:fa:
+         f1:b3:32:ed:fc:7c:70:65:5e:d0:7b:11:7b:9d:e8:5b:1a:4a:
+         76:a4:7b:51:39:ac:7d:a9:0c:74:38:e8:bb:55:df:c4:ce:c0:
+         a7:21:5a:b8:1b:9f:01:c5:a7:10:fe:7d:f9:6a:08:99:01:d1:
+         f6:35:50:38:e4:f6:43:e4:18:d8:80:4c:ec:c7:04:e2:61:8c:
+         7d:49:ed:cf:b4:a5:f1:f2:90:92:09:08:35:73:a0:23:32:ca:
+         e9:9c:9e:1c:be:0b:07:2c:77:5e:17:4c:da:9c:82:e1:80:1b:
+         a5:f3:da:f7:88:bf:bf:39:27:f8:24:fe:b1:4b:c8:97:ed:e4:
+         12:14:25:88
+-----BEGIN CERTIFICATE-----
+MIIDvTCCAqWgAwIBAgIQD2tVL56/kHsPZimpvfTYzjANBgkqhkiG9w0BAQsFADBk
+MQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xNjA0
+BgNVBAMTLVN5bWFudGVjIEVudGVycHJpc2UgTW9iaWxlIFJvb3QgZm9yIE1pY3Jv
+c29mdDAeFw0xMjAzMTUwMDAwMDBaFw0zMjAzMTQyMzU5NTlaMGQxCzAJBgNVBAYT
+AlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjE2MDQGA1UEAxMtU3lt
+YW50ZWMgRW50ZXJwcmlzZSBNb2JpbGUgUm9vdCBmb3IgTWljcm9zb2Z0MIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtT2wcu6R6aVpnBFNevmz+j3ylJsj
+t6YD7GIY/IUSIv7BcX1Uk7mRfWL2yqg4FWX4dz3lgiA61LXRbo0GSb3fgg4khefv
+eC0Y8uALaEY+JBDIV+4ObXGm07FWHNcp1bLqVAUKqDyhuCVSBwWg3+fc7lw7QbWr
+XDMy0s7r6Zb4QPQKujMd+FYDCYL1ZwfEwDTBXfxFu+o8mtV0cW3VhtPC/IW8VOuj
+1fJP1UWvV7zwIsCPokXIdTR33qFtN3Kzc40Ma1O6WeGoPoBX0l9Z7mh1z4Gco8pF
+jDfbBXI0HDIC+NX5LA3aWJ7EF7SbyZDEiFk/cZGQRBi+Iot5ki5CsIuXWwIDAQAB
+o2swaTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAnBgNVHREEIDAe
+pBwwGjEYMBYGA1UEAxMPTVBLSS0yMDQ4LTEtMTExMB0GA1UdDgQWBBRN7N8mBtwk
+EMC2mfTXOcdvGfgmKDANBgkqhkiG9w0BAQsFAAOCAQEAqVdZ0AFUFEavx3lUDGoq
+W9g6HYHkiKMxtPHzNfFGc1xDyf68omoZwL0vX8s4o21u6BRe8nh+RXrhu/Qum0Xr
+4B1QHDRbf5iKhg+H2uRkJnf8Cd8jQU8On/oO+kSF8CmXpJTi9EAtkRx29Khg3nGm
+sAXiT2nZGQuJOuD6qyv68bMy7fx8cGVe0HsRe53oWxpKdqR7UTmsfakMdDjou1Xf
+xM7ApyFauBufAcWnEP59+WoImQHR9jVQOOT2Q+QY2IBM7McE4mGMfUntz7Sl8fKQ
+kgkINXOgIzLK6ZyeHL4LByx3XhdM2pyC4YAbpfPa94i/vzkn+CT+sUvIl+3kEhQl
+iA==
+-----END CERTIFICATE-----
diff --git a/net/data/verify_certificate_chain_unittest/generate-key-rollover.py b/net/data/verify_certificate_chain_unittest/generate-key-rollover.py
new file mode 100755
index 0000000..e06b4522
--- /dev/null
+++ b/net/data/verify_certificate_chain_unittest/generate-key-rollover.py
@@ -0,0 +1,92 @@
+#!/usr/bin/python
+# Copyright (c) 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.
+
+"""A certificate tree with two self-signed root certificates(oldroot, newroot),
+and a third root certificate (newrootrollover) which has the same key as newroot
+but is signed by oldroot, all with the same subject and issuer.
+There are two intermediates with the same key, subject and issuer
+(oldintermediate signed by oldroot, and newintermediate signed by newroot).
+The target certificate is signed by the intermediate key.
+
+
+In graphical form:
+
+   oldroot-------->newrootrollover  newroot
+      |                      |        |
+      v                      v        v
+oldintermediate           newintermediate
+      |                          |
+      +------------+-------------+
+                   |
+                   v
+                 target
+
+
+Several chains are output:
+  key-rollover-oldchain.pem:
+    target<-oldintermediate<-oldroot
+  key-rollover-rolloverchain.pem:
+    target<-newintermediate<-newrootrollover<-oldroot
+  key-rollover-longrolloverchain.pem:
+    target<-newintermediate<-newroot<-newrootrollover<-oldroot
+  key-rollover-newchain.pem:
+    target<-newintermediate<-newroot
+
+All of these chains should verify successfully.
+"""
+
+import common
+
+# The new certs should have a newer notbefore date than "old" certs. This should
+# affect path builder sorting, but otherwise won't matter.
+JANUARY_2_2015_UTC = '150102120000Z'
+
+# Self-signed root certificates. Same name, different keys.
+oldroot = common.create_self_signed_root_certificate('Root')
+oldroot.set_validity_range(common.JANUARY_1_2015_UTC, common.JANUARY_1_2016_UTC)
+newroot = common.create_self_signed_root_certificate('Root')
+newroot.set_validity_range(JANUARY_2_2015_UTC, common.JANUARY_1_2016_UTC)
+# Root with the new key signed by the old key.
+newrootrollover = common.create_intermediary_certificate('Root', oldroot)
+newrootrollover.set_key_path(newroot.get_key_path())
+newrootrollover.set_validity_range(JANUARY_2_2015_UTC,
+                                   common.JANUARY_1_2016_UTC)
+
+# Intermediate signed by oldroot.
+oldintermediate = common.create_intermediary_certificate('Intermediate',
+                                                         oldroot)
+oldintermediate.set_validity_range(common.JANUARY_1_2015_UTC,
+                                   common.JANUARY_1_2016_UTC)
+# Intermediate signed by newroot. Same key as oldintermediate.
+newintermediate = common.create_intermediary_certificate('Intermediate',
+                                                         newroot)
+newintermediate.set_key_path(oldintermediate.get_key_path())
+newintermediate.set_validity_range(JANUARY_2_2015_UTC,
+                                   common.JANUARY_1_2016_UTC)
+
+# Target certificate.
+target = common.create_end_entity_certificate('Target', oldintermediate)
+
+oldchain = [target, oldintermediate]
+rolloverchain = [target, newintermediate, newrootrollover]
+longrolloverchain = [target, newintermediate, newroot, newrootrollover]
+oldtrusted = [oldroot]
+
+newchain = [target, newintermediate]
+newtrusted = [newroot]
+
+time = common.DEFAULT_TIME
+verify_result = True
+
+common.write_test_file(__doc__, oldchain, oldtrusted, time, verify_result,
+                       out_pem="key-rollover-oldchain.pem")
+common.write_test_file(__doc__, rolloverchain, oldtrusted, time, verify_result,
+                       out_pem="key-rollover-rolloverchain.pem")
+common.write_test_file(__doc__, longrolloverchain, oldtrusted, time,
+                       verify_result,
+                       out_pem="key-rollover-longrolloverchain.pem")
+common.write_test_file(__doc__, newchain, newtrusted, time, verify_result,
+                       out_pem="key-rollover-newchain.pem")
+
diff --git a/net/data/verify_certificate_chain_unittest/key-rollover-longrolloverchain.pem b/net/data/verify_certificate_chain_unittest/key-rollover-longrolloverchain.pem
new file mode 100644
index 0000000..fcd63fa
--- /dev/null
+++ b/net/data/verify_certificate_chain_unittest/key-rollover-longrolloverchain.pem
@@ -0,0 +1,489 @@
+[Created by: ./generate-key-rollover.py]
+
+A certificate tree with two self-signed root certificates(oldroot, newroot),
+and a third root certificate (newrootrollover) which has the same key as newroot
+but is signed by oldroot, all with the same subject and issuer.
+There are two intermediates with the same key, subject and issuer
+(oldintermediate signed by oldroot, and newintermediate signed by newroot).
+The target certificate is signed by the intermediate key.
+
+
+In graphical form:
+
+   oldroot-------->newrootrollover  newroot
+      |                      |        |
+      v                      v        v
+oldintermediate           newintermediate
+      |                          |
+      +------------+-------------+
+                   |
+                   v
+                 target
+
+
+Several chains are output:
+  key-rollover-oldchain.pem:
+    target<-oldintermediate<-oldroot
+  key-rollover-rolloverchain.pem:
+    target<-newintermediate<-newrootrollover<-oldroot
+  key-rollover-longrolloverchain.pem:
+    target<-newintermediate<-newroot<-newrootrollover<-oldroot
+  key-rollover-newchain.pem:
+    target<-newintermediate<-newroot
+
+All of these chains should verify successfully.
+
+
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Intermediate
+        Validity
+            Not Before: Jan  1 12:00:00 2015 GMT
+            Not After : Jan  1 12:00:00 2016 GMT
+        Subject: CN=Target
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:be:12:1c:48:e4:73:1f:5c:d2:54:a9:7b:58:1c:
+                    37:73:c2:49:26:3e:ed:b5:6b:55:17:c9:4c:52:34:
+                    ce:d9:76:86:32:74:74:ae:11:b2:99:1b:51:a0:33:
+                    48:34:2f:b9:d3:2b:06:c2:5c:29:53:35:ce:7c:a6:
+                    67:b2:6a:d4:33:c3:13:62:30:a1:53:5f:45:78:5b:
+                    bb:47:ad:07:a4:98:9a:e9:e3:b1:3b:e6:33:c2:c1:
+                    5c:95:d7:c8:b9:a6:72:27:7a:79:da:c4:c8:5a:1a:
+                    3e:5e:5e:a6:62:64:c6:72:86:b1:78:98:5b:63:27:
+                    70:15:04:6b:b1:0f:11:9c:4d:3b:5c:e7:8d:c0:be:
+                    d5:84:46:6c:bd:11:1e:21:c1:82:9c:d0:aa:2d:2f:
+                    f8:2a:e9:3b:e4:35:15:6d:c7:4a:dd:a8:65:69:b8:
+                    16:a1:8a:04:a2:44:68:40:b6:99:ae:61:df:9f:6c:
+                    40:ef:79:c9:a3:6d:e4:2d:07:01:68:f1:21:4e:0e:
+                    28:a7:fd:2f:ad:ee:7d:65:cf:36:fd:4f:1b:ba:10:
+                    8e:86:fd:ec:37:67:0c:20:71:66:48:64:f3:82:af:
+                    f5:e1:73:c9:09:36:03:3f:c2:47:7a:f2:33:b9:f9:
+                    9f:53:9b:24:5e:c3:cc:05:d9:a9:ed:d7:b2:2a:c5:
+                    b7:39
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                C9:45:0B:2A:F2:D8:8D:2A:D7:CE:AF:56:BF:82:B0:84:0C:C8:2E:F4
+            X509v3 Authority Key Identifier: 
+                keyid:B1:39:79:13:35:D0:03:6B:E9:C4:63:2B:CC:D6:61:C3:82:EC:14:C1
+
+            Authority Information Access: 
+                CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://url-for-crl/Intermediate.crl
+
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+    Signature Algorithm: sha256WithRSAEncryption
+         63:66:9e:6c:34:8c:5d:74:ae:90:25:55:ae:86:49:b9:3d:fd:
+         27:bc:4f:69:7b:70:cb:25:0e:a3:8c:7a:7d:9c:4f:0b:7c:f2:
+         85:a5:ea:82:d2:37:c2:74:a2:ae:a8:bf:62:f4:5f:d4:c6:41:
+         45:0c:cc:27:53:aa:8f:66:58:e9:b0:de:ae:98:14:bd:92:df:
+         9b:0f:f2:c5:3b:d2:bc:1c:3e:80:b4:09:0f:c1:9f:d6:3a:29:
+         52:71:b6:1a:92:95:5a:18:dc:b4:30:dc:61:61:93:54:d1:55:
+         83:92:5d:c0:c7:dc:ab:d7:08:dd:8a:44:cf:92:f9:4d:86:25:
+         aa:ac:52:f6:0e:17:99:0b:31:d2:75:5e:33:f9:f5:b6:77:42:
+         07:62:a9:53:cc:f3:79:84:57:d9:14:3f:ab:4c:8b:ae:c7:9f:
+         cf:7a:1f:bf:7e:1d:44:bd:76:b4:cd:8d:c8:1d:75:f7:3b:b5:
+         bc:35:8b:3f:29:b1:cb:67:a4:17:af:a4:ca:9f:2b:e7:15:66:
+         e4:c8:c1:7c:08:78:9e:5d:4b:c3:c6:58:66:96:42:e8:e6:40:
+         fd:dc:24:ce:3b:58:11:38:40:0e:fc:a9:c0:2c:0f:e5:cc:bb:
+         02:32:31:b9:bc:6f:2d:1d:f6:2b:7c:d3:f8:24:f6:60:38:8a:
+         1f:dd:e1:50
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+EhxI
+5HMfXNJUqXtYHDdzwkkmPu21a1UXyUxSNM7ZdoYydHSuEbKZG1GgM0g0L7nTKwbC
+XClTNc58pmeyatQzwxNiMKFTX0V4W7tHrQekmJrp47E75jPCwVyV18i5pnInenna
+xMhaGj5eXqZiZMZyhrF4mFtjJ3AVBGuxDxGcTTtc543AvtWERmy9ER4hwYKc0Kot
+L/gq6TvkNRVtx0rdqGVpuBahigSiRGhAtpmuYd+fbEDvecmjbeQtBwFo8SFODiin
+/S+t7n1lzzb9Txu6EI6G/ew3ZwwgcWZIZPOCr/Xhc8kJNgM/wkd68jO5+Z9TmyRe
+w8wF2ant17Iqxbc5AgMBAAGjgekwgeYwHQYDVR0OBBYEFMlFCyry2I0q186vVr+C
+sIQMyC70MB8GA1UdIwQYMBaAFLE5eRM10ANr6cRjK8zWYcOC7BTBMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAY2aebDSMXXSukCVVroZJ
+uT39J7xPaXtwyyUOo4x6fZxPC3zyhaXqgtI3wnSirqi/YvRf1MZBRQzMJ1Oqj2ZY
+6bDerpgUvZLfmw/yxTvSvBw+gLQJD8Gf1jopUnG2GpKVWhjctDDcYWGTVNFVg5Jd
+wMfcq9cI3YpEz5L5TYYlqqxS9g4XmQsx0nVeM/n1tndCB2KpU8zzeYRX2RQ/q0yL
+rsefz3ofv34dRL12tM2NyB119zu1vDWLPymxy2ekF6+kyp8r5xVm5MjBfAh4nl1L
+w8ZYZpZC6OZA/dwkzjtYEThADvypwCwP5cy7AjIxubxvLR32K3zT+CT2YDiKH93h
+UA==
+-----END CERTIFICATE-----
+
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 2 (0x2)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Root
+        Validity
+            Not Before: Jan  2 12:00:00 2015 GMT
+            Not After : Jan  1 12:00:00 2016 GMT
+        Subject: CN=Intermediate
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:9c:d0:2e:3b:06:d6:ea:65:bd:dd:b2:d3:e8:88:
+                    ea:08:73:01:42:ac:ca:38:28:17:32:93:5e:16:a8:
+                    c1:79:44:9a:db:24:08:ba:81:52:63:9c:b4:ed:57:
+                    d4:b2:ac:54:64:3b:70:39:7e:37:da:11:e1:8c:ba:
+                    09:bc:1a:9b:e7:fe:6d:75:f8:71:31:f0:ca:52:89:
+                    2a:9e:d5:53:db:b8:c0:76:cf:bf:58:58:e1:bb:81:
+                    de:62:bb:06:58:1f:9b:64:03:75:7d:ee:76:6f:39:
+                    47:cb:8e:34:32:07:83:89:b0:83:2a:78:d0:ac:e2:
+                    86:0a:a8:ab:3b:97:81:de:9d:36:b4:03:b7:d5:06:
+                    05:53:d7:80:03:44:86:53:72:db:7a:5f:c5:20:dd:
+                    c7:44:58:3b:40:7f:0e:39:bc:be:0d:ca:6a:f6:82:
+                    a2:97:a2:17:79:51:6f:42:5d:0d:6a:b7:a0:de:5f:
+                    6a:00:be:e7:5a:b7:91:e9:fc:77:fd:75:88:8d:52:
+                    76:3d:0e:91:4b:c7:db:96:a4:5f:39:59:55:62:65:
+                    3b:15:7a:bc:7b:09:9f:3e:75:d9:9e:c5:00:b3:19:
+                    d4:26:7e:eb:db:62:07:c2:f5:b6:4e:87:2d:eb:56:
+                    8b:5a:68:6c:85:2f:b4:3e:1d:dd:5d:31:49:98:8b:
+                    06:55
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                B1:39:79:13:35:D0:03:6B:E9:C4:63:2B:CC:D6:61:C3:82:EC:14:C1
+            X509v3 Authority Key Identifier: 
+                keyid:15:9E:A6:AD:F5:9F:8A:A1:C1:08:99:BF:66:6F:CF:CA:72:CD:0C:34
+
+            Authority Information Access: 
+                CA Issuers - URI:http://url-for-aia/Root.cer
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://url-for-crl/Root.crl
+
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+         a8:ad:48:d8:6e:1d:24:09:d2:b3:29:3c:48:60:27:7f:37:64:
+         d5:f1:3b:b3:5c:43:de:7c:b4:5f:ee:3a:f2:1a:25:24:0a:8a:
+         25:6d:19:5b:dc:0c:4e:48:61:2f:60:d3:6b:f3:9c:03:2c:d3:
+         fa:c8:9b:99:e7:2e:c5:43:c0:5f:14:cd:8b:92:62:4f:e5:3a:
+         cd:b5:0a:d8:b2:01:c7:44:b4:3a:86:66:bf:fa:11:a5:f8:24:
+         3f:d1:1a:e8:eb:1e:ad:f0:70:31:6f:bc:21:cf:db:ce:63:4e:
+         84:e9:52:9e:bb:1b:c4:72:ae:e0:6c:88:9e:99:dc:79:d9:fd:
+         83:26:8e:f6:19:70:d9:5e:fc:f4:0c:d1:17:6f:af:10:f6:64:
+         16:08:d8:72:ba:3a:2d:66:28:5a:41:0d:f3:47:87:a7:9c:78:
+         c6:cd:5e:25:71:0b:f2:93:b8:26:17:b2:19:17:cc:03:ed:c0:
+         6e:06:e2:4b:4a:57:5f:23:02:2a:69:06:7a:c4:b7:3e:2f:e8:
+         f0:03:ae:b8:2d:df:63:22:20:73:23:75:d9:3c:d7:22:e4:b4:
+         65:65:ed:b9:e6:02:1d:b5:51:11:9c:db:92:e4:fe:8c:1d:bb:
+         c5:95:87:5b:38:ee:ff:e4:01:d1:5d:84:b9:73:d3:da:23:ca:
+         5e:05:d3:7d
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMjEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnNAuOwbW
+6mW93bLT6IjqCHMBQqzKOCgXMpNeFqjBeUSa2yQIuoFSY5y07VfUsqxUZDtwOX43
+2hHhjLoJvBqb5/5tdfhxMfDKUokqntVT27jAds+/WFjhu4HeYrsGWB+bZAN1fe52
+bzlHy440MgeDibCDKnjQrOKGCqirO5eB3p02tAO31QYFU9eAA0SGU3Lbel/FIN3H
+RFg7QH8OOby+Dcpq9oKil6IXeVFvQl0Nareg3l9qAL7nWreR6fx3/XWIjVJ2PQ6R
+S8fblqRfOVlVYmU7FXq8ewmfPnXZnsUAsxnUJn7r22IHwvW2Toct61aLWmhshS+0
+Ph3dXTFJmIsGVQIDAQABo4HLMIHIMB0GA1UdDgQWBBSxOXkTNdADa+nEYyvM1mHD
+guwUwTAfBgNVHSMEGDAWgBQVnqat9Z+KocEImb9mb8/Kcs0MNDA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+AKitSNhuHSQJ0rMpPEhgJ383ZNXxO7NcQ958tF/uOvIaJSQKiiVtGVvcDE5IYS9g
+02vznAMs0/rIm5nnLsVDwF8UzYuSYk/lOs21CtiyAcdEtDqGZr/6EaX4JD/RGujr
+Hq3wcDFvvCHP285jToTpUp67G8RyruBsiJ6Z3HnZ/YMmjvYZcNle/PQM0RdvrxD2
+ZBYI2HK6Oi1mKFpBDfNHh6eceMbNXiVxC/KTuCYXshkXzAPtwG4G4ktKV18jAipp
+BnrEtz4v6PADrrgt32MiIHMjddk81yLktGVl7bnmAh21URGc25Lk/owdu8WVh1s4
+7v/kAdFdhLlz09ojyl4F030=
+-----END CERTIFICATE-----
+
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Root
+        Validity
+            Not Before: Jan  2 12:00:00 2015 GMT
+            Not After : Jan  1 12:00:00 2016 GMT
+        Subject: CN=Root
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:ae:ea:3b:3f:b6:e9:3d:ea:eb:3d:dd:e8:4d:45:
+                    83:63:78:ea:07:90:3a:3c:4f:92:54:2b:2d:02:1b:
+                    eb:9e:81:72:68:2e:73:f8:4a:a1:de:0c:d6:f0:c2:
+                    61:26:90:0b:48:59:ab:23:25:8f:e4:4a:6b:c9:2d:
+                    ba:a7:35:c4:22:df:76:99:d8:7b:f7:6d:ca:9b:da:
+                    d2:ed:7e:c8:93:b2:a7:f6:f0:05:6a:5d:c6:e1:79:
+                    d0:25:59:a9:50:1e:65:eb:1c:c9:cd:4e:6a:3a:2a:
+                    a4:1a:fa:81:a3:e7:ae:d7:de:43:d9:e8:0b:5c:b0:
+                    6b:46:39:c5:9c:4a:6d:59:bf:da:70:2e:80:ac:c8:
+                    80:e3:83:d1:71:7b:a7:0b:92:bf:a8:81:ad:5c:b2:
+                    d5:e9:b9:5f:b5:4f:93:43:67:72:36:b3:f7:17:b9:
+                    1b:da:2a:13:83:70:36:ae:59:03:3d:f0:71:de:a2:
+                    7a:41:ad:b5:e9:a2:51:e4:18:ec:88:ad:48:f1:df:
+                    17:04:43:54:2a:af:3c:c0:f5:84:39:43:d1:a7:d2:
+                    52:0f:3c:dd:ef:13:58:8c:1d:d4:dd:2e:6d:1a:e7:
+                    73:9b:8b:f3:41:7b:9a:53:4e:0d:92:d3:5d:3f:fc:
+                    c3:61:dc:5f:a0:93:3c:08:cc:b4:9b:ce:9d:78:e3:
+                    77:c9
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                15:9E:A6:AD:F5:9F:8A:A1:C1:08:99:BF:66:6F:CF:CA:72:CD:0C:34
+            X509v3 Authority Key Identifier: 
+                keyid:15:9E:A6:AD:F5:9F:8A:A1:C1:08:99:BF:66:6F:CF:CA:72:CD:0C:34
+
+            Authority Information Access: 
+                CA Issuers - URI:http://url-for-aia/Root.cer
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://url-for-crl/Root.crl
+
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+         58:4b:60:7e:0b:c2:3d:20:f3:49:34:91:55:d3:5f:5b:ce:81:
+         31:da:71:9f:72:d7:f4:cc:be:cf:58:b8:97:aa:99:87:3d:34:
+         12:ac:40:1c:8e:02:46:83:ee:04:e1:7e:5e:57:ca:a4:ae:e1:
+         d0:b4:12:e9:65:33:f5:4e:c4:f6:49:00:7f:83:6d:75:67:84:
+         b2:db:52:5a:a2:3e:5d:2d:5c:f3:45:fe:6a:d3:c4:0a:76:52:
+         c6:9b:b0:89:01:b9:b6:be:30:60:d9:b4:2e:1d:1e:bf:ef:d8:
+         12:90:9f:cb:67:29:20:61:9f:1a:67:64:88:4c:43:ec:10:7d:
+         87:11:00:44:6a:ce:37:af:73:f4:fa:d2:22:2f:24:3a:6f:79:
+         09:6c:8d:de:b5:71:0e:6e:b7:64:a9:be:73:a8:c1:c8:50:74:
+         d2:c4:2b:ef:4f:25:20:8f:41:f0:1f:6e:52:77:eb:a0:1a:94:
+         87:7c:35:11:37:5c:33:f5:83:47:e0:f2:0e:97:af:23:61:23:
+         25:0b:92:6c:3b:30:a1:aa:c6:dc:4a:05:6e:43:76:58:82:66:
+         cd:f6:d6:ef:9b:80:36:d6:95:b7:d1:ec:5c:53:f7:78:84:ef:
+         48:6a:2c:f7:93:97:f2:7a:ce:ec:f3:eb:63:e1:5a:e0:69:02:
+         5d:34:36:93
+-----BEGIN CERTIFICATE-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMjEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK7qOz+26T3q6z3d6E1F
+g2N46geQOjxPklQrLQIb656Bcmguc/hKod4M1vDCYSaQC0hZqyMlj+RKa8ktuqc1
+xCLfdpnYe/dtypva0u1+yJOyp/bwBWpdxuF50CVZqVAeZescyc1OajoqpBr6gaPn
+rtfeQ9noC1ywa0Y5xZxKbVm/2nAugKzIgOOD0XF7pwuSv6iBrVyy1em5X7VPk0Nn
+cjaz9xe5G9oqE4NwNq5ZAz3wcd6iekGttemiUeQY7IitSPHfFwRDVCqvPMD1hDlD
+0afSUg883e8TWIwd1N0ubRrnc5uL80F7mlNODZLTXT/8w2HcX6CTPAjMtJvOnXjj
+d8kCAwEAAaOByzCByDAdBgNVHQ4EFgQUFZ6mrfWfiqHBCJm/Zm/PynLNDDQwHwYD
+VR0jBBgwFoAUFZ6mrfWfiqHBCJm/Zm/PynLNDDQwNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBYS2B+C8I9
+IPNJNJFV019bzoEx2nGfctf0zL7PWLiXqpmHPTQSrEAcjgJGg+4E4X5eV8qkruHQ
+tBLpZTP1TsT2SQB/g211Z4Sy21Jaoj5dLVzzRf5q08QKdlLGm7CJAbm2vjBg2bQu
+HR6/79gSkJ/LZykgYZ8aZ2SITEPsEH2HEQBEas43r3P0+tIiLyQ6b3kJbI3etXEO
+brdkqb5zqMHIUHTSxCvvTyUgj0HwH25Sd+ugGpSHfDURN1wz9YNH4PIOl68jYSMl
+C5JsOzChqsbcSgVuQ3ZYgmbN9tbvm4A21pW30excU/d4hO9Iaiz3k5fyes7s8+tj
+4VrgaQJdNDaT
+-----END CERTIFICATE-----
+
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 3 (0x3)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Root
+        Validity
+            Not Before: Jan  2 12:00:00 2015 GMT
+            Not After : Jan  1 12:00:00 2016 GMT
+        Subject: CN=Root
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:ae:ea:3b:3f:b6:e9:3d:ea:eb:3d:dd:e8:4d:45:
+                    83:63:78:ea:07:90:3a:3c:4f:92:54:2b:2d:02:1b:
+                    eb:9e:81:72:68:2e:73:f8:4a:a1:de:0c:d6:f0:c2:
+                    61:26:90:0b:48:59:ab:23:25:8f:e4:4a:6b:c9:2d:
+                    ba:a7:35:c4:22:df:76:99:d8:7b:f7:6d:ca:9b:da:
+                    d2:ed:7e:c8:93:b2:a7:f6:f0:05:6a:5d:c6:e1:79:
+                    d0:25:59:a9:50:1e:65:eb:1c:c9:cd:4e:6a:3a:2a:
+                    a4:1a:fa:81:a3:e7:ae:d7:de:43:d9:e8:0b:5c:b0:
+                    6b:46:39:c5:9c:4a:6d:59:bf:da:70:2e:80:ac:c8:
+                    80:e3:83:d1:71:7b:a7:0b:92:bf:a8:81:ad:5c:b2:
+                    d5:e9:b9:5f:b5:4f:93:43:67:72:36:b3:f7:17:b9:
+                    1b:da:2a:13:83:70:36:ae:59:03:3d:f0:71:de:a2:
+                    7a:41:ad:b5:e9:a2:51:e4:18:ec:88:ad:48:f1:df:
+                    17:04:43:54:2a:af:3c:c0:f5:84:39:43:d1:a7:d2:
+                    52:0f:3c:dd:ef:13:58:8c:1d:d4:dd:2e:6d:1a:e7:
+                    73:9b:8b:f3:41:7b:9a:53:4e:0d:92:d3:5d:3f:fc:
+                    c3:61:dc:5f:a0:93:3c:08:cc:b4:9b:ce:9d:78:e3:
+                    77:c9
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                15:9E:A6:AD:F5:9F:8A:A1:C1:08:99:BF:66:6F:CF:CA:72:CD:0C:34
+            X509v3 Authority Key Identifier: 
+                keyid:02:CE:F6:AC:1A:39:1E:85:E8:72:D1:8A:C6:1D:E8:7A:8F:9D:15:6B
+
+            Authority Information Access: 
+                CA Issuers - URI:http://url-for-aia/Root.cer
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://url-for-crl/Root.crl
+
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+         51:9b:dd:56:f2:b1:2b:e5:36:c8:2f:1d:a9:53:1f:89:e1:24:
+         33:bd:ac:56:c1:c3:1a:38:a6:7e:fc:61:9a:ae:7c:1f:13:3e:
+         37:e4:e6:a9:11:9e:2b:6e:ce:dd:12:0c:c1:b2:b7:eb:48:0e:
+         c7:a5:65:f0:86:49:8a:dc:cf:1b:6d:33:af:af:96:51:49:01:
+         e4:82:d6:e6:5a:d0:41:c7:05:9f:16:eb:06:bd:bc:ab:fe:a0:
+         d7:ac:de:62:d1:71:7e:69:82:31:03:e3:60:28:e6:18:3b:e5:
+         93:2b:58:ee:d5:0b:7b:b6:af:f2:4f:22:eb:4d:b7:a6:74:68:
+         b7:82:68:7f:a9:b6:ee:a0:20:d7:c6:16:0e:9c:1c:39:ea:24:
+         5e:60:12:fc:39:60:0d:54:3e:aa:b3:43:e1:0f:ef:d7:8f:3e:
+         09:a9:55:95:e9:3d:0c:4f:ad:cb:c2:f3:2c:10:43:67:54:f9:
+         66:54:81:ff:62:61:94:05:b0:42:af:f0:c5:ac:00:91:28:5c:
+         aa:a3:61:44:ba:c2:a6:ab:f8:1d:7e:02:69:33:48:fe:ac:93:
+         7f:4c:99:91:d9:18:37:f9:70:3f:56:2a:ee:4a:e0:4d:f3:60:
+         12:5d:30:d8:37:bf:ca:40:85:29:0c:a7:8f:ab:ad:03:6d:7b:
+         ba:62:7f:58
+-----BEGIN CERTIFICATE-----
+MIIDZTCCAk2gAwIBAgIBAzANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMjEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK7qOz+26T3q6z3d6E1F
+g2N46geQOjxPklQrLQIb656Bcmguc/hKod4M1vDCYSaQC0hZqyMlj+RKa8ktuqc1
+xCLfdpnYe/dtypva0u1+yJOyp/bwBWpdxuF50CVZqVAeZescyc1OajoqpBr6gaPn
+rtfeQ9noC1ywa0Y5xZxKbVm/2nAugKzIgOOD0XF7pwuSv6iBrVyy1em5X7VPk0Nn
+cjaz9xe5G9oqE4NwNq5ZAz3wcd6iekGttemiUeQY7IitSPHfFwRDVCqvPMD1hDlD
+0afSUg883e8TWIwd1N0ubRrnc5uL80F7mlNODZLTXT/8w2HcX6CTPAjMtJvOnXjj
+d8kCAwEAAaOByzCByDAdBgNVHQ4EFgQUFZ6mrfWfiqHBCJm/Zm/PynLNDDQwHwYD
+VR0jBBgwFoAUAs72rBo5HoXoctGKxh3oeo+dFWswNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBRm91W8rEr
+5TbILx2pUx+J4SQzvaxWwcMaOKZ+/GGarnwfEz435OapEZ4rbs7dEgzBsrfrSA7H
+pWXwhkmK3M8bbTOvr5ZRSQHkgtbmWtBBxwWfFusGvbyr/qDXrN5i0XF+aYIxA+Ng
+KOYYO+WTK1ju1Qt7tq/yTyLrTbemdGi3gmh/qbbuoCDXxhYOnBw56iReYBL8OWAN
+VD6qs0PhD+/Xjz4JqVWV6T0MT63LwvMsEENnVPlmVIH/YmGUBbBCr/DFrACRKFyq
+o2FEusKmq/gdfgJpM0j+rJN/TJmR2Rg3+XA/ViruSuBN82ASXTDYN7/KQIUpDKeP
+q60DbXu6Yn9Y
+-----END CERTIFICATE-----
+
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Root
+        Validity
+            Not Before: Jan  1 12:00:00 2015 GMT
+            Not After : Jan  1 12:00:00 2016 GMT
+        Subject: CN=Root
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:a6:44:ec:a7:15:00:1f:89:ac:91:f8:ec:7b:03:
+                    46:0b:53:15:ed:23:40:35:94:f3:96:80:27:d3:4a:
+                    84:92:68:c9:0c:e0:14:32:c7:31:67:49:29:58:77:
+                    ea:ce:8a:72:5b:93:b1:a0:a8:e5:84:c6:52:9d:5a:
+                    c0:41:bf:98:5f:18:5d:aa:d1:65:79:fb:e9:b0:84:
+                    92:9d:2c:58:bc:f1:c4:29:59:ed:bc:ac:85:ce:d7:
+                    0e:aa:08:e8:2d:90:25:cb:91:9d:7d:91:74:42:a0:
+                    ae:77:d2:11:7b:57:49:04:24:c0:94:f4:20:54:60:
+                    d9:1b:76:76:0b:2c:23:3c:67:90:8c:06:ed:4e:df:
+                    ac:24:22:26:f7:26:8f:5a:d2:5b:79:8a:6f:6e:53:
+                    27:60:10:cb:c7:b4:9f:60:2d:8f:32:69:4b:01:d1:
+                    f0:6d:69:1a:22:14:06:66:63:97:e8:fc:79:41:8d:
+                    15:44:44:d1:43:2a:37:5e:77:e4:06:e6:a9:85:13:
+                    e9:24:63:9d:09:d0:f5:13:d5:ba:59:2e:1c:d2:70:
+                    06:b1:80:f7:57:d7:30:f7:14:f3:18:06:7f:84:38:
+                    b6:81:46:9f:a2:36:87:0e:5f:1a:45:38:b7:20:16:
+                    b7:c6:e1:91:3b:0e:0c:ab:b7:4e:3d:a4:6d:66:d8:
+                    85:fb
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                02:CE:F6:AC:1A:39:1E:85:E8:72:D1:8A:C6:1D:E8:7A:8F:9D:15:6B
+            X509v3 Authority Key Identifier: 
+                keyid:02:CE:F6:AC:1A:39:1E:85:E8:72:D1:8A:C6:1D:E8:7A:8F:9D:15:6B
+
+            Authority Information Access: 
+                CA Issuers - URI:http://url-for-aia/Root.cer
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://url-for-crl/Root.crl
+
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+         0e:00:56:5c:72:31:88:bd:95:13:f7:64:96:1c:63:c2:1c:11:
+         60:04:d2:c3:5f:7c:a2:d7:d1:33:6d:51:6b:77:61:78:a8:70:
+         2e:50:97:5d:c1:e8:9b:dd:c6:61:a7:d3:e1:2c:83:07:85:5c:
+         c9:d7:1e:22:c2:5f:76:83:19:d7:de:4a:5e:82:0f:43:80:45:
+         02:d7:d0:3d:ca:c3:c0:fc:04:c8:f6:89:32:d7:47:c6:bf:1f:
+         c6:bd:71:e1:07:00:90:12:ec:61:63:1b:6c:e9:58:2c:fc:4c:
+         a9:8f:58:e1:b1:6e:a5:ca:4d:be:7e:32:16:74:5f:fd:35:e4:
+         37:aa:1a:c5:33:21:20:8a:3e:1c:af:da:f3:c7:a2:22:d3:93:
+         6c:5e:ac:0a:65:d5:db:e4:8b:11:5e:ca:eb:8f:da:c4:5d:2f:
+         7a:98:e8:3c:d1:89:15:05:02:86:ef:eb:17:18:81:28:ca:d6:
+         58:87:bd:d4:e2:50:41:92:d9:7f:b1:f7:53:8f:f3:cc:f3:1e:
+         1d:e4:5a:c2:60:1b:17:42:78:53:e9:2d:5d:bb:f9:21:50:ff:
+         87:53:be:5f:e6:d4:8f:25:7f:d7:83:d7:f8:4d:c1:7c:7a:40:
+         0b:11:f1:d9:c6:eb:97:45:00:d6:6b:84:1c:4f:fc:8e:1f:5b:
+         b5:3d:60:0c
+-----BEGIN TRUSTED_CERTIFICATE-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKZE7KcVAB+JrJH47HsD
+RgtTFe0jQDWU85aAJ9NKhJJoyQzgFDLHMWdJKVh36s6KcluTsaCo5YTGUp1awEG/
+mF8YXarRZXn76bCEkp0sWLzxxClZ7byshc7XDqoI6C2QJcuRnX2RdEKgrnfSEXtX
+SQQkwJT0IFRg2Rt2dgssIzxnkIwG7U7frCQiJvcmj1rSW3mKb25TJ2AQy8e0n2At
+jzJpSwHR8G1pGiIUBmZjl+j8eUGNFURE0UMqN1535AbmqYUT6SRjnQnQ9RPVulku
+HNJwBrGA91fXMPcU8xgGf4Q4toFGn6I2hw5fGkU4tyAWt8bhkTsODKu3Tj2kbWbY
+hfsCAwEAAaOByzCByDAdBgNVHQ4EFgQUAs72rBo5HoXoctGKxh3oeo+dFWswHwYD
+VR0jBBgwFoAUAs72rBo5HoXoctGKxh3oeo+dFWswNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAOAFZccjGI
+vZUT92SWHGPCHBFgBNLDX3yi19EzbVFrd2F4qHAuUJddweib3cZhp9PhLIMHhVzJ
+1x4iwl92gxnX3kpegg9DgEUC19A9ysPA/ATI9oky10fGvx/GvXHhBwCQEuxhYxts
+6Vgs/Eypj1jhsW6lyk2+fjIWdF/9NeQ3qhrFMyEgij4cr9rzx6Ii05NsXqwKZdXb
+5IsRXsrrj9rEXS96mOg80YkVBQKG7+sXGIEoytZYh73U4lBBktl/sfdTj/PM8x4d
+5FrCYBsXQnhT6S1du/khUP+HU75f5tSPJX/Xg9f4TcF8ekALEfHZxuuXRQDWa4Qc
+T/yOH1u1PWAM
+-----END TRUSTED_CERTIFICATE-----
+
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/net/data/verify_certificate_chain_unittest/key-rollover-newchain.pem b/net/data/verify_certificate_chain_unittest/key-rollover-newchain.pem
new file mode 100644
index 0000000..97d56749
--- /dev/null
+++ b/net/data/verify_certificate_chain_unittest/key-rollover-newchain.pem
@@ -0,0 +1,311 @@
+[Created by: ./generate-key-rollover.py]
+
+A certificate tree with two self-signed root certificates(oldroot, newroot),
+and a third root certificate (newrootrollover) which has the same key as newroot
+but is signed by oldroot, all with the same subject and issuer.
+There are two intermediates with the same key, subject and issuer
+(oldintermediate signed by oldroot, and newintermediate signed by newroot).
+The target certificate is signed by the intermediate key.
+
+
+In graphical form:
+
+   oldroot-------->newrootrollover  newroot
+      |                      |        |
+      v                      v        v
+oldintermediate           newintermediate
+      |                          |
+      +------------+-------------+
+                   |
+                   v
+                 target
+
+
+Several chains are output:
+  key-rollover-oldchain.pem:
+    target<-oldintermediate<-oldroot
+  key-rollover-rolloverchain.pem:
+    target<-newintermediate<-newrootrollover<-oldroot
+  key-rollover-longrolloverchain.pem:
+    target<-newintermediate<-newroot<-newrootrollover<-oldroot
+  key-rollover-newchain.pem:
+    target<-newintermediate<-newroot
+
+All of these chains should verify successfully.
+
+
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Intermediate
+        Validity
+            Not Before: Jan  1 12:00:00 2015 GMT
+            Not After : Jan  1 12:00:00 2016 GMT
+        Subject: CN=Target
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:be:12:1c:48:e4:73:1f:5c:d2:54:a9:7b:58:1c:
+                    37:73:c2:49:26:3e:ed:b5:6b:55:17:c9:4c:52:34:
+                    ce:d9:76:86:32:74:74:ae:11:b2:99:1b:51:a0:33:
+                    48:34:2f:b9:d3:2b:06:c2:5c:29:53:35:ce:7c:a6:
+                    67:b2:6a:d4:33:c3:13:62:30:a1:53:5f:45:78:5b:
+                    bb:47:ad:07:a4:98:9a:e9:e3:b1:3b:e6:33:c2:c1:
+                    5c:95:d7:c8:b9:a6:72:27:7a:79:da:c4:c8:5a:1a:
+                    3e:5e:5e:a6:62:64:c6:72:86:b1:78:98:5b:63:27:
+                    70:15:04:6b:b1:0f:11:9c:4d:3b:5c:e7:8d:c0:be:
+                    d5:84:46:6c:bd:11:1e:21:c1:82:9c:d0:aa:2d:2f:
+                    f8:2a:e9:3b:e4:35:15:6d:c7:4a:dd:a8:65:69:b8:
+                    16:a1:8a:04:a2:44:68:40:b6:99:ae:61:df:9f:6c:
+                    40:ef:79:c9:a3:6d:e4:2d:07:01:68:f1:21:4e:0e:
+                    28:a7:fd:2f:ad:ee:7d:65:cf:36:fd:4f:1b:ba:10:
+                    8e:86:fd:ec:37:67:0c:20:71:66:48:64:f3:82:af:
+                    f5:e1:73:c9:09:36:03:3f:c2:47:7a:f2:33:b9:f9:
+                    9f:53:9b:24:5e:c3:cc:05:d9:a9:ed:d7:b2:2a:c5:
+                    b7:39
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                C9:45:0B:2A:F2:D8:8D:2A:D7:CE:AF:56:BF:82:B0:84:0C:C8:2E:F4
+            X509v3 Authority Key Identifier: 
+                keyid:B1:39:79:13:35:D0:03:6B:E9:C4:63:2B:CC:D6:61:C3:82:EC:14:C1
+
+            Authority Information Access: 
+                CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://url-for-crl/Intermediate.crl
+
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+    Signature Algorithm: sha256WithRSAEncryption
+         63:66:9e:6c:34:8c:5d:74:ae:90:25:55:ae:86:49:b9:3d:fd:
+         27:bc:4f:69:7b:70:cb:25:0e:a3:8c:7a:7d:9c:4f:0b:7c:f2:
+         85:a5:ea:82:d2:37:c2:74:a2:ae:a8:bf:62:f4:5f:d4:c6:41:
+         45:0c:cc:27:53:aa:8f:66:58:e9:b0:de:ae:98:14:bd:92:df:
+         9b:0f:f2:c5:3b:d2:bc:1c:3e:80:b4:09:0f:c1:9f:d6:3a:29:
+         52:71:b6:1a:92:95:5a:18:dc:b4:30:dc:61:61:93:54:d1:55:
+         83:92:5d:c0:c7:dc:ab:d7:08:dd:8a:44:cf:92:f9:4d:86:25:
+         aa:ac:52:f6:0e:17:99:0b:31:d2:75:5e:33:f9:f5:b6:77:42:
+         07:62:a9:53:cc:f3:79:84:57:d9:14:3f:ab:4c:8b:ae:c7:9f:
+         cf:7a:1f:bf:7e:1d:44:bd:76:b4:cd:8d:c8:1d:75:f7:3b:b5:
+         bc:35:8b:3f:29:b1:cb:67:a4:17:af:a4:ca:9f:2b:e7:15:66:
+         e4:c8:c1:7c:08:78:9e:5d:4b:c3:c6:58:66:96:42:e8:e6:40:
+         fd:dc:24:ce:3b:58:11:38:40:0e:fc:a9:c0:2c:0f:e5:cc:bb:
+         02:32:31:b9:bc:6f:2d:1d:f6:2b:7c:d3:f8:24:f6:60:38:8a:
+         1f:dd:e1:50
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+EhxI
+5HMfXNJUqXtYHDdzwkkmPu21a1UXyUxSNM7ZdoYydHSuEbKZG1GgM0g0L7nTKwbC
+XClTNc58pmeyatQzwxNiMKFTX0V4W7tHrQekmJrp47E75jPCwVyV18i5pnInenna
+xMhaGj5eXqZiZMZyhrF4mFtjJ3AVBGuxDxGcTTtc543AvtWERmy9ER4hwYKc0Kot
+L/gq6TvkNRVtx0rdqGVpuBahigSiRGhAtpmuYd+fbEDvecmjbeQtBwFo8SFODiin
+/S+t7n1lzzb9Txu6EI6G/ew3ZwwgcWZIZPOCr/Xhc8kJNgM/wkd68jO5+Z9TmyRe
+w8wF2ant17Iqxbc5AgMBAAGjgekwgeYwHQYDVR0OBBYEFMlFCyry2I0q186vVr+C
+sIQMyC70MB8GA1UdIwQYMBaAFLE5eRM10ANr6cRjK8zWYcOC7BTBMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAY2aebDSMXXSukCVVroZJ
+uT39J7xPaXtwyyUOo4x6fZxPC3zyhaXqgtI3wnSirqi/YvRf1MZBRQzMJ1Oqj2ZY
+6bDerpgUvZLfmw/yxTvSvBw+gLQJD8Gf1jopUnG2GpKVWhjctDDcYWGTVNFVg5Jd
+wMfcq9cI3YpEz5L5TYYlqqxS9g4XmQsx0nVeM/n1tndCB2KpU8zzeYRX2RQ/q0yL
+rsefz3ofv34dRL12tM2NyB119zu1vDWLPymxy2ekF6+kyp8r5xVm5MjBfAh4nl1L
+w8ZYZpZC6OZA/dwkzjtYEThADvypwCwP5cy7AjIxubxvLR32K3zT+CT2YDiKH93h
+UA==
+-----END CERTIFICATE-----
+
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 2 (0x2)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Root
+        Validity
+            Not Before: Jan  2 12:00:00 2015 GMT
+            Not After : Jan  1 12:00:00 2016 GMT
+        Subject: CN=Intermediate
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:9c:d0:2e:3b:06:d6:ea:65:bd:dd:b2:d3:e8:88:
+                    ea:08:73:01:42:ac:ca:38:28:17:32:93:5e:16:a8:
+                    c1:79:44:9a:db:24:08:ba:81:52:63:9c:b4:ed:57:
+                    d4:b2:ac:54:64:3b:70:39:7e:37:da:11:e1:8c:ba:
+                    09:bc:1a:9b:e7:fe:6d:75:f8:71:31:f0:ca:52:89:
+                    2a:9e:d5:53:db:b8:c0:76:cf:bf:58:58:e1:bb:81:
+                    de:62:bb:06:58:1f:9b:64:03:75:7d:ee:76:6f:39:
+                    47:cb:8e:34:32:07:83:89:b0:83:2a:78:d0:ac:e2:
+                    86:0a:a8:ab:3b:97:81:de:9d:36:b4:03:b7:d5:06:
+                    05:53:d7:80:03:44:86:53:72:db:7a:5f:c5:20:dd:
+                    c7:44:58:3b:40:7f:0e:39:bc:be:0d:ca:6a:f6:82:
+                    a2:97:a2:17:79:51:6f:42:5d:0d:6a:b7:a0:de:5f:
+                    6a:00:be:e7:5a:b7:91:e9:fc:77:fd:75:88:8d:52:
+                    76:3d:0e:91:4b:c7:db:96:a4:5f:39:59:55:62:65:
+                    3b:15:7a:bc:7b:09:9f:3e:75:d9:9e:c5:00:b3:19:
+                    d4:26:7e:eb:db:62:07:c2:f5:b6:4e:87:2d:eb:56:
+                    8b:5a:68:6c:85:2f:b4:3e:1d:dd:5d:31:49:98:8b:
+                    06:55
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                B1:39:79:13:35:D0:03:6B:E9:C4:63:2B:CC:D6:61:C3:82:EC:14:C1
+            X509v3 Authority Key Identifier: 
+                keyid:15:9E:A6:AD:F5:9F:8A:A1:C1:08:99:BF:66:6F:CF:CA:72:CD:0C:34
+
+            Authority Information Access: 
+                CA Issuers - URI:http://url-for-aia/Root.cer
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://url-for-crl/Root.crl
+
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+         a8:ad:48:d8:6e:1d:24:09:d2:b3:29:3c:48:60:27:7f:37:64:
+         d5:f1:3b:b3:5c:43:de:7c:b4:5f:ee:3a:f2:1a:25:24:0a:8a:
+         25:6d:19:5b:dc:0c:4e:48:61:2f:60:d3:6b:f3:9c:03:2c:d3:
+         fa:c8:9b:99:e7:2e:c5:43:c0:5f:14:cd:8b:92:62:4f:e5:3a:
+         cd:b5:0a:d8:b2:01:c7:44:b4:3a:86:66:bf:fa:11:a5:f8:24:
+         3f:d1:1a:e8:eb:1e:ad:f0:70:31:6f:bc:21:cf:db:ce:63:4e:
+         84:e9:52:9e:bb:1b:c4:72:ae:e0:6c:88:9e:99:dc:79:d9:fd:
+         83:26:8e:f6:19:70:d9:5e:fc:f4:0c:d1:17:6f:af:10:f6:64:
+         16:08:d8:72:ba:3a:2d:66:28:5a:41:0d:f3:47:87:a7:9c:78:
+         c6:cd:5e:25:71:0b:f2:93:b8:26:17:b2:19:17:cc:03:ed:c0:
+         6e:06:e2:4b:4a:57:5f:23:02:2a:69:06:7a:c4:b7:3e:2f:e8:
+         f0:03:ae:b8:2d:df:63:22:20:73:23:75:d9:3c:d7:22:e4:b4:
+         65:65:ed:b9:e6:02:1d:b5:51:11:9c:db:92:e4:fe:8c:1d:bb:
+         c5:95:87:5b:38:ee:ff:e4:01:d1:5d:84:b9:73:d3:da:23:ca:
+         5e:05:d3:7d
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMjEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnNAuOwbW
+6mW93bLT6IjqCHMBQqzKOCgXMpNeFqjBeUSa2yQIuoFSY5y07VfUsqxUZDtwOX43
+2hHhjLoJvBqb5/5tdfhxMfDKUokqntVT27jAds+/WFjhu4HeYrsGWB+bZAN1fe52
+bzlHy440MgeDibCDKnjQrOKGCqirO5eB3p02tAO31QYFU9eAA0SGU3Lbel/FIN3H
+RFg7QH8OOby+Dcpq9oKil6IXeVFvQl0Nareg3l9qAL7nWreR6fx3/XWIjVJ2PQ6R
+S8fblqRfOVlVYmU7FXq8ewmfPnXZnsUAsxnUJn7r22IHwvW2Toct61aLWmhshS+0
+Ph3dXTFJmIsGVQIDAQABo4HLMIHIMB0GA1UdDgQWBBSxOXkTNdADa+nEYyvM1mHD
+guwUwTAfBgNVHSMEGDAWgBQVnqat9Z+KocEImb9mb8/Kcs0MNDA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+AKitSNhuHSQJ0rMpPEhgJ383ZNXxO7NcQ958tF/uOvIaJSQKiiVtGVvcDE5IYS9g
+02vznAMs0/rIm5nnLsVDwF8UzYuSYk/lOs21CtiyAcdEtDqGZr/6EaX4JD/RGujr
+Hq3wcDFvvCHP285jToTpUp67G8RyruBsiJ6Z3HnZ/YMmjvYZcNle/PQM0RdvrxD2
+ZBYI2HK6Oi1mKFpBDfNHh6eceMbNXiVxC/KTuCYXshkXzAPtwG4G4ktKV18jAipp
+BnrEtz4v6PADrrgt32MiIHMjddk81yLktGVl7bnmAh21URGc25Lk/owdu8WVh1s4
+7v/kAdFdhLlz09ojyl4F030=
+-----END CERTIFICATE-----
+
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Root
+        Validity
+            Not Before: Jan  2 12:00:00 2015 GMT
+            Not After : Jan  1 12:00:00 2016 GMT
+        Subject: CN=Root
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:ae:ea:3b:3f:b6:e9:3d:ea:eb:3d:dd:e8:4d:45:
+                    83:63:78:ea:07:90:3a:3c:4f:92:54:2b:2d:02:1b:
+                    eb:9e:81:72:68:2e:73:f8:4a:a1:de:0c:d6:f0:c2:
+                    61:26:90:0b:48:59:ab:23:25:8f:e4:4a:6b:c9:2d:
+                    ba:a7:35:c4:22:df:76:99:d8:7b:f7:6d:ca:9b:da:
+                    d2:ed:7e:c8:93:b2:a7:f6:f0:05:6a:5d:c6:e1:79:
+                    d0:25:59:a9:50:1e:65:eb:1c:c9:cd:4e:6a:3a:2a:
+                    a4:1a:fa:81:a3:e7:ae:d7:de:43:d9:e8:0b:5c:b0:
+                    6b:46:39:c5:9c:4a:6d:59:bf:da:70:2e:80:ac:c8:
+                    80:e3:83:d1:71:7b:a7:0b:92:bf:a8:81:ad:5c:b2:
+                    d5:e9:b9:5f:b5:4f:93:43:67:72:36:b3:f7:17:b9:
+                    1b:da:2a:13:83:70:36:ae:59:03:3d:f0:71:de:a2:
+                    7a:41:ad:b5:e9:a2:51:e4:18:ec:88:ad:48:f1:df:
+                    17:04:43:54:2a:af:3c:c0:f5:84:39:43:d1:a7:d2:
+                    52:0f:3c:dd:ef:13:58:8c:1d:d4:dd:2e:6d:1a:e7:
+                    73:9b:8b:f3:41:7b:9a:53:4e:0d:92:d3:5d:3f:fc:
+                    c3:61:dc:5f:a0:93:3c:08:cc:b4:9b:ce:9d:78:e3:
+                    77:c9
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                15:9E:A6:AD:F5:9F:8A:A1:C1:08:99:BF:66:6F:CF:CA:72:CD:0C:34
+            X509v3 Authority Key Identifier: 
+                keyid:15:9E:A6:AD:F5:9F:8A:A1:C1:08:99:BF:66:6F:CF:CA:72:CD:0C:34
+
+            Authority Information Access: 
+                CA Issuers - URI:http://url-for-aia/Root.cer
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://url-for-crl/Root.crl
+
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+         58:4b:60:7e:0b:c2:3d:20:f3:49:34:91:55:d3:5f:5b:ce:81:
+         31:da:71:9f:72:d7:f4:cc:be:cf:58:b8:97:aa:99:87:3d:34:
+         12:ac:40:1c:8e:02:46:83:ee:04:e1:7e:5e:57:ca:a4:ae:e1:
+         d0:b4:12:e9:65:33:f5:4e:c4:f6:49:00:7f:83:6d:75:67:84:
+         b2:db:52:5a:a2:3e:5d:2d:5c:f3:45:fe:6a:d3:c4:0a:76:52:
+         c6:9b:b0:89:01:b9:b6:be:30:60:d9:b4:2e:1d:1e:bf:ef:d8:
+         12:90:9f:cb:67:29:20:61:9f:1a:67:64:88:4c:43:ec:10:7d:
+         87:11:00:44:6a:ce:37:af:73:f4:fa:d2:22:2f:24:3a:6f:79:
+         09:6c:8d:de:b5:71:0e:6e:b7:64:a9:be:73:a8:c1:c8:50:74:
+         d2:c4:2b:ef:4f:25:20:8f:41:f0:1f:6e:52:77:eb:a0:1a:94:
+         87:7c:35:11:37:5c:33:f5:83:47:e0:f2:0e:97:af:23:61:23:
+         25:0b:92:6c:3b:30:a1:aa:c6:dc:4a:05:6e:43:76:58:82:66:
+         cd:f6:d6:ef:9b:80:36:d6:95:b7:d1:ec:5c:53:f7:78:84:ef:
+         48:6a:2c:f7:93:97:f2:7a:ce:ec:f3:eb:63:e1:5a:e0:69:02:
+         5d:34:36:93
+-----BEGIN TRUSTED_CERTIFICATE-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMjEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK7qOz+26T3q6z3d6E1F
+g2N46geQOjxPklQrLQIb656Bcmguc/hKod4M1vDCYSaQC0hZqyMlj+RKa8ktuqc1
+xCLfdpnYe/dtypva0u1+yJOyp/bwBWpdxuF50CVZqVAeZescyc1OajoqpBr6gaPn
+rtfeQ9noC1ywa0Y5xZxKbVm/2nAugKzIgOOD0XF7pwuSv6iBrVyy1em5X7VPk0Nn
+cjaz9xe5G9oqE4NwNq5ZAz3wcd6iekGttemiUeQY7IitSPHfFwRDVCqvPMD1hDlD
+0afSUg883e8TWIwd1N0ubRrnc5uL80F7mlNODZLTXT/8w2HcX6CTPAjMtJvOnXjj
+d8kCAwEAAaOByzCByDAdBgNVHQ4EFgQUFZ6mrfWfiqHBCJm/Zm/PynLNDDQwHwYD
+VR0jBBgwFoAUFZ6mrfWfiqHBCJm/Zm/PynLNDDQwNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBYS2B+C8I9
+IPNJNJFV019bzoEx2nGfctf0zL7PWLiXqpmHPTQSrEAcjgJGg+4E4X5eV8qkruHQ
+tBLpZTP1TsT2SQB/g211Z4Sy21Jaoj5dLVzzRf5q08QKdlLGm7CJAbm2vjBg2bQu
+HR6/79gSkJ/LZykgYZ8aZ2SITEPsEH2HEQBEas43r3P0+tIiLyQ6b3kJbI3etXEO
+brdkqb5zqMHIUHTSxCvvTyUgj0HwH25Sd+ugGpSHfDURN1wz9YNH4PIOl68jYSMl
+C5JsOzChqsbcSgVuQ3ZYgmbN9tbvm4A21pW30excU/d4hO9Iaiz3k5fyes7s8+tj
+4VrgaQJdNDaT
+-----END TRUSTED_CERTIFICATE-----
+
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/net/data/verify_certificate_chain_unittest/key-rollover-oldchain.pem b/net/data/verify_certificate_chain_unittest/key-rollover-oldchain.pem
new file mode 100644
index 0000000..6669c2a
--- /dev/null
+++ b/net/data/verify_certificate_chain_unittest/key-rollover-oldchain.pem
@@ -0,0 +1,311 @@
+[Created by: ./generate-key-rollover.py]
+
+A certificate tree with two self-signed root certificates(oldroot, newroot),
+and a third root certificate (newrootrollover) which has the same key as newroot
+but is signed by oldroot, all with the same subject and issuer.
+There are two intermediates with the same key, subject and issuer
+(oldintermediate signed by oldroot, and newintermediate signed by newroot).
+The target certificate is signed by the intermediate key.
+
+
+In graphical form:
+
+   oldroot-------->newrootrollover  newroot
+      |                      |        |
+      v                      v        v
+oldintermediate           newintermediate
+      |                          |
+      +------------+-------------+
+                   |
+                   v
+                 target
+
+
+Several chains are output:
+  key-rollover-oldchain.pem:
+    target<-oldintermediate<-oldroot
+  key-rollover-rolloverchain.pem:
+    target<-newintermediate<-newrootrollover<-oldroot
+  key-rollover-longrolloverchain.pem:
+    target<-newintermediate<-newroot<-newrootrollover<-oldroot
+  key-rollover-newchain.pem:
+    target<-newintermediate<-newroot
+
+All of these chains should verify successfully.
+
+
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Intermediate
+        Validity
+            Not Before: Jan  1 12:00:00 2015 GMT
+            Not After : Jan  1 12:00:00 2016 GMT
+        Subject: CN=Target
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:be:12:1c:48:e4:73:1f:5c:d2:54:a9:7b:58:1c:
+                    37:73:c2:49:26:3e:ed:b5:6b:55:17:c9:4c:52:34:
+                    ce:d9:76:86:32:74:74:ae:11:b2:99:1b:51:a0:33:
+                    48:34:2f:b9:d3:2b:06:c2:5c:29:53:35:ce:7c:a6:
+                    67:b2:6a:d4:33:c3:13:62:30:a1:53:5f:45:78:5b:
+                    bb:47:ad:07:a4:98:9a:e9:e3:b1:3b:e6:33:c2:c1:
+                    5c:95:d7:c8:b9:a6:72:27:7a:79:da:c4:c8:5a:1a:
+                    3e:5e:5e:a6:62:64:c6:72:86:b1:78:98:5b:63:27:
+                    70:15:04:6b:b1:0f:11:9c:4d:3b:5c:e7:8d:c0:be:
+                    d5:84:46:6c:bd:11:1e:21:c1:82:9c:d0:aa:2d:2f:
+                    f8:2a:e9:3b:e4:35:15:6d:c7:4a:dd:a8:65:69:b8:
+                    16:a1:8a:04:a2:44:68:40:b6:99:ae:61:df:9f:6c:
+                    40:ef:79:c9:a3:6d:e4:2d:07:01:68:f1:21:4e:0e:
+                    28:a7:fd:2f:ad:ee:7d:65:cf:36:fd:4f:1b:ba:10:
+                    8e:86:fd:ec:37:67:0c:20:71:66:48:64:f3:82:af:
+                    f5:e1:73:c9:09:36:03:3f:c2:47:7a:f2:33:b9:f9:
+                    9f:53:9b:24:5e:c3:cc:05:d9:a9:ed:d7:b2:2a:c5:
+                    b7:39
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                C9:45:0B:2A:F2:D8:8D:2A:D7:CE:AF:56:BF:82:B0:84:0C:C8:2E:F4
+            X509v3 Authority Key Identifier: 
+                keyid:B1:39:79:13:35:D0:03:6B:E9:C4:63:2B:CC:D6:61:C3:82:EC:14:C1
+
+            Authority Information Access: 
+                CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://url-for-crl/Intermediate.crl
+
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+    Signature Algorithm: sha256WithRSAEncryption
+         63:66:9e:6c:34:8c:5d:74:ae:90:25:55:ae:86:49:b9:3d:fd:
+         27:bc:4f:69:7b:70:cb:25:0e:a3:8c:7a:7d:9c:4f:0b:7c:f2:
+         85:a5:ea:82:d2:37:c2:74:a2:ae:a8:bf:62:f4:5f:d4:c6:41:
+         45:0c:cc:27:53:aa:8f:66:58:e9:b0:de:ae:98:14:bd:92:df:
+         9b:0f:f2:c5:3b:d2:bc:1c:3e:80:b4:09:0f:c1:9f:d6:3a:29:
+         52:71:b6:1a:92:95:5a:18:dc:b4:30:dc:61:61:93:54:d1:55:
+         83:92:5d:c0:c7:dc:ab:d7:08:dd:8a:44:cf:92:f9:4d:86:25:
+         aa:ac:52:f6:0e:17:99:0b:31:d2:75:5e:33:f9:f5:b6:77:42:
+         07:62:a9:53:cc:f3:79:84:57:d9:14:3f:ab:4c:8b:ae:c7:9f:
+         cf:7a:1f:bf:7e:1d:44:bd:76:b4:cd:8d:c8:1d:75:f7:3b:b5:
+         bc:35:8b:3f:29:b1:cb:67:a4:17:af:a4:ca:9f:2b:e7:15:66:
+         e4:c8:c1:7c:08:78:9e:5d:4b:c3:c6:58:66:96:42:e8:e6:40:
+         fd:dc:24:ce:3b:58:11:38:40:0e:fc:a9:c0:2c:0f:e5:cc:bb:
+         02:32:31:b9:bc:6f:2d:1d:f6:2b:7c:d3:f8:24:f6:60:38:8a:
+         1f:dd:e1:50
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+EhxI
+5HMfXNJUqXtYHDdzwkkmPu21a1UXyUxSNM7ZdoYydHSuEbKZG1GgM0g0L7nTKwbC
+XClTNc58pmeyatQzwxNiMKFTX0V4W7tHrQekmJrp47E75jPCwVyV18i5pnInenna
+xMhaGj5eXqZiZMZyhrF4mFtjJ3AVBGuxDxGcTTtc543AvtWERmy9ER4hwYKc0Kot
+L/gq6TvkNRVtx0rdqGVpuBahigSiRGhAtpmuYd+fbEDvecmjbeQtBwFo8SFODiin
+/S+t7n1lzzb9Txu6EI6G/ew3ZwwgcWZIZPOCr/Xhc8kJNgM/wkd68jO5+Z9TmyRe
+w8wF2ant17Iqxbc5AgMBAAGjgekwgeYwHQYDVR0OBBYEFMlFCyry2I0q186vVr+C
+sIQMyC70MB8GA1UdIwQYMBaAFLE5eRM10ANr6cRjK8zWYcOC7BTBMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAY2aebDSMXXSukCVVroZJ
+uT39J7xPaXtwyyUOo4x6fZxPC3zyhaXqgtI3wnSirqi/YvRf1MZBRQzMJ1Oqj2ZY
+6bDerpgUvZLfmw/yxTvSvBw+gLQJD8Gf1jopUnG2GpKVWhjctDDcYWGTVNFVg5Jd
+wMfcq9cI3YpEz5L5TYYlqqxS9g4XmQsx0nVeM/n1tndCB2KpU8zzeYRX2RQ/q0yL
+rsefz3ofv34dRL12tM2NyB119zu1vDWLPymxy2ekF6+kyp8r5xVm5MjBfAh4nl1L
+w8ZYZpZC6OZA/dwkzjtYEThADvypwCwP5cy7AjIxubxvLR32K3zT+CT2YDiKH93h
+UA==
+-----END CERTIFICATE-----
+
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 2 (0x2)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Root
+        Validity
+            Not Before: Jan  1 12:00:00 2015 GMT
+            Not After : Jan  1 12:00:00 2016 GMT
+        Subject: CN=Intermediate
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:9c:d0:2e:3b:06:d6:ea:65:bd:dd:b2:d3:e8:88:
+                    ea:08:73:01:42:ac:ca:38:28:17:32:93:5e:16:a8:
+                    c1:79:44:9a:db:24:08:ba:81:52:63:9c:b4:ed:57:
+                    d4:b2:ac:54:64:3b:70:39:7e:37:da:11:e1:8c:ba:
+                    09:bc:1a:9b:e7:fe:6d:75:f8:71:31:f0:ca:52:89:
+                    2a:9e:d5:53:db:b8:c0:76:cf:bf:58:58:e1:bb:81:
+                    de:62:bb:06:58:1f:9b:64:03:75:7d:ee:76:6f:39:
+                    47:cb:8e:34:32:07:83:89:b0:83:2a:78:d0:ac:e2:
+                    86:0a:a8:ab:3b:97:81:de:9d:36:b4:03:b7:d5:06:
+                    05:53:d7:80:03:44:86:53:72:db:7a:5f:c5:20:dd:
+                    c7:44:58:3b:40:7f:0e:39:bc:be:0d:ca:6a:f6:82:
+                    a2:97:a2:17:79:51:6f:42:5d:0d:6a:b7:a0:de:5f:
+                    6a:00:be:e7:5a:b7:91:e9:fc:77:fd:75:88:8d:52:
+                    76:3d:0e:91:4b:c7:db:96:a4:5f:39:59:55:62:65:
+                    3b:15:7a:bc:7b:09:9f:3e:75:d9:9e:c5:00:b3:19:
+                    d4:26:7e:eb:db:62:07:c2:f5:b6:4e:87:2d:eb:56:
+                    8b:5a:68:6c:85:2f:b4:3e:1d:dd:5d:31:49:98:8b:
+                    06:55
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                B1:39:79:13:35:D0:03:6B:E9:C4:63:2B:CC:D6:61:C3:82:EC:14:C1
+            X509v3 Authority Key Identifier: 
+                keyid:02:CE:F6:AC:1A:39:1E:85:E8:72:D1:8A:C6:1D:E8:7A:8F:9D:15:6B
+
+            Authority Information Access: 
+                CA Issuers - URI:http://url-for-aia/Root.cer
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://url-for-crl/Root.crl
+
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+         56:90:dd:ae:50:4b:18:56:7f:e9:1c:e4:29:7c:60:7e:87:27:
+         b5:cd:2b:00:67:2b:f7:a2:32:db:38:92:18:46:00:22:c4:2d:
+         1f:ff:32:5f:62:69:30:db:c8:aa:63:68:6a:0f:db:2d:13:15:
+         8f:74:22:54:67:fb:95:19:35:49:66:1e:a1:65:67:3c:71:02:
+         85:34:f7:3b:20:51:03:e9:a1:b9:7d:9b:3b:21:d4:7a:28:6e:
+         bd:01:50:a6:7e:2b:a0:bc:ad:d5:55:63:3d:04:f3:f0:aa:c3:
+         4e:b3:aa:b8:68:89:a0:8c:b7:9e:38:37:81:2c:01:57:93:7c:
+         3f:aa:54:2e:35:66:a4:c0:81:ca:06:5c:c6:ab:72:f4:38:08:
+         cd:60:40:53:42:48:71:0a:e7:f5:82:3c:bb:51:89:a4:8b:1e:
+         c9:44:4c:7f:10:7d:d3:f4:60:04:07:36:b2:44:82:b2:0a:3c:
+         e9:82:55:4a:37:cf:47:b6:d3:ea:e5:fc:b8:49:4c:6b:77:a6:
+         42:29:1c:1f:97:78:18:f7:88:da:52:42:87:19:e4:13:0d:91:
+         73:cc:98:6a:22:70:e2:5c:54:d0:96:b7:94:37:3c:0f:f6:9a:
+         e3:02:fb:95:63:5a:87:d4:0d:16:16:bd:95:fa:88:c3:a8:e4:
+         d0:91:dd:be
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnNAuOwbW
+6mW93bLT6IjqCHMBQqzKOCgXMpNeFqjBeUSa2yQIuoFSY5y07VfUsqxUZDtwOX43
+2hHhjLoJvBqb5/5tdfhxMfDKUokqntVT27jAds+/WFjhu4HeYrsGWB+bZAN1fe52
+bzlHy440MgeDibCDKnjQrOKGCqirO5eB3p02tAO31QYFU9eAA0SGU3Lbel/FIN3H
+RFg7QH8OOby+Dcpq9oKil6IXeVFvQl0Nareg3l9qAL7nWreR6fx3/XWIjVJ2PQ6R
+S8fblqRfOVlVYmU7FXq8ewmfPnXZnsUAsxnUJn7r22IHwvW2Toct61aLWmhshS+0
+Ph3dXTFJmIsGVQIDAQABo4HLMIHIMB0GA1UdDgQWBBSxOXkTNdADa+nEYyvM1mHD
+guwUwTAfBgNVHSMEGDAWgBQCzvasGjkehehy0YrGHeh6j50VazA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+AFaQ3a5QSxhWf+kc5Cl8YH6HJ7XNKwBnK/eiMts4khhGACLELR//Ml9iaTDbyKpj
+aGoP2y0TFY90IlRn+5UZNUlmHqFlZzxxAoU09zsgUQPpobl9mzsh1Hoobr0BUKZ+
+K6C8rdVVYz0E8/Cqw06zqrhoiaCMt544N4EsAVeTfD+qVC41ZqTAgcoGXMarcvQ4
+CM1gQFNCSHEK5/WCPLtRiaSLHslETH8QfdP0YAQHNrJEgrIKPOmCVUo3z0e20+rl
+/LhJTGt3pkIpHB+XeBj3iNpSQocZ5BMNkXPMmGoicOJcVNCWt5Q3PA/2muMC+5Vj
+WofUDRYWvZX6iMOo5NCR3b4=
+-----END CERTIFICATE-----
+
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Root
+        Validity
+            Not Before: Jan  1 12:00:00 2015 GMT
+            Not After : Jan  1 12:00:00 2016 GMT
+        Subject: CN=Root
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:a6:44:ec:a7:15:00:1f:89:ac:91:f8:ec:7b:03:
+                    46:0b:53:15:ed:23:40:35:94:f3:96:80:27:d3:4a:
+                    84:92:68:c9:0c:e0:14:32:c7:31:67:49:29:58:77:
+                    ea:ce:8a:72:5b:93:b1:a0:a8:e5:84:c6:52:9d:5a:
+                    c0:41:bf:98:5f:18:5d:aa:d1:65:79:fb:e9:b0:84:
+                    92:9d:2c:58:bc:f1:c4:29:59:ed:bc:ac:85:ce:d7:
+                    0e:aa:08:e8:2d:90:25:cb:91:9d:7d:91:74:42:a0:
+                    ae:77:d2:11:7b:57:49:04:24:c0:94:f4:20:54:60:
+                    d9:1b:76:76:0b:2c:23:3c:67:90:8c:06:ed:4e:df:
+                    ac:24:22:26:f7:26:8f:5a:d2:5b:79:8a:6f:6e:53:
+                    27:60:10:cb:c7:b4:9f:60:2d:8f:32:69:4b:01:d1:
+                    f0:6d:69:1a:22:14:06:66:63:97:e8:fc:79:41:8d:
+                    15:44:44:d1:43:2a:37:5e:77:e4:06:e6:a9:85:13:
+                    e9:24:63:9d:09:d0:f5:13:d5:ba:59:2e:1c:d2:70:
+                    06:b1:80:f7:57:d7:30:f7:14:f3:18:06:7f:84:38:
+                    b6:81:46:9f:a2:36:87:0e:5f:1a:45:38:b7:20:16:
+                    b7:c6:e1:91:3b:0e:0c:ab:b7:4e:3d:a4:6d:66:d8:
+                    85:fb
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                02:CE:F6:AC:1A:39:1E:85:E8:72:D1:8A:C6:1D:E8:7A:8F:9D:15:6B
+            X509v3 Authority Key Identifier: 
+                keyid:02:CE:F6:AC:1A:39:1E:85:E8:72:D1:8A:C6:1D:E8:7A:8F:9D:15:6B
+
+            Authority Information Access: 
+                CA Issuers - URI:http://url-for-aia/Root.cer
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://url-for-crl/Root.crl
+
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+         0e:00:56:5c:72:31:88:bd:95:13:f7:64:96:1c:63:c2:1c:11:
+         60:04:d2:c3:5f:7c:a2:d7:d1:33:6d:51:6b:77:61:78:a8:70:
+         2e:50:97:5d:c1:e8:9b:dd:c6:61:a7:d3:e1:2c:83:07:85:5c:
+         c9:d7:1e:22:c2:5f:76:83:19:d7:de:4a:5e:82:0f:43:80:45:
+         02:d7:d0:3d:ca:c3:c0:fc:04:c8:f6:89:32:d7:47:c6:bf:1f:
+         c6:bd:71:e1:07:00:90:12:ec:61:63:1b:6c:e9:58:2c:fc:4c:
+         a9:8f:58:e1:b1:6e:a5:ca:4d:be:7e:32:16:74:5f:fd:35:e4:
+         37:aa:1a:c5:33:21:20:8a:3e:1c:af:da:f3:c7:a2:22:d3:93:
+         6c:5e:ac:0a:65:d5:db:e4:8b:11:5e:ca:eb:8f:da:c4:5d:2f:
+         7a:98:e8:3c:d1:89:15:05:02:86:ef:eb:17:18:81:28:ca:d6:
+         58:87:bd:d4:e2:50:41:92:d9:7f:b1:f7:53:8f:f3:cc:f3:1e:
+         1d:e4:5a:c2:60:1b:17:42:78:53:e9:2d:5d:bb:f9:21:50:ff:
+         87:53:be:5f:e6:d4:8f:25:7f:d7:83:d7:f8:4d:c1:7c:7a:40:
+         0b:11:f1:d9:c6:eb:97:45:00:d6:6b:84:1c:4f:fc:8e:1f:5b:
+         b5:3d:60:0c
+-----BEGIN TRUSTED_CERTIFICATE-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKZE7KcVAB+JrJH47HsD
+RgtTFe0jQDWU85aAJ9NKhJJoyQzgFDLHMWdJKVh36s6KcluTsaCo5YTGUp1awEG/
+mF8YXarRZXn76bCEkp0sWLzxxClZ7byshc7XDqoI6C2QJcuRnX2RdEKgrnfSEXtX
+SQQkwJT0IFRg2Rt2dgssIzxnkIwG7U7frCQiJvcmj1rSW3mKb25TJ2AQy8e0n2At
+jzJpSwHR8G1pGiIUBmZjl+j8eUGNFURE0UMqN1535AbmqYUT6SRjnQnQ9RPVulku
+HNJwBrGA91fXMPcU8xgGf4Q4toFGn6I2hw5fGkU4tyAWt8bhkTsODKu3Tj2kbWbY
+hfsCAwEAAaOByzCByDAdBgNVHQ4EFgQUAs72rBo5HoXoctGKxh3oeo+dFWswHwYD
+VR0jBBgwFoAUAs72rBo5HoXoctGKxh3oeo+dFWswNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAOAFZccjGI
+vZUT92SWHGPCHBFgBNLDX3yi19EzbVFrd2F4qHAuUJddweib3cZhp9PhLIMHhVzJ
+1x4iwl92gxnX3kpegg9DgEUC19A9ysPA/ATI9oky10fGvx/GvXHhBwCQEuxhYxts
+6Vgs/Eypj1jhsW6lyk2+fjIWdF/9NeQ3qhrFMyEgij4cr9rzx6Ii05NsXqwKZdXb
+5IsRXsrrj9rEXS96mOg80YkVBQKG7+sXGIEoytZYh73U4lBBktl/sfdTj/PM8x4d
+5FrCYBsXQnhT6S1du/khUP+HU75f5tSPJX/Xg9f4TcF8ekALEfHZxuuXRQDWa4Qc
+T/yOH1u1PWAM
+-----END TRUSTED_CERTIFICATE-----
+
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/net/data/verify_certificate_chain_unittest/key-rollover-rolloverchain.pem b/net/data/verify_certificate_chain_unittest/key-rollover-rolloverchain.pem
new file mode 100644
index 0000000..94105ff
--- /dev/null
+++ b/net/data/verify_certificate_chain_unittest/key-rollover-rolloverchain.pem
@@ -0,0 +1,400 @@
+[Created by: ./generate-key-rollover.py]
+
+A certificate tree with two self-signed root certificates(oldroot, newroot),
+and a third root certificate (newrootrollover) which has the same key as newroot
+but is signed by oldroot, all with the same subject and issuer.
+There are two intermediates with the same key, subject and issuer
+(oldintermediate signed by oldroot, and newintermediate signed by newroot).
+The target certificate is signed by the intermediate key.
+
+
+In graphical form:
+
+   oldroot-------->newrootrollover  newroot
+      |                      |        |
+      v                      v        v
+oldintermediate           newintermediate
+      |                          |
+      +------------+-------------+
+                   |
+                   v
+                 target
+
+
+Several chains are output:
+  key-rollover-oldchain.pem:
+    target<-oldintermediate<-oldroot
+  key-rollover-rolloverchain.pem:
+    target<-newintermediate<-newrootrollover<-oldroot
+  key-rollover-longrolloverchain.pem:
+    target<-newintermediate<-newroot<-newrootrollover<-oldroot
+  key-rollover-newchain.pem:
+    target<-newintermediate<-newroot
+
+All of these chains should verify successfully.
+
+
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Intermediate
+        Validity
+            Not Before: Jan  1 12:00:00 2015 GMT
+            Not After : Jan  1 12:00:00 2016 GMT
+        Subject: CN=Target
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:be:12:1c:48:e4:73:1f:5c:d2:54:a9:7b:58:1c:
+                    37:73:c2:49:26:3e:ed:b5:6b:55:17:c9:4c:52:34:
+                    ce:d9:76:86:32:74:74:ae:11:b2:99:1b:51:a0:33:
+                    48:34:2f:b9:d3:2b:06:c2:5c:29:53:35:ce:7c:a6:
+                    67:b2:6a:d4:33:c3:13:62:30:a1:53:5f:45:78:5b:
+                    bb:47:ad:07:a4:98:9a:e9:e3:b1:3b:e6:33:c2:c1:
+                    5c:95:d7:c8:b9:a6:72:27:7a:79:da:c4:c8:5a:1a:
+                    3e:5e:5e:a6:62:64:c6:72:86:b1:78:98:5b:63:27:
+                    70:15:04:6b:b1:0f:11:9c:4d:3b:5c:e7:8d:c0:be:
+                    d5:84:46:6c:bd:11:1e:21:c1:82:9c:d0:aa:2d:2f:
+                    f8:2a:e9:3b:e4:35:15:6d:c7:4a:dd:a8:65:69:b8:
+                    16:a1:8a:04:a2:44:68:40:b6:99:ae:61:df:9f:6c:
+                    40:ef:79:c9:a3:6d:e4:2d:07:01:68:f1:21:4e:0e:
+                    28:a7:fd:2f:ad:ee:7d:65:cf:36:fd:4f:1b:ba:10:
+                    8e:86:fd:ec:37:67:0c:20:71:66:48:64:f3:82:af:
+                    f5:e1:73:c9:09:36:03:3f:c2:47:7a:f2:33:b9:f9:
+                    9f:53:9b:24:5e:c3:cc:05:d9:a9:ed:d7:b2:2a:c5:
+                    b7:39
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                C9:45:0B:2A:F2:D8:8D:2A:D7:CE:AF:56:BF:82:B0:84:0C:C8:2E:F4
+            X509v3 Authority Key Identifier: 
+                keyid:B1:39:79:13:35:D0:03:6B:E9:C4:63:2B:CC:D6:61:C3:82:EC:14:C1
+
+            Authority Information Access: 
+                CA Issuers - URI:http://url-for-aia/Intermediate.cer
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://url-for-crl/Intermediate.crl
+
+            X509v3 Key Usage: critical
+                Digital Signature, Key Encipherment
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+    Signature Algorithm: sha256WithRSAEncryption
+         63:66:9e:6c:34:8c:5d:74:ae:90:25:55:ae:86:49:b9:3d:fd:
+         27:bc:4f:69:7b:70:cb:25:0e:a3:8c:7a:7d:9c:4f:0b:7c:f2:
+         85:a5:ea:82:d2:37:c2:74:a2:ae:a8:bf:62:f4:5f:d4:c6:41:
+         45:0c:cc:27:53:aa:8f:66:58:e9:b0:de:ae:98:14:bd:92:df:
+         9b:0f:f2:c5:3b:d2:bc:1c:3e:80:b4:09:0f:c1:9f:d6:3a:29:
+         52:71:b6:1a:92:95:5a:18:dc:b4:30:dc:61:61:93:54:d1:55:
+         83:92:5d:c0:c7:dc:ab:d7:08:dd:8a:44:cf:92:f9:4d:86:25:
+         aa:ac:52:f6:0e:17:99:0b:31:d2:75:5e:33:f9:f5:b6:77:42:
+         07:62:a9:53:cc:f3:79:84:57:d9:14:3f:ab:4c:8b:ae:c7:9f:
+         cf:7a:1f:bf:7e:1d:44:bd:76:b4:cd:8d:c8:1d:75:f7:3b:b5:
+         bc:35:8b:3f:29:b1:cb:67:a4:17:af:a4:ca:9f:2b:e7:15:66:
+         e4:c8:c1:7c:08:78:9e:5d:4b:c3:c6:58:66:96:42:e8:e6:40:
+         fd:dc:24:ce:3b:58:11:38:40:0e:fc:a9:c0:2c:0f:e5:cc:bb:
+         02:32:31:b9:bc:6f:2d:1d:f6:2b:7c:d3:f8:24:f6:60:38:8a:
+         1f:dd:e1:50
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxJbnRl
+cm1lZGlhdGUwHhcNMTUwMTAxMTIwMDAwWhcNMTYwMTAxMTIwMDAwWjARMQ8wDQYD
+VQQDDAZUYXJnZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+EhxI
+5HMfXNJUqXtYHDdzwkkmPu21a1UXyUxSNM7ZdoYydHSuEbKZG1GgM0g0L7nTKwbC
+XClTNc58pmeyatQzwxNiMKFTX0V4W7tHrQekmJrp47E75jPCwVyV18i5pnInenna
+xMhaGj5eXqZiZMZyhrF4mFtjJ3AVBGuxDxGcTTtc543AvtWERmy9ER4hwYKc0Kot
+L/gq6TvkNRVtx0rdqGVpuBahigSiRGhAtpmuYd+fbEDvecmjbeQtBwFo8SFODiin
+/S+t7n1lzzb9Txu6EI6G/ew3ZwwgcWZIZPOCr/Xhc8kJNgM/wkd68jO5+Z9TmyRe
+w8wF2ant17Iqxbc5AgMBAAGjgekwgeYwHQYDVR0OBBYEFMlFCyry2I0q186vVr+C
+sIQMyC70MB8GA1UdIwQYMBaAFLE5eRM10ANr6cRjK8zWYcOC7BTBMD8GCCsGAQUF
+BwEBBDMwMTAvBggrBgEFBQcwAoYjaHR0cDovL3VybC1mb3ItYWlhL0ludGVybWVk
+aWF0ZS5jZXIwNAYDVR0fBC0wKzApoCegJYYjaHR0cDovL3VybC1mb3ItY3JsL0lu
+dGVybWVkaWF0ZS5jcmwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
+BwMBBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAY2aebDSMXXSukCVVroZJ
+uT39J7xPaXtwyyUOo4x6fZxPC3zyhaXqgtI3wnSirqi/YvRf1MZBRQzMJ1Oqj2ZY
+6bDerpgUvZLfmw/yxTvSvBw+gLQJD8Gf1jopUnG2GpKVWhjctDDcYWGTVNFVg5Jd
+wMfcq9cI3YpEz5L5TYYlqqxS9g4XmQsx0nVeM/n1tndCB2KpU8zzeYRX2RQ/q0yL
+rsefz3ofv34dRL12tM2NyB119zu1vDWLPymxy2ekF6+kyp8r5xVm5MjBfAh4nl1L
+w8ZYZpZC6OZA/dwkzjtYEThADvypwCwP5cy7AjIxubxvLR32K3zT+CT2YDiKH93h
+UA==
+-----END CERTIFICATE-----
+
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 2 (0x2)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Root
+        Validity
+            Not Before: Jan  2 12:00:00 2015 GMT
+            Not After : Jan  1 12:00:00 2016 GMT
+        Subject: CN=Intermediate
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:9c:d0:2e:3b:06:d6:ea:65:bd:dd:b2:d3:e8:88:
+                    ea:08:73:01:42:ac:ca:38:28:17:32:93:5e:16:a8:
+                    c1:79:44:9a:db:24:08:ba:81:52:63:9c:b4:ed:57:
+                    d4:b2:ac:54:64:3b:70:39:7e:37:da:11:e1:8c:ba:
+                    09:bc:1a:9b:e7:fe:6d:75:f8:71:31:f0:ca:52:89:
+                    2a:9e:d5:53:db:b8:c0:76:cf:bf:58:58:e1:bb:81:
+                    de:62:bb:06:58:1f:9b:64:03:75:7d:ee:76:6f:39:
+                    47:cb:8e:34:32:07:83:89:b0:83:2a:78:d0:ac:e2:
+                    86:0a:a8:ab:3b:97:81:de:9d:36:b4:03:b7:d5:06:
+                    05:53:d7:80:03:44:86:53:72:db:7a:5f:c5:20:dd:
+                    c7:44:58:3b:40:7f:0e:39:bc:be:0d:ca:6a:f6:82:
+                    a2:97:a2:17:79:51:6f:42:5d:0d:6a:b7:a0:de:5f:
+                    6a:00:be:e7:5a:b7:91:e9:fc:77:fd:75:88:8d:52:
+                    76:3d:0e:91:4b:c7:db:96:a4:5f:39:59:55:62:65:
+                    3b:15:7a:bc:7b:09:9f:3e:75:d9:9e:c5:00:b3:19:
+                    d4:26:7e:eb:db:62:07:c2:f5:b6:4e:87:2d:eb:56:
+                    8b:5a:68:6c:85:2f:b4:3e:1d:dd:5d:31:49:98:8b:
+                    06:55
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                B1:39:79:13:35:D0:03:6B:E9:C4:63:2B:CC:D6:61:C3:82:EC:14:C1
+            X509v3 Authority Key Identifier: 
+                keyid:15:9E:A6:AD:F5:9F:8A:A1:C1:08:99:BF:66:6F:CF:CA:72:CD:0C:34
+
+            Authority Information Access: 
+                CA Issuers - URI:http://url-for-aia/Root.cer
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://url-for-crl/Root.crl
+
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+         a8:ad:48:d8:6e:1d:24:09:d2:b3:29:3c:48:60:27:7f:37:64:
+         d5:f1:3b:b3:5c:43:de:7c:b4:5f:ee:3a:f2:1a:25:24:0a:8a:
+         25:6d:19:5b:dc:0c:4e:48:61:2f:60:d3:6b:f3:9c:03:2c:d3:
+         fa:c8:9b:99:e7:2e:c5:43:c0:5f:14:cd:8b:92:62:4f:e5:3a:
+         cd:b5:0a:d8:b2:01:c7:44:b4:3a:86:66:bf:fa:11:a5:f8:24:
+         3f:d1:1a:e8:eb:1e:ad:f0:70:31:6f:bc:21:cf:db:ce:63:4e:
+         84:e9:52:9e:bb:1b:c4:72:ae:e0:6c:88:9e:99:dc:79:d9:fd:
+         83:26:8e:f6:19:70:d9:5e:fc:f4:0c:d1:17:6f:af:10:f6:64:
+         16:08:d8:72:ba:3a:2d:66:28:5a:41:0d:f3:47:87:a7:9c:78:
+         c6:cd:5e:25:71:0b:f2:93:b8:26:17:b2:19:17:cc:03:ed:c0:
+         6e:06:e2:4b:4a:57:5f:23:02:2a:69:06:7a:c4:b7:3e:2f:e8:
+         f0:03:ae:b8:2d:df:63:22:20:73:23:75:d9:3c:d7:22:e4:b4:
+         65:65:ed:b9:e6:02:1d:b5:51:11:9c:db:92:e4:fe:8c:1d:bb:
+         c5:95:87:5b:38:ee:ff:e4:01:d1:5d:84:b9:73:d3:da:23:ca:
+         5e:05:d3:7d
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMjEyMDAwMFoXDTE2MDEwMTEyMDAwMFowFzEVMBMGA1UEAwwMSW50
+ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnNAuOwbW
+6mW93bLT6IjqCHMBQqzKOCgXMpNeFqjBeUSa2yQIuoFSY5y07VfUsqxUZDtwOX43
+2hHhjLoJvBqb5/5tdfhxMfDKUokqntVT27jAds+/WFjhu4HeYrsGWB+bZAN1fe52
+bzlHy440MgeDibCDKnjQrOKGCqirO5eB3p02tAO31QYFU9eAA0SGU3Lbel/FIN3H
+RFg7QH8OOby+Dcpq9oKil6IXeVFvQl0Nareg3l9qAL7nWreR6fx3/XWIjVJ2PQ6R
+S8fblqRfOVlVYmU7FXq8ewmfPnXZnsUAsxnUJn7r22IHwvW2Toct61aLWmhshS+0
+Ph3dXTFJmIsGVQIDAQABo4HLMIHIMB0GA1UdDgQWBBSxOXkTNdADa+nEYyvM1mHD
+guwUwTAfBgNVHSMEGDAWgBQVnqat9Z+KocEImb9mb8/Kcs0MNDA3BggrBgEFBQcB
+AQQrMCkwJwYIKwYBBQUHMAKGG2h0dHA6Ly91cmwtZm9yLWFpYS9Sb290LmNlcjAs
+BgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vdXJsLWZvci1jcmwvUm9vdC5jcmwwDgYD
+VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+AKitSNhuHSQJ0rMpPEhgJ383ZNXxO7NcQ958tF/uOvIaJSQKiiVtGVvcDE5IYS9g
+02vznAMs0/rIm5nnLsVDwF8UzYuSYk/lOs21CtiyAcdEtDqGZr/6EaX4JD/RGujr
+Hq3wcDFvvCHP285jToTpUp67G8RyruBsiJ6Z3HnZ/YMmjvYZcNle/PQM0RdvrxD2
+ZBYI2HK6Oi1mKFpBDfNHh6eceMbNXiVxC/KTuCYXshkXzAPtwG4G4ktKV18jAipp
+BnrEtz4v6PADrrgt32MiIHMjddk81yLktGVl7bnmAh21URGc25Lk/owdu8WVh1s4
+7v/kAdFdhLlz09ojyl4F030=
+-----END CERTIFICATE-----
+
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 3 (0x3)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Root
+        Validity
+            Not Before: Jan  2 12:00:00 2015 GMT
+            Not After : Jan  1 12:00:00 2016 GMT
+        Subject: CN=Root
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:ae:ea:3b:3f:b6:e9:3d:ea:eb:3d:dd:e8:4d:45:
+                    83:63:78:ea:07:90:3a:3c:4f:92:54:2b:2d:02:1b:
+                    eb:9e:81:72:68:2e:73:f8:4a:a1:de:0c:d6:f0:c2:
+                    61:26:90:0b:48:59:ab:23:25:8f:e4:4a:6b:c9:2d:
+                    ba:a7:35:c4:22:df:76:99:d8:7b:f7:6d:ca:9b:da:
+                    d2:ed:7e:c8:93:b2:a7:f6:f0:05:6a:5d:c6:e1:79:
+                    d0:25:59:a9:50:1e:65:eb:1c:c9:cd:4e:6a:3a:2a:
+                    a4:1a:fa:81:a3:e7:ae:d7:de:43:d9:e8:0b:5c:b0:
+                    6b:46:39:c5:9c:4a:6d:59:bf:da:70:2e:80:ac:c8:
+                    80:e3:83:d1:71:7b:a7:0b:92:bf:a8:81:ad:5c:b2:
+                    d5:e9:b9:5f:b5:4f:93:43:67:72:36:b3:f7:17:b9:
+                    1b:da:2a:13:83:70:36:ae:59:03:3d:f0:71:de:a2:
+                    7a:41:ad:b5:e9:a2:51:e4:18:ec:88:ad:48:f1:df:
+                    17:04:43:54:2a:af:3c:c0:f5:84:39:43:d1:a7:d2:
+                    52:0f:3c:dd:ef:13:58:8c:1d:d4:dd:2e:6d:1a:e7:
+                    73:9b:8b:f3:41:7b:9a:53:4e:0d:92:d3:5d:3f:fc:
+                    c3:61:dc:5f:a0:93:3c:08:cc:b4:9b:ce:9d:78:e3:
+                    77:c9
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                15:9E:A6:AD:F5:9F:8A:A1:C1:08:99:BF:66:6F:CF:CA:72:CD:0C:34
+            X509v3 Authority Key Identifier: 
+                keyid:02:CE:F6:AC:1A:39:1E:85:E8:72:D1:8A:C6:1D:E8:7A:8F:9D:15:6B
+
+            Authority Information Access: 
+                CA Issuers - URI:http://url-for-aia/Root.cer
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://url-for-crl/Root.crl
+
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+         51:9b:dd:56:f2:b1:2b:e5:36:c8:2f:1d:a9:53:1f:89:e1:24:
+         33:bd:ac:56:c1:c3:1a:38:a6:7e:fc:61:9a:ae:7c:1f:13:3e:
+         37:e4:e6:a9:11:9e:2b:6e:ce:dd:12:0c:c1:b2:b7:eb:48:0e:
+         c7:a5:65:f0:86:49:8a:dc:cf:1b:6d:33:af:af:96:51:49:01:
+         e4:82:d6:e6:5a:d0:41:c7:05:9f:16:eb:06:bd:bc:ab:fe:a0:
+         d7:ac:de:62:d1:71:7e:69:82:31:03:e3:60:28:e6:18:3b:e5:
+         93:2b:58:ee:d5:0b:7b:b6:af:f2:4f:22:eb:4d:b7:a6:74:68:
+         b7:82:68:7f:a9:b6:ee:a0:20:d7:c6:16:0e:9c:1c:39:ea:24:
+         5e:60:12:fc:39:60:0d:54:3e:aa:b3:43:e1:0f:ef:d7:8f:3e:
+         09:a9:55:95:e9:3d:0c:4f:ad:cb:c2:f3:2c:10:43:67:54:f9:
+         66:54:81:ff:62:61:94:05:b0:42:af:f0:c5:ac:00:91:28:5c:
+         aa:a3:61:44:ba:c2:a6:ab:f8:1d:7e:02:69:33:48:fe:ac:93:
+         7f:4c:99:91:d9:18:37:f9:70:3f:56:2a:ee:4a:e0:4d:f3:60:
+         12:5d:30:d8:37:bf:ca:40:85:29:0c:a7:8f:ab:ad:03:6d:7b:
+         ba:62:7f:58
+-----BEGIN CERTIFICATE-----
+MIIDZTCCAk2gAwIBAgIBAzANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMjEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK7qOz+26T3q6z3d6E1F
+g2N46geQOjxPklQrLQIb656Bcmguc/hKod4M1vDCYSaQC0hZqyMlj+RKa8ktuqc1
+xCLfdpnYe/dtypva0u1+yJOyp/bwBWpdxuF50CVZqVAeZescyc1OajoqpBr6gaPn
+rtfeQ9noC1ywa0Y5xZxKbVm/2nAugKzIgOOD0XF7pwuSv6iBrVyy1em5X7VPk0Nn
+cjaz9xe5G9oqE4NwNq5ZAz3wcd6iekGttemiUeQY7IitSPHfFwRDVCqvPMD1hDlD
+0afSUg883e8TWIwd1N0ubRrnc5uL80F7mlNODZLTXT/8w2HcX6CTPAjMtJvOnXjj
+d8kCAwEAAaOByzCByDAdBgNVHQ4EFgQUFZ6mrfWfiqHBCJm/Zm/PynLNDDQwHwYD
+VR0jBBgwFoAUAs72rBo5HoXoctGKxh3oeo+dFWswNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBRm91W8rEr
+5TbILx2pUx+J4SQzvaxWwcMaOKZ+/GGarnwfEz435OapEZ4rbs7dEgzBsrfrSA7H
+pWXwhkmK3M8bbTOvr5ZRSQHkgtbmWtBBxwWfFusGvbyr/qDXrN5i0XF+aYIxA+Ng
+KOYYO+WTK1ju1Qt7tq/yTyLrTbemdGi3gmh/qbbuoCDXxhYOnBw56iReYBL8OWAN
+VD6qs0PhD+/Xjz4JqVWV6T0MT63LwvMsEENnVPlmVIH/YmGUBbBCr/DFrACRKFyq
+o2FEusKmq/gdfgJpM0j+rJN/TJmR2Rg3+XA/ViruSuBN82ASXTDYN7/KQIUpDKeP
+q60DbXu6Yn9Y
+-----END CERTIFICATE-----
+
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Root
+        Validity
+            Not Before: Jan  1 12:00:00 2015 GMT
+            Not After : Jan  1 12:00:00 2016 GMT
+        Subject: CN=Root
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:a6:44:ec:a7:15:00:1f:89:ac:91:f8:ec:7b:03:
+                    46:0b:53:15:ed:23:40:35:94:f3:96:80:27:d3:4a:
+                    84:92:68:c9:0c:e0:14:32:c7:31:67:49:29:58:77:
+                    ea:ce:8a:72:5b:93:b1:a0:a8:e5:84:c6:52:9d:5a:
+                    c0:41:bf:98:5f:18:5d:aa:d1:65:79:fb:e9:b0:84:
+                    92:9d:2c:58:bc:f1:c4:29:59:ed:bc:ac:85:ce:d7:
+                    0e:aa:08:e8:2d:90:25:cb:91:9d:7d:91:74:42:a0:
+                    ae:77:d2:11:7b:57:49:04:24:c0:94:f4:20:54:60:
+                    d9:1b:76:76:0b:2c:23:3c:67:90:8c:06:ed:4e:df:
+                    ac:24:22:26:f7:26:8f:5a:d2:5b:79:8a:6f:6e:53:
+                    27:60:10:cb:c7:b4:9f:60:2d:8f:32:69:4b:01:d1:
+                    f0:6d:69:1a:22:14:06:66:63:97:e8:fc:79:41:8d:
+                    15:44:44:d1:43:2a:37:5e:77:e4:06:e6:a9:85:13:
+                    e9:24:63:9d:09:d0:f5:13:d5:ba:59:2e:1c:d2:70:
+                    06:b1:80:f7:57:d7:30:f7:14:f3:18:06:7f:84:38:
+                    b6:81:46:9f:a2:36:87:0e:5f:1a:45:38:b7:20:16:
+                    b7:c6:e1:91:3b:0e:0c:ab:b7:4e:3d:a4:6d:66:d8:
+                    85:fb
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                02:CE:F6:AC:1A:39:1E:85:E8:72:D1:8A:C6:1D:E8:7A:8F:9D:15:6B
+            X509v3 Authority Key Identifier: 
+                keyid:02:CE:F6:AC:1A:39:1E:85:E8:72:D1:8A:C6:1D:E8:7A:8F:9D:15:6B
+
+            Authority Information Access: 
+                CA Issuers - URI:http://url-for-aia/Root.cer
+
+            X509v3 CRL Distribution Points: 
+
+                Full Name:
+                  URI:http://url-for-crl/Root.crl
+
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+         0e:00:56:5c:72:31:88:bd:95:13:f7:64:96:1c:63:c2:1c:11:
+         60:04:d2:c3:5f:7c:a2:d7:d1:33:6d:51:6b:77:61:78:a8:70:
+         2e:50:97:5d:c1:e8:9b:dd:c6:61:a7:d3:e1:2c:83:07:85:5c:
+         c9:d7:1e:22:c2:5f:76:83:19:d7:de:4a:5e:82:0f:43:80:45:
+         02:d7:d0:3d:ca:c3:c0:fc:04:c8:f6:89:32:d7:47:c6:bf:1f:
+         c6:bd:71:e1:07:00:90:12:ec:61:63:1b:6c:e9:58:2c:fc:4c:
+         a9:8f:58:e1:b1:6e:a5:ca:4d:be:7e:32:16:74:5f:fd:35:e4:
+         37:aa:1a:c5:33:21:20:8a:3e:1c:af:da:f3:c7:a2:22:d3:93:
+         6c:5e:ac:0a:65:d5:db:e4:8b:11:5e:ca:eb:8f:da:c4:5d:2f:
+         7a:98:e8:3c:d1:89:15:05:02:86:ef:eb:17:18:81:28:ca:d6:
+         58:87:bd:d4:e2:50:41:92:d9:7f:b1:f7:53:8f:f3:cc:f3:1e:
+         1d:e4:5a:c2:60:1b:17:42:78:53:e9:2d:5d:bb:f9:21:50:ff:
+         87:53:be:5f:e6:d4:8f:25:7f:d7:83:d7:f8:4d:c1:7c:7a:40:
+         0b:11:f1:d9:c6:eb:97:45:00:d6:6b:84:1c:4f:fc:8e:1f:5b:
+         b5:3d:60:0c
+-----BEGIN TRUSTED_CERTIFICATE-----
+MIIDZTCCAk2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDARSb290
+MB4XDTE1MDEwMTEyMDAwMFoXDTE2MDEwMTEyMDAwMFowDzENMAsGA1UEAwwEUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKZE7KcVAB+JrJH47HsD
+RgtTFe0jQDWU85aAJ9NKhJJoyQzgFDLHMWdJKVh36s6KcluTsaCo5YTGUp1awEG/
+mF8YXarRZXn76bCEkp0sWLzxxClZ7byshc7XDqoI6C2QJcuRnX2RdEKgrnfSEXtX
+SQQkwJT0IFRg2Rt2dgssIzxnkIwG7U7frCQiJvcmj1rSW3mKb25TJ2AQy8e0n2At
+jzJpSwHR8G1pGiIUBmZjl+j8eUGNFURE0UMqN1535AbmqYUT6SRjnQnQ9RPVulku
+HNJwBrGA91fXMPcU8xgGf4Q4toFGn6I2hw5fGkU4tyAWt8bhkTsODKu3Tj2kbWbY
+hfsCAwEAAaOByzCByDAdBgNVHQ4EFgQUAs72rBo5HoXoctGKxh3oeo+dFWswHwYD
+VR0jBBgwFoAUAs72rBo5HoXoctGKxh3oeo+dFWswNwYIKwYBBQUHAQEEKzApMCcG
+CCsGAQUFBzAChhtodHRwOi8vdXJsLWZvci1haWEvUm9vdC5jZXIwLAYDVR0fBCUw
+IzAhoB+gHYYbaHR0cDovL3VybC1mb3ItY3JsL1Jvb3QuY3JsMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAOAFZccjGI
+vZUT92SWHGPCHBFgBNLDX3yi19EzbVFrd2F4qHAuUJddweib3cZhp9PhLIMHhVzJ
+1x4iwl92gxnX3kpegg9DgEUC19A9ysPA/ATI9oky10fGvx/GvXHhBwCQEuxhYxts
+6Vgs/Eypj1jhsW6lyk2+fjIWdF/9NeQ3qhrFMyEgij4cr9rzx6Ii05NsXqwKZdXb
+5IsRXsrrj9rEXS96mOg80YkVBQKG7+sXGIEoytZYh73U4lBBktl/sfdTj/PM8x4d
+5FrCYBsXQnhT6S1du/khUP+HU75f5tSPJX/Xg9f4TcF8ekALEfHZxuuXRQDWa4Qc
+T/yOH1u1PWAM
+-----END TRUSTED_CERTIFICATE-----
+
+-----BEGIN TIME-----
+MTUwMzAyMTIwMDAwWg==
+-----END TIME-----
+
+-----BEGIN VERIFY_RESULT-----
+U1VDQ0VTUw==
+-----END VERIFY_RESULT-----
diff --git a/net/dns/record_rdata.h b/net/dns/record_rdata.h
index d2ca587..0aa29d57 100644
--- a/net/dns/record_rdata.h
+++ b/net/dns/record_rdata.h
@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
+#include "base/logging.h"
 #include "base/macros.h"
 #include "base/strings/string_piece.h"
 #include "net/base/ip_address.h"
@@ -198,7 +199,11 @@
   uint16_t Type() const override;
 
   // Length of the bitmap in bits.
-  unsigned bitmap_length() const { return bitmap_.size() * 8; }
+  // This will be between 8 and 256, per RFC 3845, Section 2.1.2.
+  uint16_t bitmap_length() const {
+    DCHECK_LE(bitmap_.size(), 32u);
+    return static_cast<uint16_t>(bitmap_.size() * 8);
+  }
 
   // Returns bit i-th bit in the bitmap, where bits withing a byte are organized
   // most to least significant. If it is set, a record with rrtype i exists for
diff --git a/net/dns/record_rdata_unittest.cc b/net/dns/record_rdata_unittest.cc
index c41e39a..f73853ed 100644
--- a/net/dns/record_rdata_unittest.cc
+++ b/net/dns/record_rdata_unittest.cc
@@ -17,9 +17,6 @@
 }
 
 TEST(RecordRdataTest, ParseSrvRecord) {
-  std::unique_ptr<SrvRecordRdata> record1_obj;
-  std::unique_ptr<SrvRecordRdata> record2_obj;
-
   // These are just the rdata portions of the DNS records, rather than complete
   // records, but it works well enough for this test.
 
@@ -40,7 +37,8 @@
   base::StringPiece record2_strpiece = MakeStringPiece(
       record + first_record_len, sizeof(record) - first_record_len);
 
-  record1_obj = SrvRecordRdata::Create(record1_strpiece, parser);
+  std::unique_ptr<SrvRecordRdata> record1_obj =
+      SrvRecordRdata::Create(record1_strpiece, parser);
   ASSERT_TRUE(record1_obj != NULL);
   ASSERT_EQ(1, record1_obj->priority());
   ASSERT_EQ(2, record1_obj->weight());
@@ -48,7 +46,8 @@
 
   ASSERT_EQ("www.google.com", record1_obj->target());
 
-  record2_obj = SrvRecordRdata::Create(record2_strpiece, parser);
+  std::unique_ptr<SrvRecordRdata> record2_obj =
+      SrvRecordRdata::Create(record2_strpiece, parser);
   ASSERT_TRUE(record2_obj != NULL);
   ASSERT_EQ(257, record2_obj->priority());
   ASSERT_EQ(258, record2_obj->weight());
@@ -61,8 +60,6 @@
 }
 
 TEST(RecordRdataTest, ParseARecord) {
-  std::unique_ptr<ARecordRdata> record_obj;
-
   // These are just the rdata portions of the DNS records, rather than complete
   // records, but it works well enough for this test.
 
@@ -73,7 +70,8 @@
   DnsRecordParser parser(record, sizeof(record), 0);
   base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
 
-  record_obj = ARecordRdata::Create(record_strpiece, parser);
+  std::unique_ptr<ARecordRdata> record_obj =
+      ARecordRdata::Create(record_strpiece, parser);
   ASSERT_TRUE(record_obj != NULL);
 
   ASSERT_EQ("127.0.0.1", record_obj->address().ToString());
@@ -82,8 +80,6 @@
 }
 
 TEST(RecordRdataTest, ParseAAAARecord) {
-  std::unique_ptr<AAAARecordRdata> record_obj;
-
   // These are just the rdata portions of the DNS records, rather than complete
   // records, but it works well enough for this test.
 
@@ -95,7 +91,8 @@
   DnsRecordParser parser(record, sizeof(record), 0);
   base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
 
-  record_obj = AAAARecordRdata::Create(record_strpiece, parser);
+  std::unique_ptr<AAAARecordRdata> record_obj =
+      AAAARecordRdata::Create(record_strpiece, parser);
   ASSERT_TRUE(record_obj != NULL);
 
   ASSERT_EQ("1234:5678::9", record_obj->address().ToString());
@@ -104,8 +101,6 @@
 }
 
 TEST(RecordRdataTest, ParseCnameRecord) {
-  std::unique_ptr<CnameRecordRdata> record_obj;
-
   // These are just the rdata portions of the DNS records, rather than complete
   // records, but it works well enough for this test.
 
@@ -115,7 +110,8 @@
   DnsRecordParser parser(record, sizeof(record), 0);
   base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
 
-  record_obj = CnameRecordRdata::Create(record_strpiece, parser);
+  std::unique_ptr<CnameRecordRdata> record_obj =
+      CnameRecordRdata::Create(record_strpiece, parser);
   ASSERT_TRUE(record_obj != NULL);
 
   ASSERT_EQ("www.google.com", record_obj->cname());
@@ -124,8 +120,6 @@
 }
 
 TEST(RecordRdataTest, ParsePtrRecord) {
-  std::unique_ptr<PtrRecordRdata> record_obj;
-
   // These are just the rdata portions of the DNS records, rather than complete
   // records, but it works well enough for this test.
 
@@ -135,7 +129,8 @@
   DnsRecordParser parser(record, sizeof(record), 0);
   base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
 
-  record_obj = PtrRecordRdata::Create(record_strpiece, parser);
+  std::unique_ptr<PtrRecordRdata> record_obj =
+      PtrRecordRdata::Create(record_strpiece, parser);
   ASSERT_TRUE(record_obj != NULL);
 
   ASSERT_EQ("www.google.com", record_obj->ptrdomain());
@@ -144,8 +139,6 @@
 }
 
 TEST(RecordRdataTest, ParseTxtRecord) {
-  std::unique_ptr<TxtRecordRdata> record_obj;
-
   // These are just the rdata portions of the DNS records, rather than complete
   // records, but it works well enough for this test.
 
@@ -155,7 +148,8 @@
   DnsRecordParser parser(record, sizeof(record), 0);
   base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
 
-  record_obj = TxtRecordRdata::Create(record_strpiece, parser);
+  std::unique_ptr<TxtRecordRdata> record_obj =
+      TxtRecordRdata::Create(record_strpiece, parser);
   ASSERT_TRUE(record_obj != NULL);
 
   std::vector<std::string> expected;
@@ -169,8 +163,6 @@
 }
 
 TEST(RecordRdataTest, ParseNsecRecord) {
-  std::unique_ptr<NsecRecordRdata> record_obj;
-
   // These are just the rdata portions of the DNS records, rather than complete
   // records, but it works well enough for this test.
 
@@ -181,7 +173,8 @@
   DnsRecordParser parser(record, sizeof(record), 0);
   base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
 
-  record_obj = NsecRecordRdata::Create(record_strpiece, parser);
+  std::unique_ptr<NsecRecordRdata> record_obj =
+      NsecRecordRdata::Create(record_strpiece, parser);
   ASSERT_TRUE(record_obj != NULL);
 
   ASSERT_EQ(16u, record_obj->bitmap_length());
@@ -196,5 +189,39 @@
   ASSERT_TRUE(record_obj->IsEqual(record_obj.get()));
 }
 
+TEST(RecordRdataTest, CreateNsecRecordWithEmptyBitmapReturnsNull) {
+  // These are just the rdata portions of the DNS records, rather than complete
+  // records, but it works well enough for this test.
+  // This record has a bitmap that is 0 bytes long.
+  const uint8_t record[] = {0x03, 'w', 'w',  'w', 0x06, 'g', 'o',  'o',  'g',
+                            'l',  'e', 0x03, 'c', 'o',  'm', 0x00, 0x00, 0x00};
+
+  DnsRecordParser parser(record, sizeof(record), 0);
+  base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
+
+  std::unique_ptr<NsecRecordRdata> record_obj =
+      NsecRecordRdata::Create(record_strpiece, parser);
+  ASSERT_FALSE(record_obj);
+}
+
+TEST(RecordRdataTest, CreateNsecRecordWithOversizedBitmapReturnsNull) {
+  // These are just the rdata portions of the DNS records, rather than complete
+  // records, but it works well enough for this test.
+  // This record has a bitmap that is 33 bytes long. The maximum size allowed by
+  // RFC 3845, Section 2.1.2, is 32 bytes.
+  const uint8_t record[] = {
+      0x03, 'w',  'w',  'w',  0x06, 'g',  'o',  'o',  'g',  'l',  'e',
+      0x03, 'c',  'o',  'm',  0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+  DnsRecordParser parser(record, sizeof(record), 0);
+  base::StringPiece record_strpiece = MakeStringPiece(record, sizeof(record));
+
+  std::unique_ptr<NsecRecordRdata> record_obj =
+      NsecRecordRdata::Create(record_strpiece, parser);
+  ASSERT_FALSE(record_obj);
+}
 
 }  // namespace net
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 4105646..081d829 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -98,7 +98,6 @@
       time_func(&base::TimeTicks::Now),
       enable_http2_alternative_service_with_different_host(false),
       enable_quic_alternative_service_with_different_host(true),
-      enable_npn(false),
       enable_priority_dependencies(true),
       enable_quic(false),
       disable_quic_on_timeout_with_open_streams(false),
@@ -377,11 +376,7 @@
 }
 
 void HttpNetworkSession::GetNpnProtos(NextProtoVector* npn_protos) const {
-  if (HttpStreamFactory::spdy_enabled() && params_.enable_npn) {
-    *npn_protos = next_protos_;
-  } else {
-    npn_protos->clear();
-  }
+  npn_protos->clear();
 }
 
 void HttpNetworkSession::GetSSLConfig(const HttpRequestInfo& request,
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index fd3b0961..a6844a4 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -101,9 +101,6 @@
     // of the origin.
     bool enable_quic_alternative_service_with_different_host;
 
-    // Enables NPN support.  Note that ALPN is always enabled.
-    bool enable_npn;
-
     // Enable setting of HTTP/2 dependencies based on priority.
     bool enable_priority_dependencies;
 
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 76bb795e..60173ab 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -15865,37 +15865,6 @@
             trans->GetTotalReceivedBytes());
 }
 
-TEST_P(HttpNetworkTransactionTest, EnableNPN) {
-  session_deps_.enable_npn = true;
-
-  std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
-  HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
-  HttpRequestInfo request;
-  TestCompletionCallback callback;
-  EXPECT_EQ(ERR_IO_PENDING,
-            trans.Start(&request, callback.callback(), BoundNetLog()));
-
-  EXPECT_THAT(trans.server_ssl_config_.alpn_protos,
-              testing::ElementsAre(kProtoHTTP2, kProtoSPDY31, kProtoHTTP11));
-  EXPECT_THAT(trans.server_ssl_config_.npn_protos,
-              testing::ElementsAre(kProtoHTTP2, kProtoSPDY31, kProtoHTTP11));
-}
-
-TEST_P(HttpNetworkTransactionTest, DisableNPN) {
-  session_deps_.enable_npn = false;
-
-  std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
-  HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
-  HttpRequestInfo request;
-  TestCompletionCallback callback;
-  EXPECT_EQ(ERR_IO_PENDING,
-            trans.Start(&request, callback.callback(), BoundNetLog()));
-
-  EXPECT_THAT(trans.server_ssl_config_.alpn_protos,
-              testing::ElementsAre(kProtoHTTP2, kProtoSPDY31, kProtoHTTP11));
-  EXPECT_TRUE(trans.server_ssl_config_.npn_protos.empty());
-}
-
 #if !defined(OS_IOS)
 TEST_P(HttpNetworkTransactionTest, TokenBindingSpdy) {
   const std::string https_url = "https://www.example.com";
diff --git a/net/http/http_server_properties.cc b/net/http/http_server_properties.cc
index cea3032..98cf6c8 100644
--- a/net/http/http_server_properties.cc
+++ b/net/http/http_server_properties.cc
@@ -14,21 +14,6 @@
 
 const char kAlternativeServiceHeader[] = "Alt-Svc";
 
-namespace {
-
-// The order of these strings much match the order of the enum definition
-// for AlternateProtocol.
-const char* const kAlternateProtocolStrings[] = {
-    "npn-spdy/3.1",
-    "npn-h2",
-    "quic"};
-
-static_assert(arraysize(kAlternateProtocolStrings) ==
-                  NUM_VALID_ALTERNATE_PROTOCOLS,
-              "kAlternateProtocolStrings has incorrect size");
-
-}  // namespace
-
 void HistogramAlternateProtocolUsage(AlternateProtocolUsage usage) {
   UMA_HISTOGRAM_ENUMERATION("Net.AlternateProtocolUsage", usage,
                             ALTERNATE_PROTOCOL_USAGE_MAX);
@@ -47,12 +32,12 @@
 
 const char* AlternateProtocolToString(AlternateProtocol protocol) {
   switch (protocol) {
-    case NPN_SPDY_3_1:
-    case NPN_HTTP_2:
     case QUIC:
-      DCHECK(IsAlternateProtocolValid(protocol));
-      return kAlternateProtocolStrings[
-          protocol - ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION];
+      return "quic";
+    case NPN_HTTP_2:
+      return "h2";
+    case NPN_SPDY_3_1:
+      return "npn-spdy/3.1";
     case UNINITIALIZED_ALTERNATE_PROTOCOL:
       return "Uninitialized";
   }
@@ -61,12 +46,17 @@
 }
 
 AlternateProtocol AlternateProtocolFromString(const std::string& str) {
-  for (int i = ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION;
-       i <= ALTERNATE_PROTOCOL_MAXIMUM_VALID_VERSION; ++i) {
-    AlternateProtocol protocol = static_cast<AlternateProtocol>(i);
-    if (str == AlternateProtocolToString(protocol))
-      return protocol;
-  }
+  if (str == "quic")
+    return QUIC;
+  if (str == "h2")
+    return NPN_HTTP_2;
+  // "npn-h2" is accepted here so that persisted settings with the old string
+  // can be loaded from disk.  TODO(bnc):  Remove around 2016 December.
+  if (str == "npn-h2")
+    return NPN_HTTP_2;
+  if (str == "npn-spdy/3.1")
+    return NPN_SPDY_3_1;
+
   return UNINITIALIZED_ALTERNATE_PROTOCOL;
 }
 
diff --git a/net/http/http_server_properties_manager_unittest.cc b/net/http/http_server_properties_manager_unittest.cc
index 9b2048a..51f50949 100644
--- a/net/http/http_server_properties_manager_unittest.cc
+++ b/net/http/http_server_properties_manager_unittest.cc
@@ -246,7 +246,7 @@
   std::unique_ptr<base::DictionaryValue> alternative_service_dict0(
       new base::DictionaryValue);
   alternative_service_dict0->SetInteger("port", 443);
-  alternative_service_dict0->SetString("protocol_str", "npn-h2");
+  alternative_service_dict0->SetString("protocol_str", "h2");
   std::unique_ptr<base::DictionaryValue> alternative_service_dict1(
       new base::DictionaryValue);
   alternative_service_dict1->SetInteger("port", 1234);
@@ -1121,9 +1121,9 @@
       "\"servers\":["
       "{\"http://www.google.com\":{"
       "\"alternative_service\":[{\"expiration\":\"13756212000000000\","
-      "\"port\":443,\"protocol_str\":\"npn-h2\"},"
+      "\"port\":443,\"protocol_str\":\"h2\"},"
       "{\"expiration\":\"13758804000000000\",\"host\":\"www.google.com\","
-      "\"port\":1234,\"protocol_str\":\"npn-h2\"}]}},"
+      "\"port\":1234,\"protocol_str\":\"h2\"}]}},"
       "{\"http://mail.google.com\":{\"alternative_service\":[{"
       "\"expiration\":\"9223372036854775807\",\"host\":\"foo.google.com\","
       "\"port\":444,\"protocol_str\":\"npn-spdy/3.1\"}],"
@@ -1142,7 +1142,7 @@
 
 TEST_P(HttpServerPropertiesManagerTest, AddToAlternativeServiceMap) {
   std::unique_ptr<base::Value> server_value = base::JSONReader::Read(
-      "{\"alternative_service\":[{\"port\":443,\"protocol_str\":\"npn-h2\"},"
+      "{\"alternative_service\":[{\"port\":443,\"protocol_str\":\"h2\"},"
       "{\"port\":123,\"protocol_str\":\"quic\","
       "\"expiration\":\"9223372036854775807\"},{\"host\":\"example.org\","
       "\"port\":1234,\"protocol_str\":\"npn-h2\","
diff --git a/net/http/transport_security_state_ct_policies.inc b/net/http/transport_security_state_ct_policies.inc
index b813ce0..af76103 100644
--- a/net/http/transport_security_state_ct_policies.inc
+++ b/net/http/transport_security_state_ct_policies.inc
@@ -104,6 +104,9 @@
     {{0x56, 0x7b, 0x82, 0x11, 0xfd, 0x20, 0xd3, 0xd2, 0x83, 0xee, 0x0c,
       0xd7, 0xce, 0x06, 0x72, 0xcb, 0x9d, 0x99, 0xbc, 0x5b, 0x48, 0x7a,
       0x58, 0xc9, 0xd5, 0x4e, 0xc6, 0x7f, 0x77, 0xd4, 0xa8, 0xf5}},
+    {{0x5c, 0x4f, 0x28, 0x53, 0x88, 0xf3, 0x83, 0x36, 0x26, 0x9a, 0x55,
+      0xc7, 0xc1, 0x2c, 0x0b, 0x3c, 0xa7, 0x3f, 0xef, 0x2a, 0x5a, 0x4d,
+      0xf8, 0x2b, 0x89, 0x14, 0x1e, 0x84, 0x1a, 0x6c, 0x4d, 0xe4}},
     {{0x67, 0xdc, 0x4f, 0x32, 0xfa, 0x10, 0xe7, 0xd0, 0x1a, 0x79, 0xa0,
       0x73, 0xaa, 0x0c, 0x9e, 0x02, 0x12, 0xec, 0x2f, 0xfc, 0x3d, 0x77,
       0x9e, 0x0a, 0xa7, 0xf9, 0xc0, 0xf0, 0xe1, 0xc2, 0xc8, 0x93}},
@@ -131,9 +134,6 @@
     {{0x87, 0xaf, 0x34, 0xd6, 0x6f, 0xb3, 0xf2, 0xfd, 0xf3, 0x6e, 0x09,
       0x11, 0x1e, 0x9a, 0xba, 0x2f, 0x6f, 0x44, 0xb2, 0x07, 0xf3, 0x86,
       0x3f, 0x3d, 0x0b, 0x54, 0xb2, 0x50, 0x23, 0x90, 0x9a, 0xa5}},
-    {{0x93, 0x92, 0xae, 0x21, 0x49, 0x92, 0x4a, 0xde, 0x37, 0xe6, 0x45,
-      0xdb, 0xa1, 0xff, 0x4b, 0xdd, 0xdc, 0xda, 0x2b, 0x29, 0x1b, 0x60,
-      0x97, 0x66, 0x9d, 0x2a, 0xfa, 0x5c, 0x7a, 0x37, 0x26, 0x19}},
     {{0x95, 0x73, 0x54, 0x73, 0xbd, 0x67, 0xa3, 0xb9, 0x5a, 0x8d, 0x5f,
       0x90, 0xc5, 0xa2, 0x1a, 0xce, 0x1e, 0x0d, 0x79, 0x47, 0x32, 0x06,
       0x74, 0xd4, 0xab, 0x84, 0x79, 0x72, 0xb9, 0x15, 0x44, 0xd2}},
diff --git a/net/net.gyp b/net/net.gyp
index 328c0a6..d033f73 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -346,8 +346,6 @@
               'dns/mdns_cache_unittest.cc',
               'dns/mdns_client_unittest.cc',
               'dns/mdns_query_unittest.cc',
-              'dns/record_parsed_unittest.cc',
-              'dns/record_rdata_unittest.cc',
             ],
         }],
         [ 'OS == "win"', {
diff --git a/net/net.gypi b/net/net.gypi
index 7dabdaa..8a4a799c 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -105,6 +105,8 @@
       'cert/internal/parse_ocsp.h',
       'cert/internal/parsed_certificate.cc',
       'cert/internal/parsed_certificate.h',
+      'cert/internal/path_builder.cc',
+      'cert/internal/path_builder.h',
       'cert/internal/signature_algorithm.cc',
       'cert/internal/signature_algorithm.h',
       'cert/internal/signature_policy.cc',
@@ -1405,11 +1407,15 @@
       'cert/internal/parse_certificate_unittest.cc',
       'cert/internal/parse_name_unittest.cc',
       'cert/internal/parse_ocsp_unittest.cc',
+      'cert/internal/path_builder_pkits_unittest.cc',
+      'cert/internal/path_builder_unittest.cc',
+      'cert/internal/path_builder_verify_certificate_chain_unittest.cc',
       'cert/internal/signature_algorithm_unittest.cc',
       'cert/internal/test_helpers.cc',
       'cert/internal/test_helpers.h',
-      'cert/internal/verify_certificate_chain_unittest.cc',
       'cert/internal/verify_certificate_chain_pkits_unittest.cc',
+      'cert/internal/verify_certificate_chain_typed_unittest.h',
+      'cert/internal/verify_certificate_chain_unittest.cc',
       'cert/internal/verify_name_match_unittest.cc',
       'cert/internal/verify_signed_data_unittest.cc',
       'cert/jwk_serializer_unittest.cc',
@@ -2465,6 +2471,10 @@
       'data/verify_certificate_chain_unittest/intermediary-unknown-non-critical-extension.pem',
       'data/verify_certificate_chain_unittest/issuer-and-subject-not-byte-for-byte-equal-anchor.pem',
       'data/verify_certificate_chain_unittest/issuer-and-subject-not-byte-for-byte-equal.pem',
+      'data/verify_certificate_chain_unittest/key-rollover-longrolloverchain.pem',
+      'data/verify_certificate_chain_unittest/key-rollover-newchain.pem',
+      'data/verify_certificate_chain_unittest/key-rollover-oldchain.pem',
+      'data/verify_certificate_chain_unittest/key-rollover-rolloverchain.pem',
       'data/verify_certificate_chain_unittest/non-self-signed-root.pem',
       'data/verify_certificate_chain_unittest/target-and-intermediary.pem',
       'data/verify_certificate_chain_unittest/target-has-keycertsign-but-not-ca.pem',
diff --git a/net/net_common.gypi b/net/net_common.gypi
index 9f91244..e5b41531 100644
--- a/net/net_common.gypi
+++ b/net/net_common.gypi
@@ -223,10 +223,6 @@
           'dns/mdns_client.h',
           'dns/mdns_client_impl.cc',
           'dns/mdns_client_impl.h',
-          'dns/record_parsed.cc',
-          'dns/record_parsed.h',
-          'dns/record_rdata.cc',
-          'dns/record_rdata.h',
         ]
     }],
     [ 'OS == "win"', {
diff --git a/net/quic/congestion_control/cubic.cc b/net/quic/congestion_control/cubic.cc
index 9a924b5..ca90d71 100644
--- a/net/quic/congestion_control/cubic.cc
+++ b/net/quic/congestion_control/cubic.cc
@@ -117,7 +117,7 @@
 
   // Cubic is "independent" of RTT, the update is limited by the time elapsed.
   if (last_congestion_window_ == current_congestion_window &&
-      (current_time.Subtract(last_update_time_) <= MaxCubicTimeInterval())) {
+      (current_time - last_update_time_ <= MaxCubicTimeInterval())) {
     return max(last_target_congestion_window_,
                estimated_tcp_congestion_window_);
   }
@@ -145,9 +145,9 @@
     // through the app-limited period.
     if (FLAGS_shift_quic_cubic_epoch_when_app_limited &&
         app_limited_start_time_ != QuicTime::Zero()) {
-      QuicTime::Delta shift = current_time.Subtract(app_limited_start_time_);
+      QuicTime::Delta shift = current_time - app_limited_start_time_;
       DVLOG(1) << "Shifting epoch for quiescence by " << shift.ToMicroseconds();
-      epoch_ = epoch_.Add(shift);
+      epoch_ = epoch_ + shift;
       app_limited_start_time_ = QuicTime::Zero();
     }
   }
@@ -156,7 +156,7 @@
   // the round trip time in account. This is done to allow us to use shift as a
   // divide operator.
   int64_t elapsed_time =
-      (current_time.Add(delay_min).Subtract(epoch_).ToMicroseconds() << 10) /
+      ((current_time + delay_min - epoch_).ToMicroseconds() << 10) /
       kNumMicrosPerSecond;
 
   int64_t offset = time_to_origin_point_ - elapsed_time;
diff --git a/net/quic/congestion_control/cubic_bytes.cc b/net/quic/congestion_control/cubic_bytes.cc
index e09cc76..cae49226 100644
--- a/net/quic/congestion_control/cubic_bytes.cc
+++ b/net/quic/congestion_control/cubic_bytes.cc
@@ -112,7 +112,7 @@
 
   // Cubic is "independent" of RTT, the update is limited by the time elapsed.
   if (last_congestion_window_ == current_congestion_window &&
-      (current_time.Subtract(last_update_time_) <= MaxCubicTimeInterval())) {
+      (current_time - last_update_time_ <= MaxCubicTimeInterval())) {
     return max(last_target_congestion_window_,
                estimated_tcp_congestion_window_);
   }
@@ -140,7 +140,7 @@
   // the round trip time in account. This is done to allow us to use shift as a
   // divide operator.
   int64_t elapsed_time =
-      (current_time.Add(delay_min).Subtract(epoch_).ToMicroseconds() << 10) /
+      ((current_time + delay_min - epoch_).ToMicroseconds() << 10) /
       kNumMicrosPerSecond;
 
   int64_t offset = time_to_origin_point_ - elapsed_time;
diff --git a/net/quic/congestion_control/general_loss_algorithm.cc b/net/quic/congestion_control/general_loss_algorithm.cc
index e99a1f57..05491b1b 100644
--- a/net/quic/congestion_control/general_loss_algorithm.cc
+++ b/net/quic/congestion_control/general_loss_algorithm.cc
@@ -67,7 +67,7 @@
       QuicTime::Delta::Max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt());
   QuicTime::Delta loss_delay =
       QuicTime::Delta::Max(QuicTime::Delta::FromMilliseconds(kMinLossDelayMs),
-                           max_rtt.Add(max_rtt >> reordering_shift_));
+                           max_rtt + (max_rtt >> reordering_shift_));
   QuicPacketNumber packet_number = unacked_packets.GetLeastUnacked();
   for (QuicUnackedPacketMap::const_iterator it = unacked_packets.begin();
        it != unacked_packets.end() && packet_number <= largest_observed;
@@ -91,7 +91,7 @@
     if ((!it->retransmittable_frames.empty() &&
          unacked_packets.largest_sent_packet() == largest_observed) ||
         (loss_type_ == kTime || loss_type_ == kAdaptiveTime)) {
-      QuicTime when_lost = it->sent_time.Add(loss_delay);
+      QuicTime when_lost = it->sent_time + loss_delay;
       if (time < when_lost) {
         loss_detection_timeout_ = when_lost;
         break;
@@ -101,7 +101,7 @@
     }
 
     // NACK-based loss detection allows for a max reordering window of 1 RTT.
-    if (it->sent_time.Add(rtt_stats.smoothed_rtt()) <
+    if (it->sent_time + rtt_stats.smoothed_rtt() <
         unacked_packets.GetTransmissionInfo(largest_observed).sent_time) {
       packets_lost->push_back(std::make_pair(packet_number, it->bytes_sent));
       continue;
@@ -128,8 +128,9 @@
   // Calculate the extra time needed so this wouldn't have been declared lost.
   // Extra time needed is based on how long it's been since the spurious
   // retransmission was sent, because the SRTT and latest RTT may have changed.
-  QuicTime::Delta extra_time_needed = time.Subtract(
-      unacked_packets.GetTransmissionInfo(spurious_retransmission).sent_time);
+  QuicTime::Delta extra_time_needed =
+      time -
+      unacked_packets.GetTransmissionInfo(spurious_retransmission).sent_time;
   // Increase the reordering fraction until enough time would be allowed.
   QuicTime::Delta max_rtt =
       QuicTime::Delta::Max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt());
diff --git a/net/quic/congestion_control/general_loss_algorithm_test.cc b/net/quic/congestion_control/general_loss_algorithm_test.cc
index b0e1519..e547557a 100644
--- a/net/quic/congestion_control/general_loss_algorithm_test.cc
+++ b/net/quic/congestion_control/general_loss_algorithm_test.cc
@@ -125,10 +125,10 @@
   // Early retransmit when the final packet gets acked and the first is nacked.
   unacked_packets_.RemoveFromInFlight(2);
   VerifyLosses(2, nullptr, 0);
-  EXPECT_EQ(clock_.Now().Add(rtt_stats_.smoothed_rtt().Multiply(1.25)),
+  EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(),
             loss_algorithm_.GetLossTimeout());
 
-  clock_.AdvanceTime(rtt_stats_.latest_rtt().Multiply(1.25));
+  clock_.AdvanceTime(1.25 * rtt_stats_.latest_rtt());
   QuicPacketNumber lost[] = {1};
   VerifyLosses(2, lost, arraysize(lost));
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
@@ -140,7 +140,7 @@
     SendDataPacket(i);
     // Advance the time 1/4 RTT between 3 and 4.
     if (i == 3) {
-      clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.25));
+      clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
     }
   }
 
@@ -152,15 +152,15 @@
   VerifyLosses(kNumSentPackets, lost, arraysize(lost));
   // The time has already advanced 1/4 an RTT, so ensure the timeout is set
   // 1.25 RTTs after the earliest pending packet(3), not the last(4).
-  EXPECT_EQ(clock_.Now().Add(rtt_stats_.smoothed_rtt()),
+  EXPECT_EQ(clock_.Now() + rtt_stats_.smoothed_rtt(),
             loss_algorithm_.GetLossTimeout());
 
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
   QuicPacketNumber lost2[] = {1, 2, 3};
   VerifyLosses(kNumSentPackets, lost2, arraysize(lost2));
-  EXPECT_EQ(clock_.Now().Add(rtt_stats_.smoothed_rtt().Multiply(0.25)),
+  EXPECT_EQ(clock_.Now() + 0.25 * rtt_stats_.smoothed_rtt(),
             loss_algorithm_.GetLossTimeout());
-  clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.25));
+  clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
   QuicPacketNumber lost3[] = {1, 2, 3, 4};
   VerifyLosses(kNumSentPackets, lost3, arraysize(lost3));
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
@@ -185,8 +185,8 @@
 TEST_F(GeneralLossAlgorithmTest, AlwaysLosePacketSent1RTTEarlier) {
   // Transmit 1 packet and then wait an rtt plus 1ms.
   SendDataPacket(1);
-  clock_.AdvanceTime(
-      rtt_stats_.smoothed_rtt().Add(QuicTime::Delta::FromMilliseconds(1)));
+  clock_.AdvanceTime(rtt_stats_.smoothed_rtt() +
+                     QuicTime::Delta::FromMilliseconds(1));
 
   // Transmit 2 packets.
   SendDataPacket(2);
@@ -212,8 +212,8 @@
   for (size_t i = 1; i < 500; ++i) {
     VerifyLosses(2, nullptr, 0);
   }
-  EXPECT_EQ(rtt_stats_.smoothed_rtt().Multiply(1.25),
-            loss_algorithm_.GetLossTimeout().Subtract(clock_.Now()));
+  EXPECT_EQ(1.25 * rtt_stats_.smoothed_rtt(),
+            loss_algorithm_.GetLossTimeout() - clock_.Now());
 }
 
 TEST_F(GeneralLossAlgorithmTest, NoLossUntilTimeout) {
@@ -222,7 +222,7 @@
   // Transmit 10 packets at 1/10th an RTT interval.
   for (size_t i = 1; i <= kNumSentPackets; ++i) {
     SendDataPacket(i);
-    clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.1));
+    clock_.AdvanceTime(0.1 * rtt_stats_.smoothed_rtt());
   }
   // Expect the timer to not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
@@ -230,10 +230,10 @@
   unacked_packets_.RemoveFromInFlight(2);
   VerifyLosses(2, nullptr, 0);
   // Expect the timer to be set to 0.25 RTT's in the future.
-  EXPECT_EQ(rtt_stats_.smoothed_rtt().Multiply(0.25),
-            loss_algorithm_.GetLossTimeout().Subtract(clock_.Now()));
+  EXPECT_EQ(0.25 * rtt_stats_.smoothed_rtt(),
+            loss_algorithm_.GetLossTimeout() - clock_.Now());
   VerifyLosses(2, nullptr, 0);
-  clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.25));
+  clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
   QuicPacketNumber lost[] = {1};
   VerifyLosses(2, lost, arraysize(lost));
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
@@ -245,7 +245,7 @@
   // Transmit 10 packets at 1/10th an RTT interval.
   for (size_t i = 1; i <= kNumSentPackets; ++i) {
     SendDataPacket(i);
-    clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.1));
+    clock_.AdvanceTime(0.1 * rtt_stats_.smoothed_rtt());
   }
   // Expect the timer to not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
@@ -254,7 +254,7 @@
   VerifyLosses(1, nullptr, 0);
   // The timer should still not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
-  clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.25));
+  clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
   VerifyLosses(1, nullptr, 0);
   clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
   VerifyLosses(1, nullptr, 0);
@@ -276,9 +276,9 @@
   unacked_packets_.RemoveFromInFlight(10);
   VerifyLosses(10, nullptr, 0);
   // Expect the timer to be set to 0.25 RTT's in the future.
-  EXPECT_EQ(rtt_stats_.smoothed_rtt().Multiply(0.25),
-            loss_algorithm_.GetLossTimeout().Subtract(clock_.Now()));
-  clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.25));
+  EXPECT_EQ(0.25 * rtt_stats_.smoothed_rtt(),
+            loss_algorithm_.GetLossTimeout() - clock_.Now());
+  clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
   QuicPacketNumber lost[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
   VerifyLosses(10, lost, arraysize(lost));
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
@@ -300,9 +300,9 @@
   unacked_packets_.RemoveFromInFlight(10);
   VerifyLosses(10, nullptr, 0);
   // Expect the timer to be set to 0.25 RTT's in the future.
-  EXPECT_EQ(rtt_stats_.smoothed_rtt().Multiply(0.25),
-            loss_algorithm_.GetLossTimeout().Subtract(clock_.Now()));
-  clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.25));
+  EXPECT_EQ(0.25 * rtt_stats_.smoothed_rtt(),
+            loss_algorithm_.GetLossTimeout() - clock_.Now());
+  clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt());
   // Now ack packets 1 to 9 and ensure the timer is no longer set and no packets
   // are lost.
   for (QuicPacketNumber i = 1; i <= 9; ++i) {
@@ -319,9 +319,9 @@
   // Transmit 2 packets at 1/10th an RTT interval.
   for (size_t i = 1; i <= kNumSentPackets; ++i) {
     SendDataPacket(i);
-    clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(0.1));
+    clock_.AdvanceTime(0.1 * rtt_stats_.smoothed_rtt());
   }
-  EXPECT_EQ(QuicTime::Zero().Add(rtt_stats_.smoothed_rtt()), clock_.Now());
+  EXPECT_EQ(QuicTime::Zero() + rtt_stats_.smoothed_rtt(), clock_.Now());
 
   // Expect the timer to not be set.
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
@@ -329,10 +329,10 @@
   unacked_packets_.RemoveFromInFlight(2);
   VerifyLosses(2, nullptr, 0);
   // Expect the timer to be set to 1/16 RTT's in the future.
-  EXPECT_EQ(rtt_stats_.smoothed_rtt().Multiply(1.0f / 16),
-            loss_algorithm_.GetLossTimeout().Subtract(clock_.Now()));
+  EXPECT_EQ(rtt_stats_.smoothed_rtt() * (1.0f / 16),
+            loss_algorithm_.GetLossTimeout() - clock_.Now());
   VerifyLosses(2, nullptr, 0);
-  clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(1.0f / 16));
+  clock_.AdvanceTime(rtt_stats_.smoothed_rtt() * (1.0f / 16));
   QuicPacketNumber lost[] = {1};
   VerifyLosses(2, lost, arraysize(lost));
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
@@ -342,7 +342,7 @@
 
   // Advance the time 1/4 RTT and indicate the loss was spurious.
   // The new threshold should be 1/2 RTT.
-  clock_.AdvanceTime(rtt_stats_.smoothed_rtt().Multiply(1.0f / 4));
+  clock_.AdvanceTime(rtt_stats_.smoothed_rtt() * (1.0f / 4));
   loss_algorithm_.SpuriousRetransmitDetected(unacked_packets_, clock_.Now(),
                                              rtt_stats_, 11);
   EXPECT_EQ(1, loss_algorithm_.reordering_shift());
diff --git a/net/quic/congestion_control/hybrid_slow_start.cc b/net/quic/congestion_control/hybrid_slow_start.cc
index 5f334c7..6774396 100644
--- a/net/quic/congestion_control/hybrid_slow_start.cc
+++ b/net/quic/congestion_control/hybrid_slow_start.cc
@@ -94,7 +94,7 @@
         QuicTime::Delta::FromMicroseconds(max(min_rtt_increase_threshold_us,
                                               kHybridStartDelayMinThresholdUs));
 
-    if (current_min_rtt_ > min_rtt.Add(min_rtt_increase_threshold)) {
+    if (current_min_rtt_ > min_rtt + min_rtt_increase_threshold) {
       hystart_found_ = DELAY;
     }
   }
diff --git a/net/quic/congestion_control/hybrid_slow_start_test.cc b/net/quic/congestion_control/hybrid_slow_start_test.cc
index 0e8c934..18601af 100644
--- a/net/quic/congestion_control/hybrid_slow_start_test.cc
+++ b/net/quic/congestion_control/hybrid_slow_start_test.cc
@@ -59,17 +59,17 @@
   // term RTT provided.
   for (int n = 0; n < kHybridStartMinSamples; ++n) {
     EXPECT_FALSE(slow_start_->ShouldExitSlowStart(
-        rtt_.Add(QuicTime::Delta::FromMilliseconds(n)), rtt_, 100));
+        rtt_ + QuicTime::Delta::FromMilliseconds(n), rtt_, 100));
   }
   slow_start_->StartReceiveRound(end_packet_number++);
   for (int n = 1; n < kHybridStartMinSamples; ++n) {
     EXPECT_FALSE(slow_start_->ShouldExitSlowStart(
-        rtt_.Add(QuicTime::Delta::FromMilliseconds(n + 10)), rtt_, 100));
+        rtt_ + QuicTime::Delta::FromMilliseconds(n + 10), rtt_, 100));
   }
   // Expect to trigger since all packets in this burst was above the long term
   // RTT provided.
   EXPECT_TRUE(slow_start_->ShouldExitSlowStart(
-      rtt_.Add(QuicTime::Delta::FromMilliseconds(10)), rtt_, 100));
+      rtt_ + QuicTime::Delta::FromMilliseconds(10), rtt_, 100));
 }
 
 }  // namespace test
diff --git a/net/quic/congestion_control/pacing_sender.cc b/net/quic/congestion_control/pacing_sender.cc
index e18183f..7f366c9 100644
--- a/net/quic/congestion_control/pacing_sender.cc
+++ b/net/quic/congestion_control/pacing_sender.cc
@@ -40,10 +40,6 @@
   sender_->SetNumEmulatedConnections(num_connections);
 }
 
-void PacingSender::SetMaxCongestionWindow(QuicByteCount max_congestion_window) {
-  sender_->SetMaxCongestionWindow(max_congestion_window);
-}
-
 void PacingSender::SetMaxPacingRate(QuicBandwidth max_pacing_rate) {
   max_pacing_rate_ = max_pacing_rate;
 }
@@ -95,12 +91,12 @@
   // If the last send was delayed, and the alarm took a long time to get
   // invoked, allow the connection to make up for lost time.
   if (was_last_send_delayed_) {
-    ideal_next_packet_send_time_ = ideal_next_packet_send_time_.Add(delay);
+    ideal_next_packet_send_time_ = ideal_next_packet_send_time_ + delay;
     // The send was application limited if it takes longer than the
     // pacing delay between sent packets.
     const bool application_limited =
         last_delayed_packet_sent_time_.IsInitialized() &&
-        sent_time > last_delayed_packet_sent_time_.Add(delay);
+        sent_time > last_delayed_packet_sent_time_ + delay;
     const bool making_up_for_lost_time =
         ideal_next_packet_send_time_ <= sent_time;
     // As long as we're making up time and not application limited,
@@ -113,8 +109,8 @@
       last_delayed_packet_sent_time_ = QuicTime::Zero();
     }
   } else {
-    ideal_next_packet_send_time_ = QuicTime::Max(
-        ideal_next_packet_send_time_.Add(delay), sent_time.Add(delay));
+    ideal_next_packet_send_time_ =
+        QuicTime::Max(ideal_next_packet_send_time_ + delay, sent_time + delay);
   }
   return in_flight;
 }
@@ -144,11 +140,11 @@
   }
 
   // If the next send time is within the alarm granularity, send immediately.
-  if (ideal_next_packet_send_time_ > now.Add(alarm_granularity_)) {
+  if (ideal_next_packet_send_time_ > now + alarm_granularity_) {
     DVLOG(1) << "Delaying packet: "
-             << ideal_next_packet_send_time_.Subtract(now).ToMicroseconds();
+             << (ideal_next_packet_send_time_ - now).ToMicroseconds();
     was_last_send_delayed_ = true;
-    return ideal_next_packet_send_time_.Subtract(now);
+    return ideal_next_packet_send_time_ - now;
   }
 
   DVLOG(1) << "Sending packet now";
diff --git a/net/quic/congestion_control/pacing_sender.h b/net/quic/congestion_control/pacing_sender.h
index 207901ed..e587aca 100644
--- a/net/quic/congestion_control/pacing_sender.h
+++ b/net/quic/congestion_control/pacing_sender.h
@@ -45,7 +45,6 @@
       const CachedNetworkParameters& cached_network_params,
       bool max_bandwidth_resumption) override;
   void SetNumEmulatedConnections(int num_connections) override;
-  void SetMaxCongestionWindow(QuicByteCount max_congestion_window) override;
   void OnCongestionEvent(bool rtt_updated,
                          QuicByteCount bytes_in_flight,
                          const CongestionVector& acked_packets,
diff --git a/net/quic/congestion_control/pacing_sender_test.cc b/net/quic/congestion_control/pacing_sender_test.cc
index fbcbaa19..c531a59a 100644
--- a/net/quic/congestion_control/pacing_sender_test.cc
+++ b/net/quic/congestion_control/pacing_sender_test.cc
@@ -354,9 +354,6 @@
   EXPECT_CALL(*mock_sender_, SetNumEmulatedConnections(2));
   pacing_sender_->SetNumEmulatedConnections(2);
 
-  EXPECT_CALL(*mock_sender_, SetMaxCongestionWindow(kBytes));
-  pacing_sender_->SetMaxCongestionWindow(kBytes);
-
   SendAlgorithmInterface::CongestionVector packets;
   EXPECT_CALL(*mock_sender_, OnCongestionEvent(true, kBytes, packets, packets));
   pacing_sender_->OnCongestionEvent(true, kBytes, packets, packets);
diff --git a/net/quic/congestion_control/rtt_stats.cc b/net/quic/congestion_control/rtt_stats.cc
index 4809f1a..86eb3ab 100644
--- a/net/quic/congestion_control/rtt_stats.cc
+++ b/net/quic/congestion_control/rtt_stats.cc
@@ -37,7 +37,8 @@
       num_samples_for_forced_min_(0),
       windowed_min_rtt_(
           QuicTime::Delta::FromMilliseconds(kMinRttWindowLengthMs),
-          QuicTime::Delta::Zero()) {}
+          QuicTime::Delta::Zero(),
+          QuicTime::Zero()) {}
 
 void RttStats::SampleNewWindowedMinRtt(uint32_t num_samples) {
   num_samples_for_forced_min_ = num_samples;
@@ -46,10 +47,9 @@
 }
 
 void RttStats::ExpireSmoothedMetrics() {
-  mean_deviation_ =
-      max(mean_deviation_,
-          QuicTime::Delta::FromMicroseconds(
-              std::abs(smoothed_rtt_.Subtract(latest_rtt_).ToMicroseconds())));
+  mean_deviation_ = max(mean_deviation_,
+                        QuicTime::Delta::FromMicroseconds(std::abs(
+                            (smoothed_rtt_ - latest_rtt_).ToMicroseconds())));
   smoothed_rtt_ = max(smoothed_rtt_, latest_rtt_);
 }
 
@@ -80,7 +80,7 @@
   previous_srtt_ = smoothed_rtt_;
 
   if (rtt_sample > ack_delay) {
-    rtt_sample = rtt_sample.Subtract(ack_delay);
+    rtt_sample = rtt_sample - ack_delay;
   }
   latest_rtt_ = rtt_sample;
   // First time call.
@@ -91,9 +91,8 @@
   } else {
     mean_deviation_ = QuicTime::Delta::FromMicroseconds(static_cast<int64_t>(
         kOneMinusBeta * mean_deviation_.ToMicroseconds() +
-        kBeta * std::abs(smoothed_rtt_.Subtract(rtt_sample).ToMicroseconds())));
-    smoothed_rtt_ =
-        smoothed_rtt_.Multiply(kOneMinusAlpha).Add(rtt_sample.Multiply(kAlpha));
+        kBeta * std::abs((smoothed_rtt_ - rtt_sample).ToMicroseconds())));
+    smoothed_rtt_ = kOneMinusAlpha * smoothed_rtt_ + kAlpha * rtt_sample;
     DVLOG(1) << " smoothed_rtt(us):" << smoothed_rtt_.ToMicroseconds()
              << " mean_deviation(us):" << mean_deviation_.ToMicroseconds();
   }
diff --git a/net/quic/congestion_control/rtt_stats.h b/net/quic/congestion_control/rtt_stats.h
index ac15149..009f07ec 100644
--- a/net/quic/congestion_control/rtt_stats.h
+++ b/net/quic/congestion_control/rtt_stats.h
@@ -99,7 +99,11 @@
   uint32_t num_samples_for_forced_min_;
 
   // Windowed min_rtt.
-  WindowedFilter<QuicTime::Delta, MinFilter<QuicTime::Delta>> windowed_min_rtt_;
+  WindowedFilter<QuicTime::Delta,
+                 MinFilter<QuicTime::Delta>,
+                 QuicTime,
+                 QuicTime::Delta>
+      windowed_min_rtt_;
 
   DISALLOW_COPY_AND_ASSIGN(RttStats);
 };
diff --git a/net/quic/congestion_control/rtt_stats_test.cc b/net/quic/congestion_control/rtt_stats_test.cc
index 9a25946..1402883 100644
--- a/net/quic/congestion_control/rtt_stats_test.cc
+++ b/net/quic/congestion_control/rtt_stats_test.cc
@@ -78,29 +78,29 @@
             rtt_stats_.WindowedMinRtt());
   rtt_stats_.UpdateRtt(
       QuicTime::Delta::FromMilliseconds(10), QuicTime::Delta::Zero(),
-      QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(10)));
+      QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(10));
   EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
   EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.WindowedMinRtt());
   rtt_stats_.UpdateRtt(
       QuicTime::Delta::FromMilliseconds(50), QuicTime::Delta::Zero(),
-      QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(20)));
+      QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(20));
   EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
   EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.WindowedMinRtt());
   rtt_stats_.UpdateRtt(
       QuicTime::Delta::FromMilliseconds(50), QuicTime::Delta::Zero(),
-      QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(30)));
+      QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(30));
   EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
   EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.WindowedMinRtt());
   rtt_stats_.UpdateRtt(
       QuicTime::Delta::FromMilliseconds(50), QuicTime::Delta::Zero(),
-      QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(40)));
+      QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(40));
   EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.min_rtt());
   EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), rtt_stats_.WindowedMinRtt());
   // Verify that ack_delay does not go into recording of min_rtt_.
   rtt_stats_.UpdateRtt(
       QuicTime::Delta::FromMilliseconds(7),
       QuicTime::Delta::FromMilliseconds(2),
-      QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(50)));
+      QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(50));
   EXPECT_EQ(QuicTime::Delta::FromMilliseconds(7), rtt_stats_.min_rtt());
   EXPECT_EQ(QuicTime::Delta::FromMilliseconds(7), rtt_stats_.WindowedMinRtt());
 }
@@ -132,21 +132,21 @@
   EXPECT_EQ(initial_rtt, rtt_stats_.WindowedMinRtt());
   EXPECT_EQ(initial_rtt, rtt_stats_.smoothed_rtt());
 
-  EXPECT_EQ(initial_rtt.Multiply(0.5), rtt_stats_.mean_deviation());
+  EXPECT_EQ(0.5 * initial_rtt, rtt_stats_.mean_deviation());
 
   // Update once with a 20ms RTT.
-  QuicTime::Delta doubled_rtt = initial_rtt.Multiply(2);
+  QuicTime::Delta doubled_rtt = 2 * initial_rtt;
   rtt_stats_.UpdateRtt(doubled_rtt, QuicTime::Delta::Zero(), QuicTime::Zero());
-  EXPECT_EQ(initial_rtt.Multiply(1.125), rtt_stats_.smoothed_rtt());
+  EXPECT_EQ(1.125 * initial_rtt, rtt_stats_.smoothed_rtt());
 
   // Expire the smoothed metrics, increasing smoothed rtt and mean deviation.
   rtt_stats_.ExpireSmoothedMetrics();
   EXPECT_EQ(doubled_rtt, rtt_stats_.smoothed_rtt());
-  EXPECT_EQ(initial_rtt.Multiply(0.875), rtt_stats_.mean_deviation());
+  EXPECT_EQ(0.875 * initial_rtt, rtt_stats_.mean_deviation());
 
   // Now go back down to 5ms and expire the smoothed metrics, and ensure the
   // mean deviation increases to 15ms.
-  QuicTime::Delta half_rtt = initial_rtt.Multiply(0.5);
+  QuicTime::Delta half_rtt = 0.5 * initial_rtt;
   rtt_stats_.UpdateRtt(half_rtt, QuicTime::Delta::Zero(), QuicTime::Zero());
   EXPECT_GT(doubled_rtt, rtt_stats_.smoothed_rtt());
   EXPECT_LT(initial_rtt, rtt_stats_.mean_deviation());
diff --git a/net/quic/congestion_control/send_algorithm_interface.cc b/net/quic/congestion_control/send_algorithm_interface.cc
index 821beb7..205e15c 100644
--- a/net/quic/congestion_control/send_algorithm_interface.cc
+++ b/net/quic/congestion_control/send_algorithm_interface.cc
@@ -20,12 +20,7 @@
     CongestionControlType congestion_control_type,
     QuicConnectionStats* stats,
     QuicPacketCount initial_congestion_window) {
-  QuicPacketCount max_congestion_window =
-      (kDefaultSocketReceiveBuffer * kConservativeReceiveBufferFraction) /
-      kDefaultTCPMSS;
-  if (FLAGS_quic_ignore_srbf) {
-    max_congestion_window = kDefaultMaxCongestionWindowPackets;
-  }
+  QuicPacketCount max_congestion_window = kDefaultMaxCongestionWindowPackets;
   switch (congestion_control_type) {
     case kCubic:
       return new TcpCubicSenderPackets(
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index f711e76f..e6c0728 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -47,9 +47,6 @@
   // particularly for congestion avoidance.  Can be set any time.
   virtual void SetNumEmulatedConnections(int num_connections) = 0;
 
-  // Sets the maximum congestion window in bytes.
-  virtual void SetMaxCongestionWindow(QuicByteCount max_congestion_window) = 0;
-
   // Indicates an update to the congestion state, caused either by an incoming
   // ack or loss event timeout.  |rtt_updated| indicates whether a new
   // latest_rtt sample has been taken, |byte_in_flight| the bytes in flight
diff --git a/net/quic/congestion_control/send_algorithm_simulator.cc b/net/quic/congestion_control/send_algorithm_simulator.cc
index 46f7db36..bb1316f 100644
--- a/net/quic/congestion_control/send_algorithm_simulator.cc
+++ b/net/quic/congestion_control/send_algorithm_simulator.cc
@@ -98,9 +98,9 @@
 
 void SendAlgorithmSimulator::TransferBytes(QuicByteCount max_bytes,
                                            QuicTime::Delta max_time) {
-  const QuicTime end_time =
-      max_time.IsInfinite() ? QuicTime::Zero().Add(QuicTime::Delta::Infinite())
-                            : clock_->Now().Add(max_time);
+  const QuicTime end_time = max_time.IsInfinite()
+                                ? QuicTime::Zero() + QuicTime::Delta::Infinite()
+                                : clock_->Now() + max_time;
   QuicByteCount bytes_sent = 0;
   while (!pending_transfers_.empty() && clock_->Now() < end_time &&
          bytes_sent < max_bytes) {
@@ -145,7 +145,7 @@
       continue;
     }
     // If the flow hasn't started, use the start time.
-    QuicTime::Delta transfer_send_time = it->start_time.Subtract(clock_->Now());
+    QuicTime::Delta transfer_send_time = it->start_time - clock_->Now();
     if (clock_->Now() >= it->start_time) {
       transfer_send_time = it->sender->send_algorithm->TimeUntilSend(
           clock_->Now(), it->bytes_in_flight);
@@ -225,16 +225,16 @@
     }
     DCHECK_LT(*next_acked, it->packet_number);
     // Consider a delayed ack for the current next_acked.
-    if (ack_delay < it->ack_time.Subtract(clock_->Now())) {
+    if (ack_delay < it->ack_time - clock_->Now()) {
       break;
     }
     *next_acked = it->packet_number;
-    ack_delay = it->ack_time.Subtract(clock_->Now());
+    ack_delay = it->ack_time - clock_->Now();
     if (HasRecentLostPackets(transfer, *next_acked) ||
         (*next_acked - last_acked) >= 2) {
       break;
     }
-    ack_delay = ack_delay.Add(delayed_ack_timer_);
+    ack_delay = ack_delay + delayed_ack_timer_;
   }
 
   DVLOG(1) << "FindNextAck found next_acked_:" << transfer->sender->next_acked
@@ -308,7 +308,7 @@
            << largest_observed.send_time.ToDebuggingValue()
            << " to ack_time:" << largest_observed.ack_time.ToDebuggingValue();
   QuicTime::Delta measured_rtt =
-      largest_observed.ack_time.Subtract(largest_observed.send_time);
+      largest_observed.ack_time - largest_observed.send_time;
   DCHECK_GE(measured_rtt.ToMicroseconds(), rtt_.ToMicroseconds());
   sender->rtt_stats->UpdateRtt(measured_rtt, QuicTime::Delta::Zero(),
                                clock_->Now());
@@ -324,8 +324,7 @@
   transfer->bytes_lost += lost_packets.size() * kPacketSize;
   if (transfer->bytes_acked >= transfer->num_bytes) {
     // Remove completed transfers and record transfer bandwidth.
-    QuicTime::Delta transfer_time =
-        clock_->Now().Subtract(transfer->start_time);
+    QuicTime::Delta transfer_time = clock_->Now() - transfer->start_time;
     sender->last_transfer_loss_rate =
         static_cast<float>(transfer->bytes_lost) /
         (transfer->bytes_lost + transfer->bytes_acked);
@@ -373,14 +372,14 @@
     // If the number of bytes in flight are less than the bdp, there's
     // no buffering delay.  Bytes lost from the buffer are not counted.
     QuicByteCount bdp = bandwidth_.ToBytesPerPeriod(rtt_);
-    QuicTime ack_time = clock_->Now().Add(rtt_).Add(sender->additional_rtt);
+    QuicTime ack_time = clock_->Now() + rtt_ + sender->additional_rtt;
     if (kPacketSize > bdp) {
-      ack_time = ack_time.Add(bandwidth_.TransferTime(kPacketSize - bdp));
+      ack_time = ack_time + bandwidth_.TransferTime(kPacketSize - bdp);
     }
     QuicTime queue_ack_time = sent_packets_.empty()
                                   ? QuicTime::Zero()
-                                  : sent_packets_.back().ack_time.Add(
-                                        bandwidth_.TransferTime(kPacketSize));
+                                  : sent_packets_.back().ack_time +
+                                        bandwidth_.TransferTime(kPacketSize);
     ack_time = QuicTime::Max(ack_time, queue_ack_time);
     sent_packets_.push_back(SentPacket(sender->last_sent, clock_->Now(),
                                        ack_time, packet_lost, transfer));
diff --git a/net/quic/congestion_control/tcp_cubic_sender_base.cc b/net/quic/congestion_control/tcp_cubic_sender_base.cc
index 9ab49e92..539eadc 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_base.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_base.cc
@@ -243,8 +243,7 @@
   if (rtt_stats_->smoothed_rtt().IsZero()) {
     return QuicTime::Delta::Zero();
   }
-  return rtt_stats_->smoothed_rtt().Add(
-      rtt_stats_->mean_deviation().Multiply(4));
+  return rtt_stats_->smoothed_rtt() + 4 * rtt_stats_->mean_deviation();
 }
 
 bool TcpCubicSenderBase::InSlowStart() const {
diff --git a/net/quic/congestion_control/tcp_cubic_sender_bytes.cc b/net/quic/congestion_control/tcp_cubic_sender_bytes.cc
index 012bf04..88f02e2 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_bytes.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_bytes.cc
@@ -80,12 +80,6 @@
   cubic_.SetNumConnections(num_connections_);
 }
 
-void TcpCubicSenderBytes::SetMaxCongestionWindow(
-    QuicByteCount max_congestion_window) {
-  DCHECK(!FLAGS_quic_ignore_srbf);
-  max_congestion_window_ = max_congestion_window;
-}
-
 void TcpCubicSenderBytes::ExitSlowstart() {
   slowstart_threshold_ = congestion_window_;
 }
@@ -123,8 +117,7 @@
   // TODO(jri): Separate out all of slow start into a separate class.
   if (slow_start_large_reduction_ && InSlowStart()) {
     DCHECK_LT(kDefaultTCPMSS, congestion_window_);
-    if (FLAGS_quic_sslr_limit_reduction &&
-        congestion_window_ >= 2 * initial_tcp_congestion_window_) {
+    if (congestion_window_ >= 2 * initial_tcp_congestion_window_) {
       min_slow_start_exit_window_ = congestion_window_ / 2;
     }
     congestion_window_ = congestion_window_ - kDefaultTCPMSS;
diff --git a/net/quic/congestion_control/tcp_cubic_sender_bytes.h b/net/quic/congestion_control/tcp_cubic_sender_bytes.h
index e7a0765..375b572 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_bytes.h
+++ b/net/quic/congestion_control/tcp_cubic_sender_bytes.h
@@ -40,7 +40,6 @@
 
   // Start implementation of SendAlgorithmInterface.
   void SetNumEmulatedConnections(int num_connections) override;
-  void SetMaxCongestionWindow(QuicByteCount max_congestion_window) override;
   void OnConnectionMigration() override;
   QuicByteCount GetCongestionWindow() const override;
   QuicByteCount GetSlowStartThreshold() const override;
diff --git a/net/quic/congestion_control/tcp_cubic_sender_bytes_test.cc b/net/quic/congestion_control/tcp_cubic_sender_bytes_test.cc
index 9c33e1d..6415172f 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_bytes_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_bytes_test.cc
@@ -232,7 +232,6 @@
 }
 
 TEST_F(TcpCubicSenderBytesTest, SlowStartPacketLossWithLargeReduction) {
-  FLAGS_quic_sslr_limit_reduction = true;
   QuicConfig config;
   QuicTagVector options;
   options.push_back(kSSLR);
@@ -327,7 +326,6 @@
 }
 
 TEST_F(TcpCubicSenderBytesTest, SlowStartPacketLossWithMaxHalfReduction) {
-  FLAGS_quic_sslr_limit_reduction = true;
   QuicConfig config;
   QuicTagVector options;
   options.push_back(kSSLR);
@@ -876,7 +874,6 @@
 }
 
 TEST_F(TcpCubicSenderBytesTest, DefaultMaxCwnd) {
-  ValueRestore<bool> old_flag(&FLAGS_quic_ignore_srbf, true);
   RttStats rtt_stats;
   QuicConnectionStats stats;
   std::unique_ptr<SendAlgorithmInterface> sender(SendAlgorithmInterface::Create(
diff --git a/net/quic/congestion_control/tcp_cubic_sender_packets.cc b/net/quic/congestion_control/tcp_cubic_sender_packets.cc
index 33960df..65dae271 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_packets.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_packets.cc
@@ -78,12 +78,6 @@
   cubic_.SetNumConnections(num_connections_);
 }
 
-void TcpCubicSenderPackets::SetMaxCongestionWindow(
-    QuicByteCount max_congestion_window) {
-  DCHECK(!FLAGS_quic_ignore_srbf);
-  max_tcp_congestion_window_ = max_congestion_window / kDefaultTCPMSS;
-}
-
 void TcpCubicSenderPackets::ExitSlowstart() {
   slowstart_threshold_ = congestion_window_;
 }
@@ -125,8 +119,7 @@
   // TODO(jri): Separate out all of slow start into a separate class.
   if (slow_start_large_reduction_ && InSlowStart()) {
     DCHECK_LT(1u, congestion_window_);
-    if (FLAGS_quic_sslr_limit_reduction &&
-        congestion_window_ >= 2 * initial_tcp_congestion_window_) {
+    if (congestion_window_ >= 2 * initial_tcp_congestion_window_) {
       min_slow_start_exit_window_ = congestion_window_ / 2;
     }
     congestion_window_ = congestion_window_ - 1;
diff --git a/net/quic/congestion_control/tcp_cubic_sender_packets.h b/net/quic/congestion_control/tcp_cubic_sender_packets.h
index 610e75e1..2fe630f 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_packets.h
+++ b/net/quic/congestion_control/tcp_cubic_sender_packets.h
@@ -42,7 +42,6 @@
 
   // Start implementation of SendAlgorithmInterface.
   void SetNumEmulatedConnections(int num_connections) override;
-  void SetMaxCongestionWindow(QuicByteCount max_congestion_window) override;
   void OnConnectionMigration() override;
   QuicByteCount GetCongestionWindow() const override;
   QuicByteCount GetSlowStartThreshold() const override;
diff --git a/net/quic/congestion_control/tcp_cubic_sender_packets_test.cc b/net/quic/congestion_control/tcp_cubic_sender_packets_test.cc
index 91094a6..57cda3f 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_packets_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_packets_test.cc
@@ -243,7 +243,6 @@
 }
 
 TEST_F(TcpCubicSenderPacketsTest, SlowStartPacketLossWithLargeReduction) {
-  FLAGS_quic_sslr_limit_reduction = true;
   QuicConfig config;
   QuicTagVector options;
   options.push_back(kSSLR);
@@ -338,7 +337,6 @@
 }
 
 TEST_F(TcpCubicSenderPacketsTest, SlowStartPacketLossWithMaxHalfReduction) {
-  FLAGS_quic_sslr_limit_reduction = true;
   QuicConfig config;
   QuicTagVector options;
   options.push_back(kSSLR);
@@ -1028,7 +1026,6 @@
 }
 
 TEST_F(TcpCubicSenderPacketsTest, DefaultMaxCwnd) {
-  ValueRestore<bool> old_flag(&FLAGS_quic_ignore_srbf, true);
   RttStats rtt_stats;
   QuicConnectionStats stats;
   std::unique_ptr<SendAlgorithmInterface> sender(SendAlgorithmInterface::Create(
diff --git a/net/quic/congestion_control/windowed_filter.h b/net/quic/congestion_control/windowed_filter.h
index 9c2ce1a..50a6b1c 100644
--- a/net/quic/congestion_control/windowed_filter.h
+++ b/net/quic/congestion_control/windowed_filter.h
@@ -51,29 +51,39 @@
 };
 
 // Use the following to construct a windowed filter object of type T.
-// For a min filter: WindowedFilter<T, MinFilter<T>> ObjectName;
-// For a max filter: WindowedFilter<T, MaxFilter<T>> ObjectName;
-template <class T, class Compare>
+// For example, a min filter using QuicTime as the time type:
+//   WindowedFilter<T, MinFilter<T>, QuicTime, QuicTime::Delta> ObjectName;
+// A max filter using 64-bit integers as the time type:
+//   WindowedFilter<T, MaxFilter<T>, uint64_t, int64_t> ObjectName;
+// Specifically, this template takes four arguments:
+// 1. T -- type of the measurement that is being filtered.
+// 2. Compare -- MinFilter<T> or MaxFilter<T>, depending on the type of filter
+//    desired.
+// 3. TimeT -- the type used to represent timestamps.
+// 4. TimeDeltaT -- the type used to represent continuous time intervals between
+//    two timestamps.  Has to be the type of (a - b) if both |a| and |b| are
+//    of type TimeT.
+template <class T, class Compare, typename TimeT, typename TimeDeltaT>
 class WindowedFilter {
  public:
   // |window_length| is the period after which a best estimate expires.
   // |zero_value| is used as the uninitialized value for objects of T.
   // Importantly, |zero_value| should be an invalid value for a true sample.
-  WindowedFilter(QuicTime::Delta window_length, T zero_value)
+  WindowedFilter(TimeDeltaT window_length, T zero_value, TimeT zero_time)
       : window_length_(window_length),
         zero_value_(zero_value),
-        estimates_{Sample(zero_value_, QuicTime::Zero()),
-                   Sample(zero_value_, QuicTime::Zero()),
-                   Sample(zero_value_, QuicTime::Zero())} {}
+        estimates_{Sample(zero_value_, zero_time),
+                   Sample(zero_value_, zero_time),
+                   Sample(zero_value_, zero_time)} {}
 
   // Updates best estimates with |sample|, and expires and updates best
   // estimates as necessary.
-  void Update(T new_sample, QuicTime new_time) {
+  void Update(T new_sample, TimeT new_time) {
     // Reset all estimates if they have not yet been initialized, if new sample
     // is a new best, or if the newest recorded estimate is too old.
     if (estimates_[0].sample == zero_value_ ||
         Compare()(new_sample, estimates_[0].sample) ||
-        new_time.Subtract(estimates_[2].time) > window_length_) {
+        new_time - estimates_[2].time > window_length_) {
       Reset(new_sample, new_time);
       return;
     }
@@ -86,7 +96,7 @@
     }
 
     // Expire and update estimates as necessary.
-    if (new_time.Subtract(estimates_[0].time) > window_length_) {
+    if (new_time - estimates_[0].time > window_length_) {
       // The best estimate hasn't been updated for an entire window, so promote
       // second and third best estimates.
       estimates_[0] = estimates_[1];
@@ -96,14 +106,14 @@
       // outside the window as well, since it may also have been recorded a
       // long time ago. Don't need to iterate once more since we cover that
       // case at the beginning of the method.
-      if (new_time.Subtract(estimates_[0].time) > window_length_) {
+      if (new_time - estimates_[0].time > window_length_) {
         estimates_[0] = estimates_[1];
         estimates_[1] = estimates_[2];
       }
       return;
     }
     if (estimates_[1].sample == estimates_[0].sample &&
-        new_time.Subtract(estimates_[1].time) > window_length_ >> 2) {
+        new_time - estimates_[1].time > window_length_ >> 2) {
       // A quarter of the window has passed without a better sample, so the
       // second-best estimate is taken from the second quarter of the window.
       estimates_[2] = estimates_[1] = Sample(new_sample, new_time);
@@ -111,7 +121,7 @@
     }
 
     if (estimates_[2].sample == estimates_[1].sample &&
-        new_time.Subtract(estimates_[2].time) > window_length_ >> 1) {
+        new_time - estimates_[2].time > window_length_ >> 1) {
       // We've passed a half of the window without a better estimate, so take
       // a third-best estimate from the second half of the window.
       estimates_[2] = Sample(new_sample, new_time);
@@ -119,7 +129,7 @@
   }
 
   // Resets all estimates to new sample.
-  void Reset(T new_sample, QuicTime new_time) {
+  void Reset(T new_sample, TimeT new_time) {
     estimates_[0] = estimates_[1] = estimates_[2] =
         Sample(new_sample, new_time);
   }
@@ -131,14 +141,14 @@
  private:
   struct Sample {
     T sample;
-    QuicTime time;
-    Sample(T init_sample, QuicTime init_time)
+    TimeT time;
+    Sample(T init_sample, TimeT init_time)
         : sample(init_sample), time(init_time) {}
   };
 
-  QuicTime::Delta window_length_;  // Time length of window.
-  T zero_value_;                   // Uninitialized value of T.
-  Sample estimates_[3];            // Best estimate is element 0.
+  TimeDeltaT window_length_;  // Time length of window.
+  T zero_value_;              // Uninitialized value of T.
+  Sample estimates_[3];       // Best estimate is element 0.
 };
 
 }  // namespace net
diff --git a/net/quic/congestion_control/windowed_filter_test.cc b/net/quic/congestion_control/windowed_filter_test.cc
index 25870b86..fd540d0c 100644
--- a/net/quic/congestion_control/windowed_filter_test.cc
+++ b/net/quic/congestion_control/windowed_filter_test.cc
@@ -19,9 +19,11 @@
   // Set the window to 99ms, so 25ms is more than a quarter rtt.
   WindowedFilterTest()
       : windowed_min_rtt_(QuicTime::Delta::FromMilliseconds(99),
-                          QuicTime::Delta::Zero()),
+                          QuicTime::Delta::Zero(),
+                          QuicTime::Zero()),
         windowed_max_bw_(QuicTime::Delta::FromMilliseconds(99),
-                         QuicBandwidth::Zero()) {}
+                         QuicBandwidth::Zero(),
+                         QuicTime::Zero()) {}
 
   // Sets up windowed_min_rtt_ to have the following values:
   // Best = 20ms, recorded at 25ms
@@ -37,8 +39,8 @@
               << " " << windowed_min_rtt_.GetBest().ToMilliseconds() << " "
               << windowed_min_rtt_.GetSecondBest().ToMilliseconds() << " "
               << windowed_min_rtt_.GetThirdBest().ToMilliseconds();
-      now = now.Add(QuicTime::Delta::FromMilliseconds(25));
-      rtt_sample = rtt_sample.Add(QuicTime::Delta::FromMilliseconds(10));
+      now = now + QuicTime::Delta::FromMilliseconds(25);
+      rtt_sample = rtt_sample + QuicTime::Delta::FromMilliseconds(10);
     }
     EXPECT_EQ(QuicTime::Delta::FromMilliseconds(20),
               windowed_min_rtt_.GetBest());
@@ -62,7 +64,7 @@
               << " " << windowed_max_bw_.GetBest().ToBitsPerSecond() << " "
               << windowed_max_bw_.GetSecondBest().ToBitsPerSecond() << " "
               << windowed_max_bw_.GetThirdBest().ToBitsPerSecond();
-      now = now.Add(QuicTime::Delta::FromMilliseconds(25));
+      now = now + QuicTime::Delta::FromMilliseconds(25);
       bw_sample = bw_sample.Subtract(QuicBandwidth::FromBitsPerSecond(100));
     }
     EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(900),
@@ -74,10 +76,31 @@
   }
 
  protected:
-  WindowedFilter<QuicTime::Delta, MinFilter<QuicTime::Delta>> windowed_min_rtt_;
-  WindowedFilter<QuicBandwidth, MaxFilter<QuicBandwidth>> windowed_max_bw_;
+  WindowedFilter<QuicTime::Delta,
+                 MinFilter<QuicTime::Delta>,
+                 QuicTime,
+                 QuicTime::Delta>
+      windowed_min_rtt_;
+  WindowedFilter<QuicBandwidth,
+                 MaxFilter<QuicBandwidth>,
+                 QuicTime,
+                 QuicTime::Delta>
+      windowed_max_bw_;
 };
 
+namespace {
+// Test helper function: updates the filter with a lot of small values in order
+// to ensure that it is not susceptible to noise.
+void UpdateWithIrrelevantSamples(
+    WindowedFilter<uint64_t, MaxFilter<uint64_t>, uint64_t, uint64_t>* filter,
+    uint64_t max_value,
+    uint64_t time) {
+  for (uint64_t i = 0; i < 1000; i++) {
+    filter->Update(i % max_value, time);
+  }
+}
+}  // namespace
+
 TEST_F(WindowedFilterTest, UninitializedEstimates) {
   EXPECT_EQ(QuicTime::Delta::Zero(), windowed_min_rtt_.GetBest());
   EXPECT_EQ(QuicTime::Delta::Zero(), windowed_min_rtt_.GetSecondBest());
@@ -96,8 +119,8 @@
   // Gradually increase the rtt samples and ensure the windowed min rtt starts
   // rising.
   for (int i = 0; i < 6; ++i) {
-    now = now.Add(QuicTime::Delta::FromMilliseconds(25));
-    rtt_sample = rtt_sample.Add(QuicTime::Delta::FromMilliseconds(10));
+    now = now + QuicTime::Delta::FromMilliseconds(25);
+    rtt_sample = rtt_sample + QuicTime::Delta::FromMilliseconds(10);
     windowed_min_rtt_.Update(rtt_sample, now);
     VLOG(1) << "i: " << i << " sample: " << rtt_sample.ToMilliseconds()
             << " mins: "
@@ -126,7 +149,7 @@
   // Gradually decrease the bw samples and ensure the windowed max bw starts
   // decreasing.
   for (int i = 0; i < 6; ++i) {
-    now = now.Add(QuicTime::Delta::FromMilliseconds(25));
+    now = now + QuicTime::Delta::FromMilliseconds(25);
     bw_sample = bw_sample.Subtract(QuicBandwidth::FromBitsPerSecond(100));
     windowed_max_bw_.Update(bw_sample, now);
     VLOG(1) << "i: " << i << " sample: " << bw_sample.ToBitsPerSecond()
@@ -150,14 +173,15 @@
 TEST_F(WindowedFilterTest, SampleChangesThirdBestMin) {
   InitializeMinFilter();
   // RTT sample lower than the third-choice min-rtt sets that, but nothing else.
-  QuicTime::Delta rtt_sample = windowed_min_rtt_.GetThirdBest().Subtract(
-      QuicTime::Delta::FromMilliseconds(5));
+  QuicTime::Delta rtt_sample =
+      windowed_min_rtt_.GetThirdBest() - QuicTime::Delta::FromMilliseconds(5);
   // This assert is necessary to avoid triggering -Wstrict-overflow
   // See crbug/616957
   ASSERT_GT(windowed_min_rtt_.GetThirdBest(),
             QuicTime::Delta::FromMilliseconds(5));
   // Latest sample was recorded at 100ms.
-  QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(101));
+  QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101);
+  windowed_min_rtt_.Update(rtt_sample, now);
   windowed_min_rtt_.Update(rtt_sample, now);
   EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
   EXPECT_EQ(QuicTime::Delta::FromMilliseconds(40),
@@ -171,7 +195,7 @@
   QuicBandwidth bw_sample =
       windowed_max_bw_.GetThirdBest().Add(QuicBandwidth::FromBitsPerSecond(50));
   // Latest sample was recorded at 100ms.
-  QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(101));
+  QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101);
   windowed_max_bw_.Update(bw_sample, now);
   EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
   EXPECT_EQ(QuicBandwidth::FromBitsPerSecond(700),
@@ -183,14 +207,14 @@
   InitializeMinFilter();
   // RTT sample lower than the second-choice min sets that and also
   // the third-choice min.
-  QuicTime::Delta rtt_sample = windowed_min_rtt_.GetSecondBest().Subtract(
-      QuicTime::Delta::FromMilliseconds(5));
+  QuicTime::Delta rtt_sample =
+      windowed_min_rtt_.GetSecondBest() - QuicTime::Delta::FromMilliseconds(5);
   // This assert is necessary to avoid triggering -Wstrict-overflow
   // See crbug/616957
   ASSERT_GT(windowed_min_rtt_.GetSecondBest(),
             QuicTime::Delta::FromMilliseconds(5));
   // Latest sample was recorded at 100ms.
-  QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(101));
+  QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101);
   windowed_min_rtt_.Update(rtt_sample, now);
   EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
   EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetSecondBest());
@@ -204,7 +228,7 @@
   QuicBandwidth bw_sample = windowed_max_bw_.GetSecondBest().Add(
       QuicBandwidth::FromBitsPerSecond(50));
   // Latest sample was recorded at 100ms.
-  QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(101));
+  QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101);
   windowed_max_bw_.Update(bw_sample, now);
   EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
   EXPECT_EQ(bw_sample, windowed_max_bw_.GetSecondBest());
@@ -215,13 +239,13 @@
   InitializeMinFilter();
   // RTT sample lower than the first-choice min-rtt sets that and also
   // the second and third-choice mins.
-  QuicTime::Delta rtt_sample = windowed_min_rtt_.GetBest().Subtract(
-      QuicTime::Delta::FromMilliseconds(5));
+  QuicTime::Delta rtt_sample =
+      windowed_min_rtt_.GetBest() - QuicTime::Delta::FromMilliseconds(5);
   // This assert is necessary to avoid triggering -Wstrict-overflow
   // See crbug/616957
   ASSERT_GT(windowed_min_rtt_.GetBest(), QuicTime::Delta::FromMilliseconds(5));
   // Latest sample was recorded at 100ms.
-  QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(101));
+  QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101);
   windowed_min_rtt_.Update(rtt_sample, now);
   EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
   EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetSecondBest());
@@ -235,7 +259,7 @@
   QuicBandwidth bw_sample =
       windowed_max_bw_.GetBest().Add(QuicBandwidth::FromBitsPerSecond(50));
   // Latest sample was recorded at 100ms.
-  QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(101));
+  QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(101);
   windowed_max_bw_.Update(bw_sample, now);
   EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
   EXPECT_EQ(bw_sample, windowed_max_bw_.GetSecondBest());
@@ -247,9 +271,9 @@
   QuicTime::Delta old_third_best = windowed_min_rtt_.GetThirdBest();
   QuicTime::Delta old_second_best = windowed_min_rtt_.GetSecondBest();
   QuicTime::Delta rtt_sample =
-      old_third_best.Add(QuicTime::Delta::FromMilliseconds(5));
+      old_third_best + QuicTime::Delta::FromMilliseconds(5);
   // Best min sample was recorded at 25ms, so expiry time is 124ms.
-  QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(125));
+  QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(125);
   windowed_min_rtt_.Update(rtt_sample, now);
   EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
   EXPECT_EQ(old_third_best, windowed_min_rtt_.GetSecondBest());
@@ -263,7 +287,7 @@
   QuicBandwidth bw_sample =
       old_third_best.Subtract(QuicBandwidth::FromBitsPerSecond(50));
   // Best max sample was recorded at 25ms, so expiry time is 124ms.
-  QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(125));
+  QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(125);
   windowed_max_bw_.Update(bw_sample, now);
   EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
   EXPECT_EQ(old_third_best, windowed_max_bw_.GetSecondBest());
@@ -274,9 +298,9 @@
   InitializeMinFilter();
   QuicTime::Delta old_third_best = windowed_min_rtt_.GetThirdBest();
   QuicTime::Delta rtt_sample =
-      old_third_best.Add(QuicTime::Delta::FromMilliseconds(5));
+      old_third_best + QuicTime::Delta::FromMilliseconds(5);
   // Second best min sample was recorded at 75ms, so expiry time is 174ms.
-  QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(175));
+  QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(175);
   windowed_min_rtt_.Update(rtt_sample, now);
   EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
   EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetSecondBest());
@@ -289,7 +313,7 @@
   QuicBandwidth bw_sample =
       old_third_best.Subtract(QuicBandwidth::FromBitsPerSecond(50));
   // Second best max sample was recorded at 75ms, so expiry time is 174ms.
-  QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(175));
+  QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(175);
   windowed_max_bw_.Update(bw_sample, now);
   EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
   EXPECT_EQ(bw_sample, windowed_max_bw_.GetSecondBest());
@@ -298,15 +322,15 @@
 
 TEST_F(WindowedFilterTest, ExpireAllMins) {
   InitializeMinFilter();
-  QuicTime::Delta rtt_sample = windowed_min_rtt_.GetThirdBest().Add(
-      QuicTime::Delta::FromMilliseconds(5));
+  QuicTime::Delta rtt_sample =
+      windowed_min_rtt_.GetThirdBest() + QuicTime::Delta::FromMilliseconds(5);
   // This assert is necessary to avoid triggering -Wstrict-overflow
   // See crbug/616957
   ASSERT_LT(windowed_min_rtt_.GetThirdBest(),
-            QuicTime::Delta::Infinite().Subtract(
-                QuicTime::Delta::FromMilliseconds(5)));
+            QuicTime::Delta::Infinite() - QuicTime::Delta::FromMilliseconds(5));
+
   // Third best min sample was recorded at 100ms, so expiry time is 199ms.
-  QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(200));
+  QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(200);
   windowed_min_rtt_.Update(rtt_sample, now);
   EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetThirdBest());
   EXPECT_EQ(rtt_sample, windowed_min_rtt_.GetSecondBest());
@@ -318,13 +342,51 @@
   QuicBandwidth bw_sample = windowed_max_bw_.GetThirdBest().Subtract(
       QuicBandwidth::FromBitsPerSecond(50));
   // Third best max sample was recorded at 100ms, so expiry time is 199ms.
-  QuicTime now = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(200));
+  QuicTime now = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(200);
   windowed_max_bw_.Update(bw_sample, now);
   EXPECT_EQ(bw_sample, windowed_max_bw_.GetThirdBest());
   EXPECT_EQ(bw_sample, windowed_max_bw_.GetSecondBest());
   EXPECT_EQ(bw_sample, windowed_max_bw_.GetBest());
 }
 
+// Test the windowed filter where the time used is an exact counter instead of a
+// timestamp.  This is useful if, for example, the time is measured in round
+// trips.
+TEST_F(WindowedFilterTest, ExpireCounterBasedMax) {
+  // Create a window which starts at t = 0 and expires after two cycles.
+  WindowedFilter<uint64_t, MaxFilter<uint64_t>, uint64_t, uint64_t> max_filter(
+      2, 0, 0);
+
+  // Insert 50000 at t = 1.
+  const uint64_t kBest = 50000;
+  max_filter.Update(50000, 1);
+  EXPECT_EQ(kBest, max_filter.GetBest());
+  UpdateWithIrrelevantSamples(&max_filter, 20, 1);
+  EXPECT_EQ(kBest, max_filter.GetBest());
+
+  // Insert 40000 at t = 2.  Nothing is expected to expire.
+  max_filter.Update(40000, 2);
+  EXPECT_EQ(kBest, max_filter.GetBest());
+  UpdateWithIrrelevantSamples(&max_filter, 20, 2);
+  EXPECT_EQ(kBest, max_filter.GetBest());
+
+  // Insert 30000 at t = 3.  Nothing is expected to expire yet.
+  max_filter.Update(30000, 3);
+  EXPECT_EQ(kBest, max_filter.GetBest());
+  UpdateWithIrrelevantSamples(&max_filter, 20, 3);
+  EXPECT_EQ(kBest, max_filter.GetBest());
+  VLOG(0) << max_filter.GetSecondBest();
+  VLOG(0) << max_filter.GetThirdBest();
+
+  // Insert 20000 at t = 4.  50000 at t = 1 expires, so 40000 becomes the new
+  // maximum.
+  const uint64_t kNewBest = 40000;
+  max_filter.Update(20000, 4);
+  EXPECT_EQ(kNewBest, max_filter.GetBest());
+  UpdateWithIrrelevantSamples(&max_filter, 20, 4);
+  EXPECT_EQ(kNewBest, max_filter.GetBest());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index 4c47af0..0b8ddcc 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -126,6 +126,8 @@
 const QuicTag kMTUH = TAG('M', 'T', 'U', 'H');  // High-target MTU discovery.
 const QuicTag kMTUL = TAG('M', 'T', 'U', 'L');  // Low-target MTU discovery.
 
+const QuicTag kFHOL = TAG('F', 'H', 'O', 'L');   // Force head of line blocking.
+
 // Proof types (i.e. certificate types)
 // NOTE: although it would be silly to do so, specifying both kX509 and kX59R
 // is allowed and is equivalent to specifying only kX509.
diff --git a/net/quic/crypto/crypto_server_test.cc b/net/quic/crypto/crypto_server_test.cc
index 2e73826..91a4458b 100644
--- a/net/quic/crypto/crypto_server_test.cc
+++ b/net/quic/crypto/crypto_server_test.cc
@@ -149,6 +149,7 @@
     // clang-format off
     CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
         "CHLO",
+        "PDMD", "X509",
         "AEAD", "AESG",
         "KEXS", "C255",
         "PUBS", pub_hex_.c_str(),
@@ -399,6 +400,7 @@
     // clang-format off
     CryptoHandshakeMessage msg = CryptoTestUtils::Message(
         "CHLO",
+        "PDMD", "X509",
         "SNI", kBadSNIs[i],
         "VER\0", client_version_string_.c_str(),
         "$padding", static_cast<int>(kClientHelloMinimumSize),
@@ -448,6 +450,7 @@
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "AEAD", "AESG",
       "KEXS", "C255",
       "PUBS", pub_hex_.c_str(),
@@ -477,6 +480,7 @@
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "AEAD", "AESG",
       "KEXS", "C255",
       "PUBS", pub_hex_.c_str(),
@@ -508,6 +512,7 @@
   // clang-format off
   ShouldFailMentioning("too small", CryptoTestUtils::Message(
         "CHLO",
+        "PDMD", "X509",
         "VER\0", client_version_string_.c_str(),
         nullptr));
   // clang-format on
@@ -531,6 +536,7 @@
     // clang-format off
     CryptoHandshakeMessage msg = CryptoTestUtils::Message(
         "CHLO",
+        "PDMD", "X509",
         "STK", kBadSourceAddressTokens[i],
         "VER\0", client_version_string_.c_str(),
         "$padding", static_cast<int>(kClientHelloMinimumSize), nullptr);
@@ -556,6 +562,7 @@
     // clang-format off
     CryptoHandshakeMessage msg = CryptoTestUtils::Message(
         "CHLO",
+        "PDMD", "X509",
         "NONC", kBadNonces[i],
         "VER\0", client_version_string_.c_str(),
         "$padding", static_cast<int>(kClientHelloMinimumSize),
@@ -570,6 +577,7 @@
     // clang-format off
     CryptoHandshakeMessage msg1 = CryptoTestUtils::Message(
         "CHLO",
+        "PDMD", "X509",
         "AEAD", "AESG",
         "KEXS", "C255",
         "SCID", scid_hex_.c_str(),
@@ -597,6 +605,7 @@
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "VER\0", client_version_string_.c_str(),
       "$padding", static_cast<int>(kClientHelloMinimumSize),
       nullptr);
@@ -610,6 +619,7 @@
   // clang-format off
   CryptoHandshakeMessage msg1 = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "AEAD", "AESG",
       "KEXS", "C255",
       "SCID", scid_hex_.c_str(),
@@ -641,6 +651,7 @@
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "VER\0", bad_version.c_str(),
       "$padding", static_cast<int>(kClientHelloMinimumSize),
       nullptr);
@@ -656,6 +667,7 @@
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "AEAD", "AESG",
       "KEXS", "C255",
       "SCID", (string(1, 'X') + scid_hex_).c_str(),
@@ -678,6 +690,7 @@
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "AEAD", "AESG",
       "KEXS", "C255",
       "SCID", scid_hex_.c_str(),
@@ -701,6 +714,7 @@
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "AEAD", "AESG",
       "KEXS", "C255",
       "SCID", scid_hex_.c_str(),
@@ -724,6 +738,7 @@
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "AEAD", "AESG",
       "KEXS", "C255",
       "SCID", scid_hex_.c_str(),
@@ -758,6 +773,7 @@
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "AEAD", "AESG",
       "KEXS", "C255",
       "SCID", scid_hex_.c_str(),
@@ -836,14 +852,15 @@
       CryptoTestUtils::ProofVerifyContextForTesting());
   std::unique_ptr<ProofVerifyDetails> details;
   string error_details;
-  DummyProofVerifierCallback callback;
+  std::unique_ptr<ProofVerifierCallback> callback(
+      new DummyProofVerifierCallback());
   string chlo_hash;
   CryptoUtils::HashHandshakeMessage(msg, &chlo_hash);
   EXPECT_EQ(QUIC_SUCCESS,
             proof_verifier->VerifyProof(
                 "test.example.com", 443, scfg_str.as_string(), client_version_,
                 chlo_hash, certs, "", proof.as_string(), verify_context.get(),
-                &error_details, &details, &callback));
+                &error_details, &details, std::move(callback)));
 }
 
 TEST_P(CryptoServerTest, RejectInvalidXlct) {
@@ -854,6 +871,7 @@
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "AEAD", "AESG",
       "KEXS", "C255",
       "SCID", scid_hex_.c_str(),
@@ -883,6 +901,7 @@
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "AEAD", "AESG",
       "KEXS", "C255",
       "SCID", scid_hex_.c_str(),
@@ -909,6 +928,7 @@
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "AEAD", "AESG",
       "KEXS", "C255",
       "SCID", scid_hex_.c_str(),
@@ -1021,6 +1041,7 @@
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "VER\0", client_version_string_.c_str(),
       "$padding", static_cast<int>(kClientHelloMinimumSize),
       nullptr);
@@ -1046,6 +1067,7 @@
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "AEAD", "AESG",
       "KEXS", "C255",
       "SCID", scid_hex_.c_str(),
@@ -1070,6 +1092,7 @@
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "AEAD", "AESG",
       "KEXS", "C255",
       "SCID", scid_hex_.c_str(),
@@ -1115,6 +1138,7 @@
   // clang-format off
   CryptoHandshakeMessage msg = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "AEAD", "AESG",
       "KEXS", "C255",
       "SCID", scid_hex_.c_str(),
diff --git a/net/quic/crypto/proof_source.h b/net/quic/crypto/proof_source.h
index 74b9df3c..a03c798f 100644
--- a/net/quic/crypto/proof_source.h
+++ b/net/quic/crypto/proof_source.h
@@ -5,6 +5,7 @@
 #ifndef NET_QUIC_CRYPTO_PROOF_SOURCE_H_
 #define NET_QUIC_CRYPTO_PROOF_SOURCE_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -35,9 +36,36 @@
     DISALLOW_COPY_AND_ASSIGN(Chain);
   };
 
+  // Callback base class for receiving the results of an async call to GetProof.
+  class Callback {
+   public:
+    Callback() {}
+    virtual ~Callback() {}
+
+    // Invoked upon completion of GetProof.
+    //
+    // |ok| indicates whether the operation completed successfully.  If false,
+    // the values of the remaining three arguments are undefined.
+    //
+    // |chain| is a reference-counted pointer to an object representing the
+    // certificate chain.
+    //
+    // |signature| contains the signature of the server config.
+    //
+    // |leaf_cert_sct| holds the signed timestamp (RFC6962) of the leaf cert.
+    virtual void Run(bool ok,
+                     const scoped_refptr<Chain>& chain,
+                     const std::string& signature,
+                     const std::string& leaf_cert_sct) = 0;
+
+   private:
+    Callback(const Callback&) = delete;
+    Callback& operator=(const Callback&) = delete;
+  };
+
   virtual ~ProofSource() {}
 
-  // GetProof finds a certificate chain for |hostname|, sets |out_certs| to
+  // GetProof finds a certificate chain for |hostname|, sets |out_chain| to
   // point to it (in leaf-first order), calculates a signature of
   // |server_config| using that chain and puts the result in |out_signature|.
   //
@@ -52,13 +80,13 @@
   // |out_chain| is reference counted to avoid the (assumed) expense of copying
   // out the certificates.
   //
-  // The number of certificate chains is expected to be small and fixed thus
-  // the ProofSource retains ownership of the contents of |out_certs|. The
+  // The number of certificate chains is expected to be small and fixed, thus
+  // the ProofSource retains ownership of the contents of |out_chain|. The
   // expectation is that they will be cached forever.
   //
   // For version before QUIC_VERSION_30, the signature values should be cached
   // because |server_config| will be somewhat static. However, since they aren't
-  // bounded, the ProofSource may wish to evicit entries from that cache, thus
+  // bounded, the ProofSource may wish to evict entries from that cache, thus
   // the caller takes ownership of |*out_signature|.
   //
   // For QUIC_VERSION_30 and later, the signature depends on |chlo_hash|
@@ -70,6 +98,7 @@
   //
   // |out_leaf_cert_sct| points to the signed timestamp (RFC6962) of the leaf
   // cert.
+  //
   // This function may be called concurrently.
   virtual bool GetProof(const IPAddress& server_ip,
                         const std::string& hostname,
@@ -80,6 +109,18 @@
                         scoped_refptr<Chain>* out_chain,
                         std::string* out_signature,
                         std::string* out_leaf_cert_sct) = 0;
+
+  // Async version of GetProof with identical semantics, except that the results
+  // are delivered to |callback|.  Callers should expect that |callback| might
+  // be invoked synchronously.  The ProofSource takes ownership of |callback| in
+  // any case.
+  virtual void GetProof(const IPAddress& server_ip,
+                        const std::string& hostname,
+                        const std::string& server_config,
+                        QuicVersion quic_version,
+                        base::StringPiece chlo_hash,
+                        bool ecdsa_ok,
+                        std::unique_ptr<Callback> callback) = 0;
 };
 
 }  // namespace net
diff --git a/net/quic/crypto/proof_source_chromium.cc b/net/quic/crypto/proof_source_chromium.cc
index 3a62346..a5c21c58 100644
--- a/net/quic/crypto/proof_source_chromium.cc
+++ b/net/quic/crypto/proof_source_chromium.cc
@@ -151,4 +151,22 @@
   return true;
 }
 
+void ProofSourceChromium::GetProof(const IPAddress& server_ip,
+                                   const std::string& hostname,
+                                   const std::string& server_config,
+                                   QuicVersion quic_version,
+                                   base::StringPiece chlo_hash,
+                                   bool ecdsa_ok,
+                                   std::unique_ptr<Callback> callback) {
+  // As a transitional implementation, just call the synchronous version of
+  // GetProof, then invoke the callback with the results and destroy it.
+  scoped_refptr<ProofSource::Chain> chain;
+  string signature;
+  string leaf_cert_sct;
+  const bool ok =
+      GetProof(server_ip, hostname, server_config, quic_version, chlo_hash,
+               ecdsa_ok, &chain, &signature, &leaf_cert_sct);
+  callback->Run(ok, chain, signature, leaf_cert_sct);
+}
+
 }  // namespace net
diff --git a/net/quic/crypto/proof_source_chromium.h b/net/quic/crypto/proof_source_chromium.h
index f84746e..904bd0d 100644
--- a/net/quic/crypto/proof_source_chromium.h
+++ b/net/quic/crypto/proof_source_chromium.h
@@ -43,6 +43,14 @@
                 std::string* out_signature,
                 std::string* out_leaf_cert_sct) override;
 
+  void GetProof(const IPAddress& server_ip,
+                const std::string& hostname,
+                const std::string& server_config,
+                QuicVersion quic_version,
+                base::StringPiece chlo_hash,
+                bool ecdsa_ok,
+                std::unique_ptr<Callback> callback) override;
+
  private:
   std::unique_ptr<crypto::RSAPrivateKey> private_key_;
   scoped_refptr<ProofSource::Chain> chain_;
diff --git a/net/quic/crypto/proof_test.cc b/net/quic/crypto/proof_test.cc
index 697674c..1b95f65 100644
--- a/net/quic/crypto/proof_test.cc
+++ b/net/quic/crypto/proof_test.cc
@@ -67,21 +67,19 @@
   string error_details;
   std::unique_ptr<ProofVerifyContext> verify_context(
       CryptoTestUtils::ProofVerifyContextForTesting());
-  TestProofVerifierCallback* callback =
-      new TestProofVerifierCallback(&comp_callback, &ok, &error_details);
+  std::unique_ptr<TestProofVerifierCallback> callback(
+      new TestProofVerifierCallback(&comp_callback, &ok, &error_details));
 
   QuicAsyncStatus status = verifier->VerifyProof(
       hostname, port, server_config, quic_version, chlo_hash, certs, "", proof,
-      verify_context.get(), &error_details, &details, callback);
+      verify_context.get(), &error_details, &details, std::move(callback));
 
   switch (status) {
     case QUIC_FAILURE:
-      delete callback;
       ASSERT_FALSE(expected_ok);
       ASSERT_NE("", error_details);
       return;
     case QUIC_SUCCESS:
-      delete callback;
       ASSERT_TRUE(expected_ok);
       ASSERT_EQ("", error_details);
       return;
@@ -105,6 +103,38 @@
   return der_bytes;
 }
 
+class TestCallback : public ProofSource::Callback {
+ public:
+  explicit TestCallback(bool* called,
+                        bool* ok,
+                        scoped_refptr<ProofSource::Chain>* chain,
+                        string* signature,
+                        string* leaf_cert_sct)
+      : called_(called),
+        ok_(ok),
+        chain_(chain),
+        signature_(signature),
+        leaf_cert_sct_(leaf_cert_sct) {}
+
+  void Run(bool ok,
+           const scoped_refptr<ProofSource::Chain>& chain,
+           const string& signature,
+           const string& leaf_cert_sct) override {
+    *ok_ = ok;
+    *chain_ = chain;
+    *signature_ = signature;
+    *leaf_cert_sct_ = leaf_cert_sct;
+    *called_ = true;
+  }
+
+ private:
+  bool* called_;
+  bool* ok_;
+  scoped_refptr<ProofSource::Chain>* chain_;
+  string* signature_;
+  string* leaf_cert_sct_;
+};
+
 class ProofTest : public ::testing::TestWithParam<QuicVersion> {};
 
 }  // namespace
@@ -171,6 +201,43 @@
                   first_chlo_hash, wrong_certs, corrupt_signature, false);
 }
 
+TEST_P(ProofTest, VerifySourceAsync) {
+  std::unique_ptr<ProofSource> source(CryptoTestUtils::ProofSourceForTesting());
+
+  const string server_config = "server config bytes";
+  const string hostname = "test.example.com";
+  const string first_chlo_hash = "first chlo hash bytes";
+  const string second_chlo_hash = "first chlo hash bytes";
+  const QuicVersion quic_version = GetParam();
+  IPAddress server_ip;
+
+  // Call synchronous version
+  scoped_refptr<ProofSource::Chain> expected_chain;
+  string expected_signature;
+  string expected_leaf_cert_sct;
+  ASSERT_TRUE(source->GetProof(server_ip, hostname, server_config, quic_version,
+                               first_chlo_hash, false /* no ECDSA */,
+                               &expected_chain, &expected_signature,
+                               &expected_leaf_cert_sct));
+
+  // Call asynchronous version and compare results
+  bool called = false;
+  bool ok;
+  scoped_refptr<ProofSource::Chain> chain;
+  string signature;
+  string leaf_cert_sct;
+  std::unique_ptr<ProofSource::Callback> cb(
+      new TestCallback(&called, &ok, &chain, &signature, &leaf_cert_sct));
+  source->GetProof(server_ip, hostname, server_config, quic_version,
+                   first_chlo_hash, false /* no ECDSA */, std::move(cb));
+  // TODO(gredner): whan GetProof really invokes the callback asynchronously,
+  // figure out what to do here.
+  ASSERT_TRUE(called);
+  ASSERT_TRUE(ok);
+  EXPECT_THAT(chain->certs, ::testing::ContainerEq(expected_chain->certs));
+  EXPECT_EQ(leaf_cert_sct, expected_leaf_cert_sct);
+}
+
 TEST_P(ProofTest, UseAfterFree) {
   ProofSource* source = CryptoTestUtils::ProofSourceForTesting();
 
diff --git a/net/quic/crypto/proof_verifier.h b/net/quic/crypto/proof_verifier.h
index fc520aa..d05e1dd 100644
--- a/net/quic/crypto/proof_verifier.h
+++ b/net/quic/crypto/proof_verifier.h
@@ -70,7 +70,6 @@
   //
   // This function may also return QUIC_PENDING, in which case the ProofVerifier
   // will call back, on the original thread, via |callback| when complete.
-  // In this case, the ProofVerifier will take ownership of |callback|.
   //
   // The signature uses SHA-256 as the hash function and PSS padding in the
   // case of RSA.
@@ -86,7 +85,7 @@
       const ProofVerifyContext* context,
       std::string* error_details,
       std::unique_ptr<ProofVerifyDetails>* details,
-      ProofVerifierCallback* callback) = 0;
+      std::unique_ptr<ProofVerifierCallback> callback) = 0;
 };
 
 }  // namespace net
diff --git a/net/quic/crypto/proof_verifier_chromium.cc b/net/quic/crypto/proof_verifier_chromium.cc
index 096374a..621eb1f 100644
--- a/net/quic/crypto/proof_verifier_chromium.cc
+++ b/net/quic/crypto/proof_verifier_chromium.cc
@@ -76,7 +76,7 @@
       const std::string& signature,
       std::string* error_details,
       std::unique_ptr<ProofVerifyDetails>* verify_details,
-      ProofVerifierCallback* callback);
+      std::unique_ptr<ProofVerifierCallback> callback);
 
  private:
   enum State {
@@ -180,7 +180,7 @@
     const string& signature,
     std::string* error_details,
     std::unique_ptr<ProofVerifyDetails>* verify_details,
-    ProofVerifierCallback* callback) {
+    std::unique_ptr<ProofVerifierCallback> callback) {
   DCHECK(error_details);
   DCHECK(verify_details);
   DCHECK(callback);
@@ -246,7 +246,7 @@
       *verify_details = std::move(verify_details_);
       return QUIC_SUCCESS;
     case ERR_IO_PENDING:
-      callback_.reset(callback);
+      callback_ = std::move(callback);
       return QUIC_PENDING;
     default:
       *error_details = error_details_;
@@ -491,7 +491,7 @@
     const ProofVerifyContext* verify_context,
     std::string* error_details,
     std::unique_ptr<ProofVerifyDetails>* verify_details,
-    ProofVerifierCallback* callback) {
+    std::unique_ptr<ProofVerifierCallback> callback) {
   if (!verify_context) {
     *error_details = "Missing context";
     return QUIC_FAILURE;
@@ -504,7 +504,7 @@
               chromium_context->cert_verify_flags, chromium_context->net_log));
   QuicAsyncStatus status = job->VerifyProof(
       hostname, port, server_config, quic_version, chlo_hash, certs, cert_sct,
-      signature, error_details, verify_details, callback);
+      signature, error_details, verify_details, std::move(callback));
   if (status == QUIC_PENDING) {
     active_jobs_.insert(job.release());
   }
diff --git a/net/quic/crypto/proof_verifier_chromium.h b/net/quic/crypto/proof_verifier_chromium.h
index fe84992e..b15751c 100644
--- a/net/quic/crypto/proof_verifier_chromium.h
+++ b/net/quic/crypto/proof_verifier_chromium.h
@@ -84,7 +84,7 @@
       const ProofVerifyContext* verify_context,
       std::string* error_details,
       std::unique_ptr<ProofVerifyDetails>* verify_details,
-      ProofVerifierCallback* callback) override;
+      std::unique_ptr<ProofVerifierCallback> callback) override;
 
  private:
   class Job;
diff --git a/net/quic/crypto/proof_verifier_chromium_test.cc b/net/quic/crypto/proof_verifier_chromium_test.cc
index ba881c6..fff1bf6d 100644
--- a/net/quic/crypto/proof_verifier_chromium_test.cc
+++ b/net/quic/crypto/proof_verifier_chromium_test.cc
@@ -233,7 +233,7 @@
   QuicAsyncStatus status = proof_verifier.VerifyProof(
       kTestHostname, kTestPort, kTestConfig, QUIC_VERSION_25, "", certs_, "",
       GetTestSignature(), verify_context_.get(), &error_details_, &details_,
-      callback.get());
+      std::move(callback));
   ASSERT_EQ(QUIC_FAILURE, status);
 }
 
@@ -252,7 +252,7 @@
   QuicAsyncStatus status = proof_verifier.VerifyProof(
       kTestHostname, kTestPort, kTestConfig, QUIC_VERSION_25, "", certs_,
       ct::GetSCTListForTesting(), "", verify_context_.get(), &error_details_,
-      &details_, callback.get());
+      &details_, std::move(callback));
   ASSERT_EQ(QUIC_FAILURE, status);
   CheckSCT(/*sct_expected_ok=*/true);
 }
@@ -272,7 +272,7 @@
   QuicAsyncStatus status = proof_verifier.VerifyProof(
       kTestHostname, kTestPort, kTestConfig, QUIC_VERSION_25, "", certs_,
       ct::GetSCTListWithInvalidSCT(), "", verify_context_.get(),
-      &error_details_, &details_, callback.get());
+      &error_details_, &details_, std::move(callback));
   ASSERT_EQ(QUIC_FAILURE, status);
   CheckSCT(/*sct_expected_ok=*/false);
 }
@@ -290,7 +290,7 @@
   QuicAsyncStatus status = proof_verifier.VerifyProof(
       kTestHostname, kTestPort, kTestConfig, QUIC_VERSION_25, "", certs_, "",
       kTestConfig, verify_context_.get(), &error_details_, &details_,
-      callback.get());
+      std::move(callback));
   ASSERT_EQ(QUIC_FAILURE, status);
 }
 
@@ -320,7 +320,7 @@
   QuicAsyncStatus status = proof_verifier.VerifyProof(
       kTestHostname, kTestPort, kTestConfig, QUIC_VERSION_25, "", certs_, "",
       GetTestSignature(), verify_context_.get(), &error_details_, &details_,
-      callback.get());
+      std::move(callback));
   ASSERT_EQ(QUIC_SUCCESS, status);
 
   ASSERT_TRUE(details_.get());
@@ -356,7 +356,7 @@
   QuicAsyncStatus status = proof_verifier.VerifyProof(
       kTestHostname, kTestPort, kTestConfig, QUIC_VERSION_25, "", certs_, "",
       GetTestSignature(), verify_context_.get(), &error_details_, &details_,
-      callback.get());
+      std::move(callback));
   ASSERT_EQ(QUIC_SUCCESS, status);
 
   ASSERT_TRUE(details_.get());
@@ -391,7 +391,7 @@
   QuicAsyncStatus status = proof_verifier.VerifyProof(
       kTestHostname, kTestPort, kTestConfig, QUIC_VERSION_25, "", certs_, "",
       GetTestSignature(), verify_context_.get(), &error_details_, &details_,
-      callback.get());
+      std::move(callback));
   ASSERT_EQ(QUIC_SUCCESS, status);
 
   ASSERT_TRUE(details_.get());
@@ -436,7 +436,7 @@
   QuicAsyncStatus status = proof_verifier.VerifyProof(
       kTestHostname, kTestPort, kTestConfig, QUIC_VERSION_25, "", certs_, "",
       GetTestSignature(), verify_context_.get(), &error_details_, &details_,
-      callback.get());
+      std::move(callback));
   ASSERT_EQ(QUIC_FAILURE, status);
 
   ASSERT_TRUE(details_.get());
@@ -477,7 +477,7 @@
   QuicAsyncStatus status = proof_verifier.VerifyProof(
       kTestHostname, kTestPort, kTestConfig, QUIC_VERSION_25, "", certs_, "",
       GetTestSignature(), verify_context_.get(), &error_details_, &details_,
-      callback.get());
+      std::move(callback));
   ASSERT_EQ(QUIC_SUCCESS, status);
 
   ASSERT_TRUE(details_.get());
@@ -523,7 +523,7 @@
   QuicAsyncStatus status = proof_verifier.VerifyProof(
       kTestHostname, kTestPort, kTestConfig, QUIC_VERSION_25, "", certs_, "",
       GetTestSignature(), verify_context_.get(), &error_details_, &details_,
-      callback.get());
+      std::move(callback));
   ASSERT_EQ(QUIC_FAILURE, status);
 
   ASSERT_TRUE(details_.get());
@@ -575,7 +575,7 @@
   QuicAsyncStatus status = proof_verifier.VerifyProof(
       kTestHostname, kTestPort, kTestConfig, QUIC_VERSION_25, "", certs_, "",
       GetTestSignature(), verify_context_.get(), &error_details_, &details_,
-      callback.get());
+      std::move(callback));
   ASSERT_EQ(QUIC_FAILURE, status);
 
   ASSERT_TRUE(details_.get());
diff --git a/net/quic/crypto/quic_crypto_client_config.cc b/net/quic/crypto/quic_crypto_client_config.cc
index 53c60c2..b31a737 100644
--- a/net/quic/crypto/quic_crypto_client_config.cc
+++ b/net/quic/crypto/quic_crypto_client_config.cc
@@ -413,6 +413,7 @@
     const QuicVersion preferred_version,
     const CachedState* cached,
     QuicRandom* rand,
+    bool demand_x509_proof,
     QuicCryptoNegotiatedParameters* out_params,
     CryptoHandshakeMessage* out) const {
   out->set_tag(kCHLO);
@@ -429,10 +430,6 @@
     out->SetStringPiece(kUAID, user_agent_id_);
   }
 
-  char proof_nonce[32];
-  rand->RandBytes(proof_nonce, arraysize(proof_nonce));
-  out->SetStringPiece(kNONP, StringPiece(proof_nonce, arraysize(proof_nonce)));
-
   // Even though this is an inchoate CHLO, send the SCID so that
   // the STK can be validated by the server.
   const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
@@ -447,6 +444,14 @@
     out->SetStringPiece(kSourceAddressTokenTag, cached->source_address_token());
   }
 
+  if (!demand_x509_proof) {
+    return;
+  }
+
+  char proof_nonce[32];
+  rand->RandBytes(proof_nonce, arraysize(proof_nonce));
+  out->SetStringPiece(kNONP, StringPiece(proof_nonce, arraysize(proof_nonce)));
+
   if (disable_ecdsa_) {
     out->SetVector(kPDMD, QuicTagVector{kX59R});
   } else {
@@ -493,7 +498,7 @@
   DCHECK(error_details != nullptr);
 
   FillInchoateClientHello(server_id, preferred_version, cached, rand,
-                          out_params, out);
+                          /* demand_x509_proof= */ true, out_params, out);
 
   const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
   if (!scfg) {
diff --git a/net/quic/crypto/quic_crypto_client_config.h b/net/quic/crypto/quic_crypto_client_config.h
index b306392..6a7a5c99 100644
--- a/net/quic/crypto/quic_crypto_client_config.h
+++ b/net/quic/crypto/quic_crypto_client_config.h
@@ -210,11 +210,14 @@
   // to store the cached certs that were sent as hints to the server in
   // |out_params->cached_certs|. |preferred_version| is the version of the
   // QUIC protocol that this client chose to use initially. This allows the
-  // server to detect downgrade attacks.
+  // server to detect downgrade attacks.  If |demand_x509_proof| is true,
+  // then |out| will include an X509 proof demand, and the associated
+  // certificate related fields.
   void FillInchoateClientHello(const QuicServerId& server_id,
                                const QuicVersion preferred_version,
                                const CachedState* cached,
                                QuicRandom* rand,
+                               bool demand_x509_proof,
                                QuicCryptoNegotiatedParameters* out_params,
                                CryptoHandshakeMessage* out) const;
 
diff --git a/net/quic/crypto/quic_crypto_client_config_test.cc b/net/quic/crypto/quic_crypto_client_config_test.cc
index d15f6b0c..8fb6e058 100644
--- a/net/quic/crypto/quic_crypto_client_config_test.cc
+++ b/net/quic/crypto/quic_crypto_client_config_test.cc
@@ -158,7 +158,7 @@
   QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
   MockRandom rand;
   config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
-                                 &params, &msg);
+                                 /* demand_x509_proof= */ true, &params, &msg);
 
   QuicTag cver;
   EXPECT_EQ(QUIC_NO_ERROR, msg.GetUint32(kVER, &cver));
@@ -184,7 +184,7 @@
   QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
   MockRandom rand;
   config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
-                                 &params, &msg);
+                                 /* demand_x509_proof= */ true, &params, &msg);
 
   QuicTag pdmd;
   EXPECT_EQ(QUIC_NO_ERROR, msg.GetUint32(kPDMD, &pdmd));
@@ -210,7 +210,7 @@
   QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
   MockRandom rand;
   config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
-                                 &params, &msg);
+                                 /* demand_x509_proof= */ true, &params, &msg);
 
   StringPiece scid;
   EXPECT_TRUE(msg.GetStringPiece(kSCID, &scid));
@@ -226,7 +226,7 @@
   QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
   MockRandom rand;
   config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
-                                 &params, &msg);
+                                 /* demand_x509_proof= */ true, &params, &msg);
 
   QuicTag pdmd;
   EXPECT_EQ(QUIC_NO_ERROR, msg.GetUint32(kPDMD, &pdmd));
diff --git a/net/quic/crypto/quic_crypto_server_config.cc b/net/quic/crypto/quic_crypto_server_config.cc
index df3a3ced..4f0e1144 100644
--- a/net/quic/crypto/quic_crypto_server_config.cc
+++ b/net/quic/crypto/quic_crypto_server_config.cc
@@ -604,6 +604,10 @@
   bool x509_supported = false;
   bool x509_ecdsa_supported = false;
   ParseProofDemand(client_hello, &x509_supported, &x509_ecdsa_supported);
+  if (!x509_supported && FLAGS_quic_require_x509) {
+    *error_details = "Missing or invalid PDMD";
+    return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+  }
   DCHECK(proof_source_.get());
   string chlo_hash;
   CryptoUtils::HashHandshakeMessage(client_hello, &chlo_hash);
@@ -1163,21 +1167,27 @@
     const QuicCryptoNegotiatedParameters& params,
     const CachedNetworkParameters* cached_network_params,
     CryptoHandshakeMessage* out) const {
-  base::AutoLock locked(configs_lock_);
+  string serialized;
+  string source_address_token;
+  const CommonCertSets* common_cert_sets;
+  {
+    base::AutoLock locked(configs_lock_);
+    serialized = primary_config_->serialized;
+    common_cert_sets = primary_config_->common_cert_sets;
+    source_address_token = NewSourceAddressToken(
+        *primary_config_, previous_source_address_tokens, client_ip, rand,
+        clock->WallNow(), cached_network_params);
+  }
+
   out->set_tag(kSCUP);
-  out->SetStringPiece(kSCFG, primary_config_->serialized);
-  out->SetStringPiece(
-      kSourceAddressTokenTag,
-      NewSourceAddressToken(*primary_config_.get(),
-                            previous_source_address_tokens, client_ip, rand,
-                            clock->WallNow(), cached_network_params));
+  out->SetStringPiece(kSCFG, serialized);
+  out->SetStringPiece(kSourceAddressTokenTag, source_address_token);
 
   scoped_refptr<ProofSource::Chain> chain;
   string signature;
   string cert_sct;
   if (FLAGS_quic_use_hash_in_scup) {
-    if (!proof_source_->GetProof(server_ip, params.sni,
-                                 primary_config_->serialized, version,
+    if (!proof_source_->GetProof(server_ip, params.sni, serialized, version,
                                  chlo_hash, params.x509_ecdsa_supported, &chain,
                                  &signature, &cert_sct)) {
       DVLOG(1) << "Server: failed to get proof.";
@@ -1185,9 +1195,8 @@
     }
   } else {
     if (!proof_source_->GetProof(
-            server_ip, params.sni, primary_config_->serialized, version,
-            params.client_nonce, params.x509_ecdsa_supported, &chain,
-            &signature, &cert_sct)) {
+            server_ip, params.sni, serialized, version, params.client_nonce,
+            params.x509_ecdsa_supported, &chain, &signature, &cert_sct)) {
       DVLOG(1) << "Server: failed to get proof.";
       return false;
     }
@@ -1195,7 +1204,7 @@
 
   const string compressed = CompressChain(
       compressed_certs_cache, chain, params.client_common_set_hashes,
-      params.client_cached_cert_hashes, primary_config_->common_cert_sets);
+      params.client_cached_cert_hashes, common_cert_sets);
 
   out->SetStringPiece(kCertificateTag, compressed);
   out->SetStringPiece(kPROF, signature);
@@ -1249,7 +1258,8 @@
   bool x509_supported = false;
   ParseProofDemand(client_hello, &x509_supported,
                    &params->x509_ecdsa_supported);
-  if (!x509_supported) {
+  if (!x509_supported && FLAGS_quic_require_x509) {
+    QUIC_BUG << "x509 certificates not supported in proof demand";
     return;
   }
 
diff --git a/net/quic/quic_alarm.cc b/net/quic/quic_alarm.cc
index 30edcaa..3067a29 100644
--- a/net/quic/quic_alarm.cc
+++ b/net/quic/quic_alarm.cc
@@ -35,7 +35,7 @@
     Cancel();
     return;
   }
-  if (std::abs(new_deadline.Subtract(deadline_).ToMicroseconds()) <
+  if (std::abs((new_deadline - deadline_).ToMicroseconds()) <
       granularity.ToMicroseconds()) {
     return;
   }
diff --git a/net/quic/quic_alarm_test.cc b/net/quic/quic_alarm_test.cc
index 0509090..fb6ef5c 100644
--- a/net/quic/quic_alarm_test.cc
+++ b/net/quic/quic_alarm_test.cc
@@ -80,8 +80,8 @@
   QuicAlarmTest()
       : delegate_(new MockDelegate()),
         alarm_(delegate_),
-        deadline_(QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(7))),
-        deadline2_(QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(14))),
+        deadline_(QuicTime::Zero() + QuicTime::Delta::FromSeconds(7)),
+        deadline2_(QuicTime::Zero() + QuicTime::Delta::FromSeconds(14)),
         new_deadline_(QuicTime::Zero()) {}
 
   void ResetAlarm() { alarm_.Set(new_deadline_); }
@@ -98,7 +98,7 @@
 }
 
 TEST_F(QuicAlarmTest, Set) {
-  QuicTime deadline = QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(7));
+  QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
   alarm_.Set(deadline);
   EXPECT_TRUE(alarm_.IsSet());
   EXPECT_TRUE(alarm_.scheduled());
@@ -106,7 +106,7 @@
 }
 
 TEST_F(QuicAlarmTest, Cancel) {
-  QuicTime deadline = QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(7));
+  QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
   alarm_.Set(deadline);
   alarm_.Cancel();
   EXPECT_FALSE(alarm_.IsSet());
@@ -115,9 +115,9 @@
 }
 
 TEST_F(QuicAlarmTest, Update) {
-  QuicTime deadline = QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(7));
+  QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
   alarm_.Set(deadline);
-  QuicTime new_deadline = QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(8));
+  QuicTime new_deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(8);
   alarm_.Update(new_deadline, QuicTime::Delta::Zero());
   EXPECT_TRUE(alarm_.IsSet());
   EXPECT_TRUE(alarm_.scheduled());
@@ -125,7 +125,7 @@
 }
 
 TEST_F(QuicAlarmTest, UpdateWithZero) {
-  QuicTime deadline = QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(7));
+  QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
   alarm_.Set(deadline);
   alarm_.Update(QuicTime::Zero(), QuicTime::Delta::Zero());
   EXPECT_FALSE(alarm_.IsSet());
@@ -134,7 +134,7 @@
 }
 
 TEST_F(QuicAlarmTest, Fire) {
-  QuicTime deadline = QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(7));
+  QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
   alarm_.Set(deadline);
   alarm_.FireAlarm();
   EXPECT_FALSE(alarm_.IsSet());
@@ -157,7 +157,7 @@
   DestructiveDelegate* delegate(new DestructiveDelegate);
   DestructiveAlarm* alarm = new DestructiveAlarm(delegate);
   delegate->set_alarm(alarm);
-  QuicTime deadline = QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(7));
+  QuicTime deadline = QuicTime::Zero() + QuicTime::Delta::FromSeconds(7);
   alarm->Set(deadline);
   // This should not crash, even though it will destroy alarm.
   alarm->FireAlarm();
diff --git a/net/quic/quic_buffered_packet_store.cc b/net/quic/quic_buffered_packet_store.cc
index 5d6b88056..c5771de 100644
--- a/net/quic/quic_buffered_packet_store.cc
+++ b/net/quic/quic_buffered_packet_store.cc
@@ -109,7 +109,7 @@
   queue.buffered_packets.push_back(std::move(new_entry));
 
   if (!expiration_alarm_->IsSet()) {
-    expiration_alarm_->Set(clock_->ApproximateNow().Add(connection_life_span_));
+    expiration_alarm_->Set(clock_->ApproximateNow() + connection_life_span_);
   }
   return SUCCESS;
 }
@@ -131,8 +131,7 @@
 }
 
 void QuicBufferedPacketStore::OnExpirationTimeout() {
-  QuicTime expiration_time =
-      clock_->ApproximateNow().Subtract(connection_life_span_);
+  QuicTime expiration_time = clock_->ApproximateNow() - connection_life_span_;
   while (!undecryptable_packets_.empty()) {
     auto& entry = undecryptable_packets_.front();
     if (entry.second.creation_time > expiration_time) {
@@ -142,7 +141,7 @@
     undecryptable_packets_.erase(undecryptable_packets_.begin());
   }
   if (!undecryptable_packets_.empty()) {
-    expiration_alarm_->Set(clock_->ApproximateNow().Add(connection_life_span_));
+    expiration_alarm_->Set(clock_->ApproximateNow() + connection_life_span_);
   }
 }
 
diff --git a/net/quic/quic_buffered_packet_store_test.cc b/net/quic/quic_buffered_packet_store_test.cc
index 84f22f0f..ba0b25f 100644
--- a/net/quic/quic_buffered_packet_store_test.cc
+++ b/net/quic/quic_buffered_packet_store_test.cc
@@ -59,8 +59,7 @@
         server_address_(Loopback6(), 65535),
         client_address_(Loopback6(), 65535),
         packet_content_("some encrypted content"),
-        packet_time_(
-            QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(42))),
+        packet_time_(QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(42)),
         data_packet_(packet_content_.data(),
                      packet_content_.size(),
                      packet_time_) {}
@@ -190,9 +189,9 @@
   store_.EnqueuePacket(connection_id2, data_packet_, server_address_,
                        another_client_address);
   // Advance clock to the time when connection 1 expires.
-  clock_.AdvanceTime(QuicBufferedPacketStorePeer::expiration_alarm(&store_)
-                         ->deadline()
-                         .Subtract(clock_.ApproximateNow()));
+  clock_.AdvanceTime(
+      QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() -
+      clock_.ApproximateNow());
   ASSERT_GE(clock_.ApproximateNow(),
             QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline());
   // Fire alarm to remove long-staying connection 1 packets.
@@ -217,9 +216,9 @@
                        client_address_);
   store_.EnqueuePacket(connection_id3, data_packet_, server_address_,
                        client_address_);
-  clock_.AdvanceTime(QuicBufferedPacketStorePeer::expiration_alarm(&store_)
-                         ->deadline()
-                         .Subtract(clock_.ApproximateNow()));
+  clock_.AdvanceTime(
+      QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() -
+      clock_.ApproximateNow());
   alarm_factory_.FireAlarm(
       QuicBufferedPacketStorePeer::expiration_alarm(&store_));
   // |last_expired_packet_queue_| should be updated.
diff --git a/net/quic/quic_chromium_alarm_factory.cc b/net/quic/quic_chromium_alarm_factory.cc
index 8973b97..05b8e6e1 100644
--- a/net/quic/quic_chromium_alarm_factory.cc
+++ b/net/quic/quic_chromium_alarm_factory.cc
@@ -41,7 +41,7 @@
       weak_factory_.InvalidateWeakPtrs();
     }
 
-    int64_t delay_us = deadline().Subtract(clock_->Now()).ToMicroseconds();
+    int64_t delay_us = (deadline() - (clock_->Now())).ToMicroseconds();
     if (delay_us < 0) {
       delay_us = 0;
     }
diff --git a/net/quic/quic_chromium_alarm_factory_test.cc b/net/quic/quic_chromium_alarm_factory_test.cc
index d47c98e..62c56790 100644
--- a/net/quic/quic_chromium_alarm_factory_test.cc
+++ b/net/quic/quic_chromium_alarm_factory_test.cc
@@ -41,7 +41,7 @@
   std::unique_ptr<QuicAlarm> alarm(alarm_factory_.CreateAlarm(delegate));
 
   QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
-  alarm->Set(clock_.Now().Add(delta));
+  alarm->Set(clock_.Now() + delta);
 
   // Verify that the alarm task has been posted.
   ASSERT_EQ(1u, runner_->GetPostedTasks().size());
@@ -49,7 +49,7 @@
             runner_->GetPostedTasks()[0].delay);
 
   runner_->RunNextTask();
-  EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.Now());
+  EXPECT_EQ(QuicTime::Zero() + delta, clock_.Now());
   EXPECT_TRUE(delegate->fired());
 }
 
@@ -58,7 +58,7 @@
   std::unique_ptr<QuicAlarm> alarm(alarm_factory_.CreateAlarm(delegate));
 
   QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
-  alarm->Set(clock_.Now().Add(delta));
+  alarm->Set(clock_.Now() + delta);
   alarm->Cancel();
 
   // The alarm task should still be posted.
@@ -67,7 +67,7 @@
             runner_->GetPostedTasks()[0].delay);
 
   runner_->RunNextTask();
-  EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.Now());
+  EXPECT_EQ(QuicTime::Zero() + delta, clock_.Now());
   EXPECT_FALSE(delegate->fired());
 }
 
@@ -76,10 +76,10 @@
   std::unique_ptr<QuicAlarm> alarm(alarm_factory_.CreateAlarm(delegate));
 
   QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
-  alarm->Set(clock_.Now().Add(delta));
+  alarm->Set(clock_.Now() + delta);
   alarm->Cancel();
   QuicTime::Delta new_delta = QuicTime::Delta::FromMicroseconds(3);
-  alarm->Set(clock_.Now().Add(new_delta));
+  alarm->Set(clock_.Now() + new_delta);
 
   // The alarm task should still be posted.
   ASSERT_EQ(1u, runner_->GetPostedTasks().size());
@@ -87,14 +87,14 @@
             runner_->GetPostedTasks()[0].delay);
 
   runner_->RunNextTask();
-  EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.Now());
+  EXPECT_EQ(QuicTime::Zero() + delta, clock_.Now());
   EXPECT_FALSE(delegate->fired());
 
   // The alarm task should be posted again.
   ASSERT_EQ(1u, runner_->GetPostedTasks().size());
 
   runner_->RunNextTask();
-  EXPECT_EQ(QuicTime::Zero().Add(new_delta), clock_.Now());
+  EXPECT_EQ(QuicTime::Zero() + new_delta, clock_.Now());
   EXPECT_TRUE(delegate->fired());
 }
 
@@ -103,17 +103,17 @@
   std::unique_ptr<QuicAlarm> alarm(alarm_factory_.CreateAlarm(delegate));
 
   QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(3);
-  alarm->Set(clock_.Now().Add(delta));
+  alarm->Set(clock_.Now() + delta);
   alarm->Cancel();
   QuicTime::Delta new_delta = QuicTime::Delta::FromMicroseconds(1);
-  alarm->Set(clock_.Now().Add(new_delta));
+  alarm->Set(clock_.Now() + new_delta);
 
   // Both alarm tasks will be posted.
   ASSERT_EQ(2u, runner_->GetPostedTasks().size());
 
   // The earlier task will execute and will fire the alarm->
   runner_->RunNextTask();
-  EXPECT_EQ(QuicTime::Zero().Add(new_delta), clock_.Now());
+  EXPECT_EQ(QuicTime::Zero() + new_delta, clock_.Now());
   EXPECT_TRUE(delegate->fired());
   delegate->Clear();
 
@@ -123,7 +123,7 @@
   // When the latter task is executed, the weak ptr will be invalid and
   // the alarm will not fire.
   runner_->RunNextTask();
-  EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.Now());
+  EXPECT_EQ(QuicTime::Zero() + delta, clock_.Now());
   EXPECT_FALSE(delegate->fired());
 }
 
@@ -133,10 +133,9 @@
 
   QuicTime start = clock_.Now();
   QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
-  alarm->Set(clock_.Now().Add(delta));
+  alarm->Set(clock_.Now() + delta);
   QuicTime::Delta new_delta = QuicTime::Delta::FromMicroseconds(3);
-  alarm->Update(clock_.Now().Add(new_delta),
-                QuicTime::Delta::FromMicroseconds(1));
+  alarm->Update(clock_.Now() + new_delta, QuicTime::Delta::FromMicroseconds(1));
 
   // The alarm task should still be posted.
   ASSERT_EQ(1u, runner_->GetPostedTasks().size());
@@ -144,25 +143,23 @@
             runner_->GetPostedTasks()[0].delay);
 
   runner_->RunNextTask();
-  EXPECT_EQ(QuicTime::Zero().Add(delta), clock_.Now());
+  EXPECT_EQ(QuicTime::Zero() + delta, clock_.Now());
   EXPECT_FALSE(delegate->fired());
 
   // Move the alarm forward 1us and ensure it doesn't move forward.
-  alarm->Update(clock_.Now().Add(new_delta),
-                QuicTime::Delta::FromMicroseconds(2));
+  alarm->Update(clock_.Now() + new_delta, QuicTime::Delta::FromMicroseconds(2));
 
   ASSERT_EQ(1u, runner_->GetPostedTasks().size());
-  EXPECT_EQ(base::TimeDelta::FromMicroseconds(
-                new_delta.Subtract(delta).ToMicroseconds()),
-            runner_->GetPostedTasks()[0].delay);
+  EXPECT_EQ(
+      base::TimeDelta::FromMicroseconds((new_delta - delta).ToMicroseconds()),
+      runner_->GetPostedTasks()[0].delay);
   runner_->RunNextTask();
-  EXPECT_EQ(start.Add(new_delta), clock_.Now());
+  EXPECT_EQ(start + new_delta, clock_.Now());
   EXPECT_TRUE(delegate->fired());
 
   // Set the alarm via an update call.
   new_delta = QuicTime::Delta::FromMicroseconds(5);
-  alarm->Update(clock_.Now().Add(new_delta),
-                QuicTime::Delta::FromMicroseconds(1));
+  alarm->Update(clock_.Now() + new_delta, QuicTime::Delta::FromMicroseconds(1));
   EXPECT_TRUE(alarm->IsSet());
 
   // Update it with an uninitialized time and ensure it's cancelled.
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc
index a10373a..f18ff5bc 100644
--- a/net/quic/quic_chromium_client_session.cc
+++ b/net/quic/quic_chromium_client_session.cc
@@ -1057,7 +1057,7 @@
   dict->SetString("version", QuicVersionToString(connection()->version()));
   dict->SetInteger("open_streams", GetNumOpenOutgoingStreams());
   std::unique_ptr<base::ListValue> stream_list(new base::ListValue());
-  for (StreamMap::const_iterator it = dynamic_streams().begin();
+  for (DynamicStreamMap::const_iterator it = dynamic_streams().begin();
        it != dynamic_streams().end(); ++it) {
     stream_list->AppendString(base::UintToString(it->second->id()));
   }
diff --git a/net/quic/quic_chromium_packet_reader.cc b/net/quic/quic_chromium_packet_reader.cc
index dbd67a5..af9e7a5 100644
--- a/net/quic/quic_chromium_packet_reader.cc
+++ b/net/quic/quic_chromium_packet_reader.cc
@@ -39,7 +39,7 @@
     return;
 
   if (num_packets_read_ == 0)
-    yield_after_ = clock_->Now().Add(yield_after_duration_);
+    yield_after_ = clock_->Now() + yield_after_duration_;
 
   DCHECK(socket_);
   read_pending_ = true;
diff --git a/net/quic/quic_client_promised_info.cc b/net/quic/quic_client_promised_info.cc
index 4de7adf..120db553 100644
--- a/net/quic/quic_client_promised_info.cc
+++ b/net/quic/quic_client_promised_info.cc
@@ -32,8 +32,8 @@
   cleanup_alarm_.reset(session_->connection()->alarm_factory()->CreateAlarm(
       new QuicClientPromisedInfo::CleanupAlarm(this)));
   cleanup_alarm_->Set(
-      session_->connection()->helper()->GetClock()->ApproximateNow().Add(
-          QuicTime::Delta::FromSeconds(kPushPromiseTimeoutSecs)));
+      session_->connection()->helper()->GetClock()->ApproximateNow() +
+      QuicTime::Delta::FromSeconds(kPushPromiseTimeoutSecs));
 }
 
 void QuicClientPromisedInfo::OnPromiseHeaders(const SpdyHeaderBlock& headers) {
diff --git a/net/quic/quic_client_session_base.cc b/net/quic/quic_client_session_base.cc
index dff71e4..1d83ee39 100644
--- a/net/quic/quic_client_session_base.cc
+++ b/net/quic/quic_client_session_base.cc
@@ -174,7 +174,7 @@
   if (IsClosedStream(id)) {
     return nullptr;
   }
-  StreamMap::iterator it = dynamic_streams().find(id);
+  DynamicStreamMap::iterator it = dynamic_streams().find(id);
   if (it != dynamic_streams().end()) {
     return static_cast<QuicSpdyStream*>(it->second);
   }
diff --git a/net/quic/quic_clock.cc b/net/quic/quic_clock.cc
index 6196bbb..673fe69d 100644
--- a/net/quic/quic_clock.cc
+++ b/net/quic/quic_clock.cc
@@ -38,11 +38,11 @@
   //               result
   //
   // result = Now() - (WallNow() - walltime)
-  return Now().Subtract(QuicTime::Delta::FromMicroseconds(
-      WallNow()
-          .Subtract(
-              QuicTime::Delta::FromMicroseconds(walltime.ToUNIXMicroseconds()))
-          .ToUNIXMicroseconds()));
+  return Now() - QuicTime::Delta::FromMicroseconds(
+                     WallNow()
+                         .Subtract(QuicTime::Delta::FromMicroseconds(
+                             walltime.ToUNIXMicroseconds()))
+                         .ToUNIXMicroseconds());
 }
 
 }  // namespace net
diff --git a/net/quic/quic_config.cc b/net/quic/quic_config.cc
index 25e567c..516c32d 100644
--- a/net/quic/quic_config.cc
+++ b/net/quic/quic_config.cc
@@ -417,7 +417,8 @@
       socket_receive_buffer_(kSRBF, PRESENCE_OPTIONAL),
       multipath_enabled_(kMPTH, PRESENCE_OPTIONAL),
       connection_migration_disabled_(kNCMR, PRESENCE_OPTIONAL),
-      alternate_server_address_(kASAD, PRESENCE_OPTIONAL) {
+      alternate_server_address_(kASAD, PRESENCE_OPTIONAL),
+      force_hol_blocking_(kFHOL, PRESENCE_OPTIONAL) {
   SetDefaults();
 }
 
@@ -643,6 +644,18 @@
   return alternate_server_address_.GetReceivedValue();
 }
 
+void QuicConfig::SetForceHolBlocking() {
+  force_hol_blocking_.SetSendValue(1);
+}
+
+bool QuicConfig::ForceHolBlocking(Perspective perspective) const {
+  if (perspective == Perspective::IS_SERVER) {
+    return force_hol_blocking_.HasReceivedValue();
+  } else {
+    return force_hol_blocking_.HasSendValue();
+  }
+}
+
 bool QuicConfig::negotiated() const {
   // TODO(ianswett): Add the negotiated parameters once and iterate over all
   // of them in negotiated, ToHandshakeMessage, ProcessClientHello, and
diff --git a/net/quic/quic_config.h b/net/quic/quic_config.h
index ddafce4..5baeb33 100644
--- a/net/quic/quic_config.h
+++ b/net/quic/quic_config.h
@@ -386,6 +386,10 @@
 
   const IPEndPoint& ReceivedAlternateServerAddress() const;
 
+  void SetForceHolBlocking();
+
+  bool ForceHolBlocking(Perspective perspective) const;
+
   bool negotiated() const;
 
   // ToHandshakeMessage serialises the settings in this object as a series of
@@ -445,6 +449,9 @@
 
   // An alternate server address the client could connect to.
   QuicFixedIPEndPoint alternate_server_address_;
+
+  // Force HOL blocking for measurement purposes.
+  QuicFixedUint32 force_hol_blocking_;
 };
 
 }  // namespace net
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index c529062..957cc399 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -829,9 +829,9 @@
 
 const char* QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
   if (incoming_ack.largest_observed > packet_generator_.packet_number()) {
-    LOG(WARNING) << ENDPOINT << "Peer's observed unsent packet:"
-                 << incoming_ack.largest_observed << " vs "
-                 << packet_generator_.packet_number();
+    DLOG(WARNING) << ENDPOINT << "Peer's observed unsent packet:"
+                  << incoming_ack.largest_observed << " vs "
+                  << packet_generator_.packet_number();
     // We got an error for data we have not sent.  Error out.
     return "Largest observed too high.";
   }
@@ -874,9 +874,9 @@
     if (!sent_entropy_manager_.IsValidEntropy(incoming_ack.largest_observed,
                                               incoming_ack.packets,
                                               incoming_ack.entropy_hash)) {
-      LOG(WARNING) << ENDPOINT << "Peer sent invalid entropy."
-                   << " largest_observed:" << incoming_ack.largest_observed
-                   << " last_received:" << last_header_.packet_number;
+      DLOG(WARNING) << ENDPOINT << "Peer sent invalid entropy."
+                    << " largest_observed:" << incoming_ack.largest_observed
+                    << " last_received:" << last_header_.packet_number;
       return "Invalid entropy.";
     }
   } else {
@@ -1065,10 +1065,9 @@
       } else if (!ack_alarm_->IsSet()) {
         // Wait the minimum of a quarter min_rtt and the delayed ack time.
         QuicTime::Delta ack_delay = QuicTime::Delta::Min(
-            DelayedAckTime(),
-            sent_packet_manager_->GetRttStats()->min_rtt().Multiply(
-                ack_decimation_delay_));
-        ack_alarm_->Set(clock_->ApproximateNow().Add(ack_delay));
+            DelayedAckTime(), sent_packet_manager_->GetRttStats()->min_rtt() *
+                                  ack_decimation_delay_);
+        ack_alarm_->Set(clock_->ApproximateNow() + ack_delay);
       }
     } else {
       // Ack with a timer or every 2 packets by default.
@@ -1076,7 +1075,7 @@
           kDefaultRetransmittablePacketsBeforeAck) {
         ack_queued_ = true;
       } else if (!ack_alarm_->IsSet()) {
-        ack_alarm_->Set(clock_->ApproximateNow().Add(DelayedAckTime()));
+        ack_alarm_->Set(clock_->ApproximateNow() + DelayedAckTime());
       }
     }
 
@@ -1084,8 +1083,9 @@
     if (received_packet_manager_.HasNewMissingPackets()) {
       if (ack_mode_ == ACK_DECIMATION_WITH_REORDERING) {
         // Wait the minimum of an eighth min_rtt and the existing ack time.
-        QuicTime ack_time = clock_->ApproximateNow().Add(
-            sent_packet_manager_->GetRttStats()->min_rtt().Multiply(0.125));
+        QuicTime ack_time =
+            clock_->ApproximateNow() +
+            0.125 * sent_packet_manager_->GetRttStats()->min_rtt();
         if (!ack_alarm_->IsSet() || ack_alarm_->deadline() > ack_time) {
           ack_alarm_->Cancel();
           ack_alarm_->Set(ack_time);
@@ -1578,7 +1578,7 @@
   DCHECK_NE(kInvalidPathId, path_id);
   // If the scheduler requires a delay, then we can not send this packet now.
   if (!delay.IsZero()) {
-    send_alarm_->Update(now.Add(delay), QuicTime::Delta::FromMilliseconds(1));
+    send_alarm_->Update(now + delay, QuicTime::Delta::FromMilliseconds(1));
     DVLOG(1) << ENDPOINT << "Delaying sending " << delay.ToMilliseconds()
              << "ms";
     return false;
@@ -2141,9 +2141,9 @@
   // Adjust the idle timeout on client and server to prevent clients from
   // sending requests to servers which have already closed the connection.
   if (perspective_ == Perspective::IS_SERVER) {
-    idle_timeout = idle_timeout.Add(QuicTime::Delta::FromSeconds(3));
+    idle_timeout = idle_timeout + QuicTime::Delta::FromSeconds(3);
   } else if (idle_timeout > QuicTime::Delta::FromSeconds(1)) {
-    idle_timeout = idle_timeout.Subtract(QuicTime::Delta::FromSeconds(1));
+    idle_timeout = idle_timeout - QuicTime::Delta::FromSeconds(1);
   }
   handshake_timeout_ = handshake_timeout;
   idle_network_timeout_ = idle_timeout;
@@ -2159,7 +2159,7 @@
   // |delta| can be < 0 as |now| is approximate time but |time_of_last_packet|
   // is accurate time. However, this should not change the behavior of
   // timeout handling.
-  QuicTime::Delta idle_duration = now.Subtract(time_of_last_packet);
+  QuicTime::Delta idle_duration = now - time_of_last_packet;
   DVLOG(1) << ENDPOINT << "last packet "
            << time_of_last_packet.ToDebuggingValue()
            << " now:" << now.ToDebuggingValue()
@@ -2175,8 +2175,7 @@
   }
 
   if (!handshake_timeout_.IsInfinite()) {
-    QuicTime::Delta connected_duration =
-        now.Subtract(stats_.connection_creation_time);
+    QuicTime::Delta connected_duration = now - stats_.connection_creation_time;
     DVLOG(1) << ENDPOINT
              << "connection time: " << connected_duration.ToMicroseconds()
              << " handshake timeout: " << handshake_timeout_.ToMicroseconds();
@@ -2196,10 +2195,10 @@
   QuicTime time_of_last_packet =
       max(time_of_last_received_packet_, time_of_last_sent_new_packet_);
 
-  QuicTime deadline = time_of_last_packet.Add(idle_network_timeout_);
+  QuicTime deadline = time_of_last_packet + idle_network_timeout_;
   if (!handshake_timeout_.IsInfinite()) {
     deadline =
-        min(deadline, stats_.connection_creation_time.Add(handshake_timeout_));
+        min(deadline, stats_.connection_creation_time + handshake_timeout_);
   }
 
   timeout_alarm_->Cancel();
@@ -2217,7 +2216,7 @@
     return;
   }
   QuicTime::Delta ping_timeout = QuicTime::Delta::FromSeconds(kPingTimeoutSecs);
-  ping_alarm_->Update(clock_->ApproximateNow().Add(ping_timeout),
+  ping_alarm_->Update(clock_->ApproximateNow() + ping_timeout,
                       QuicTime::Delta::FromSeconds(1));
 }
 
@@ -2266,7 +2265,7 @@
   // Move generator into batch mode. If caller wants us to include an ack,
   // check the delayed-ack timer to see if there's ack info to be sent.
   if (!already_in_batch_mode_) {
-    DVLOG(1) << "Entering Batch Mode.";
+    DVLOG(2) << "Entering Batch Mode.";
     connection_->packet_generator_.StartBatchOperations();
   }
   if (ShouldSendAck(ack_mode)) {
@@ -2299,7 +2298,7 @@
   }
   // If we changed the generator's batch state, restore original batch state.
   if (!already_in_batch_mode_) {
-    DVLOG(1) << "Leaving Batch Mode.";
+    DVLOG(2) << "Leaving Batch Mode.";
     connection_->packet_generator_.FinishBatchOperations();
   }
   DCHECK_EQ(already_in_batch_mode_,
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index fd4c088..232b0e3 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -463,7 +463,7 @@
     UMA_HISTOGRAM_CUSTOM_TIMES(
         "Net.QuicTimeBetweenTwoPacketSent",
         base::TimeDelta::FromMilliseconds(
-            sent_time.Subtract(last_packet_sent_time_).ToMilliseconds()),
+            (sent_time - last_packet_sent_time_).ToMilliseconds()),
         base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(10),
         100);
   }
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 80ba471..c604b4d 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -2475,7 +2475,7 @@
   EXPECT_EQ(1u, writer_->header().packet_number);
   // Simulate the retransmission alarm firing and sending a tlp,
   // so send algorithm's OnRetransmissionTimeout is not called.
-  clock_.AdvanceTime(retransmission_time.Subtract(clock_.Now()));
+  clock_.AdvanceTime(retransmission_time - clock_.Now());
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 2u, _, _));
   connection_.GetRetransmissionAlarm()->Fire();
   EXPECT_EQ(2u, writer_->header().packet_number);
@@ -2487,7 +2487,7 @@
   connection_.DisableTailLossProbe();
 
   QuicTime default_retransmission_time =
-      clock_.ApproximateNow().Add(DefaultRetransmissionTime());
+      clock_.ApproximateNow() + DefaultRetransmissionTime();
   SendStreamDataToPeer(3, "foo", 0, !kFin, nullptr);
   EXPECT_EQ(1u, stop_waiting()->least_unacked);
 
@@ -2507,7 +2507,7 @@
   connection_.DisableTailLossProbe();
 
   QuicTime default_retransmission_time =
-      clock_.ApproximateNow().Add(DefaultRetransmissionTime());
+      clock_.ApproximateNow() + DefaultRetransmissionTime();
   use_tagging_decrypter();
 
   // A TaggingEncrypter puts kTagSize copies of the given byte (0x01 here) at
@@ -2783,7 +2783,7 @@
   connection_.SendStreamDataWithString(3, "bar", 0, !kFin, nullptr);
   QuicAlarm* retransmission_alarm = connection_.GetRetransmissionAlarm();
   EXPECT_TRUE(retransmission_alarm->IsSet());
-  EXPECT_EQ(clock_.Now().Add(DefaultRetransmissionTime()),
+  EXPECT_EQ(clock_.Now() + DefaultRetransmissionTime(),
             retransmission_alarm->deadline());
 
   // Advance the time right before the RTO, then receive an ack for the first
@@ -2796,7 +2796,7 @@
   EXPECT_GT(retransmission_alarm->deadline(), clock_.Now());
 
   // Move forward past the original RTO and ensure the RTO is still pending.
-  clock_.AdvanceTime(DefaultRetransmissionTime().Multiply(2));
+  clock_.AdvanceTime(2 * DefaultRetransmissionTime());
 
   // Ensure the second packet gets retransmitted when it finally fires.
   EXPECT_TRUE(retransmission_alarm->IsSet());
@@ -2838,8 +2838,9 @@
   QuicConfig config;
   connection_.SetFromConfig(config);
   // Subtract a second from the idle timeout on the client side.
-  QuicTime default_timeout = clock_.ApproximateNow().Add(
-      QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1));
+  QuicTime default_timeout =
+      clock_.ApproximateNow() +
+      QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
   EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
 
   EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_NETWORK_IDLE_TIMEOUT, _,
@@ -2866,8 +2867,8 @@
   EXPECT_TRUE(connection_.connected());
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
 
-  QuicTime handshake_timeout = clock_.ApproximateNow().Add(timeout).Subtract(
-      QuicTime::Delta::FromSeconds(1));
+  QuicTime handshake_timeout =
+      clock_.ApproximateNow() + timeout - QuicTime::Delta::FromSeconds(1);
   EXPECT_EQ(handshake_timeout, connection_.GetTimeoutAlarm()->deadline());
   EXPECT_TRUE(connection_.connected());
 
@@ -2884,7 +2885,7 @@
   EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
   EXPECT_TRUE(connection_.connected());
 
-  clock_.AdvanceTime(timeout.Subtract(QuicTime::Delta::FromSeconds(2)));
+  clock_.AdvanceTime(timeout - QuicTime::Delta::FromSeconds(2));
 
   EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_HANDSHAKE_TIMEOUT, _,
                                            ConnectionCloseSource::FROM_SELF));
@@ -2912,7 +2913,7 @@
   EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
   SendStreamDataToPeer(kHeadersStreamId, "GET /", 0, kFin, nullptr);
   EXPECT_TRUE(connection_.GetPingAlarm()->IsSet());
-  EXPECT_EQ(clock_.ApproximateNow().Add(QuicTime::Delta::FromSeconds(15)),
+  EXPECT_EQ(clock_.ApproximateNow() + QuicTime::Delta::FromSeconds(15),
             connection_.GetPingAlarm()->deadline());
 
   // Now recevie and ACK of the previous packet, which will move the
@@ -2925,9 +2926,8 @@
   EXPECT_TRUE(connection_.GetPingAlarm()->IsSet());
   // The ping timer is set slightly less than 15 seconds in the future, because
   // of the 1s ping timer alarm granularity.
-  EXPECT_EQ(clock_.ApproximateNow()
-                .Add(QuicTime::Delta::FromSeconds(15))
-                .Subtract(QuicTime::Delta::FromMilliseconds(5)),
+  EXPECT_EQ(clock_.ApproximateNow() + QuicTime::Delta::FromSeconds(15) -
+                QuicTime::Delta::FromMilliseconds(5),
             connection_.GetPingAlarm()->deadline());
 
   writer_->Reset();
@@ -3186,7 +3186,7 @@
   const QuicTime::Delta initial_idle_timeout =
       QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
   const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
-  QuicTime default_timeout = clock_.ApproximateNow().Add(initial_idle_timeout);
+  QuicTime default_timeout = clock_.ApproximateNow() + initial_idle_timeout;
 
   // When we send a packet, the timeout will change to 5ms +
   // kInitialIdleTimeoutSecs.
@@ -3202,12 +3202,12 @@
 
   // The original alarm will fire.  We should not time out because we had a
   // network event at t=5ms.  The alarm will reregister.
-  clock_.AdvanceTime(initial_idle_timeout.Subtract(five_ms).Subtract(five_ms));
+  clock_.AdvanceTime(initial_idle_timeout - five_ms - five_ms);
   EXPECT_EQ(default_timeout, clock_.ApproximateNow());
   connection_.GetTimeoutAlarm()->Fire();
   EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
   EXPECT_TRUE(connection_.connected());
-  EXPECT_EQ(default_timeout.Add(five_ms).Add(five_ms),
+  EXPECT_EQ(default_timeout + five_ms + five_ms,
             connection_.GetTimeoutAlarm()->deadline());
 
   // This time, we should time out.
@@ -3215,7 +3215,7 @@
                                            ConnectionCloseSource::FROM_SELF));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
   clock_.AdvanceTime(five_ms);
-  EXPECT_EQ(default_timeout.Add(five_ms), clock_.ApproximateNow());
+  EXPECT_EQ(default_timeout + five_ms, clock_.ApproximateNow());
   connection_.GetTimeoutAlarm()->Fire();
   EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
   EXPECT_FALSE(connection_.connected());
@@ -3250,7 +3250,7 @@
   const QuicTime::Delta default_idle_timeout =
       QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs - 1);
   const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
-  QuicTime default_timeout = clock_.ApproximateNow().Add(default_idle_timeout);
+  QuicTime default_timeout = clock_.ApproximateNow() + default_idle_timeout;
 
   // When we send a packet, the timeout will change to 5ms +
   // kInitialIdleTimeoutSecs.
@@ -3266,19 +3266,19 @@
 
   // The original alarm will fire.  We should not time out because we had a
   // network event at t=5ms.  The alarm will reregister.
-  clock_.AdvanceTime(default_idle_timeout.Subtract(five_ms).Subtract(five_ms));
+  clock_.AdvanceTime(default_idle_timeout - five_ms - five_ms);
   EXPECT_EQ(default_timeout, clock_.ApproximateNow());
   connection_.GetTimeoutAlarm()->Fire();
   EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
   EXPECT_TRUE(connection_.connected());
-  EXPECT_EQ(default_timeout.Add(five_ms).Add(five_ms),
+  EXPECT_EQ(default_timeout + five_ms + five_ms,
             connection_.GetTimeoutAlarm()->deadline());
 
   // This time, we should time out.
   EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_NETWORK_IDLE_TIMEOUT, _,
                                            ConnectionCloseSource::FROM_SELF));
   clock_.AdvanceTime(five_ms);
-  EXPECT_EQ(default_timeout.Add(five_ms), clock_.ApproximateNow());
+  EXPECT_EQ(default_timeout + five_ms, clock_.ApproximateNow());
   connection_.GetTimeoutAlarm()->Fire();
   EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
   EXPECT_FALSE(connection_.connected());
@@ -3295,7 +3295,7 @@
   const QuicTime::Delta initial_idle_timeout =
       QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
   const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
-  QuicTime default_timeout = clock_.ApproximateNow().Add(initial_idle_timeout);
+  QuicTime default_timeout = clock_.ApproximateNow() + initial_idle_timeout;
 
   connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 0, !kFin,
                                        nullptr);
@@ -3313,12 +3313,12 @@
 
   // The original alarm will fire.  We should not time out because we had a
   // network event at t=5ms.  The alarm will reregister.
-  clock_.AdvanceTime(initial_idle_timeout.Subtract(five_ms));
+  clock_.AdvanceTime(initial_idle_timeout - five_ms);
   EXPECT_EQ(default_timeout, clock_.ApproximateNow());
   connection_.GetTimeoutAlarm()->Fire();
   EXPECT_TRUE(connection_.connected());
   EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
-  EXPECT_EQ(default_timeout.Add(five_ms),
+  EXPECT_EQ(default_timeout + five_ms,
             connection_.GetTimeoutAlarm()->deadline());
 
   // This time, we should time out.
@@ -3326,7 +3326,7 @@
                                            ConnectionCloseSource::FROM_SELF));
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
   clock_.AdvanceTime(five_ms);
-  EXPECT_EQ(default_timeout.Add(five_ms), clock_.ApproximateNow());
+  EXPECT_EQ(default_timeout + five_ms, clock_.ApproximateNow());
   connection_.GetTimeoutAlarm()->Fire();
   EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
   EXPECT_FALSE(connection_.connected());
@@ -3344,9 +3344,9 @@
       QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1);
   connection_.SetNetworkTimeouts(
       QuicTime::Delta::Infinite(),
-      initial_idle_timeout.Add(QuicTime::Delta::FromSeconds(1)));
+      initial_idle_timeout + QuicTime::Delta::FromSeconds(1));
   const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5);
-  QuicTime default_timeout = clock_.ApproximateNow().Add(initial_idle_timeout);
+  QuicTime default_timeout = clock_.ApproximateNow() + initial_idle_timeout;
 
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
   connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 0, !kFin,
@@ -3367,12 +3367,12 @@
 
   // The original alarm will fire.  We should not time out because we had a
   // network event at t=5ms.  The alarm will reregister.
-  clock_.AdvanceTime(initial_idle_timeout.Subtract(five_ms));
+  clock_.AdvanceTime(initial_idle_timeout - five_ms);
   EXPECT_EQ(default_timeout, clock_.ApproximateNow());
   connection_.GetTimeoutAlarm()->Fire();
   EXPECT_TRUE(connection_.connected());
   EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
-  EXPECT_EQ(default_timeout.Add(five_ms),
+  EXPECT_EQ(default_timeout + five_ms,
             connection_.GetTimeoutAlarm()->deadline());
 
   // Now, send packets while advancing the time and verify that the connection
@@ -3528,7 +3528,7 @@
 }
 
 TEST_P(QuicConnectionTest, SendDelayedAck) {
-  QuicTime ack_time = clock_.ApproximateNow().Add(DefaultDelayedAckTime());
+  QuicTime ack_time = clock_.ApproximateNow() + DefaultDelayedAckTime();
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
   const uint8_t tag = 0x07;
@@ -3564,8 +3564,8 @@
                        QuicTime::Delta::Zero(), QuicTime::Zero());
   // The ack time should be based on min_rtt/4, since it's less than the
   // default delayed ack time.
-  QuicTime ack_time = clock_.ApproximateNow().Add(
-      QuicTime::Delta::FromMilliseconds(kMinRttMs / 4));
+  QuicTime ack_time = clock_.ApproximateNow() +
+                      QuicTime::Delta::FromMilliseconds(kMinRttMs / 4);
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
   const uint8_t tag = 0x07;
@@ -3617,8 +3617,8 @@
                        QuicTime::Delta::Zero(), QuicTime::Zero());
   // The ack time should be based on min_rtt/8, since it's less than the
   // default delayed ack time.
-  QuicTime ack_time = clock_.ApproximateNow().Add(
-      QuicTime::Delta::FromMilliseconds(kMinRttMs / 8));
+  QuicTime ack_time = clock_.ApproximateNow() +
+                      QuicTime::Delta::FromMilliseconds(kMinRttMs / 8);
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
   const uint8_t tag = 0x07;
@@ -3670,8 +3670,8 @@
                        QuicTime::Delta::Zero(), QuicTime::Zero());
   // The ack time should be based on min_rtt/4, since it's less than the
   // default delayed ack time.
-  QuicTime ack_time = clock_.ApproximateNow().Add(
-      QuicTime::Delta::FromMilliseconds(kMinRttMs / 4));
+  QuicTime ack_time = clock_.ApproximateNow() +
+                      QuicTime::Delta::FromMilliseconds(kMinRttMs / 4);
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
   const uint8_t tag = 0x07;
@@ -3702,7 +3702,7 @@
   EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
   ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 9,
                            !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL);
-  ack_time = clock_.ApproximateNow().Add(QuicTime::Delta::FromMilliseconds(5));
+  ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
   EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
   EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
 
@@ -3731,8 +3731,8 @@
                        QuicTime::Delta::Zero(), QuicTime::Zero());
   // The ack time should be based on min_rtt/4, since it's less than the
   // default delayed ack time.
-  QuicTime ack_time = clock_.ApproximateNow().Add(
-      QuicTime::Delta::FromMilliseconds(kMinRttMs / 4));
+  QuicTime ack_time = clock_.ApproximateNow() +
+                      QuicTime::Delta::FromMilliseconds(kMinRttMs / 4);
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
   const uint8_t tag = 0x07;
@@ -3763,7 +3763,7 @@
   EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
   ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 19,
                            !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL);
-  ack_time = clock_.ApproximateNow().Add(QuicTime::Delta::FromMilliseconds(5));
+  ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
   EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
   EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
 
@@ -3805,8 +3805,8 @@
                        QuicTime::Delta::Zero(), QuicTime::Zero());
   // The ack time should be based on min_rtt/8, since it's less than the
   // default delayed ack time.
-  QuicTime ack_time = clock_.ApproximateNow().Add(
-      QuicTime::Delta::FromMilliseconds(kMinRttMs / 8));
+  QuicTime ack_time = clock_.ApproximateNow() +
+                      QuicTime::Delta::FromMilliseconds(kMinRttMs / 8);
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
   const uint8_t tag = 0x07;
@@ -3837,7 +3837,7 @@
   EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
   ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 9,
                            !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL);
-  ack_time = clock_.ApproximateNow().Add(QuicTime::Delta::FromMilliseconds(5));
+  ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
   EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
   EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
 
@@ -3868,8 +3868,8 @@
                        QuicTime::Delta::Zero(), QuicTime::Zero());
   // The ack time should be based on min_rtt/8, since it's less than the
   // default delayed ack time.
-  QuicTime ack_time = clock_.ApproximateNow().Add(
-      QuicTime::Delta::FromMilliseconds(kMinRttMs / 8));
+  QuicTime ack_time = clock_.ApproximateNow() +
+                      QuicTime::Delta::FromMilliseconds(kMinRttMs / 8);
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
   const uint8_t tag = 0x07;
@@ -3900,7 +3900,7 @@
   EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1);
   ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 19,
                            !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL);
-  ack_time = clock_.ApproximateNow().Add(QuicTime::Delta::FromMilliseconds(5));
+  ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5);
   EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
   EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
 
@@ -3936,7 +3936,7 @@
   ProcessPacket(kDefaultPathId, 1);
   // Check that ack is sent and that delayed ack alarm is set.
   EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
-  QuicTime ack_time = clock_.ApproximateNow().Add(DefaultDelayedAckTime());
+  QuicTime ack_time = clock_.ApproximateNow() + DefaultDelayedAckTime();
   EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
 
   // Completing the handshake as the server does nothing.
@@ -4661,7 +4661,7 @@
   scoped_refptr<MockAckListener> listener(new StrictMock<MockAckListener>);
 
   QuicTime default_retransmission_time =
-      clock_.ApproximateNow().Add(DefaultRetransmissionTime());
+      clock_.ApproximateNow() + DefaultRetransmissionTime();
   connection_.SendStreamDataWithString(3, "foo", 0, !kFin, listener.get());
   EXPECT_EQ(1u, stop_waiting()->least_unacked);
 
@@ -4817,7 +4817,7 @@
       .WillRepeatedly(Return(QuicTime::Delta::FromMilliseconds(1)));
   connection_.OnCanWrite();
   EXPECT_TRUE(connection_.GetSendAlarm()->IsSet());
-  EXPECT_EQ(clock_.Now().Add(QuicTime::Delta::FromMilliseconds(1)),
+  EXPECT_EQ(clock_.Now() + QuicTime::Delta::FromMilliseconds(1),
             connection_.GetSendAlarm()->deadline());
 
   // Process an ack and the send alarm will be set to the  new 2ms delay.
@@ -4830,7 +4830,7 @@
   EXPECT_EQ(1u, writer_->frame_count());
   EXPECT_EQ(1u, writer_->stream_frames().size());
   EXPECT_TRUE(connection_.GetSendAlarm()->IsSet());
-  EXPECT_EQ(clock_.Now().Add(QuicTime::Delta::FromMilliseconds(2)),
+  EXPECT_EQ(clock_.Now() + QuicTime::Delta::FromMilliseconds(2),
             connection_.GetSendAlarm()->deadline());
   writer_->Reset();
 }
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index 68d0f0d7..7ac7fc50 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -321,7 +321,7 @@
     crypto_config_->FillInchoateClientHello(
         server_id_, session()->connection()->supported_versions().front(),
         cached, session()->connection()->random_generator(),
-        &crypto_negotiated_params_, &out);
+        /* demand_x509_proof= */ true, &crypto_negotiated_params_, &out);
     // Pad the inchoate client hello to fill up a packet.
     const QuicByteCount kFramingOverhead = 50;  // A rough estimate.
     const QuicByteCount max_packet_size =
@@ -390,20 +390,10 @@
       crypto_negotiated_params_.initial_crypters.encrypter.release());
   session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
 
-  if (FLAGS_quic_reply_to_rej) {
-    // TODO(ianswett): Merge ENCRYPTION_REESTABLISHED and
-    // ENCRYPTION_FIRST_ESTABLSIHED.
-    encryption_established_ = true;
-    session()->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_REESTABLISHED);
-  } else {
-    if (!encryption_established_) {
-      encryption_established_ = true;
-      session()->OnCryptoHandshakeEvent(
-          QuicSession::ENCRYPTION_FIRST_ESTABLISHED);
-    } else {
-      session()->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_REESTABLISHED);
-    }
-  }
+  // TODO(ianswett): Merge ENCRYPTION_REESTABLISHED and
+  // ENCRYPTION_FIRST_ESTABLSIHED
+  encryption_established_ = true;
+  session()->OnCryptoHandshakeEvent(QuicSession::ENCRYPTION_REESTABLISHED);
 }
 
 void QuicCryptoClientStream::DoReceiveREJ(
@@ -486,7 +476,8 @@
       server_id_.host(), server_id_.port(), cached->server_config(),
       session()->connection()->version(), chlo_hash_, cached->certs(),
       cached->cert_sct(), cached->signature(), verify_context_.get(),
-      &verify_error_details_, &verify_details_, proof_verify_callback);
+      &verify_error_details_, &verify_details_,
+      std::unique_ptr<ProofVerifierCallback>(proof_verify_callback));
 
   switch (status) {
     case QUIC_PENDING:
@@ -494,10 +485,8 @@
       DVLOG(1) << "Doing VerifyProof";
       break;
     case QUIC_FAILURE:
-      delete proof_verify_callback;
       break;
     case QUIC_SUCCESS:
-      delete proof_verify_callback;
       verify_ok_ = true;
       break;
   }
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc
index 3358002f..cd92ea6 100644
--- a/net/quic/quic_flags.cc
+++ b/net/quic/quic_flags.cc
@@ -66,21 +66,10 @@
 // If true, headers stream will support receiving PUSH_PROMISE frames.
 bool FLAGS_quic_supports_push_promise = true;
 
-// If true, make sure new incoming streams correctly cede to higher
-// priority (or batch) streams when doing QUIC writes.
-bool FLAGS_quic_cede_correctly = true;
-
-// Resend 0RTT requests in response to an REJ that re-establishes encryption.
-bool FLAGS_quic_reply_to_rej = true;
-
 // If true, QUIC connections can do bandwidth resumption with an initial window
 // of < 10 packets.
 bool FLAGS_quic_no_lower_bw_resumption_limit = true;
 
-// Limit the ruction of slow start large reduction to 1/2 the current CWND once
-// the initial flight has been acked.
-bool FLAGS_quic_sslr_limit_reduction = true;
-
 // If true, flow controller may grow the receive window size if necessary.
 bool FLAGS_quic_auto_tune_receive_window = true;
 
@@ -103,10 +92,6 @@
 // flags.
 bool FLAGS_quic_use_old_public_reset_packets = true;
 
-// Ignore the peer's recieve buffer size and instead set max CWND based on the
-// amount of data the sender is willing to have in flight.
-bool FLAGS_quic_ignore_srbf = true;
-
 // Allow the NPRR connection option which reduces QUIC\'s pacing rate during
 // recovery instead of PRR.
 bool FLAGS_quic_allow_noprr = true;
@@ -164,3 +149,9 @@
 
 // If true, enables QUIC_VERSION_35.
 bool FLAGS_quic_enable_version_35 = false;
+
+// If true, enables QUIC_VERSION_36.
+bool FLAGS_quic_enable_version_36 = false;
+
+// If true, requires support for X509 certificates in QUIC CHLO PDMDs.
+bool FLAGS_quic_require_x509 = false;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h
index 8677ca7..0a54c7b 100644
--- a/net/quic/quic_flags.h
+++ b/net/quic/quic_flags.h
@@ -25,17 +25,13 @@
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_require_fix;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_supports_push_promise;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_supports_push_promise;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_cede_correctly;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_reply_to_rej;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_no_lower_bw_resumption_limit;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_sslr_limit_reduction;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_auto_tune_receive_window;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_enable_autotune_by_default;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_loss_recovery_use_largest_acked;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_only_one_sending_alarm;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_hash_in_scup;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_old_public_reset_packets;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_ignore_srbf;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_allow_noprr;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_optimized_write_path;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_dispatcher_creates_id;
@@ -52,5 +48,7 @@
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_no_mtu_discovery_ack_listener;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_simple_packet_number_length;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_enable_version_35;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_enable_version_36;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_require_x509;
 
 #endif  // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_flow_controller.cc b/net/quic/quic_flow_controller.cc
index 30c5386..f3c8eef 100644
--- a/net/quic/quic_flow_controller.cc
+++ b/net/quic/quic_flow_controller.cc
@@ -135,8 +135,8 @@
   }
 
   // Now we can compare timing of window updates with RTT.
-  QuicTime::Delta since_last = now.Subtract(prev);
-  QuicTime::Delta two_rtt = rtt.Multiply(2);
+  QuicTime::Delta since_last = now - prev;
+  QuicTime::Delta two_rtt = 2 * rtt;
 
   if (since_last >= two_rtt) {
     // If interval between window updates is sufficiently large, there
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index 889e0705..007a947 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -1595,7 +1595,7 @@
 
     ack_frame->received_packet_times.reserve(num_received_packets);
     ack_frame->received_packet_times.push_back(
-        std::make_pair(seq_num, creation_time_.Add(last_timestamp_)));
+        std::make_pair(seq_num, creation_time_ + last_timestamp_));
 
     for (uint8_t i = 1; i < num_received_packets; ++i) {
       if (!reader->ReadBytes(&delta_from_largest_observed,
@@ -1614,10 +1614,10 @@
         return false;
       }
 
-      last_timestamp_ = last_timestamp_.Add(
-          QuicTime::Delta::FromMicroseconds(incremental_time_delta_us));
+      last_timestamp_ = last_timestamp_ + QuicTime::Delta::FromMicroseconds(
+                                              incremental_time_delta_us);
       ack_frame->received_packet_times.push_back(
-          std::make_pair(seq_num, creation_time_.Add(last_timestamp_)));
+          std::make_pair(seq_num, creation_time_ + last_timestamp_));
     }
   }
   return true;
@@ -2447,9 +2447,9 @@
 
   // Use the lowest 4 bytes of the time delta from the creation_time_.
   const uint64_t time_epoch_delta_us = UINT64_C(1) << 32;
-  uint32_t time_delta_us = static_cast<uint32_t>(
-      it->second.Subtract(creation_time_).ToMicroseconds() &
-      (time_epoch_delta_us - 1));
+  uint32_t time_delta_us =
+      static_cast<uint32_t>((it->second - creation_time_).ToMicroseconds() &
+                            (time_epoch_delta_us - 1));
   if (!writer->WriteBytes(&time_delta_us, sizeof(time_delta_us))) {
     return false;
   }
@@ -2469,8 +2469,7 @@
       return false;
     }
 
-    uint64_t frame_time_delta_us =
-        it->second.Subtract(prev_time).ToMicroseconds();
+    uint64_t frame_time_delta_us = (it->second - prev_time).ToMicroseconds();
     prev_time = it->second;
     if (!writer->WriteUFloat16(frame_time_delta_us)) {
       return false;
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index 4f2ba4f..88a0b8e 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -351,7 +351,7 @@
   QuicFramerTest()
       : encrypter_(new test::TestEncrypter()),
         decrypter_(new test::TestDecrypter()),
-        start_(QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(0x10))),
+        start_(QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(0x10)),
         framer_(QuicSupportedVersions(), start_, Perspective::IS_SERVER) {
     version_ = GetParam();
     framer_.set_version(version_);
diff --git a/net/quic/quic_headers_stream.cc b/net/quic/quic_headers_stream.cc
index 72c3ac9..fc56faf2 100644
--- a/net/quic/quic_headers_stream.cc
+++ b/net/quic/quic_headers_stream.cc
@@ -35,14 +35,14 @@
 
   int64_t OnNewEntry(const HpackEntry& entry) override {
     DVLOG(1) << entry.GetDebugString();
-    return clock_->ApproximateNow().Subtract(QuicTime::Zero()).ToMicroseconds();
+    return (clock_->ApproximateNow() - QuicTime::Zero()).ToMicroseconds();
   }
 
   void OnUseEntry(const HpackEntry& entry) override {
     const QuicTime::Delta elapsed(
-        clock_->ApproximateNow()
-            .Subtract(QuicTime::Delta::FromMicroseconds(entry.time_added()))
-            .Subtract(QuicTime::Zero()));
+        clock_->ApproximateNow() -
+        QuicTime::Delta::FromMicroseconds(entry.time_added()) -
+        QuicTime::Zero());
     DVLOG(1) << entry.GetDebugString() << " " << elapsed.ToMilliseconds()
              << " ms";
     headers_stream_hpack_visitor_->OnUseEntry(elapsed);
@@ -56,6 +56,46 @@
   DISALLOW_COPY_AND_ASSIGN(HeaderTableDebugVisitor);
 };
 
+// When forced HOL blocking is enabled, extra bytes in the form of
+// HTTP/2 DATA frame headers are inserted on the way down to the
+// session layer.  |ForceAckListener| filters the |OnPacketAcked()|
+// notifications generated by the session layer to not count the extra
+// bytes.  Otherwise, code that is using ack listener on streams might
+// consider it an error if more bytes are acked than were written to
+// the stream, it is the case with some internal stats gathering code.
+class ForceHolAckListener : public QuicAckListenerInterface {
+ public:
+  // |extra_bytes| should be initialized to the size of the HTTP/2
+  // DATA frame header inserted when forced HOL blocking is enabled.
+  ForceHolAckListener(QuicAckListenerInterface* stream_ack_listener,
+                      int extra_bytes)
+      : stream_ack_listener_(stream_ack_listener), extra_bytes_(extra_bytes) {
+    DCHECK_GE(extra_bytes, 0);
+  }
+
+  void OnPacketAcked(int acked_bytes, QuicTime::Delta ack_delay_time) override {
+    if (extra_bytes_ > 0) {
+      // Don't count the added HTTP/2 DATA frame header bytes
+      int delta = std::min(extra_bytes_, acked_bytes);
+      extra_bytes_ -= delta;
+      acked_bytes -= delta;
+    }
+    stream_ack_listener_->OnPacketAcked(acked_bytes, ack_delay_time);
+  }
+
+  void OnPacketRetransmitted(int retransmitted_bytes) override {
+    stream_ack_listener_->OnPacketRetransmitted(retransmitted_bytes);
+  }
+
+ private:
+  ~ForceHolAckListener() override {}
+
+  scoped_refptr<QuicAckListenerInterface> stream_ack_listener_;
+  int extra_bytes_;
+
+  DISALLOW_COPY_AND_ASSIGN(ForceHolAckListener);
+};
+
 }  // namespace
 
 QuicHeadersStream::HpackDebugVisitor::HpackDebugVisitor() {}
@@ -97,6 +137,9 @@
   void OnStreamFrameData(SpdyStreamId stream_id,
                          const char* data,
                          size_t len) override {
+    if (stream_->OnStreamFrameData(stream_id, data, len)) {
+      return;
+    }
     CloseConnection("SPDY DATA frame received.");
   }
 
@@ -133,6 +176,9 @@
   void OnDataFrameHeader(SpdyStreamId stream_id,
                          size_t length,
                          bool fin) override {
+    if (stream_->OnDataFrameHeader(stream_id, length, fin)) {
+      return;
+    }
     CloseConnection("SPDY DATA frame received.");
   }
 
@@ -330,6 +376,63 @@
   return frame.size();
 }
 
+QuicConsumedData QuicHeadersStream::WritevStreamData(
+    QuicStreamId id,
+    QuicIOVector iov,
+    QuicStreamOffset offset,
+    bool fin,
+    QuicAckListenerInterface* ack_notifier_delegate) {
+  const size_t max_len = SpdyConstants::GetFrameMaximumSize(HTTP2) -
+                         SpdyConstants::GetDataFrameMinimumSize(HTTP2);
+
+  QuicConsumedData result(0, false);
+  size_t total_length = iov.total_length;
+
+  // Encapsulate the data into HTTP/2 DATA frames.  The outer loop
+  // handles each element of the source iov, the inner loop handles
+  // the possibility of fragmenting eacho of those into multiple DATA
+  // frames, as the DATA frames have a max size of 16KB.
+  for (int i = 0; i < iov.iov_count; i++) {
+    size_t offset = 0;
+    const struct iovec* src_iov = &iov.iov[i];
+    do {
+      size_t len =
+          std::min(std::min(src_iov->iov_len - offset, max_len), total_length);
+      char* data = static_cast<char*>(src_iov->iov_base) + offset;
+      SpdyDataIR spdy_data(id, StringPiece(data, len));
+      offset += len;
+      // fin handling, set it only it only very last generated HTTP/2
+      // DATA frame.
+      bool last_iov = i == iov.iov_count - 1;
+      bool last_fragment_within_iov = offset >= src_iov->iov_len;
+      bool frame_fin = (last_iov && last_fragment_within_iov) ? fin : false;
+      spdy_data.set_fin(frame_fin);
+      if (frame_fin) {
+        result.fin_consumed = true;
+      }
+      SpdySerializedFrame frame(spdy_framer_.SerializeFrame(spdy_data));
+      DVLOG(1) << "Encapsulating in DATA frame for stream " << id << " len "
+               << len << " fin " << spdy_data.fin() << " remaining "
+               << src_iov->iov_len - offset;
+
+      scoped_refptr<ForceHolAckListener> ack_listener;
+      if (ack_notifier_delegate != nullptr) {
+        ack_listener =
+            new ForceHolAckListener(ack_notifier_delegate, frame.size() - len);
+      }
+
+      WriteOrBufferData(StringPiece(frame.data(), frame.size()), false,
+                        ack_listener.get());
+      result.bytes_consumed += len;
+      total_length -= len;
+      if (total_length <= 0) {
+        return result;
+      }
+    } while (offset < src_iov->iov_len);
+  }
+  return result;
+}
+
 void QuicHeadersStream::OnDataAvailable() {
   char buffer[1024];
   struct iovec iov;
@@ -405,7 +508,7 @@
         // headers from lower numbered streams actually came off the
         // wire after headers for the current stream, hence there was
         // HOL blocking.
-        QuicTime::Delta delta(prev_max_timestamp_.Subtract(cur_max_timestamp_));
+        QuicTime::Delta delta = prev_max_timestamp_ - cur_max_timestamp_;
         DVLOG(1) << "stream " << stream_id
                  << ": Net.QuicSession.HeadersHOLBlockedTime "
                  << delta.ToMilliseconds();
@@ -452,7 +555,7 @@
       // headers from lower numbered streams actually came off the
       // wire after headers for the current stream, hence there was
       // HOL blocking.
-      QuicTime::Delta delta = prev_max_timestamp_.Subtract(cur_max_timestamp_);
+      QuicTime::Delta delta = prev_max_timestamp_ - cur_max_timestamp_;
       DVLOG(1) << "stream " << stream_id_
                << ": Net.QuicSession.HeadersHOLBlockedTime "
                << delta.ToMilliseconds();
@@ -506,4 +609,39 @@
   spdy_framer_.UpdateHeaderEncoderTableSize(value);
 }
 
+bool QuicHeadersStream::OnDataFrameHeader(QuicStreamId stream_id,
+                                          size_t length,
+                                          bool fin) {
+  if (!spdy_session_->force_hol_blocking()) {
+    return false;
+  }
+  if (!IsConnected()) {
+    return true;
+  }
+  DVLOG(1) << "DATA frame header for stream " << stream_id << " length "
+           << length << " fin " << fin;
+  fin_ = fin;
+  frame_len_ = length;
+  if (fin && length == 0) {
+    OnStreamFrameData(stream_id, "", 0);
+  }
+  return true;
+}
+
+bool QuicHeadersStream::OnStreamFrameData(QuicStreamId stream_id,
+                                          const char* data,
+                                          size_t len) {
+  if (!spdy_session_->force_hol_blocking()) {
+    return false;
+  }
+  if (!IsConnected()) {
+    return true;
+  }
+  frame_len_ -= len;
+  // Ignore fin_ while there is more data coming, if frame_len_ > 0.
+  spdy_session_->OnStreamFrameData(stream_id, data, len,
+                                   frame_len_ > 0 ? false : fin_);
+  return true;
+}
+
 }  // namespace net
diff --git a/net/quic/quic_headers_stream.h b/net/quic/quic_headers_stream.h
index 3f17403..e80040e0 100644
--- a/net/quic/quic_headers_stream.h
+++ b/net/quic/quic_headers_stream.h
@@ -65,6 +65,15 @@
                                   SpdyHeaderBlock headers,
                                   QuicAckListenerInterface* ack_listener);
 
+  // For forcing HOL blocking.  This encapsulates data from other
+  // streams into HTTP/2 data frames on the headers stream.
+  QuicConsumedData WritevStreamData(
+      QuicStreamId id,
+      QuicIOVector iov,
+      QuicStreamOffset offset,
+      bool fin,
+      QuicAckListenerInterface* ack_notifier_delegate);
+
   // ReliableQuicStream implementation
   void OnDataAvailable() override;
 
@@ -123,6 +132,12 @@
   // Called when the size of the compressed frame payload is available.
   void OnCompressedFrameSize(size_t frame_len);
 
+  // For force HOL blocking, where stream frames from all streams are
+  // plumbed through headers stream as HTTP/2 data frames.  Return false
+  // if force_hol_blocking_ is false;
+  bool OnDataFrameHeader(QuicStreamId stream_id, size_t length, bool fin);
+  bool OnStreamFrameData(QuicStreamId stream_id, const char* data, size_t len);
+
   // Returns true if the session is still connected.
   bool IsConnected();
 
diff --git a/net/quic/quic_headers_stream_test.cc b/net/quic/quic_headers_stream_test.cc
index 1dbc07e..728e897 100644
--- a/net/quic/quic_headers_stream_test.cc
+++ b/net/quic/quic_headers_stream_test.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "base/strings/string_number_conversions.h"
+#include "net/quic/quic_bug_tracker.h"
 #include "net/quic/quic_utils.h"
 #include "net/quic/spdy_utils.h"
 #include "net/quic/test_tools/quic_connection_peer.h"
@@ -26,6 +27,9 @@
 using std::string;
 using std::vector;
 using testing::ElementsAre;
+using testing::_;
+using testing::AtLeast;
+using testing::HasSubstr;
 using testing::InSequence;
 using testing::Invoke;
 using testing::Return;
@@ -114,6 +118,26 @@
   MOCK_METHOD2(OnUnknownFrame, bool(SpdyStreamId stream_id, int frame_type));
 };
 
+class ForceHolAckListener : public QuicAckListenerInterface {
+ public:
+  ForceHolAckListener() : total_acked_bytes_(0) {}
+
+  void OnPacketAcked(int acked_bytes, QuicTime::Delta ack_delay_time) override {
+    total_acked_bytes_ += acked_bytes;
+  }
+
+  void OnPacketRetransmitted(int retransmitted_bytes) override {}
+
+  size_t total_acked_bytes() { return total_acked_bytes_; }
+
+ private:
+  ~ForceHolAckListener() override {}
+
+  size_t total_acked_bytes_;
+
+  DISALLOW_COPY_AND_ASSIGN(ForceHolAckListener);
+};
+
 // Run all tests with each version, perspective (client or server),
 // and relevant flag options (false or true)
 struct TestParams {
@@ -171,10 +195,27 @@
   QuicConsumedData SaveIov(const QuicIOVector& data) {
     const iovec* iov = data.iov;
     int count = data.iov_count;
+    int consumed = 0;
     for (int i = 0; i < count; ++i) {
       saved_data_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len);
+      consumed += iov[i].iov_len;
     }
-    return QuicConsumedData(saved_data_.length(), false);
+    return QuicConsumedData(consumed, false);
+  }
+
+  QuicConsumedData SaveIovAndNotifyAckListener(
+      const QuicIOVector& data,
+      QuicAckListenerInterface* ack_listener) {
+    QuicConsumedData result = SaveIov(data);
+    if (ack_listener) {
+      ack_listener->OnPacketAcked(result.bytes_consumed,
+                                  QuicTime::Delta::Zero());
+    }
+    return result;
+  }
+
+  void SavePayload(const char* data, size_t len) {
+    saved_payloads_.append(data, len);
   }
 
   bool SaveHeaderData(const char* data, int len) {
@@ -293,6 +334,7 @@
   string body_;
   string saved_data_;
   string saved_header_data_;
+  string saved_payloads_;
   std::unique_ptr<SpdyFramer> framer_;
   StrictMock<MockVisitor> visitor_;
   std::unique_ptr<StrictMock<MockHpackDebugVisitor>> hpack_encoder_visitor_;
@@ -455,9 +497,6 @@
 }
 
 TEST_P(QuicHeadersStreamTest, NonEmptyHeaderHOLBlockedTime) {
-  if (!FLAGS_quic_measure_headers_hol_blocking_time) {
-    return;
-  }
   QuicStreamId stream_id;
   bool fin = true;
   QuicStreamFrame stream_frames[10];
@@ -550,8 +589,9 @@
 }
 
 TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrame) {
-  SpdyDataIR data(2, "");
+  SpdyDataIR data(2, "ping");
   SpdySerializedFrame frame(framer_->SerializeFrame(data));
+
   EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA,
                                             "SPDY DATA frame received.", _))
       .WillOnce(InvokeWithoutArgs(
@@ -561,6 +601,33 @@
   headers_stream_->OnStreamFrame(stream_frame_);
 }
 
+TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrameForceHolBlocking) {
+  if (version() <= QUIC_VERSION_35) {
+    return;
+  }
+  QuicSpdySessionPeer::SetForceHolBlocking(&session_, true);
+  SpdyDataIR data(2, "ping");
+  SpdySerializedFrame frame(framer_->SerializeFrame(data));
+  EXPECT_CALL(session_, OnStreamFrameData(2, _, 4, false));
+  stream_frame_.data_buffer = frame.data();
+  stream_frame_.data_length = frame.size();
+  headers_stream_->OnStreamFrame(stream_frame_);
+}
+
+TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrameEmptyWithFin) {
+  if (version() <= QUIC_VERSION_35) {
+    return;
+  }
+  QuicSpdySessionPeer::SetForceHolBlocking(&session_, true);
+  SpdyDataIR data(2, "");
+  data.set_fin(true);
+  SpdySerializedFrame frame(framer_->SerializeFrame(data));
+  EXPECT_CALL(session_, OnStreamFrameData(2, _, 0, true));
+  stream_frame_.data_buffer = frame.data();
+  stream_frame_.data_length = frame.size();
+  headers_stream_->OnStreamFrame(stream_frame_);
+}
+
 TEST_P(QuicHeadersStreamTest, ProcessSpdyRstStreamFrame) {
   SpdyRstStreamIR data(2, RST_STREAM_PROTOCOL_ERROR);
   SpdySerializedFrame frame(framer_->SerializeFrame(data));
@@ -781,6 +848,61 @@
   }
 }
 
+TEST_P(QuicHeadersStreamTest, WritevStreamData) {
+  QuicStreamId id = kClientDataStreamId1;
+  QuicStreamOffset offset = 0;
+  struct iovec iov;
+  string data;
+
+  // This test will issue a write that will require fragmenting into
+  // multiple HTTP/2 DATA frames.
+  const int kMinDataFrames = 4;
+  const size_t data_len =
+      SpdyConstants::GetFrameMaximumSize(HTTP2) * kMinDataFrames + 1024;
+  // Set headers stream send window large enough for data written below.
+  headers_stream_->flow_controller()->UpdateSendWindowOffset(data_len * 2 * 4);
+  test::GenerateBody(&data, data_len);
+
+  for (bool fin : {true, false}) {
+    for (bool use_ack_listener : {true, false}) {
+      scoped_refptr<ForceHolAckListener> ack_listener;
+      if (use_ack_listener) {
+        ack_listener = new ForceHolAckListener();
+      }
+      EXPECT_CALL(session_,
+                  WritevData(headers_stream_, kHeadersStreamId, _, _, false, _))
+          .WillRepeatedly(WithArgs<2, 5>(Invoke(
+              this, &QuicHeadersStreamTest::SaveIovAndNotifyAckListener)));
+
+      QuicConsumedData consumed_data = headers_stream_->WritevStreamData(
+          id, MakeIOVector(data, &iov), offset, fin, ack_listener.get());
+
+      EXPECT_EQ(consumed_data.bytes_consumed, data_len);
+      EXPECT_EQ(consumed_data.fin_consumed, fin);
+      // Now process the written data with the SPDY framer, and verify
+      // that the original data is unchanged.
+      EXPECT_CALL(visitor_, OnDataFrameHeader(id, _, _))
+          .Times(AtLeast(kMinDataFrames));
+      EXPECT_CALL(visitor_, OnStreamFrameData(id, _, _))
+          .WillRepeatedly(WithArgs<1, 2>(
+              Invoke(this, &QuicHeadersStreamTest::SavePayload)));
+      if (fin) {
+        EXPECT_CALL(visitor_, OnStreamEnd(id));
+      }
+      framer_->ProcessInput(saved_data_.data(), saved_data_.length());
+      EXPECT_EQ(saved_payloads_, data);
+
+      if (use_ack_listener) {
+        // Notice, acked bytes doesn't include extra bytes used by
+        // HTTP/2 DATA frame headers.
+        EXPECT_EQ(ack_listener->total_acked_bytes(), data_len);
+      }
+      saved_data_.clear();
+      saved_payloads_.clear();
+    }
+  }
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index 41ef5c7b..9829ab46 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -192,6 +192,10 @@
         if (FLAGS_quic_enable_version_35) {
           filtered_versions.push_back(version);
         }
+      } else if (version == QUIC_VERSION_36) {
+        if (FLAGS_quic_enable_version_35 && FLAGS_quic_enable_version_36) {
+          filtered_versions.push_back(version);
+        }
       } else {
         filtered_versions.push_back(version);
       }
@@ -224,6 +228,8 @@
       return MakeQuicTag('Q', '0', '3', '4');
     case QUIC_VERSION_35:
       return MakeQuicTag('Q', '0', '3', '5');
+    case QUIC_VERSION_36:
+      return MakeQuicTag('Q', '0', '3', '6');
     default:
       // This shold be an ERROR because we should never attempt to convert an
       // invalid QuicVersion to be written to the wire.
@@ -261,6 +267,7 @@
     RETURN_STRING_LITERAL(QUIC_VERSION_33);
     RETURN_STRING_LITERAL(QUIC_VERSION_34);
     RETURN_STRING_LITERAL(QUIC_VERSION_35);
+    RETURN_STRING_LITERAL(QUIC_VERSION_36);
     default:
       return "QUIC_VERSION_UNSUPPORTED";
   }
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index d5b6c53..c3089f7 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -372,6 +372,7 @@
   QUIC_VERSION_34 = 34,  // Deprecates entropy, removes private flag from packet
                          // header, uses new ack and stop waiting wire format.
   QUIC_VERSION_35 = 35,  // Allows endpoints to independently set stream limit.
+  QUIC_VERSION_36 = 36,  // Add support to force HOL blocking.
 };
 
 // This vector contains QUIC versions which we currently support.
@@ -382,9 +383,9 @@
 // IMPORTANT: if you are adding to this list, follow the instructions at
 // http://sites/quic/adding-and-removing-versions
 static const QuicVersion kSupportedQuicVersions[] = {
-    QUIC_VERSION_35, QUIC_VERSION_34, QUIC_VERSION_33, QUIC_VERSION_32,
-    QUIC_VERSION_31, QUIC_VERSION_30, QUIC_VERSION_29, QUIC_VERSION_28,
-    QUIC_VERSION_27, QUIC_VERSION_26, QUIC_VERSION_25};
+    QUIC_VERSION_36, QUIC_VERSION_35, QUIC_VERSION_34, QUIC_VERSION_33,
+    QUIC_VERSION_32, QUIC_VERSION_31, QUIC_VERSION_30, QUIC_VERSION_29,
+    QUIC_VERSION_28, QUIC_VERSION_27, QUIC_VERSION_26, QUIC_VERSION_25};
 
 typedef std::vector<QuicVersion> QuicVersionVector;
 
diff --git a/net/quic/quic_protocol_test.cc b/net/quic/quic_protocol_test.cc
index 64ac095..126f610 100644
--- a/net/quic/quic_protocol_test.cc
+++ b/net/quic/quic_protocol_test.cc
@@ -189,7 +189,7 @@
   frame.packets.Add(4);
   frame.packets.Add(5);
   frame.received_packet_times = {
-      {6, QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(7))}};
+      {6, QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(7)}};
   std::ostringstream stream;
   stream << frame;
   EXPECT_EQ(
diff --git a/net/quic/quic_received_packet_manager.cc b/net/quic/quic_received_packet_manager.cc
index 73226a1..4ce6945 100644
--- a/net/quic/quic_received_packet_manager.cc
+++ b/net/quic/quic_received_packet_manager.cc
@@ -175,7 +175,7 @@
         max(stats_->max_sequence_reordering,
             ack_frame_.largest_observed - packet_number);
     int64_t reordering_time_us =
-        receipt_time.Subtract(time_largest_observed_).ToMicroseconds();
+        (receipt_time - time_largest_observed_).ToMicroseconds();
     stats_->max_time_reordering_us =
         max(stats_->max_time_reordering_us, reordering_time_us);
   }
@@ -231,10 +231,9 @@
     ack_frame_.ack_delay_time = QuicTime::Delta::Infinite();
   } else {
     // Ensure the delta is zero if approximate now is "in the past".
-    ack_frame_.ack_delay_time =
-        approximate_now < time_largest_observed_
-            ? QuicTime::Delta::Zero()
-            : approximate_now.Subtract(time_largest_observed_);
+    ack_frame_.ack_delay_time = approximate_now < time_largest_observed_
+                                    ? QuicTime::Delta::Zero()
+                                    : approximate_now - time_largest_observed_;
   }
 
   // Clear all packet times if any are too far from largest observed.
diff --git a/net/quic/quic_received_packet_manager_test.cc b/net/quic/quic_received_packet_manager_test.cc
index a3bca2f5..ee654b75 100644
--- a/net/quic/quic_received_packet_manager_test.cc
+++ b/net/quic/quic_received_packet_manager_test.cc
@@ -342,7 +342,7 @@
 TEST_P(QuicReceivedPacketManagerTest, GetUpdatedAckFrame) {
   QuicPacketHeader header;
   header.packet_number = 2u;
-  QuicTime two_ms = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(2));
+  QuicTime two_ms = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(2);
   EXPECT_FALSE(received_manager_.ack_frame_updated());
   received_manager_.RecordPacketReceived(0u, header, two_ms);
   EXPECT_TRUE(received_manager_.ack_frame_updated());
@@ -354,7 +354,7 @@
   EXPECT_EQ(QuicTime::Delta::Zero(), ack.ack_frame->ack_delay_time);
   EXPECT_EQ(1u, ack.ack_frame->received_packet_times.size());
 
-  QuicTime four_ms = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(4));
+  QuicTime four_ms = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(4);
   ack = received_manager_.GetUpdatedAckFrame(four_ms);
   EXPECT_FALSE(received_manager_.ack_frame_updated());
   // When UpdateReceivedPacketInfo after not having received a new packet,
@@ -383,8 +383,8 @@
   RecordPacketReceipt(1, 0);
   EXPECT_TRUE(received_manager_.ack_frame_updated());
   RecordPacketReceipt(6, 0);
-  RecordPacketReceipt(
-      2, 0, QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1)));
+  RecordPacketReceipt(2, 0,
+                      QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1));
 
   EXPECT_EQ(4u, stats_.max_sequence_reordering);
   EXPECT_EQ(1000, stats_.max_time_reordering_us);
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index 33e79fe..7ec63fc 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -163,14 +163,6 @@
       config.HasClientSentConnectionOption(kUNDO, perspective_)) {
     undo_pending_retransmits_ = true;
   }
-  if (!FLAGS_quic_ignore_srbf && config.HasReceivedSocketReceiveBuffer()) {
-    receive_buffer_bytes_ =
-        max(kMinSocketReceiveBuffer,
-            static_cast<QuicByteCount>(config.ReceivedSocketReceiveBuffer()));
-    QuicByteCount max_cwnd_bytes = static_cast<QuicByteCount>(
-        receive_buffer_bytes_ * kConservativeReceiveBufferFraction);
-    send_algorithm_->SetMaxCongestionWindow(max_cwnd_bytes);
-  }
   send_algorithm_->SetFromConfig(config, perspective_);
 
   if (network_change_visitor_ != nullptr) {
@@ -772,8 +764,7 @@
     return false;
   }
 
-  QuicTime::Delta send_delta =
-      ack_receive_time.Subtract(transmission_info.sent_time);
+  QuicTime::Delta send_delta = ack_receive_time - transmission_info.sent_time;
   const int kMaxSendDeltaSeconds = 30;
   if (FLAGS_quic_socket_walltimestamps &&
       send_delta.ToSeconds() > kMaxSendDeltaSeconds) {
@@ -815,7 +806,7 @@
   }
   switch (GetRetransmissionMode()) {
     case HANDSHAKE_MODE:
-      return clock_->ApproximateNow().Add(GetCryptoRetransmissionDelay());
+      return clock_->ApproximateNow() + GetCryptoRetransmissionDelay();
     case LOSS_MODE:
       return loss_algorithm_->GetLossTimeout();
     case TLP_MODE: {
@@ -823,17 +814,17 @@
       // set the timer based on the earliest retransmittable packet.
       // Base the updated timer on the send time of the last packet.
       const QuicTime sent_time = unacked_packets_.GetLastPacketSentTime();
-      const QuicTime tlp_time = sent_time.Add(GetTailLossProbeDelay());
+      const QuicTime tlp_time = sent_time + GetTailLossProbeDelay();
       // Ensure the TLP timer never gets set to a time in the past.
       return QuicTime::Max(clock_->ApproximateNow(), tlp_time);
     }
     case RTO_MODE: {
       // The RTO is based on the first outstanding packet.
       const QuicTime sent_time = unacked_packets_.GetLastPacketSentTime();
-      QuicTime rto_time = sent_time.Add(GetRetransmissionDelay());
+      QuicTime rto_time = sent_time + GetRetransmissionDelay();
       // Wait for TLP packets to be acked before an RTO fires.
       QuicTime tlp_time =
-          unacked_packets_.GetLastPacketSentTime().Add(GetTailLossProbeDelay());
+          unacked_packets_.GetLastPacketSentTime() + GetTailLossProbeDelay();
       return QuicTime::Max(tlp_time, rto_time);
     }
   }
@@ -866,10 +857,9 @@
             static_cast<int64_t>(0.5 * srtt.ToMilliseconds())));
   }
   if (!unacked_packets_.HasMultipleInFlightPackets()) {
-    return QuicTime::Delta::Max(
-        srtt.Multiply(2),
-        srtt.Multiply(1.5).Add(
-            QuicTime::Delta::FromMilliseconds(kMinRetransmissionTimeMs / 2)));
+    return QuicTime::Delta::Max(2 * srtt,
+                                1.5 * srtt + QuicTime::Delta::FromMilliseconds(
+                                                 kMinRetransmissionTimeMs / 2));
   }
   return QuicTime::Delta::FromMilliseconds(
       max(kMinTailLossProbeTimeoutMs,
@@ -888,8 +878,9 @@
   }
 
   // Calculate exponential back off.
-  retransmission_delay = retransmission_delay.Multiply(
-      1 << min<size_t>(consecutive_rto_count_, kMaxRetransmissions));
+  retransmission_delay =
+      retransmission_delay *
+      (1 << min<size_t>(consecutive_rto_count_, kMaxRetransmissions));
 
   if (retransmission_delay.ToMilliseconds() > kMaxRetransmissionTimeMs) {
     return QuicTime::Delta::FromMilliseconds(kMaxRetransmissionTimeMs);
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index 45cd30b..b21d39e9 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -766,7 +766,7 @@
   }
   QuicTime rto_packet_time = clock_.Now();
   // Advance the time.
-  clock_.AdvanceTime(manager_.GetRetransmissionTime().Subtract(clock_.Now()));
+  clock_.AdvanceTime(manager_.GetRetransmissionTime() - clock_.Now());
 
   // The first tail loss probe retransmits 1 packet.
   manager_.OnRetransmissionTimeout();
@@ -784,7 +784,7 @@
       QuicTime::Delta::Infinite(),
       manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
   EXPECT_FALSE(manager_.HasPendingRetransmissions());
-  clock_.AdvanceTime(manager_.GetRetransmissionTime().Subtract(clock_.Now()));
+  clock_.AdvanceTime(manager_.GetRetransmissionTime() - clock_.Now());
 
   // The second tail loss probe retransmits 1 packet.
   manager_.OnRetransmissionTimeout();
@@ -805,7 +805,7 @@
   rto_packet_time = clock_.Now();
   EXPECT_CALL(*send_algorithm_, RetransmissionDelay())
       .WillOnce(Return(QuicTime::Delta::FromSeconds(1)));
-  EXPECT_EQ(rto_packet_time.Add(QuicTime::Delta::FromSeconds(1)),
+  EXPECT_EQ(rto_packet_time + QuicTime::Delta::FromSeconds(1),
             manager_.GetRetransmissionTime());
 
   // Advance the time enough to ensure all packets are RTO'd.
@@ -1195,7 +1195,7 @@
   // Check the min.
   RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
   rtt_stats->set_initial_rtt_us(1 * kNumMicrosPerMilli);
-  EXPECT_EQ(clock_.Now().Add(QuicTime::Delta::FromMilliseconds(10)),
+  EXPECT_EQ(clock_.Now() + QuicTime::Delta::FromMilliseconds(10),
             manager_.GetRetransmissionTime());
 
   // Test with a standard smoothed RTT.
@@ -1203,16 +1203,16 @@
 
   QuicTime::Delta srtt =
       QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us());
-  QuicTime expected_time = clock_.Now().Add(srtt.Multiply(1.5));
+  QuicTime expected_time = clock_.Now() + 1.5 * srtt;
   EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
 
   // Retransmit the packet by invoking the retransmission timeout.
-  clock_.AdvanceTime(srtt.Multiply(1.5));
+  clock_.AdvanceTime(1.5 * srtt);
   manager_.OnRetransmissionTimeout();
   RetransmitNextPacket(2);
 
   // The retransmission time should now be twice as far in the future.
-  expected_time = clock_.Now().Add(srtt.Multiply(2).Multiply(1.5));
+  expected_time = clock_.Now() + srtt * 2 * 1.5;
   EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
 }
 
@@ -1224,15 +1224,15 @@
   // Check the min.
   RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats());
   rtt_stats->set_initial_rtt_us(1 * kNumMicrosPerMilli);
-  EXPECT_EQ(clock_.Now().Add(QuicTime::Delta::FromMilliseconds(10)),
+  EXPECT_EQ(clock_.Now() + QuicTime::Delta::FromMilliseconds(10),
             manager_.GetRetransmissionTime());
 
   // Test with a standard smoothed RTT.
   rtt_stats->set_initial_rtt_us(100 * kNumMicrosPerMilli);
   QuicTime::Delta srtt =
       QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us());
-  QuicTime::Delta expected_tlp_delay = srtt.Multiply(2);
-  QuicTime expected_time = clock_.Now().Add(expected_tlp_delay);
+  QuicTime::Delta expected_tlp_delay = 2 * srtt;
+  QuicTime expected_time = clock_.Now() + expected_tlp_delay;
   EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
 
   // Retransmit the packet by invoking the retransmission timeout.
@@ -1253,7 +1253,7 @@
       manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
   EXPECT_FALSE(manager_.HasPendingRetransmissions());
 
-  expected_time = clock_.Now().Add(expected_tlp_delay);
+  expected_time = clock_.Now() + expected_tlp_delay;
   EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
 }
 
@@ -1269,7 +1269,7 @@
   QuicTime::Delta expected_rto_delay = QuicTime::Delta::FromMilliseconds(500);
   EXPECT_CALL(*send_algorithm_, RetransmissionDelay())
       .WillRepeatedly(Return(expected_rto_delay));
-  QuicTime expected_time = clock_.Now().Add(expected_rto_delay);
+  QuicTime expected_time = clock_.Now() + expected_rto_delay;
   EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
 
   // Retransmit the packet by invoking the retransmission timeout.
@@ -1286,7 +1286,7 @@
   EXPECT_FALSE(manager_.HasPendingRetransmissions());
 
   // The delay should double the second time.
-  expected_time = clock_.Now().Add(expected_rto_delay).Add(expected_rto_delay);
+  expected_time = clock_.Now() + expected_rto_delay + expected_rto_delay;
   // Once we always base the timer on the right edge, leaving the older packets
   // in flight doesn't change the timeout.
   EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
@@ -1305,7 +1305,7 @@
   // and the TLP time.  In production, there would always be two TLP's first.
   // Since retransmission was spurious, smoothed_rtt_ is expired, and replaced
   // by the latest RTT sample of 500ms.
-  expected_time = clock_.Now().Add(QuicTime::Delta::FromMilliseconds(1000));
+  expected_time = clock_.Now() + QuicTime::Delta::FromMilliseconds(1000);
   // Once we always base the timer on the right edge, leaving the older packets
   // in flight doesn't change the timeout.
   EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
@@ -1323,7 +1323,7 @@
   for (int i = 0; i < 5; ++i) {
     EXPECT_EQ(delay,
               QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_));
-    delay = delay.Add(delay);
+    delay = delay + delay;
     manager_.OnRetransmissionTimeout();
     RetransmitNextPacket(i + 2);
   }
@@ -1348,7 +1348,7 @@
   for (int i = 0; i < 5; ++i) {
     EXPECT_EQ(delay,
               QuicSentPacketManagerPeer::GetRetransmissionDelay(&manager_));
-    delay = delay.Add(delay);
+    delay = delay + delay;
     manager_.OnRetransmissionTimeout();
     RetransmitNextPacket(i + 2);
   }
@@ -1371,7 +1371,7 @@
   NackPackets(1, 2, &ack_frame);
   manager_.OnIncomingAck(ack_frame, clock_.Now());
 
-  QuicTime timeout(clock_.Now().Add(QuicTime::Delta::FromMilliseconds(10)));
+  QuicTime timeout(clock_.Now() + QuicTime::Delta::FromMilliseconds(10));
   EXPECT_CALL(*loss_algorithm, GetLossTimeout())
       .WillRepeatedly(Return(timeout));
   EXPECT_EQ(timeout, manager_.GetRetransmissionTime());
@@ -1622,79 +1622,6 @@
   EXPECT_TRUE(QuicSentPacketManagerPeer::GetUndoRetransmits(&manager_));
 }
 
-TEST_P(QuicSentPacketManagerTest,
-       NegotiateConservativeReceiveWindowFromOptions) {
-  ValueRestore<bool> old_flag(&FLAGS_quic_ignore_srbf, false);
-  EXPECT_EQ(kDefaultSocketReceiveBuffer,
-            QuicSentPacketManagerPeer::GetReceiveWindow(&manager_));
-
-  // Try to set a size below the minimum and ensure it gets set to the min.
-  QuicConfig client_config;
-  QuicConfigPeer::SetReceivedSocketReceiveBuffer(&client_config, 1024);
-  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
-  EXPECT_CALL(*send_algorithm_,
-              SetMaxCongestionWindow(kMinSocketReceiveBuffer * 0.6));
-  EXPECT_CALL(*send_algorithm_, PacingRate(_))
-      .WillRepeatedly(Return(QuicBandwidth::Zero()));
-  EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
-      .WillOnce(Return(10 * kDefaultTCPMSS));
-  EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
-  manager_.SetFromConfig(client_config);
-
-  EXPECT_EQ(kMinSocketReceiveBuffer,
-            QuicSentPacketManagerPeer::GetReceiveWindow(&manager_));
-
-  // Ensure the smaller send window only allows 16 packets to be sent.
-  QuicPathId path_id = kInvalidPathId;
-  for (QuicPacketNumber i = 1; i <= 16; ++i) {
-    EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
-        .WillOnce(Return(QuicTime::Delta::Zero()));
-    EXPECT_EQ(QuicTime::Delta::Zero(),
-              manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA,
-                                     &path_id));
-    EXPECT_CALL(*send_algorithm_,
-                OnPacketSent(_, BytesInFlight(), i, kDefaultLength,
-                             HAS_RETRANSMITTABLE_DATA))
-        .WillOnce(Return(true));
-    SerializedPacket packet(CreatePacket(i, true));
-    manager_.OnPacketSent(&packet, kInvalidPathId, 0, clock_.Now(),
-                          NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
-  }
-  EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
-      .WillOnce(Return(QuicTime::Delta::Infinite()));
-  EXPECT_EQ(
-      QuicTime::Delta::Infinite(),
-      manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
-}
-
-TEST_P(QuicSentPacketManagerTest, ReceiveWindowLimited) {
-  ValueRestore<bool> old_flag(&FLAGS_quic_ignore_srbf, false);
-  EXPECT_EQ(kDefaultSocketReceiveBuffer,
-            QuicSentPacketManagerPeer::GetReceiveWindow(&manager_));
-
-  // Ensure the smaller send window only allows 256 * 0.95 packets to be sent.
-  QuicPathId path_id = kInvalidPathId;
-  for (QuicPacketNumber i = 1; i <= 244; ++i) {
-    EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
-        .WillOnce(Return(QuicTime::Delta::Zero()));
-    EXPECT_EQ(QuicTime::Delta::Zero(),
-              manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA,
-                                     &path_id));
-    EXPECT_CALL(*send_algorithm_,
-                OnPacketSent(_, BytesInFlight(), i, kDefaultLength,
-                             HAS_RETRANSMITTABLE_DATA))
-        .WillOnce(Return(true));
-    SerializedPacket packet(CreatePacket(i, true));
-    manager_.OnPacketSent(&packet, kInvalidPathId, 0, clock_.Now(),
-                          NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
-  }
-  EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _))
-      .WillOnce(Return(QuicTime::Delta::Infinite()));
-  EXPECT_EQ(
-      QuicTime::Delta::Infinite(),
-      manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA, &path_id));
-}
-
 TEST_P(QuicSentPacketManagerTest, UseInitialRoundTripTimeToSend) {
   uint32_t initial_rtt_us = 325000;
   EXPECT_NE(initial_rtt_us,
diff --git a/net/quic/quic_server_session_base.cc b/net/quic/quic_server_session_base.cc
index 63a4602..44bee9903 100644
--- a/net/quic/quic_server_session_base.cc
+++ b/net/quic/quic_server_session_base.cc
@@ -116,7 +116,7 @@
       connection()->sent_packet_manager();
   int64_t srtt_ms =
       sent_packet_manager.GetRttStats()->smoothed_rtt().ToMilliseconds();
-  int64_t now_ms = now.Subtract(last_scup_time_).ToMilliseconds();
+  int64_t now_ms = (now - last_scup_time_).ToMilliseconds();
   int64_t packets_since_last_scup =
       connection()->packet_number_of_last_sent_packet() -
       last_scup_packet_number_;
diff --git a/net/quic/quic_server_session_base_test.cc b/net/quic/quic_server_session_base_test.cc
index 96479f1..980fdb1 100644
--- a/net/quic/quic_server_session_base_test.cc
+++ b/net/quic/quic_server_session_base_test.cc
@@ -459,8 +459,8 @@
   // but not enough packets have been sent.
   int64_t srtt_ms =
       sent_packet_manager->GetRttStats()->smoothed_rtt().ToMilliseconds();
-  now = now.Add(QuicTime::Delta::FromMilliseconds(
-      kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms));
+  now = now + QuicTime::Delta::FromMilliseconds(
+                  kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms);
   session_->OnCongestionWindowChange(now);
 
   // The connection no longer has pending data to be written.
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index b232a1e..788cc68b 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -121,7 +121,7 @@
   }
 
   while (!dynamic_stream_map_.empty()) {
-    StreamMap::iterator it = dynamic_stream_map_.begin();
+    DynamicStreamMap::iterator it = dynamic_stream_map_.begin();
     QuicStreamId id = it->first;
     it->second->OnConnectionClosed(error, source);
     // The stream should call CloseStream as part of OnConnectionClosed.
@@ -308,7 +308,7 @@
 void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) {
   DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
 
-  StreamMap::iterator it = dynamic_stream_map_.find(stream_id);
+  DynamicStreamMap::iterator it = dynamic_stream_map_.find(stream_id);
   if (it == dynamic_stream_map_.end()) {
     // When CloseStreamInner has been called recursively (via
     // ReliableQuicStream::OnClose), the stream will already have been deleted
@@ -615,7 +615,7 @@
 
 ReliableQuicStream* QuicSession::GetOrCreateStream(
     const QuicStreamId stream_id) {
-  StreamMap::iterator it = static_stream_map_.find(stream_id);
+  StaticStreamMap::iterator it = static_stream_map_.find(stream_id);
   if (it != static_stream_map_.end()) {
     return it->second;
   }
@@ -679,7 +679,7 @@
   DCHECK(!ContainsKey(static_stream_map_, stream_id))
       << "Attempt to call GetOrCreateDynamicStream for a static stream";
 
-  StreamMap::iterator it = dynamic_stream_map_.find(stream_id);
+  DynamicStreamMap::iterator it = dynamic_stream_map_.find(stream_id);
   if (it != dynamic_stream_map_.end()) {
     return it->second;
   }
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index 46c22d3..16f96c7 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -17,6 +17,7 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
+#include "base/containers/small_map.h"
 #include "base/macros.h"
 #include "base/strings/string_piece.h"
 #include "net/base/ip_endpoint.h"
@@ -227,7 +228,11 @@
   bool ShouldYield(QuicStreamId stream_id);
 
  protected:
-  typedef std::unordered_map<QuicStreamId, ReliableQuicStream*> StreamMap;
+  using StaticStreamMap =
+      base::SmallMap<std::unordered_map<QuicStreamId, ReliableQuicStream*>, 2>;
+
+  using DynamicStreamMap =
+      base::SmallMap<std::unordered_map<QuicStreamId, ReliableQuicStream*>, 10>;
 
   // Creates a new stream to handle a peer-initiated stream.
   // Caller does not own the returned stream.
@@ -273,11 +278,13 @@
   // Return true if given stream is peer initiated.
   bool IsIncomingStream(QuicStreamId id) const;
 
-  StreamMap& static_streams() { return static_stream_map_; }
-  const StreamMap& static_streams() const { return static_stream_map_; }
+  StaticStreamMap& static_streams() { return static_stream_map_; }
+  const StaticStreamMap& static_streams() const { return static_stream_map_; }
 
-  StreamMap& dynamic_streams() { return dynamic_stream_map_; }
-  const StreamMap& dynamic_streams() const { return dynamic_stream_map_; }
+  DynamicStreamMap& dynamic_streams() { return dynamic_stream_map_; }
+  const DynamicStreamMap& dynamic_streams() const {
+    return dynamic_stream_map_;
+  }
 
   std::vector<ReliableQuicStream*>* closed_streams() {
     return &closed_streams_;
@@ -367,10 +374,10 @@
 
   // Static streams, such as crypto and header streams. Owned by child classes
   // that create these streams.
-  StreamMap static_stream_map_;
+  StaticStreamMap static_stream_map_;
 
   // Map from StreamId to pointers to streams. Owns the streams.
-  StreamMap dynamic_stream_map_;
+  DynamicStreamMap dynamic_stream_map_;
 
   // The ID to use for the next outgoing stream.
   QuicStreamId next_outgoing_stream_id_;
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index fbc4c8f..7b5925a8 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -32,10 +32,13 @@
 #include "testing/gmock_mutant.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using net::SpdyHeaderBlock;
+using net::SpdyPriority;
 using std::set;
 using std::string;
 using std::vector;
 using testing::CreateFunctor;
+using testing::AtLeast;
 using testing::InSequence;
 using testing::Invoke;
 using testing::Return;
@@ -721,7 +724,7 @@
   EXPECT_FALSE(stream2->flow_controller()->IsBlocked());
   EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
   EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
-  EXPECT_CALL(*connection_, SendBlocked(stream2->id()));
+  EXPECT_CALL(*connection_, SendBlocked(_)).Times(AtLeast(1));
   EXPECT_CALL(*connection_, SendBlocked(0));
   stream2->WriteOrBufferBody(body, false, nullptr);
   EXPECT_TRUE(stream2->flow_controller()->IsBlocked());
@@ -1118,6 +1121,16 @@
             kDefaultMaxStreamsPerConnection);
 }
 
+TEST_P(QuicSessionTestServer, EnableFHOLThroughConfigOption) {
+  QuicConfigPeer::SetReceivedForceHolBlocking(session_.config());
+  session_.OnConfigNegotiated();
+  if (version() <= QUIC_VERSION_35) {
+    EXPECT_FALSE(session_.force_hol_blocking());
+  } else {
+    EXPECT_TRUE(session_.force_hol_blocking());
+  }
+}
+
 class QuicSessionTestClient : public QuicSessionTestBase {
  protected:
   QuicSessionTestClient() : QuicSessionTestBase(Perspective::IS_CLIENT) {}
@@ -1195,6 +1208,16 @@
             0UL);
 }
 
+TEST_P(QuicSessionTestClient, EnableFHOLThroughConfigOption) {
+  session_.config()->SetForceHolBlocking();
+  session_.OnConfigNegotiated();
+  if (version() <= QUIC_VERSION_35) {
+    EXPECT_FALSE(session_.force_hol_blocking());
+  } else {
+    EXPECT_TRUE(session_.force_hol_blocking());
+  }
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/quic_spdy_session.cc b/net/quic/quic_spdy_session.cc
index ef0a422..fe1923a 100644
--- a/net/quic/quic_spdy_session.cc
+++ b/net/quic/quic_spdy_session.cc
@@ -16,7 +16,7 @@
 
 QuicSpdySession::QuicSpdySession(QuicConnection* connection,
                                  const QuicConfig& config)
-    : QuicSession(connection, config) {}
+    : QuicSession(connection, config), force_hol_blocking_(false) {}
 
 QuicSpdySession::~QuicSpdySession() {
   // Set the streams' session pointers in closed and dynamic stream lists
@@ -153,6 +153,32 @@
       config()->HasClientSentConnectionOption(kDHDT, perspective())) {
     headers_stream_->DisableHpackDynamicTable();
   }
+  const QuicVersion version = connection()->version();
+  if (version > QUIC_VERSION_35 && config()->ForceHolBlocking(perspective())) {
+    force_hol_blocking_ = true;
+    // Autotuning makes sure that the headers stream flow control does
+    // not get in the way, and normal stream and connection level flow
+    // control are active anyway. This is really only for the client
+    // side (and mainly there just in tests and toys), where
+    // autotuning and/or large buffers are not enabled by default.
+    headers_stream_->flow_controller()->set_auto_tune_receive_window(true);
+  }
+}
+
+void QuicSpdySession::OnStreamFrameData(QuicStreamId stream_id,
+                                        const char* data,
+                                        size_t len,
+                                        bool fin) {
+  QuicSpdyStream* stream = GetSpdyDataStream(stream_id);
+  if (stream == nullptr) {
+    return;
+  }
+  const QuicStreamOffset offset =
+      stream->flow_controller()->highest_received_byte_offset();
+  const QuicStreamFrame frame(stream_id, fin, offset, StringPiece(data, len));
+  DVLOG(1) << "De-encapsulating DATA frame for stream " << stream_id
+           << " offset " << offset << " len " << len << " fin " << fin;
+  OnStreamFrame(frame);
 }
 
 }  // namespace net
diff --git a/net/quic/quic_spdy_session.h b/net/quic/quic_spdy_session.h
index f08ad4c..28a2437 100644
--- a/net/quic/quic_spdy_session.h
+++ b/net/quic/quic_spdy_session.h
@@ -100,6 +100,14 @@
 
   void OnConfigNegotiated() override;
 
+  // Called by |headers_stream_| when |force_hol_blocking_| is true.
+  virtual void OnStreamFrameData(QuicStreamId stream_id,
+                                 const char* data,
+                                 size_t len,
+                                 bool fin);
+
+  bool force_hol_blocking() const { return force_hol_blocking_; }
+
  protected:
   // Override CreateIncomingDynamicStream() and CreateOutgoingDynamicStream()
   // with QuicSpdyStream return type to make sure that all data streams are
@@ -121,6 +129,11 @@
 
   std::unique_ptr<QuicHeadersStream> headers_stream_;
 
+  // If set, redirect all data through the headers stream in order to
+  // simulate forced HOL blocking between streams as happens in
+  // HTTP/2 over TCP.
+  bool force_hol_blocking_;
+
   DISALLOW_COPY_AND_ASSIGN(QuicSpdySession);
 };
 
diff --git a/net/quic/quic_spdy_stream.cc b/net/quic/quic_spdy_stream.cc
index 7b1b3ee..3cbceb64 100644
--- a/net/quic/quic_spdy_stream.cc
+++ b/net/quic/quic_spdy_stream.cc
@@ -402,4 +402,18 @@
   spdy_session_ = nullptr;
 }
 
+QuicConsumedData QuicSpdyStream::WritevDataInner(
+    QuicIOVector iov,
+    QuicStreamOffset offset,
+    bool fin,
+    QuicAckListenerInterface* ack_notifier_delegate) {
+  if (spdy_session_->headers_stream() != nullptr &&
+      spdy_session_->force_hol_blocking()) {
+    return spdy_session_->headers_stream()->WritevStreamData(
+        id(), iov, offset, fin, ack_notifier_delegate);
+  }
+  return ReliableQuicStream::WritevDataInner(iov, offset, fin,
+                                             ack_notifier_delegate);
+}
+
 }  // namespace net
diff --git a/net/quic/quic_spdy_stream.h b/net/quic/quic_spdy_stream.h
index 86d69a8e..01f7a29 100644
--- a/net/quic/quic_spdy_stream.h
+++ b/net/quic/quic_spdy_stream.h
@@ -210,6 +210,14 @@
   // Returns true if headers have been fully read and consumed.
   bool FinishedReadingHeaders() const;
 
+  // Redirects to the headers stream if force HOL blocking enabled,
+  // otherwise just pass through.
+  QuicConsumedData WritevDataInner(
+      QuicIOVector iov,
+      QuicStreamOffset offset,
+      bool fin,
+      QuicAckListenerInterface* ack_notifier_delegate) override;
+
  private:
   friend class test::QuicSpdyStreamPeer;
   friend class test::ReliableQuicStreamPeer;
diff --git a/net/quic/quic_spdy_stream_test.cc b/net/quic/quic_spdy_stream_test.cc
index a869ded..94be546b 100644
--- a/net/quic/quic_spdy_stream_test.cc
+++ b/net/quic/quic_spdy_stream_test.cc
@@ -444,7 +444,7 @@
   GenerateBody(&body, kWindow + kOverflow);
 
   EXPECT_CALL(*connection_, SendBlocked(kClientDataStreamId1));
-  EXPECT_CALL(*session_, WritevData(stream_, kClientDataStreamId1, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(Return(QuicConsumedData(kWindow, true)));
   stream_->WriteOrBufferData(body, false, nullptr);
 
@@ -690,7 +690,7 @@
   bool fin = true;
 
   EXPECT_CALL(*connection_, SendBlocked(kClientDataStreamId1)).Times(0);
-  EXPECT_CALL(*session_, WritevData(stream_, kClientDataStreamId1, _, _, _, _))
+  EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(Return(QuicConsumedData(0, fin)));
 
   stream_->WriteOrBufferData(body, fin, nullptr);
@@ -966,14 +966,18 @@
   EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
       .WillOnce(Return(QuicConsumedData(kBodySize - 1, false)));
   stream_->WriteOrBufferData(string(kBodySize, 'x'), false, nullptr);
-  EXPECT_EQ(1u, stream_->queued_data_bytes());
+  if (!session_->force_hol_blocking()) {
+    EXPECT_EQ(1u, stream_->queued_data_bytes());
+  }
 
   // Writing trailers will send a FIN, but not close the write side of the
   // stream as there are queued bytes.
   EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _));
   stream_->WriteTrailers(SpdyHeaderBlock(), nullptr);
   EXPECT_TRUE(stream_->fin_sent());
-  EXPECT_FALSE(stream_->write_side_closed());
+  if (!session_->force_hol_blocking()) {
+    EXPECT_FALSE(stream_->write_side_closed());
+  }
 }
 
 TEST_P(QuicSpdyStreamTest, WritingTrailersAfterFIN) {
diff --git a/net/quic/quic_stream_sequencer.cc b/net/quic/quic_stream_sequencer.cc
index da26cc52f..f6f0182 100644
--- a/net/quic/quic_stream_sequencer.cc
+++ b/net/quic/quic_stream_sequencer.cc
@@ -19,6 +19,7 @@
 #include "net/quic/quic_utils.h"
 #include "net/quic/reliable_quic_stream.h"
 
+using base::IntToString;
 using base::StringPiece;
 using std::min;
 using std::numeric_limits;
@@ -158,7 +159,7 @@
   if (!result) {
     QUIC_BUG << "Invalid argument to MarkConsumed."
              << " expect to consume: " << num_bytes_consumed
-             << ", but not enough bytes available.";
+             << ", but not enough bytes available. " << DebugString();
     stream_->Reset(QUIC_ERROR_PROCESSING_STREAM);
     return;
   }
@@ -202,4 +203,16 @@
   return buffered_frames_.BytesConsumed();
 }
 
+const string QuicStreamSequencer::DebugString() const {
+  // clang-format off
+  return "QuicStreamSequencer:"
+         "\n  bytes buffered: " + IntToString(NumBytesBuffered()) +
+         "\n  bytes consumed: " + IntToString( NumBytesConsumed()) +
+         "\n  has bytes to read: " +  (HasBytesToRead() ? "true" : "false") +
+         "\n  frames received: " + IntToString(num_frames_received()) +
+         "\n  close offset bytes: " + IntToString( close_offset_) +
+         "\n  is closed: " + (IsClosed() ? "true" : "false");
+  // clang-format on
+}
+
 }  // namespace net
diff --git a/net/quic/quic_stream_sequencer.h b/net/quic/quic_stream_sequencer.h
index 3f37a7ec..d0e5d93a 100644
--- a/net/quic/quic_stream_sequencer.h
+++ b/net/quic/quic_stream_sequencer.h
@@ -95,6 +95,9 @@
 
   bool ignore_read_data() const { return ignore_read_data_; }
 
+  // Returns std::string describing internal state.
+  const std::string DebugString() const;
+
  private:
   friend class test::QuicStreamSequencerPeer;
 
diff --git a/net/quic/quic_sustained_bandwidth_recorder.cc b/net/quic/quic_sustained_bandwidth_recorder.cc
index 41aa51e70..b4b4a61 100644
--- a/net/quic/quic_sustained_bandwidth_recorder.cc
+++ b/net/quic/quic_sustained_bandwidth_recorder.cc
@@ -41,7 +41,7 @@
 
   // If we have been recording for at least 3 * srtt, then record the latest
   // bandwidth estimate as a valid sustained bandwidth estimate.
-  if (estimate_time.Subtract(start_time_) >= srtt.Multiply(3)) {
+  if (estimate_time - start_time_ >= 3 * srtt) {
     has_estimate_ = true;
     bandwidth_estimate_recorded_during_slow_start_ = in_slow_start;
     bandwidth_estimate_ = bandwidth;
diff --git a/net/quic/quic_sustained_bandwidth_recorder_test.cc b/net/quic/quic_sustained_bandwidth_recorder_test.cc
index 91cff412..c369907 100644
--- a/net/quic/quic_sustained_bandwidth_recorder_test.cc
+++ b/net/quic/quic_sustained_bandwidth_recorder_test.cc
@@ -33,14 +33,14 @@
 
   // Send a second reading, again this should not result in a valid estimate,
   // as not enough time has passed.
-  estimate_time = estimate_time.Add(srtt);
+  estimate_time = estimate_time + srtt;
   recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
                           wall_time, srtt);
   EXPECT_FALSE(recorder.HasEstimate());
 
   // Now 3 * kSRTT has elapsed since first recording, expect a valid estimate.
-  estimate_time = estimate_time.Add(srtt);
-  estimate_time = estimate_time.Add(srtt);
+  estimate_time = estimate_time + srtt;
+  estimate_time = estimate_time + srtt;
   recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
                           wall_time, srtt);
   EXPECT_TRUE(recorder.HasEstimate());
@@ -60,7 +60,7 @@
                           wall_time, srtt);
   EXPECT_EQ(recorder.BandwidthEstimate(), bandwidth);
 
-  estimate_time = estimate_time.Add(srtt.Multiply(3));
+  estimate_time = estimate_time + 3 * srtt;
   const int64_t kSeconds = 556677;
   QuicWallTime second_bandwidth_wall_time =
       QuicWallTime::FromUNIXSeconds(kSeconds);
@@ -80,7 +80,7 @@
                           estimate_time, wall_time, srtt);
   EXPECT_EQ(recorder.BandwidthEstimate(), third_bandwidth);
 
-  estimate_time = estimate_time.Add(srtt.Multiply(3));
+  estimate_time = estimate_time + 3 * srtt;
   recorder.RecordEstimate(in_recovery, in_slow_start, third_bandwidth,
                           estimate_time, wall_time, srtt);
   EXPECT_EQ(recorder.BandwidthEstimate(), third_bandwidth);
@@ -111,14 +111,14 @@
                           wall_time, srtt);
 
   // Now 3 * kSRTT has elapsed since first recording, expect a valid estimate.
-  estimate_time = estimate_time.Add(srtt.Multiply(3));
+  estimate_time = estimate_time + 3 * srtt;
   recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
                           wall_time, srtt);
   EXPECT_TRUE(recorder.HasEstimate());
   EXPECT_TRUE(recorder.EstimateRecordedDuringSlowStart());
 
   // Now send another estimate, this time not in slow start.
-  estimate_time = estimate_time.Add(srtt.Multiply(3));
+  estimate_time = estimate_time + 3 * srtt;
   in_slow_start = false;
   recorder.RecordEstimate(in_recovery, in_slow_start, bandwidth, estimate_time,
                           wall_time, srtt);
diff --git a/net/quic/quic_time.h b/net/quic/quic_time.h
index 63b2a34..3c5a670 100644
--- a/net/quic/quic_time.h
+++ b/net/quic/quic_time.h
@@ -70,22 +70,6 @@
     // Converts the time offset to a rounded number of microseconds.
     inline int64_t ToMicroseconds() const { return time_offset_; }
 
-    inline Delta Add(Delta delta) const WARN_UNUSED_RESULT {
-      return Delta(time_offset_ + delta.time_offset_);
-    }
-
-    inline Delta Subtract(Delta delta) const WARN_UNUSED_RESULT {
-      return Delta(time_offset_ - delta.time_offset_);
-    }
-
-    inline Delta Multiply(int i) const WARN_UNUSED_RESULT {
-      return Delta(time_offset_ * i);
-    }
-
-    inline Delta Multiply(double d) const WARN_UNUSED_RESULT {
-      return Delta(time_offset_ * d);
-    }
-
     // Returns the larger delta of time1 and time2.
     static inline Delta Max(Delta delta1, Delta delta2) {
       return delta1 < delta2 ? delta2 : delta1;
@@ -109,8 +93,19 @@
     friend inline QuicTime::Delta operator<<(QuicTime::Delta lhs, size_t rhs);
     friend inline QuicTime::Delta operator>>(QuicTime::Delta lhs, size_t rhs);
 
-    // Highest number of microseconds that DateTimeOffset can hold.
-    static const int64_t kQuicInfiniteTimeUs = INT64_C(0x7fffffffffffffff) / 10;
+    friend inline QuicTime::Delta operator+(QuicTime::Delta lhs,
+                                            QuicTime::Delta rhs);
+    friend inline QuicTime::Delta operator-(QuicTime::Delta lhs,
+                                            QuicTime::Delta rhs);
+    friend inline QuicTime::Delta operator*(QuicTime::Delta lhs, int rhs);
+    friend inline QuicTime::Delta operator*(QuicTime::Delta lhs, double rhs);
+
+    friend inline QuicTime operator+(QuicTime lhs, QuicTime::Delta rhs);
+    friend inline QuicTime operator-(QuicTime lhs, QuicTime::Delta rhs);
+    friend inline QuicTime::Delta operator-(QuicTime lhs, QuicTime rhs);
+
+    static const int64_t kQuicInfiniteTimeUs =
+        std::numeric_limits<int64_t>::max();
 
     explicit QUICTIME_CONSTEXPR Delta(int64_t time_offset)
         : time_offset_(time_offset) {}
@@ -144,23 +139,12 @@
 
   inline bool IsInitialized() const { return 0 != time_; }
 
-  inline QuicTime Add(Delta delta) const WARN_UNUSED_RESULT {
-    return QuicTime(time_ + delta.time_offset_);
-  }
-
-  inline QuicTime Subtract(Delta delta) const WARN_UNUSED_RESULT {
-    return QuicTime(time_ - delta.time_offset_);
-  }
-
-  inline Delta Subtract(QuicTime other) const WARN_UNUSED_RESULT {
-    return Delta(time_ - other.time_);
-  }
-
  private:
   friend inline bool operator==(QuicTime lhs, QuicTime rhs);
   friend inline bool operator<(QuicTime lhs, QuicTime rhs);
-  friend class QuicClock;
-  friend class QuicClockTest;
+  friend inline QuicTime operator+(QuicTime lhs, QuicTime::Delta rhs);
+  friend inline QuicTime operator-(QuicTime lhs, QuicTime::Delta rhs);
+  friend inline QuicTime::Delta operator-(QuicTime lhs, QuicTime rhs);
 
   explicit QUICTIME_CONSTEXPR QuicTime(int64_t time) : time_(time) {}
 
@@ -169,7 +153,7 @@
 
 // A QuicWallTime represents an absolute time that is globally consistent. In
 // practice, clock-skew means that comparing values from different machines
-// requires some flexibility in interpretation.
+// requires some flexibility.
 class NET_EXPORT_PRIVATE QuicWallTime {
  public:
   // FromUNIXSeconds constructs a QuicWallTime from a count of the seconds
@@ -263,6 +247,37 @@
   return !(lhs < rhs);
 }
 
+// Non-member arithmetic operators for QuicTime::Delta.
+inline QuicTime::Delta operator+(QuicTime::Delta lhs, QuicTime::Delta rhs) {
+  return QuicTime::Delta(lhs.time_offset_ + rhs.time_offset_);
+}
+inline QuicTime::Delta operator-(QuicTime::Delta lhs, QuicTime::Delta rhs) {
+  return QuicTime::Delta(lhs.time_offset_ - rhs.time_offset_);
+}
+inline QuicTime::Delta operator*(QuicTime::Delta lhs, int rhs) {
+  return QuicTime::Delta(lhs.time_offset_ * rhs);
+}
+inline QuicTime::Delta operator*(QuicTime::Delta lhs, double rhs) {
+  return QuicTime::Delta(lhs.time_offset_ * rhs);
+}
+inline QuicTime::Delta operator*(int lhs, QuicTime::Delta rhs) {
+  return rhs * lhs;
+}
+inline QuicTime::Delta operator*(double lhs, QuicTime::Delta rhs) {
+  return rhs * lhs;
+}
+
+// Non-member arithmetic operators for QuicTime and QuicTime::Delta.
+inline QuicTime operator+(QuicTime lhs, QuicTime::Delta rhs) {
+  return QuicTime(lhs.time_ + rhs.time_offset_);
+}
+inline QuicTime operator-(QuicTime lhs, QuicTime::Delta rhs) {
+  return QuicTime(lhs.time_ - rhs.time_offset_);
+}
+inline QuicTime::Delta operator-(QuicTime lhs, QuicTime rhs) {
+  return QuicTime::Delta(lhs.time_ - rhs.time_);
+}
+
 }  // namespace net
 
 #endif  // NET_QUIC_QUIC_TIME_H_
diff --git a/net/quic/quic_time_test.cc b/net/quic/quic_time_test.cc
index 602de36..9bdba53 100644
--- a/net/quic/quic_time_test.cc
+++ b/net/quic/quic_time_test.cc
@@ -39,22 +39,26 @@
 
 TEST(QuicTimeDeltaTest, Add) {
   EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2000),
-            QuicTime::Delta::Zero().Add(QuicTime::Delta::FromMilliseconds(2)));
+            QuicTime::Delta::Zero() + QuicTime::Delta::FromMilliseconds(2));
 }
 
 TEST(QuicTimeDeltaTest, Subtract) {
   EXPECT_EQ(QuicTime::Delta::FromMicroseconds(1000),
-            QuicTime::Delta::FromMilliseconds(2).Subtract(
-                QuicTime::Delta::FromMilliseconds(1)));
+            QuicTime::Delta::FromMilliseconds(2) -
+                QuicTime::Delta::FromMilliseconds(1));
 }
 
 TEST(QuicTimeDeltaTest, Multiply) {
   int i = 2;
   EXPECT_EQ(QuicTime::Delta::FromMicroseconds(4000),
-            QuicTime::Delta::FromMilliseconds(2).Multiply(i));
+            QuicTime::Delta::FromMilliseconds(2) * i);
+  EXPECT_EQ(QuicTime::Delta::FromMicroseconds(4000),
+            i * QuicTime::Delta::FromMilliseconds(2));
   double d = 2;
   EXPECT_EQ(QuicTime::Delta::FromMicroseconds(4000),
-            QuicTime::Delta::FromMilliseconds(2).Multiply(d));
+            QuicTime::Delta::FromMilliseconds(2) * d);
+  EXPECT_EQ(QuicTime::Delta::FromMicroseconds(4000),
+            d * QuicTime::Delta::FromMilliseconds(2));
 }
 
 TEST(QuicTimeDeltaTest, Max) {
@@ -77,16 +81,15 @@
 
 TEST_F(QuicTimeTest, Initialized) {
   EXPECT_FALSE(QuicTime::Zero().IsInitialized());
-  EXPECT_TRUE(QuicTime::Zero()
-                  .Add(QuicTime::Delta::FromMicroseconds(1))
+  EXPECT_TRUE((QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(1))
                   .IsInitialized());
 }
 
 TEST_F(QuicTimeTest, Add) {
-  QuicTime time_1 = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1));
-  QuicTime time_2 = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(2));
+  QuicTime time_1 = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1);
+  QuicTime time_2 = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(2);
 
-  QuicTime::Delta diff = time_2.Subtract(time_1);
+  QuicTime::Delta diff = time_2 - time_1;
 
   EXPECT_EQ(QuicTime::Delta::FromMilliseconds(1), diff);
   EXPECT_EQ(1000, diff.ToMicroseconds());
@@ -94,21 +97,21 @@
 }
 
 TEST_F(QuicTimeTest, Subtract) {
-  QuicTime time_1 = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1));
-  QuicTime time_2 = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(2));
+  QuicTime time_1 = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1);
+  QuicTime time_2 = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(2);
 
-  EXPECT_EQ(QuicTime::Delta::FromMilliseconds(1), time_2.Subtract(time_1));
+  EXPECT_EQ(QuicTime::Delta::FromMilliseconds(1), time_2 - time_1);
 }
 
 TEST_F(QuicTimeTest, SubtractDelta) {
-  QuicTime time = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(2));
-  EXPECT_EQ(QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1)),
-            time.Subtract(QuicTime::Delta::FromMilliseconds(1)));
+  QuicTime time = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(2);
+  EXPECT_EQ(QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1),
+            time - QuicTime::Delta::FromMilliseconds(1));
 }
 
 TEST_F(QuicTimeTest, Max) {
-  QuicTime time_1 = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1));
-  QuicTime time_2 = QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(2));
+  QuicTime time_1 = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1);
+  QuicTime time_2 = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(2);
 
   EXPECT_EQ(time_2, QuicTime::Max(time_1, time_2));
 }
@@ -117,7 +120,7 @@
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
 
   QuicTime now = clock_.ApproximateNow();
-  QuicTime time = QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(1000));
+  QuicTime time = QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(1000);
 
   EXPECT_EQ(now, time);
 
@@ -126,13 +129,13 @@
 
   EXPECT_NE(now, time);
 
-  time = time.Add(QuicTime::Delta::FromMilliseconds(1));
+  time = time + QuicTime::Delta::FromMilliseconds(1);
   EXPECT_EQ(now, time);
 }
 
 TEST_F(QuicTimeTest, LE) {
   const QuicTime zero = QuicTime::Zero();
-  const QuicTime one = zero.Add(QuicTime::Delta::FromSeconds(1));
+  const QuicTime one = zero + QuicTime::Delta::FromSeconds(1);
   EXPECT_TRUE(zero <= zero);
   EXPECT_TRUE(zero <= one);
   EXPECT_TRUE(one <= one);
diff --git a/net/quic/quic_unacked_packet_map_test.cc b/net/quic/quic_unacked_packet_map_test.cc
index 26a0043..5d85da9 100644
--- a/net/quic/quic_unacked_packet_map_test.cc
+++ b/net/quic/quic_unacked_packet_map_test.cc
@@ -24,7 +24,7 @@
  protected:
   QuicUnackedPacketMapTest()
       : unacked_packets_(),
-        now_(QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1000))) {}
+        now_(QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1000)) {}
 
   ~QuicUnackedPacketMapTest() override { STLDeleteElements(&packets_); }
 
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index 1af16db..0fddb62 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -569,16 +569,39 @@
   return out;
 }
 
-string QuicUtils::BinaryToAscii(StringPiece binary) {
+string QuicUtils::HexDump(StringPiece binary_input) {
   string out = "";
-  for (const unsigned char c : binary) {
-    // Leading space.
-    out += " ";
-    if (isprint(c)) {
-      out += c;
-    } else {
-      out += '.';
+  const int kBytesPerRow = 16;
+  const int size = binary_input.size();
+  for (int i = 0; i < size;) {
+    // Print one row of hex.
+    for (int j = i; j < i + kBytesPerRow; ++j) {
+      if (j < size) {
+        out += HexEncode(string(1, binary_input[j]));
+      } else {
+        out += "  ";
+      }
+      out += " ";
     }
+    out += " |";
+
+    // Print one row of ascii.
+    for (int j = i; j < i + kBytesPerRow; ++j) {
+      if (j < size) {
+        char c = binary_input[j];
+        bool is_printable = (c >= 32 && c < 127);
+        if (!is_printable) {
+          // Non-printable characters are replaced with '.'.
+          c = '.';
+        }
+        out += string(1, c);
+      } else {
+        out += " ";
+      }
+    }
+
+    out += "|\n";
+    i += kBytesPerRow;
   }
   return out;
 }
diff --git a/net/quic/quic_utils.h b/net/quic/quic_utils.h
index 69e8372..726cef4 100644
--- a/net/quic/quic_utils.h
+++ b/net/quic/quic_utils.h
@@ -143,9 +143,12 @@
   static std::string HexDecode(const char* data, size_t length);
   static std::string HexDecode(base::StringPiece data);
 
-  // Converts binary data into an ASCII string. Each character in the resulting
-  // string is preceeded by a space, and replaced with a '.' if not printable.
-  static std::string BinaryToAscii(base::StringPiece binary);
+  // Returns a std::string containing hex and ASCII representations of |binary|,
+  // side-by-side in the style of hexdump. Non-printable characters will be
+  // printed as '.' in the ASCII output.
+  // For example:
+  // "48 65 6c 6c 6f 2c 20 51 55 49 43 21 01 02 03 04  |Hello, QUIC!....|"
+  static std::string HexDump(base::StringPiece binary_data);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(QuicUtils);
diff --git a/net/quic/quic_utils_test.cc b/net/quic/quic_utils_test.cc
index 7412a24..e8e864b 100644
--- a/net/quic/quic_utils_test.cc
+++ b/net/quic/quic_utils_test.cc
@@ -185,6 +185,27 @@
                 reinterpret_cast<const char*>(data.data()), data.size()));
 }
 
+TEST(QuicUtilsTest, HexDump) {
+  // Verify output of the HexDump method is as expected.
+  char packet[] = {
+      0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x51, 0x55, 0x49, 0x43, 0x21,
+      0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+      0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x6c,
+      0x6f, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x6f, 0x75, 0x67, 0x68, 0x20, 0x74,
+      0x6f, 0x20, 0x73, 0x70, 0x61, 0x6e, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69,
+      0x70, 0x6c, 0x65, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x6f, 0x66,
+      0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x01, 0x02, 0x03, 0x00,
+  };
+  EXPECT_EQ(
+      QuicUtils::HexDump(packet),
+      "48 65 6C 6C 6F 2C 20 51 55 49 43 21 20 54 68 69  |Hello, QUIC! Thi|\n"
+      "73 20 73 74 72 69 6E 67 20 73 68 6F 75 6C 64 20  |s string should |\n"
+      "62 65 20 6C 6F 6E 67 20 65 6E 6F 75 67 68 20 74  |be long enough t|\n"
+      "6F 20 73 70 61 6E 20 6D 75 6C 74 69 70 6C 65 20  |o span multiple |\n"
+      "6C 69 6E 65 73 20 6F 66 20 6F 75 74 70 75 74 2E  |lines of output.|\n"
+      "01 02 03                                         |...             |\n");
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc
index c7d3b6ac..749749b1 100644
--- a/net/quic/reliable_quic_stream.cc
+++ b/net/quic/reliable_quic_stream.cc
@@ -290,7 +290,7 @@
         min(send_window, connection_flow_controller_->SendWindowSize());
   }
 
-  if (FLAGS_quic_cede_correctly && session_->ShouldYield(id())) {
+  if (session_->ShouldYield(id())) {
     session_->MarkConnectionLevelWriteBlocked(id());
     return QuicConsumedData(0, false);
   }
@@ -309,9 +309,9 @@
     write_length = static_cast<size_t>(send_window);
   }
 
-  QuicConsumedData consumed_data = session()->WritevData(
-      this, id(), QuicIOVector(iov, iov_count, write_length),
-      stream_bytes_written_, fin, ack_listener);
+  QuicConsumedData consumed_data =
+      WritevDataInner(QuicIOVector(iov, iov_count, write_length),
+                      stream_bytes_written_, fin, ack_listener);
   stream_bytes_written_ += consumed_data.bytes_consumed;
 
   AddBytesSent(consumed_data.bytes_consumed);
@@ -341,6 +341,15 @@
   return consumed_data;
 }
 
+QuicConsumedData ReliableQuicStream::WritevDataInner(
+    QuicIOVector iov,
+    QuicStreamOffset offset,
+    bool fin,
+    QuicAckListenerInterface* ack_notifier_delegate) {
+  return session()->WritevData(this, id(), iov, offset, fin,
+                               ack_notifier_delegate);
+}
+
 void ReliableQuicStream::CloseReadSide() {
   if (read_side_closed_) {
     return;
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h
index da320363..67bc4b8b 100644
--- a/net/quic/reliable_quic_stream.h
+++ b/net/quic/reliable_quic_stream.h
@@ -191,6 +191,14 @@
                               bool fin,
                               QuicAckListenerInterface* ack_listener);
 
+  // Allows override of the session level writev, for the force HOL
+  // blocking experiment.
+  virtual QuicConsumedData WritevDataInner(
+      QuicIOVector iov,
+      QuicStreamOffset offset,
+      bool fin,
+      QuicAckListenerInterface* ack_notifier_delegate);
+
   // Close the write side of the socket.  Further writes will fail.
   // Can be called by the subclass or internally.
   // Does not send a FIN.  May cause the stream to be closed.
diff --git a/net/quic/test_tools/mock_clock.cc b/net/quic/test_tools/mock_clock.cc
index 63e088a0..524f4341 100644
--- a/net/quic/test_tools/mock_clock.cc
+++ b/net/quic/test_tools/mock_clock.cc
@@ -11,7 +11,7 @@
 MockClock::~MockClock() {}
 
 void MockClock::AdvanceTime(QuicTime::Delta delta) {
-  now_ = now_.Add(delta);
+  now_ = now_ + delta;
 }
 
 QuicTime MockClock::Now() const {
@@ -23,14 +23,13 @@
 }
 
 QuicWallTime MockClock::WallNow() const {
-  return QuicWallTime::FromUNIXSeconds(
-      now_.Subtract(QuicTime::Zero()).ToSeconds());
+  return QuicWallTime::FromUNIXSeconds((now_ - QuicTime::Zero()).ToSeconds());
 }
 
 base::TimeTicks MockClock::NowInTicks() const {
   base::TimeTicks ticks;
   return ticks + base::TimeDelta::FromMicroseconds(
-                     now_.Subtract(QuicTime::Zero()).ToMicroseconds());
+                     (now_ - QuicTime::Zero()).ToMicroseconds());
 }
 
 }  // namespace net
diff --git a/net/quic/test_tools/quic_config_peer.cc b/net/quic/test_tools/quic_config_peer.cc
index 0d60ba8..f272e9ad 100644
--- a/net/quic/test_tools/quic_config_peer.cc
+++ b/net/quic/test_tools/quic_config_peer.cc
@@ -59,10 +59,15 @@
 }
 
 // static
+
 void QuicConfigPeer::SetConnectionOptionsToSend(QuicConfig* config,
                                                 const QuicTagVector& options) {
   config->SetConnectionOptionsToSend(options);
 }
 
+void QuicConfigPeer::SetReceivedForceHolBlocking(QuicConfig* config) {
+  config->force_hol_blocking_.SetReceivedValue(1);
+}
+
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/test_tools/quic_config_peer.h b/net/quic/test_tools/quic_config_peer.h
index bbcf98d..4c9f3cb 100644
--- a/net/quic/test_tools/quic_config_peer.h
+++ b/net/quic/test_tools/quic_config_peer.h
@@ -41,6 +41,8 @@
   static void SetConnectionOptionsToSend(QuicConfig* config,
                                          const QuicTagVector& options);
 
+  static void SetReceivedForceHolBlocking(QuicConfig* config);
+
  private:
   DISALLOW_COPY_AND_ASSIGN(QuicConfigPeer);
 };
diff --git a/net/quic/test_tools/quic_session_peer.cc b/net/quic/test_tools/quic_session_peer.cc
index 14c1475..953aaec 100644
--- a/net/quic/test_tools/quic_session_peer.cc
+++ b/net/quic/test_tools/quic_session_peer.cc
@@ -61,7 +61,8 @@
 }
 
 // static
-QuicSession::StreamMap& QuicSessionPeer::static_streams(QuicSession* session) {
+QuicSession::StaticStreamMap& QuicSessionPeer::static_streams(
+    QuicSession* session) {
   return session->static_streams();
 }
 
diff --git a/net/quic/test_tools/quic_session_peer.h b/net/quic/test_tools/quic_session_peer.h
index 19dd88d6..edc77be 100644
--- a/net/quic/test_tools/quic_session_peer.h
+++ b/net/quic/test_tools/quic_session_peer.h
@@ -38,7 +38,7 @@
                                                       QuicStreamId stream_id);
   static std::map<QuicStreamId, QuicStreamOffset>&
   GetLocallyClosedStreamsHighestOffset(QuicSession* session);
-  static QuicSession::StreamMap& static_streams(QuicSession* session);
+  static QuicSession::StaticStreamMap& static_streams(QuicSession* session);
   static std::unordered_set<QuicStreamId>* GetDrainingStreams(
       QuicSession* session);
   static void ActivateStream(QuicSession* session, ReliableQuicStream* stream);
diff --git a/net/quic/test_tools/quic_spdy_session_peer.cc b/net/quic/test_tools/quic_spdy_session_peer.cc
index e13e477..de80802 100644
--- a/net/quic/test_tools/quic_spdy_session_peer.cc
+++ b/net/quic/test_tools/quic_spdy_session_peer.cc
@@ -22,5 +22,11 @@
   session->static_streams()[headers_stream->id()] = headers_stream;
 }
 
+// static
+void QuicSpdySessionPeer::SetForceHolBlocking(QuicSpdySession* session,
+                                              bool value) {
+  session->force_hol_blocking_ = value;
+}
+
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/test_tools/quic_spdy_session_peer.h b/net/quic/test_tools/quic_spdy_session_peer.h
index d6597c75..7f87287 100644
--- a/net/quic/test_tools/quic_spdy_session_peer.h
+++ b/net/quic/test_tools/quic_spdy_session_peer.h
@@ -21,6 +21,7 @@
   static QuicHeadersStream* GetHeadersStream(QuicSpdySession* session);
   static void SetHeadersStream(QuicSpdySession* session,
                                QuicHeadersStream* headers_stream);
+  static void SetForceHolBlocking(QuicSpdySession* session, bool value);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(QuicSpdySessionPeer);
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index dd0d83d..b770728d 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -625,6 +625,9 @@
                       SpdyPriority priority,
                       QuicAckListenerInterface* ack_notifier_delegate));
   MOCK_METHOD1(OnHeadersHeadOfLineBlocking, void(QuicTime::Delta delta));
+  MOCK_METHOD4(
+      OnStreamFrameData,
+      void(QuicStreamId stream_id, const char* data, size_t len, bool fin));
 
   using QuicSession::ActivateStream;
 
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index d1edfbb..97a3997 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -1208,10 +1208,10 @@
   if (IsRenegotiationAllowed())
     SSL_set_renegotiate_mode(ssl_, ssl_renegotiate_freely);
 
-  uint8_t server_key_exchange_hash = SSL_get_server_key_exchange_hash(ssl_);
-  if (server_key_exchange_hash != TLSEXT_hash_none) {
-    UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLServerKeyExchangeHash",
-                                server_key_exchange_hash);
+  uint16_t signature_algorithm = SSL_get_peer_signature_algorithm(ssl_);
+  if (signature_algorithm != 0) {
+    UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLSignatureAlgorithm",
+                                signature_algorithm);
   }
 
   // Verify the certificate.
diff --git a/net/spdy/hpack/hpack_decoder.cc b/net/spdy/hpack/hpack_decoder.cc
index 1352dc35..d2d90a4 100644
--- a/net/spdy/hpack/hpack_decoder.cc
+++ b/net/spdy/hpack/hpack_decoder.cc
@@ -103,7 +103,7 @@
   return true;
 }
 
-const SpdyHeaderBlock& HpackDecoder::decoded_block() {
+const SpdyHeaderBlock& HpackDecoder::decoded_block() const {
   return decoded_block_;
 }
 
diff --git a/net/spdy/hpack/hpack_decoder.h b/net/spdy/hpack/hpack_decoder.h
index 6af2721..f4134a4 100644
--- a/net/spdy/hpack/hpack_decoder.h
+++ b/net/spdy/hpack/hpack_decoder.h
@@ -68,7 +68,7 @@
   // call to HandleControlFrameHeadersData().
   // TODO(birenroy): Remove this method when all users of HpackDecoder specify
   // a SpdyHeadersHandlerInterface.
-  const SpdyHeaderBlock& decoded_block() override;
+  const SpdyHeaderBlock& decoded_block() const override;
 
   void SetHeaderTableDebugVisitor(
       std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor)
diff --git a/net/spdy/hpack/hpack_decoder_interface.h b/net/spdy/hpack/hpack_decoder_interface.h
index 1a7cdd7..76e6b2b 100644
--- a/net/spdy/hpack/hpack_decoder_interface.h
+++ b/net/spdy/hpack/hpack_decoder_interface.h
@@ -51,7 +51,7 @@
   // call to HandleControlFrameHeadersData().
   // TODO(birenroy): Remove this method when all users of HpackDecoder specify
   // a SpdyHeadersHandlerInterface.
-  virtual const SpdyHeaderBlock& decoded_block() = 0;
+  virtual const SpdyHeaderBlock& decoded_block() const = 0;
 
   virtual void SetHeaderTableDebugVisitor(
       std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) = 0;
diff --git a/net/spdy/hpack/hpack_decoder_test.cc b/net/spdy/hpack/hpack_decoder_test.cc
index 8657a35..8c711d7 100644
--- a/net/spdy/hpack/hpack_decoder_test.cc
+++ b/net/spdy/hpack/hpack_decoder_test.cc
@@ -35,9 +35,6 @@
     return decoder_->DecodeNextName(in, out);
   }
   HpackHeaderTable* header_table() { return &decoder_->header_table_; }
-  const SpdyHeaderBlock& decoded_block() const {
-    return decoder_->decoded_block_;
-  }
 
   bool DecodeNextStringLiteral(HpackInputStream* in,
                                bool is_header_key,
@@ -88,7 +85,7 @@
     if (handler_exists_) {
       return handler_.decoded_block();
     } else {
-      return decoder_peer_.decoded_block();
+      return decoder_.decoded_block();
     }
   }
 
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc
index 5cb0edc..0a9066d 100644
--- a/net/spdy/spdy_test_util_common.cc
+++ b/net/spdy/spdy_test_util_common.cc
@@ -356,7 +356,6 @@
       enable_ip_pooling(true),
       enable_ping(false),
       enable_user_alternate_protocol_ports(false),
-      enable_npn(false),
       enable_priority_dependencies(true),
       enable_spdy31(true),
       enable_quic(false),
@@ -416,7 +415,6 @@
   params.enable_spdy_ping_based_connection_checking = session_deps->enable_ping;
   params.enable_user_alternate_protocol_ports =
       session_deps->enable_user_alternate_protocol_ports;
-  params.enable_npn = session_deps->enable_npn;
   params.enable_priority_dependencies =
       session_deps->enable_priority_dependencies;
   params.enable_spdy31 = session_deps->enable_spdy31;
diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h
index acfeaee3..252ecd8 100644
--- a/net/spdy/spdy_test_util_common.h
+++ b/net/spdy/spdy_test_util_common.h
@@ -203,7 +203,6 @@
   bool enable_ip_pooling;
   bool enable_ping;
   bool enable_user_alternate_protocol_ports;
-  bool enable_npn;
   bool enable_priority_dependencies;
   bool enable_spdy31;
   bool enable_quic;
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 7f4451c..381ebabd 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -29,6 +29,7 @@
 #include "net/quic/quic_session.h"
 #include "net/quic/quic_utils.h"
 #include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/quic_config_peer.h"
 #include "net/quic/test_tools/quic_connection_peer.h"
 #include "net/quic/test_tools/quic_flow_controller_peer.h"
 #include "net/quic/test_tools/quic_sent_packet_manager_peer.h"
@@ -99,7 +100,8 @@
              bool server_uses_stateless_rejects_if_peer_supported,
              QuicTag congestion_control_tag,
              bool auto_tune_flow_control_window,
-             bool disable_hpack_dynamic_table)
+             bool disable_hpack_dynamic_table,
+             bool force_hol_blocking)
       : client_supported_versions(client_supported_versions),
         server_supported_versions(server_supported_versions),
         negotiated_version(negotiated_version),
@@ -108,7 +110,8 @@
             server_uses_stateless_rejects_if_peer_supported),
         congestion_control_tag(congestion_control_tag),
         auto_tune_flow_control_window(auto_tune_flow_control_window),
-        disable_hpack_dynamic_table(disable_hpack_dynamic_table) {}
+        disable_hpack_dynamic_table(disable_hpack_dynamic_table),
+        force_hol_blocking(force_hol_blocking) {}
 
   friend ostream& operator<<(ostream& os, const TestParams& p) {
     os << "{ server_supported_versions: "
@@ -123,8 +126,8 @@
     os << " congestion_control_tag: "
        << QuicUtils::TagToString(p.congestion_control_tag);
     os << " auto_tune_flow_control_window: " << p.auto_tune_flow_control_window;
-    os << " disable_hpack_dynamic_table: " << p.disable_hpack_dynamic_table
-       << " }";
+    os << " disable_hpack_dynamic_table: " << p.disable_hpack_dynamic_table;
+    os << " force_hol_blocking: " << p.force_hol_blocking << " }";
     return os;
   }
 
@@ -136,6 +139,7 @@
   QuicTag congestion_control_tag;
   bool auto_tune_flow_control_window;
   bool disable_hpack_dynamic_table;
+  bool force_hol_blocking;
 };
 
 // Constructs various test permutations.
@@ -181,72 +185,80 @@
     for (bool client_supports_stateless_rejects : {true, false}) {
       for (const QuicTag congestion_control_tag : {kRENO, kQBIC}) {
         for (bool auto_tune_flow_control_window : {true, false}) {
-          for (bool disable_hpack_dynamic_table : {true, false}) {
-            int enabled_options = 0;
-            if (congestion_control_tag != kQBIC) {
-              ++enabled_options;
-            }
-            if (auto_tune_flow_control_window) {
-              ++enabled_options;
-            }
-            if (disable_hpack_dynamic_table) {
-              ++enabled_options;
-            }
-            if (client_supports_stateless_rejects) {
-              ++enabled_options;
-            }
-            if (server_uses_stateless_rejects_if_peer_supported) {
-              ++enabled_options;
-            }
-            CHECK_GE(kMaxEnabledOptions, enabled_options);
-            if (enabled_options > max_enabled_options) {
-              max_enabled_options = enabled_options;
-            }
-
-            // Run tests with no options, a single option, or all the options
-            // enabled to avoid a combinatorial explosion.
-            if (enabled_options > 1 && enabled_options < kMaxEnabledOptions) {
-              continue;
-            }
-
-            for (const QuicVersionVector& client_versions : version_buckets) {
-              if (client_versions.front() < QUIC_VERSION_30 &&
-                  FLAGS_quic_disable_pre_30) {
-                continue;
+          for (bool disable_hpack_dynamic_table : {false}) {
+            for (bool force_hol_blocking : {true, false}) {
+              int enabled_options = 0;
+              if (force_hol_blocking) {
+                ++enabled_options;
               }
-              CHECK(!client_versions.empty());
-              // Add an entry for server and client supporting all versions.
-              params.push_back(TestParams(
-                  client_versions, all_supported_versions,
-                  client_versions.front(), client_supports_stateless_rejects,
-                  server_uses_stateless_rejects_if_peer_supported,
-                  congestion_control_tag, auto_tune_flow_control_window,
-                  disable_hpack_dynamic_table));
+              if (congestion_control_tag != kQBIC) {
+                ++enabled_options;
+              }
+              if (auto_tune_flow_control_window) {
+                ++enabled_options;
+              }
+              if (disable_hpack_dynamic_table) {
+                ++enabled_options;
+              }
+              if (client_supports_stateless_rejects) {
+                ++enabled_options;
+              }
+              if (server_uses_stateless_rejects_if_peer_supported) {
+                ++enabled_options;
+              }
+              CHECK_GE(kMaxEnabledOptions, enabled_options);
+              if (enabled_options > max_enabled_options) {
+                max_enabled_options = enabled_options;
+              }
 
-              // Run version negotiation tests tests with no options, or all
-              // the options enabled to avoid a combinatorial explosion.
-              if (enabled_options > 0 && enabled_options < kMaxEnabledOptions) {
+              // Run tests with no options, a single option, or all the options
+              // enabled to avoid a combinatorial explosion.
+              if (enabled_options > 1 && enabled_options < kMaxEnabledOptions) {
                 continue;
               }
 
-              // Test client supporting all versions and server supporting 1
-              // version. Simulate an old server and exercise version downgrade
-              // in the client. Protocol negotiation should occur. Skip the i =
-              // 0 case because it is essentially the same as the default case.
-              for (size_t i = 1; i < client_versions.size(); ++i) {
-                if (client_versions[i] < QUIC_VERSION_30 &&
+              for (const QuicVersionVector& client_versions : version_buckets) {
+                if (client_versions.front() < QUIC_VERSION_30 &&
                     FLAGS_quic_disable_pre_30) {
                   continue;
                 }
-                QuicVersionVector server_supported_versions;
-                server_supported_versions.push_back(client_versions[i]);
+                CHECK(!client_versions.empty());
+                // Add an entry for server and client supporting all versions.
                 params.push_back(TestParams(
-                    client_versions, server_supported_versions,
-                    server_supported_versions.front(),
-                    client_supports_stateless_rejects,
+                    client_versions, all_supported_versions,
+                    client_versions.front(), client_supports_stateless_rejects,
                     server_uses_stateless_rejects_if_peer_supported,
                     congestion_control_tag, auto_tune_flow_control_window,
-                    disable_hpack_dynamic_table));
+                    disable_hpack_dynamic_table, force_hol_blocking));
+
+                // Run version negotiation tests tests with no options, or all
+                // the options enabled to avoid a combinatorial explosion.
+                if (enabled_options > 0 &&
+                    enabled_options < kMaxEnabledOptions) {
+                  continue;
+                }
+
+                // Test client supporting all versions and server
+                // supporting 1 version. Simulate an old server and
+                // exercise version downgrade in the client. Protocol
+                // negotiation should occur. Skip the i = 0 case
+                // because it is essentially the same as the default
+                // case.
+                for (size_t i = 1; i < client_versions.size(); ++i) {
+                  if (client_versions[i] < QUIC_VERSION_30 &&
+                      FLAGS_quic_disable_pre_30) {
+                    continue;
+                  }
+                  QuicVersionVector server_supported_versions;
+                  server_supported_versions.push_back(client_versions[i]);
+                  params.push_back(TestParams(
+                      client_versions, server_supported_versions,
+                      server_supported_versions.front(),
+                      client_supports_stateless_rejects,
+                      server_uses_stateless_rejects_if_peer_supported,
+                      congestion_control_tag, auto_tune_flow_control_window,
+                      disable_hpack_dynamic_table, force_hol_blocking));
+                }
               }
             }
           }
@@ -402,6 +414,10 @@
     if (GetParam().disable_hpack_dynamic_table) {
       copt.push_back(kDHDT);
     }
+    if (GetParam().force_hol_blocking) {
+      client_config_.SetForceHolBlocking();
+      QuicConfigPeer::SetReceivedForceHolBlocking(&server_config_);
+    }
     client_config_.SetConnectionOptionsToSend(copt);
 
     // Start the server first, because CreateQuicClient() attempts
@@ -509,7 +525,7 @@
   void VerifyCleanConnection(bool had_packet_loss) {
     QuicConnectionStats client_stats =
         client_->client()->session()->connection()->GetStats();
-    if (FLAGS_quic_reply_to_rej && !had_packet_loss) {
+    if (!had_packet_loss) {
       EXPECT_EQ(0u, client_stats.packets_lost);
     }
     EXPECT_EQ(0u, client_stats.packets_discarded);
@@ -534,7 +550,7 @@
     ASSERT_EQ(1u, dispatcher->session_map().size());
     QuicSession* session = dispatcher->session_map().begin()->second;
     QuicConnectionStats server_stats = session->connection()->GetStats();
-    if (FLAGS_quic_reply_to_rej && !had_packet_loss) {
+    if (!had_packet_loss) {
       EXPECT_EQ(0u, server_stats.packets_lost);
     }
     EXPECT_EQ(0u, server_stats.packets_discarded);
@@ -579,6 +595,7 @@
   size_t chlo_multiplier_;
   QuicTestServer::StreamFactory* stream_factory_;
   bool support_server_push_;
+  bool force_hol_blocking_;
 };
 
 // Run all end to end tests with all supported versions.
diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h
index 99e529c..0beccc1 100644
--- a/net/tools/quic/quic_client.h
+++ b/net/tools/quic/quic_client.h
@@ -171,7 +171,11 @@
 
   const IPEndPoint& server_address() const { return server_address_; }
 
-  // Takes ownership of the listener.
+  void set_server_address(const IPEndPoint& server_address) {
+    server_address_ = server_address;
+  }
+
+  // Takes ownership of the std::listener.
   void set_response_listener(ResponseListener* listener) {
     response_listener_.reset(listener);
   }
@@ -246,7 +250,7 @@
                            bool fin);
 
   // Address of the server.
-  const IPEndPoint server_address_;
+  IPEndPoint server_address_;
 
   // If initialized, the address to bind to.
   IPAddress bind_to_address_;
diff --git a/net/tools/quic/quic_client_bin.cc b/net/tools/quic/quic_client_bin.cc
index 26820af6..1d6d6ec 100644
--- a/net/tools/quic/quic_client_bin.cc
+++ b/net/tools/quic/quic_client_bin.cc
@@ -324,9 +324,8 @@
     cout << "headers:" << header_block.DebugString();
     if (!FLAGS_body_hex.empty()) {
       // Print the user provided hex, rather than binary body.
-      cout << "body hex:   " << FLAGS_body_hex << endl;
-      cout << "body ascii: " << net::QuicUtils::BinaryToAscii(
-                                    net::QuicUtils::HexDecode(FLAGS_body_hex))
+      cout << "body:\n"
+           << net::QuicUtils::HexDump(net::QuicUtils::HexDecode(FLAGS_body_hex))
            << endl;
     } else {
       cout << "body: " << body << endl;
@@ -337,10 +336,7 @@
     string response_body = client.latest_response_body();
     if (!FLAGS_body_hex.empty()) {
       // Assume response is binary data.
-      cout << "body hex:   " << net::QuicUtils::HexEncode(response_body)
-           << endl;
-      cout << "body ascii: " << net::QuicUtils::BinaryToAscii(response_body)
-           << endl;
+      cout << "body:\n" << net::QuicUtils::HexDump(response_body) << endl;
     } else {
       cout << "body: " << response_body << endl;
     }
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index 70f2af1..b4826907 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -200,6 +200,7 @@
       alarm_factory_(std::move(alarm_factory)),
       delete_sessions_alarm_(
           alarm_factory_->CreateAlarm(new DeleteSessionsAlarm(this))),
+      buffered_packets_(this, helper_->GetClock(), alarm_factory_.get()),
       supported_versions_(supported_versions),
       disable_quic_pre_30_(FLAGS_quic_disable_pre_30),
       allowed_supported_versions_(supported_versions),
@@ -260,6 +261,7 @@
   QuicConnectionId connection_id = header.connection_id;
   SessionMap::iterator it = session_map_.find(connection_id);
   if (it != session_map_.end()) {
+    DCHECK(!buffered_packets_.HasBufferedPackets(connection_id));
     it->second->ProcessUdpPacket(current_server_address_,
                                  current_client_address_, *current_packet_);
     return false;
@@ -334,6 +336,16 @@
       session_map_.insert(std::make_pair(connection_id, session));
       session->ProcessUdpPacket(current_server_address_,
                                 current_client_address_, *current_packet_);
+      std::list<QuicBufferedPacketStore::BufferedPacket> packets =
+          buffered_packets_.DeliverPackets(connection_id);
+      for (const auto& packet : packets) {
+        SessionMap::iterator it = session_map_.find(connection_id);
+        if (it == session_map_.end()) {
+          break;
+        }
+        it->second->ProcessUdpPacket(packet.server_address,
+                                     packet.client_address, *packet.packet);
+      }
       break;
     }
     case kFateTimeWait:
@@ -594,6 +606,10 @@
   DCHECK(false);
 }
 
+void QuicDispatcher::OnExpiredPackets(
+    QuicConnectionId connection_id,
+    QuicBufferedPacketStore::BufferedPacketList early_arrived_packets) {}
+
 QuicServerSessionBase* QuicDispatcher::CreateQuicSession(
     QuicConnectionId connection_id,
     const IPEndPoint& client_address) {
@@ -673,9 +689,10 @@
                           &rejector);
   if (!ChloExtractor::Extract(*current_packet_, supported_versions_,
                               &validator)) {
-    // TODO(rch): Since there was no CHLO in this packet, buffer it until one
-    // arrives.
-    DLOG(ERROR) << "Dropping undecryptable packet.";
+    DVLOG(1) << "Buffering undecryptable packet.";
+    buffered_packets_.EnqueuePacket(connection_id, *current_packet_,
+                                    current_server_address_,
+                                    current_client_address_);
     return kFateDrop;
   }
 
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h
index db97253..3d4093d 100644
--- a/net/tools/quic/quic_dispatcher.h
+++ b/net/tools/quic/quic_dispatcher.h
@@ -18,6 +18,7 @@
 #include "net/quic/crypto/quic_compressed_certs_cache.h"
 #include "net/quic/crypto/quic_random.h"
 #include "net/quic/quic_blocked_writer_interface.h"
+#include "net/quic/quic_buffered_packet_store.h"
 #include "net/quic/quic_connection.h"
 #include "net/quic/quic_protocol.h"
 #include "net/quic/quic_server_session_base.h"
@@ -37,7 +38,8 @@
 class QuicDispatcher : public QuicServerSessionBase::Visitor,
                        public ProcessPacketInterface,
                        public QuicBlockedWriterInterface,
-                       public QuicFramerVisitorInterface {
+                       public QuicFramerVisitorInterface,
+                       public QuicBufferedPacketStore::VisitorInterface {
  public:
   // Ideally we'd have a linked_hash_set: the  boolean is unused.
   typedef linked_hash_map<QuicBlockedWriterInterface*,
@@ -139,6 +141,11 @@
   bool OnPathCloseFrame(const QuicPathCloseFrame& frame) override;
   void OnPacketComplete() override;
 
+  // QuicBufferedPacketStore::VisitorInterface
+  void OnExpiredPackets(QuicConnectionId connection_id,
+                        QuicBufferedPacketStore::BufferedPacketList
+                            early_arrived_packets) override;
+
  protected:
   virtual QuicServerSessionBase* CreateQuicSession(
       QuicConnectionId connection_id,
@@ -275,6 +282,10 @@
   // The writer to write to the socket with.
   std::unique_ptr<QuicPacketWriter> writer_;
 
+  // Undecryptable packets which are buffered until a connection can be
+  // created to handle them.
+  QuicBufferedPacketStore buffered_packets_;
+
   // This vector contains QUIC versions which we currently support.
   // This should be ordered such that the highest supported version is the first
   // element, with subsequent elements in descending order (versions can be
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
index a063a2d..2b88e05 100644
--- a/net/tools/quic/quic_dispatcher_test.cc
+++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -176,11 +176,11 @@
         crypto_config_(QuicCryptoServerConfig::TESTING,
                        QuicRandom::GetInstance(),
                        CryptoTestUtils::ProofSourceForTesting()),
-        dispatcher_(config_, &crypto_config_, &eps_),
+        dispatcher_(new TestDispatcher(config_, &crypto_config_, &eps_)),
         time_wait_list_manager_(nullptr),
         session1_(nullptr),
         session2_(nullptr) {
-    dispatcher_.InitializeWithWriter(new QuicDefaultPacketWriter(1));
+    dispatcher_->InitializeWithWriter(new QuicDefaultPacketWriter(1));
   }
 
   ~QuicDispatcherTest() override {}
@@ -252,8 +252,8 @@
         ConstructReceivedPacket(*packet, helper_.GetClock()->Now()));
 
     data_ = string(packet->data(), packet->length());
-    dispatcher_.ProcessPacket(server_address_, client_address,
-                              *received_packet);
+    dispatcher_->ProcessPacket(server_address_, client_address,
+                               *received_packet);
   }
 
   void ValidatePacket(const QuicEncryptedPacket& packet) {
@@ -262,11 +262,11 @@
   }
 
   void CreateTimeWaitListManager() {
-    time_wait_list_manager_ =
-        new MockTimeWaitListManager(QuicDispatcherPeer::GetWriter(&dispatcher_),
-                                    &dispatcher_, &helper_, &alarm_factory_);
+    time_wait_list_manager_ = new MockTimeWaitListManager(
+        QuicDispatcherPeer::GetWriter(dispatcher_.get()), dispatcher_.get(),
+        &helper_, &alarm_factory_);
     // dispatcher_ takes the ownership of time_wait_list_manager_.
-    QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_,
+    QuicDispatcherPeer::SetTimeWaitListManager(dispatcher_.get(),
                                                time_wait_list_manager_);
   }
 
@@ -284,7 +284,7 @@
   QuicConfig config_;
   QuicCryptoServerConfig crypto_config_;
   IPEndPoint server_address_;
-  TestDispatcher dispatcher_;
+  std::unique_ptr<TestDispatcher> dispatcher_;
   MockTimeWaitListManager* time_wait_list_manager_;
   TestQuicSpdyServerSession* session1_;
   TestQuicSpdyServerSession* session2_;
@@ -295,20 +295,20 @@
   IPEndPoint client_address(net::test::Loopback4(), 1);
   server_address_ = IPEndPoint(net::test::Any4(), 5);
 
-  EXPECT_CALL(dispatcher_, CreateQuicSession(1, client_address))
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(1, client_address))
       .WillOnce(testing::Return(CreateSession(
-          &dispatcher_, config_, 1, client_address, &mock_helper_,
+          dispatcher_.get(), config_, 1, client_address, &mock_helper_,
           &mock_alarm_factory_, &crypto_config_,
-          QuicDispatcherPeer::GetCache(&dispatcher_), &session1_)));
+          QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
   ProcessPacket(client_address, 1, true, false, SerializeCHLO());
-  EXPECT_EQ(client_address, dispatcher_.current_client_address());
-  EXPECT_EQ(server_address_, dispatcher_.current_server_address());
+  EXPECT_EQ(client_address, dispatcher_->current_client_address());
+  EXPECT_EQ(server_address_, dispatcher_->current_server_address());
 
-  EXPECT_CALL(dispatcher_, CreateQuicSession(2, client_address))
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(2, client_address))
       .WillOnce(testing::Return(CreateSession(
-          &dispatcher_, config_, 2, client_address, &mock_helper_,
+          dispatcher_.get(), config_, 2, client_address, &mock_helper_,
           &mock_alarm_factory_, &crypto_config_,
-          QuicDispatcherPeer::GetCache(&dispatcher_), &session2_)));
+          QuicDispatcherPeer::GetCache(dispatcher_.get()), &session2_)));
   ProcessPacket(client_address, 2, true, false, SerializeCHLO());
 
   EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
@@ -323,7 +323,7 @@
   IPEndPoint client_address(net::test::Loopback4(), 1);
   server_address_ = IPEndPoint(net::test::Any4(), 5);
 
-  EXPECT_CALL(dispatcher_, CreateQuicSession(1, client_address)).Times(0);
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(1, client_address)).Times(0);
   QuicVersion version = static_cast<QuicVersion>(QuicVersionMin() - 1);
   ProcessPacket(client_address, 1, true, version, SerializeCHLO(),
                 PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, 1);
@@ -332,18 +332,18 @@
 TEST_F(QuicDispatcherTest, Shutdown) {
   IPEndPoint client_address(net::test::Loopback4(), 1);
 
-  EXPECT_CALL(dispatcher_, CreateQuicSession(_, client_address))
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(_, client_address))
       .WillOnce(testing::Return(CreateSession(
-          &dispatcher_, config_, 1, client_address, &mock_helper_,
+          dispatcher_.get(), config_, 1, client_address, &mock_helper_,
           &mock_alarm_factory_, &crypto_config_,
-          QuicDispatcherPeer::GetCache(&dispatcher_), &session1_)));
+          QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
 
   ProcessPacket(client_address, 1, true, false, SerializeCHLO());
 
   EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
               CloseConnection(QUIC_PEER_GOING_AWAY, _, _));
 
-  dispatcher_.Shutdown();
+  dispatcher_->Shutdown();
 }
 
 TEST_F(QuicDispatcherTest, TimeWaitListManager) {
@@ -352,11 +352,11 @@
   // Create a new session.
   IPEndPoint client_address(net::test::Loopback4(), 1);
   QuicConnectionId connection_id = 1;
-  EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, client_address))
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
       .WillOnce(testing::Return(CreateSession(
-          &dispatcher_, config_, connection_id, client_address, &mock_helper_,
-          &mock_alarm_factory_, &crypto_config_,
-          QuicDispatcherPeer::GetCache(&dispatcher_), &session1_)));
+          dispatcher_.get(), config_, connection_id, client_address,
+          &mock_helper_, &mock_alarm_factory_, &crypto_config_,
+          QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
   ProcessPacket(client_address, connection_id, true, false, SerializeCHLO());
 
   // Close the connection by sending public reset packet.
@@ -381,7 +381,7 @@
       .WillOnce(
           Invoke(reinterpret_cast<MockQuicConnection*>(session1_->connection()),
                  &MockQuicConnection::ReallyProcessUdpPacket));
-  dispatcher_.ProcessPacket(IPEndPoint(), client_address, *received);
+  dispatcher_->ProcessPacket(IPEndPoint(), client_address, *received);
   EXPECT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
 
   // Dispatcher forwards subsequent packets for this connection_id to the time
@@ -401,7 +401,7 @@
   QuicConnectionId connection_id = 1;
   // Dispatcher forwards all packets for this connection_id to the time wait
   // list manager.
-  EXPECT_CALL(dispatcher_, CreateQuicSession(_, _)).Times(0);
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _)).Times(0);
   EXPECT_CALL(*time_wait_list_manager_,
               ProcessPacket(_, _, connection_id, _, _))
       .Times(1);
@@ -417,7 +417,7 @@
   server_address_ = IPEndPoint(net::test::Any4(), 5);
 
   // dispatcher_ should drop this packet.
-  EXPECT_CALL(dispatcher_, CreateQuicSession(1, client_address)).Times(0);
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(1, client_address)).Times(0);
   EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _)).Times(0);
   EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _))
       .Times(0);
@@ -429,19 +429,19 @@
   QuicConnectionId connection_id = 1;
   server_address_ = IPEndPoint(net::test::Any4(), 5);
 
-  EXPECT_CALL(dispatcher_, CreateQuicSession(1, client_address))
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(1, client_address))
       .WillOnce(testing::Return(CreateSession(
-          &dispatcher_, config_, 1, client_address, &mock_helper_,
+          dispatcher_.get(), config_, 1, client_address, &mock_helper_,
           &mock_alarm_factory_, &crypto_config_,
-          QuicDispatcherPeer::GetCache(&dispatcher_), &session1_)));
+          QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
   // A packet whose packet number is the largest that is allowed to start a
   // connection.
   ProcessPacket(client_address, connection_id, true, false, SerializeCHLO(),
                 PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER,
                 kDefaultPathId,
                 QuicDispatcher::kMaxReasonableInitialPacketNumber);
-  EXPECT_EQ(client_address, dispatcher_.current_client_address());
-  EXPECT_EQ(server_address_, dispatcher_.current_server_address());
+  EXPECT_EQ(client_address, dispatcher_->current_client_address());
+  EXPECT_EQ(server_address_, dispatcher_->current_server_address());
 }
 
 TEST_F(QuicDispatcherTest, TooBigSeqNoPacketToTimeWaitListManager) {
@@ -451,7 +451,7 @@
   QuicConnectionId connection_id = 1;
   // Dispatcher forwards this packet for this connection_id to the time wait
   // list manager.
-  EXPECT_CALL(dispatcher_, CreateQuicSession(_, _)).Times(0);
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _)).Times(0);
   EXPECT_CALL(*time_wait_list_manager_,
               ProcessPacket(_, _, connection_id, _, _))
       .Times(1);
@@ -558,12 +558,13 @@
   QuicServerSessionBase* CreateSessionBasedOnTestParams(
       QuicConnectionId connection_id,
       const IPEndPoint& client_address) {
-    CreateSession(&dispatcher_, config_, connection_id, client_address,
+    CreateSession(dispatcher_.get(), config_, connection_id, client_address,
                   &mock_helper_, &mock_alarm_factory_, &crypto_config_,
-                  QuicDispatcherPeer::GetCache(&dispatcher_), &session1_);
+                  QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_);
 
     crypto_stream1_ = new MockQuicCryptoServerStream(
-        crypto_config_, QuicDispatcherPeer::GetCache(&dispatcher_), session1_);
+        crypto_config_, QuicDispatcherPeer::GetCache(dispatcher_.get()),
+        session1_);
     session1_->SetCryptoStream(crypto_stream1_);
     crypto_stream1_->set_handshake_confirmed_for_testing(
         GetParam().crypto_handshake_successful);
@@ -587,7 +588,7 @@
 
   IPEndPoint client_address(net::test::Loopback4(), 1);
   QuicConnectionId connection_id = 1;
-  EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, client_address))
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
       .WillOnce(testing::Return(
           CreateSessionBasedOnTestParams(connection_id, client_address)));
 
@@ -628,10 +629,10 @@
   IPEndPoint client_address(net::test::Loopback4(), 1);
   QuicConnectionId connection_id = 1;
   if (GetParam().enable_stateless_rejects_via_flag) {
-    EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, client_address))
+    EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
         .Times(0);
   } else {
-    EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, client_address))
+    EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
         .WillOnce(testing::Return(
             CreateSessionBasedOnTestParams(connection_id, client_address)));
   }
@@ -660,6 +661,51 @@
   }
 }
 
+TEST_P(QuicDispatcherStatelessRejectTest, BufferNonChlo) {
+  FLAGS_quic_use_cheap_stateless_rejects = true;
+  CreateTimeWaitListManager();
+
+  const IPEndPoint client_address(net::test::Loopback4(), 1);
+  const QuicConnectionId connection_id = 1;
+
+  if (!GetParam().enable_stateless_rejects_via_flag) {
+    // If stateless rejects are not being used, then a connection will be
+    // created immediately.
+    EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
+        .WillOnce(testing::Return(
+            CreateSessionBasedOnTestParams(connection_id, client_address)));
+  }
+  ProcessPacket(client_address, connection_id, true, false,
+                "NOT DATA FOR A CHLO");
+
+  // Process the first packet for the connection.
+  // clang-format off
+  CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
+      "CHLO",
+      "AEAD", "AESG",
+      "KEXS", "C255",
+      "NONC", "1234567890123456789012",
+      "VER\0", "Q025",
+      "$padding", static_cast<int>(kClientHelloMinimumSize),
+      nullptr);
+  // clang-format on
+
+  if (GetParam().enable_stateless_rejects_via_flag) {
+    // If stateless rejects are enabled then a connection will be created now
+    // and the buffered packet will be processed
+    EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address))
+        .WillOnce(testing::Return(
+            CreateSessionBasedOnTestParams(connection_id, client_address)));
+  }
+  EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+              ProcessUdpPacket(_, client_address, _))
+      .RetiresOnSaturation();
+  ProcessPacket(client_address, connection_id, true, false,
+                client_hello.GetSerialized().AsStringPiece().as_string());
+  EXPECT_FALSE(
+      time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
+}
+
 // Verify the stopgap test: Packets with truncated connection IDs should be
 // dropped.
 class QuicDispatcherTestStrayPacketConnectionId : public QuicDispatcherTest {};
@@ -672,7 +718,7 @@
   IPEndPoint client_address(net::test::Loopback4(), 1);
   QuicConnectionId connection_id = 1;
   // Dispatcher drops this packet.
-  EXPECT_CALL(dispatcher_, CreateQuicSession(_, _)).Times(0);
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _)).Times(0);
   EXPECT_CALL(*time_wait_list_manager_,
               ProcessPacket(_, _, connection_id, _, _))
       .Times(0);
@@ -708,38 +754,38 @@
  public:
   void SetUp() override {
     writer_ = new BlockingWriter;
-    QuicDispatcherPeer::UseWriter(&dispatcher_, writer_);
+    QuicDispatcherPeer::UseWriter(dispatcher_.get(), writer_);
 
     IPEndPoint client_address(net::test::Loopback4(), 1);
 
-    EXPECT_CALL(dispatcher_, CreateQuicSession(_, client_address))
+    EXPECT_CALL(*dispatcher_, CreateQuicSession(_, client_address))
         .WillOnce(testing::Return(CreateSession(
-            &dispatcher_, config_, 1, client_address, &helper_, &alarm_factory_,
-            &crypto_config_, QuicDispatcherPeer::GetCache(&dispatcher_),
-            &session1_)));
+            dispatcher_.get(), config_, 1, client_address, &helper_,
+            &alarm_factory_, &crypto_config_,
+            QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
     ProcessPacket(client_address, 1, true, false, SerializeCHLO());
 
-    EXPECT_CALL(dispatcher_, CreateQuicSession(_, client_address))
+    EXPECT_CALL(*dispatcher_, CreateQuicSession(_, client_address))
         .WillOnce(testing::Return(CreateSession(
-            &dispatcher_, config_, 2, client_address, &helper_, &alarm_factory_,
-            &crypto_config_, QuicDispatcherPeer::GetCache(&dispatcher_),
-            &session2_)));
+            dispatcher_.get(), config_, 2, client_address, &helper_,
+            &alarm_factory_, &crypto_config_,
+            QuicDispatcherPeer::GetCache(dispatcher_.get()), &session2_)));
     ProcessPacket(client_address, 2, true, false, SerializeCHLO());
 
-    blocked_list_ = QuicDispatcherPeer::GetWriteBlockedList(&dispatcher_);
+    blocked_list_ = QuicDispatcherPeer::GetWriteBlockedList(dispatcher_.get());
   }
 
   void TearDown() override {
     EXPECT_CALL(*connection1(), CloseConnection(QUIC_PEER_GOING_AWAY, _, _));
     EXPECT_CALL(*connection2(), CloseConnection(QUIC_PEER_GOING_AWAY, _, _));
-    dispatcher_.Shutdown();
+    dispatcher_->Shutdown();
   }
 
   void SetBlocked() { writer_->write_blocked_ = true; }
 
   void BlockConnection2() {
     writer_->write_blocked_ = true;
-    dispatcher_.OnWriteBlocked(connection2());
+    dispatcher_->OnWriteBlocked(connection2());
   }
 
  protected:
@@ -751,95 +797,95 @@
 
 TEST_F(QuicDispatcherWriteBlockedListTest, BasicOnCanWrite) {
   // No OnCanWrite calls because no connections are blocked.
-  dispatcher_.OnCanWrite();
+  dispatcher_->OnCanWrite();
 
   // Register connection 1 for events, and make sure it's notified.
   SetBlocked();
-  dispatcher_.OnWriteBlocked(connection1());
+  dispatcher_->OnWriteBlocked(connection1());
   EXPECT_CALL(*connection1(), OnCanWrite());
-  dispatcher_.OnCanWrite();
+  dispatcher_->OnCanWrite();
 
   // It should get only one notification.
   EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
-  dispatcher_.OnCanWrite();
-  EXPECT_FALSE(dispatcher_.HasPendingWrites());
+  dispatcher_->OnCanWrite();
+  EXPECT_FALSE(dispatcher_->HasPendingWrites());
 }
 
 TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteOrder) {
   // Make sure we handle events in order.
   InSequence s;
   SetBlocked();
-  dispatcher_.OnWriteBlocked(connection1());
-  dispatcher_.OnWriteBlocked(connection2());
+  dispatcher_->OnWriteBlocked(connection1());
+  dispatcher_->OnWriteBlocked(connection2());
   EXPECT_CALL(*connection1(), OnCanWrite());
   EXPECT_CALL(*connection2(), OnCanWrite());
-  dispatcher_.OnCanWrite();
+  dispatcher_->OnCanWrite();
 
   // Check the other ordering.
   SetBlocked();
-  dispatcher_.OnWriteBlocked(connection2());
-  dispatcher_.OnWriteBlocked(connection1());
+  dispatcher_->OnWriteBlocked(connection2());
+  dispatcher_->OnWriteBlocked(connection1());
   EXPECT_CALL(*connection2(), OnCanWrite());
   EXPECT_CALL(*connection1(), OnCanWrite());
-  dispatcher_.OnCanWrite();
+  dispatcher_->OnCanWrite();
 }
 
 TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteRemove) {
   // Add and remove one connction.
   SetBlocked();
-  dispatcher_.OnWriteBlocked(connection1());
+  dispatcher_->OnWriteBlocked(connection1());
   blocked_list_->erase(connection1());
   EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
-  dispatcher_.OnCanWrite();
+  dispatcher_->OnCanWrite();
 
   // Add and remove one connction and make sure it doesn't affect others.
   SetBlocked();
-  dispatcher_.OnWriteBlocked(connection1());
-  dispatcher_.OnWriteBlocked(connection2());
+  dispatcher_->OnWriteBlocked(connection1());
+  dispatcher_->OnWriteBlocked(connection2());
   blocked_list_->erase(connection1());
   EXPECT_CALL(*connection2(), OnCanWrite());
-  dispatcher_.OnCanWrite();
+  dispatcher_->OnCanWrite();
 
   // Add it, remove it, and add it back and make sure things are OK.
   SetBlocked();
-  dispatcher_.OnWriteBlocked(connection1());
+  dispatcher_->OnWriteBlocked(connection1());
   blocked_list_->erase(connection1());
-  dispatcher_.OnWriteBlocked(connection1());
+  dispatcher_->OnWriteBlocked(connection1());
   EXPECT_CALL(*connection1(), OnCanWrite()).Times(1);
-  dispatcher_.OnCanWrite();
+  dispatcher_->OnCanWrite();
 }
 
 TEST_F(QuicDispatcherWriteBlockedListTest, DoubleAdd) {
   // Make sure a double add does not necessitate a double remove.
   SetBlocked();
-  dispatcher_.OnWriteBlocked(connection1());
-  dispatcher_.OnWriteBlocked(connection1());
+  dispatcher_->OnWriteBlocked(connection1());
+  dispatcher_->OnWriteBlocked(connection1());
   blocked_list_->erase(connection1());
   EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
-  dispatcher_.OnCanWrite();
+  dispatcher_->OnCanWrite();
 
   // Make sure a double add does not result in two OnCanWrite calls.
   SetBlocked();
-  dispatcher_.OnWriteBlocked(connection1());
-  dispatcher_.OnWriteBlocked(connection1());
+  dispatcher_->OnWriteBlocked(connection1());
+  dispatcher_->OnWriteBlocked(connection1());
   EXPECT_CALL(*connection1(), OnCanWrite()).Times(1);
-  dispatcher_.OnCanWrite();
+  dispatcher_->OnCanWrite();
 }
 
 TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteHandleBlock) {
   // Finally make sure if we write block on a write call, we stop calling.
   InSequence s;
   SetBlocked();
-  dispatcher_.OnWriteBlocked(connection1());
-  dispatcher_.OnWriteBlocked(connection2());
+  dispatcher_->OnWriteBlocked(connection1());
+  dispatcher_->OnWriteBlocked(connection2());
   EXPECT_CALL(*connection1(), OnCanWrite())
       .WillOnce(Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked));
   EXPECT_CALL(*connection2(), OnCanWrite()).Times(0);
-  dispatcher_.OnCanWrite();
+  dispatcher_->OnCanWrite();
 
   // And we'll resume where we left off when we get another call.
   EXPECT_CALL(*connection2(), OnCanWrite());
-  dispatcher_.OnCanWrite();
+  dispatcher_->OnCanWrite();
 }
 
 TEST_F(QuicDispatcherWriteBlockedListTest, LimitedWrites) {
@@ -847,37 +893,37 @@
   // but should not be immediately called due to limits.
   InSequence s;
   SetBlocked();
-  dispatcher_.OnWriteBlocked(connection1());
-  dispatcher_.OnWriteBlocked(connection2());
+  dispatcher_->OnWriteBlocked(connection1());
+  dispatcher_->OnWriteBlocked(connection2());
   EXPECT_CALL(*connection1(), OnCanWrite());
   EXPECT_CALL(*connection2(), OnCanWrite())
       .WillOnce(
           Invoke(this, &QuicDispatcherWriteBlockedListTest::BlockConnection2));
-  dispatcher_.OnCanWrite();
-  EXPECT_TRUE(dispatcher_.HasPendingWrites());
+  dispatcher_->OnCanWrite();
+  EXPECT_TRUE(dispatcher_->HasPendingWrites());
 
   // Now call OnCanWrite again, and connection1 should get its second chance
   EXPECT_CALL(*connection2(), OnCanWrite());
-  dispatcher_.OnCanWrite();
-  EXPECT_FALSE(dispatcher_.HasPendingWrites());
+  dispatcher_->OnCanWrite();
+  EXPECT_FALSE(dispatcher_->HasPendingWrites());
 }
 
 TEST_F(QuicDispatcherWriteBlockedListTest, TestWriteLimits) {
   // Finally make sure if we write block on a write call, we stop calling.
   InSequence s;
   SetBlocked();
-  dispatcher_.OnWriteBlocked(connection1());
-  dispatcher_.OnWriteBlocked(connection2());
+  dispatcher_->OnWriteBlocked(connection1());
+  dispatcher_->OnWriteBlocked(connection2());
   EXPECT_CALL(*connection1(), OnCanWrite())
       .WillOnce(Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked));
   EXPECT_CALL(*connection2(), OnCanWrite()).Times(0);
-  dispatcher_.OnCanWrite();
-  EXPECT_TRUE(dispatcher_.HasPendingWrites());
+  dispatcher_->OnCanWrite();
+  EXPECT_TRUE(dispatcher_->HasPendingWrites());
 
   // And we'll resume where we left off when we get another call.
   EXPECT_CALL(*connection2(), OnCanWrite());
-  dispatcher_.OnCanWrite();
-  EXPECT_FALSE(dispatcher_.HasPendingWrites());
+  dispatcher_->OnCanWrite();
+  EXPECT_FALSE(dispatcher_->HasPendingWrites());
 }
 
 }  // namespace
diff --git a/net/tools/quic/quic_epoll_alarm_factory.cc b/net/tools/quic/quic_epoll_alarm_factory.cc
index 21a166a7..56377b2 100644
--- a/net/tools/quic/quic_epoll_alarm_factory.cc
+++ b/net/tools/quic/quic_epoll_alarm_factory.cc
@@ -23,8 +23,7 @@
   void SetImpl() override {
     DCHECK(deadline().IsInitialized());
     epoll_server_->RegisterAlarm(
-        deadline().Subtract(QuicTime::Zero()).ToMicroseconds(),
-        &epoll_alarm_impl_);
+        (deadline() - QuicTime::Zero()).ToMicroseconds(), &epoll_alarm_impl_);
   }
 
   void CancelImpl() override {
diff --git a/net/tools/quic/quic_epoll_alarm_factory_test.cc b/net/tools/quic/quic_epoll_alarm_factory_test.cc
index 5dfe701..3118be8 100644
--- a/net/tools/quic/quic_epoll_alarm_factory_test.cc
+++ b/net/tools/quic/quic_epoll_alarm_factory_test.cc
@@ -48,11 +48,11 @@
 
   QuicTime start = clock_.Now();
   QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
-  alarm->Set(start.Add(delta));
+  alarm->Set(start + delta);
 
   epoll_server_.AdvanceByAndWaitForEventsAndExecuteCallbacks(
       delta.ToMicroseconds());
-  EXPECT_EQ(start.Add(delta), clock_.Now());
+  EXPECT_EQ(start + delta, clock_.Now());
 }
 
 TEST_P(QuicEpollAlarmFactoryTest, CreateAlarmAndCancel) {
@@ -64,11 +64,11 @@
 
   QuicTime start = clock_.Now();
   QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
-  alarm->Set(start.Add(delta));
+  alarm->Set(start + delta);
   alarm->Cancel();
 
   epoll_server_.AdvanceByExactlyAndCallCallbacks(delta.ToMicroseconds());
-  EXPECT_EQ(start.Add(delta), clock_.Now());
+  EXPECT_EQ(start + delta, clock_.Now());
   EXPECT_FALSE(unowned_delegate->fired());
 }
 
@@ -81,18 +81,18 @@
 
   QuicTime start = clock_.Now();
   QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
-  alarm->Set(clock_.Now().Add(delta));
+  alarm->Set(clock_.Now() + delta);
   alarm->Cancel();
   QuicTime::Delta new_delta = QuicTime::Delta::FromMicroseconds(3);
-  alarm->Set(clock_.Now().Add(new_delta));
+  alarm->Set(clock_.Now() + new_delta);
 
   epoll_server_.AdvanceByExactlyAndCallCallbacks(delta.ToMicroseconds());
-  EXPECT_EQ(start.Add(delta), clock_.Now());
+  EXPECT_EQ(start + delta, clock_.Now());
   EXPECT_FALSE(unowned_delegate->fired());
 
   epoll_server_.AdvanceByExactlyAndCallCallbacks(
-      new_delta.Subtract(delta).ToMicroseconds());
-  EXPECT_EQ(start.Add(new_delta), clock_.Now());
+      (new_delta - delta).ToMicroseconds());
+  EXPECT_EQ(start + new_delta, clock_.Now());
   EXPECT_TRUE(unowned_delegate->fired());
 }
 
@@ -105,28 +105,25 @@
 
   QuicTime start = clock_.Now();
   QuicTime::Delta delta = QuicTime::Delta::FromMicroseconds(1);
-  alarm->Set(clock_.Now().Add(delta));
+  alarm->Set(clock_.Now() + delta);
   QuicTime::Delta new_delta = QuicTime::Delta::FromMicroseconds(3);
-  alarm->Update(clock_.Now().Add(new_delta),
-                QuicTime::Delta::FromMicroseconds(1));
+  alarm->Update(clock_.Now() + new_delta, QuicTime::Delta::FromMicroseconds(1));
 
   epoll_server_.AdvanceByExactlyAndCallCallbacks(delta.ToMicroseconds());
-  EXPECT_EQ(start.Add(delta), clock_.Now());
+  EXPECT_EQ(start + delta, clock_.Now());
   EXPECT_FALSE(unowned_delegate->fired());
 
   // Move the alarm forward 1us and ensure it doesn't move forward.
-  alarm->Update(clock_.Now().Add(new_delta),
-                QuicTime::Delta::FromMicroseconds(2));
+  alarm->Update(clock_.Now() + new_delta, QuicTime::Delta::FromMicroseconds(2));
 
   epoll_server_.AdvanceByExactlyAndCallCallbacks(
-      new_delta.Subtract(delta).ToMicroseconds());
-  EXPECT_EQ(start.Add(new_delta), clock_.Now());
+      (new_delta - delta).ToMicroseconds());
+  EXPECT_EQ(start + new_delta, clock_.Now());
   EXPECT_TRUE(unowned_delegate->fired());
 
   // Set the alarm via an update call.
   new_delta = QuicTime::Delta::FromMicroseconds(5);
-  alarm->Update(clock_.Now().Add(new_delta),
-                QuicTime::Delta::FromMicroseconds(1));
+  alarm->Update(clock_.Now() + new_delta, QuicTime::Delta::FromMicroseconds(1));
   EXPECT_TRUE(alarm->IsSet());
 
   // Update it with an uninitialized time and ensure it's cancelled.
diff --git a/net/tools/quic/quic_epoll_clock.cc b/net/tools/quic/quic_epoll_clock.cc
index cb77176..357bc50 100644
--- a/net/tools/quic/quic_epoll_clock.cc
+++ b/net/tools/quic/quic_epoll_clock.cc
@@ -14,13 +14,13 @@
 QuicEpollClock::~QuicEpollClock() {}
 
 QuicTime QuicEpollClock::ApproximateNow() const {
-  return QuicTime::Zero().Add(
-      QuicTime::Delta::FromMicroseconds(epoll_server_->ApproximateNowInUsec()));
+  return QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(
+                                epoll_server_->ApproximateNowInUsec());
 }
 
 QuicTime QuicEpollClock::Now() const {
-  return QuicTime::Zero().Add(
-      QuicTime::Delta::FromMicroseconds(epoll_server_->NowInUsec()));
+  return QuicTime::Zero() +
+         QuicTime::Delta::FromMicroseconds(epoll_server_->NowInUsec());
 }
 
 QuicWallTime QuicEpollClock::WallNow() const {
@@ -30,8 +30,8 @@
 
 QuicTime QuicEpollClock::ConvertWallTimeToQuicTime(
     const QuicWallTime& walltime) const {
-  return QuicTime::Zero().Add(
-      QuicTime::Delta::FromMicroseconds(walltime.ToUNIXMicroseconds()));
-};
+  return QuicTime::Zero() +
+         QuicTime::Delta::FromMicroseconds(walltime.ToUNIXMicroseconds());
+}
 
 }  // namespace net
diff --git a/net/tools/quic/quic_epoll_clock_test.cc b/net/tools/quic/quic_epoll_clock_test.cc
index 039e8bf..03d26b821 100644
--- a/net/tools/quic/quic_epoll_clock_test.cc
+++ b/net/tools/quic/quic_epoll_clock_test.cc
@@ -16,13 +16,13 @@
 
   epoll_server.set_now_in_usec(1000000);
   EXPECT_EQ(1000000,
-            clock.ApproximateNow().Subtract(QuicTime::Zero()).ToMicroseconds());
+            (clock.ApproximateNow() - QuicTime::Zero()).ToMicroseconds());
   EXPECT_EQ(1u, clock.WallNow().ToUNIXSeconds());
   EXPECT_EQ(1000000u, clock.WallNow().ToUNIXMicroseconds());
 
   epoll_server.AdvanceBy(5);
   EXPECT_EQ(1000005,
-            clock.ApproximateNow().Subtract(QuicTime::Zero()).ToMicroseconds());
+            (clock.ApproximateNow() - QuicTime::Zero()).ToMicroseconds());
   EXPECT_EQ(1u, clock.WallNow().ToUNIXSeconds());
   EXPECT_EQ(1000005u, clock.WallNow().ToUNIXMicroseconds());
 
@@ -36,10 +36,10 @@
   QuicEpollClock clock(&epoll_server);
 
   epoll_server.set_now_in_usec(1000000);
-  EXPECT_EQ(1000000, clock.Now().Subtract(QuicTime::Zero()).ToMicroseconds());
+  EXPECT_EQ(1000000, (clock.Now() - QuicTime::Zero()).ToMicroseconds());
 
   epoll_server.AdvanceBy(5);
-  EXPECT_EQ(1000005, clock.Now().Subtract(QuicTime::Zero()).ToMicroseconds());
+  EXPECT_EQ(1000005, (clock.Now() - QuicTime::Zero()).ToMicroseconds());
 }
 
 }  // namespace test
diff --git a/net/tools/quic/quic_epoll_connection_helper_test.cc b/net/tools/quic/quic_epoll_connection_helper_test.cc
index 078eef7..85b82aaa 100644
--- a/net/tools/quic/quic_epoll_connection_helper_test.cc
+++ b/net/tools/quic/quic_epoll_connection_helper_test.cc
@@ -30,7 +30,7 @@
   QuicTime::Delta delta = QuicTime::Delta::FromMilliseconds(5);
   epoll_server_.AdvanceBy(delta.ToMicroseconds());
 
-  EXPECT_EQ(start.Add(delta), clock->Now());
+  EXPECT_EQ(start + delta, clock->Now());
 }
 
 TEST_F(QuicEpollConnectionHelperTest, GetRandomGenerator) {
diff --git a/net/tools/quic/quic_simple_client_bin.cc b/net/tools/quic/quic_simple_client_bin.cc
index 7cbb6dbd..75dca39 100644
--- a/net/tools/quic/quic_simple_client_bin.cc
+++ b/net/tools/quic/quic_simple_client_bin.cc
@@ -326,9 +326,8 @@
     cout << "headers:" << header_block.DebugString();
     if (!FLAGS_body_hex.empty()) {
       // Print the user provided hex, rather than binary body.
-      cout << "body hex:   " << FLAGS_body_hex << endl;
-      cout << "body ascii: " << net::QuicUtils::BinaryToAscii(
-                                    net::QuicUtils::HexDecode(FLAGS_body_hex))
+      cout << "body:\n"
+           << net::QuicUtils::HexDump(net::QuicUtils::HexDecode(FLAGS_body_hex))
            << endl;
     } else {
       cout << "body: " << body << endl;
@@ -339,10 +338,7 @@
     string response_body = client.latest_response_body();
     if (!FLAGS_body_hex.empty()) {
       // Assume response is binary data.
-      cout << "body hex:   " << net::QuicUtils::HexEncode(response_body)
-           << endl;
-      cout << "body ascii: " << net::QuicUtils::BinaryToAscii(response_body)
-           << endl;
+      cout << "body:\n" << net::QuicUtils::HexDump(response_body) << endl;
     } else {
       cout << "body: " << response_body << endl;
     }
diff --git a/net/tools/quic/quic_simple_server_session_test.cc b/net/tools/quic/quic_simple_server_session_test.cc
index 8e93f9b..646783d6 100644
--- a/net/tools/quic/quic_simple_server_session_test.cc
+++ b/net/tools/quic/quic_simple_server_session_test.cc
@@ -54,6 +54,7 @@
 using testing::_;
 using testing::InSequence;
 using testing::Return;
+using testing::AtLeast;
 
 namespace net {
 namespace test {
@@ -205,8 +206,6 @@
     visitor_ = QuicConnectionPeer::GetVisitor(connection_);
     headers_stream_ = new MockQuicHeadersStream(session_.get());
     QuicSpdySessionPeer::SetHeadersStream(session_.get(), headers_stream_);
-    // TODO(jri): Remove this line once tests pass.
-    FLAGS_quic_cede_correctly = false;
 
     session_->OnConfigNegotiated();
   }
@@ -493,11 +492,25 @@
             WriteHeadersMock(stream_id, _, false, kDefaultPriority, nullptr));
         // Since flow control window is smaller than response body, not the
         // whole body will be sent.
-        EXPECT_CALL(*connection_,
-                    SendStreamData(stream_id, _, 0, false, nullptr))
-            .WillOnce(
-                Return(QuicConsumedData(kStreamFlowControlWindowSize, false)));
-        EXPECT_CALL(*connection_, SendBlocked(stream_id));
+        if (!session_->force_hol_blocking()) {
+          EXPECT_CALL(*connection_,
+                      SendStreamData(stream_id, _, 0, false, nullptr))
+              .WillOnce(Return(
+                  QuicConsumedData(kStreamFlowControlWindowSize, false)));
+          EXPECT_CALL(*connection_, SendBlocked(stream_id));
+        } else {
+          // The forced HOL blocking encapsulates the stream data into
+          // HTTP/2 DATA frames within the headers stream.  HTTP/2
+          // DATA frames are limited to a max size of 16KB, so the
+          // 64KB body will be fragemented into four DATA frames.
+          EXPECT_CALL(*connection_, SendStreamData(_, _, _, false, nullptr))
+              .Times(body_size / 16384)
+              .WillOnce(Return(QuicConsumedData(9 + 16394, false)))
+              .WillOnce(Return(QuicConsumedData(9 + 16394, false)))
+              .WillOnce(Return(QuicConsumedData(9 + 16394, false)))
+              .WillOnce(Return(QuicConsumedData(9 + 16394, false)));
+          EXPECT_CALL(*connection_, SendBlocked(_));
+        }
       }
     }
     session_->PromisePushResources(request_url, push_resources,
@@ -513,6 +526,10 @@
   // Tests that given more than kMaxOpenStreamForTest resources, all their
   // PUSH_PROMISE's will be sent out and only |kMaxOpenStreamForTest| streams
   // will be opened and send push response.
+
+  if (session_->force_hol_blocking()) {
+    return;
+  }
   size_t num_resources = kMaxStreamsForTest + 5;
   PromisePushResources(num_resources);
   EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams());
@@ -520,6 +537,10 @@
 
 TEST_P(QuicSimpleServerSessionServerPushTest,
        HandlePromisedPushRequestsAfterStreamDraining) {
+  if (session_->force_hol_blocking()) {
+    return;
+  }
+
   // Tests that after promised stream queued up, when an opened stream is marked
   // draining, a queued promised stream will become open and send push response.
   size_t num_resources = kMaxStreamsForTest + 1;
@@ -543,6 +564,9 @@
 
 TEST_P(QuicSimpleServerSessionServerPushTest,
        ResetPromisedStreamToCancelServerPush) {
+  if (session_->force_hol_blocking()) {
+    return;
+  }
   // Tests that after all resources are promised, a RST frame from client can
   // prevent a promised resource to be send out.
 
@@ -579,6 +603,9 @@
 
 TEST_P(QuicSimpleServerSessionServerPushTest,
        CloseStreamToHandleMorePromisedStream) {
+  if (session_->force_hol_blocking()) {
+    return;
+  }
   // Tests that closing a open outgoing stream can trigger a promised resource
   // in the queue to be send out.
   size_t num_resources = kMaxStreamsForTest + 1;
diff --git a/net/tools/quic/quic_socket_utils.cc b/net/tools/quic/quic_socket_utils.cc
index 61ec378..7fcc964 100644
--- a/net/tools/quic/quic_socket_utils.cc
+++ b/net/tools/quic/quic_socket_utils.cc
@@ -56,7 +56,7 @@
           *walltimestamp = QuicWallTime::FromUNIXMicroseconds(usec);
         } else {
           *timestamp =
-              QuicTime::Zero().Add(QuicTime::Delta::FromMicroseconds(usec));
+              QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(usec);
         }
       }
     }
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc
index 6686238..ffe3dd4d 100644
--- a/net/tools/quic/quic_time_wait_list_manager.cc
+++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -267,9 +267,8 @@
     QuicTime oldest_connection_id =
         connection_id_map_.begin()->second.time_added;
     QuicTime now = clock_->ApproximateNow();
-    if (now.Subtract(oldest_connection_id) < time_wait_period_) {
-      next_alarm_interval =
-          oldest_connection_id.Add(time_wait_period_).Subtract(now);
+    if (now - oldest_connection_id < time_wait_period_) {
+      next_alarm_interval = oldest_connection_id + time_wait_period_ - now;
     } else {
       LOG(ERROR) << "ConnectionId lingered for longer than time_wait_period_";
     }
@@ -278,8 +277,8 @@
     next_alarm_interval = time_wait_period_;
   }
 
-  connection_id_clean_up_alarm_->Set(
-      clock_->ApproximateNow().Add(next_alarm_interval));
+  connection_id_clean_up_alarm_->Set(clock_->ApproximateNow() +
+                                     next_alarm_interval);
 }
 
 bool QuicTimeWaitListManager::MaybeExpireOldestConnection(
@@ -300,7 +299,7 @@
 
 void QuicTimeWaitListManager::CleanUpOldConnectionIds() {
   QuicTime now = clock_->ApproximateNow();
-  QuicTime expiration = now.Subtract(time_wait_period_);
+  QuicTime expiration = now - time_wait_period_;
 
   while (MaybeExpireOldestConnection(expiration)) {
   }
diff --git a/net/tools/quic/quic_time_wait_list_manager_test.cc b/net/tools/quic/quic_time_wait_list_manager_test.cc
index a1d06b4..70a7576 100644
--- a/net/tools/quic/quic_time_wait_list_manager_test.cc
+++ b/net/tools/quic/quic_time_wait_list_manager_test.cc
@@ -353,11 +353,11 @@
 
   QuicTime::Delta offset = QuicTime::Delta::FromMicroseconds(39);
   // Now set the current time as time_wait_period + offset usecs.
-  epoll_server_.set_now_in_usec(time_wait_period.Add(offset).ToMicroseconds());
+  epoll_server_.set_now_in_usec((time_wait_period + offset).ToMicroseconds());
   // After all the old connection_ids are cleaned up, check the next alarm
   // interval.
   int64_t next_alarm_time = epoll_server_.ApproximateNowInUsec() +
-                            time_wait_period.Subtract(offset).ToMicroseconds();
+                            (time_wait_period - offset).ToMicroseconds();
   EXPECT_CALL(epoll_server_, RegisterAlarm(next_alarm_time, _));
 
   time_wait_list_manager_.CleanUpOldConnectionIds();
@@ -479,7 +479,7 @@
 
   QuicTime::Delta offset = QuicTime::Delta::FromMicroseconds(39);
   // Now set the current time as time_wait_period + offset usecs.
-  epoll_server_.set_now_in_usec(time_wait_period.Add(offset).ToMicroseconds());
+  epoll_server_.set_now_in_usec((time_wait_period + offset).ToMicroseconds());
   // After the connection_ids are cleaned up, check the next alarm interval.
   int64_t next_alarm_time =
       epoll_server_.ApproximateNowInUsec() + time_wait_period.ToMicroseconds();
diff --git a/net/tools/quic/stateless_rejector_test.cc b/net/tools/quic/stateless_rejector_test.cc
index 97f7839..bac095b 100644
--- a/net/tools/quic/stateless_rejector_test.cc
+++ b/net/tools/quic/stateless_rejector_test.cc
@@ -135,6 +135,7 @@
   // clang-format off
   const CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "COPT", "SREJ",
       nullptr);
   // clang-format on
@@ -154,6 +155,7 @@
   // clang-format off
   const CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "AEAD", "AESG",
       "KEXS", "C255",
       "PUBS", pubs_hex_.c_str(),
@@ -172,6 +174,7 @@
   // clang-format off
   const CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "AEAD", "AESG",
       "KEXS", "C255",
       "COPT", "SREJ",
@@ -210,6 +213,7 @@
   // clang-format off
   const CryptoHandshakeMessage client_hello = CryptoTestUtils::Message(
       "CHLO",
+      "PDMD", "X509",
       "AEAD", "AESG",
       "KEXS", "C255",
       "COPT", "SREJ",
diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.cc b/net/tools/quic/test_tools/packet_dropping_test_writer.cc
index 4d85d5a..8b2141c 100644
--- a/net/tools/quic/test_tools/packet_dropping_test_writer.cc
+++ b/net/tools/quic/test_tools/packet_dropping_test_writer.cc
@@ -118,14 +118,14 @@
     }
 
     // Queue it to be sent.
-    QuicTime send_time = clock_->ApproximateNow().Add(fake_packet_delay_);
+    QuicTime send_time = clock_->ApproximateNow() + fake_packet_delay_;
     if (!fake_bandwidth_.IsZero()) {
       // Calculate a time the bandwidth limit would impose.
       QuicTime::Delta bandwidth_delay = QuicTime::Delta::FromMicroseconds(
           (buf_len * kNumMicrosPerSecond) / fake_bandwidth_.ToBytesPerSecond());
       send_time = delayed_packets_.empty()
-                      ? send_time.Add(bandwidth_delay)
-                      : delayed_packets_.back().send_time.Add(bandwidth_delay);
+                      ? send_time + bandwidth_delay
+                      : delayed_packets_.back().send_time + bandwidth_delay;
     }
     std::unique_ptr<PerPacketOptions> delayed_options;
     if (options != nullptr) {
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc
index 914c4f8a..ad5748d 100644
--- a/net/tools/quic/test_tools/quic_test_client.cc
+++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -45,18 +45,19 @@
 class RecordingProofVerifier : public ProofVerifier {
  public:
   // ProofVerifier interface.
-  QuicAsyncStatus VerifyProof(const string& hostname,
-                              const uint16_t port,
-                              const string& server_config,
-                              QuicVersion quic_version,
-                              StringPiece chlo_hash,
-                              const vector<string>& certs,
-                              const string& cert_sct,
-                              const string& signature,
-                              const ProofVerifyContext* context,
-                              string* error_details,
-                              std::unique_ptr<ProofVerifyDetails>* details,
-                              ProofVerifierCallback* callback) override {
+  QuicAsyncStatus VerifyProof(
+      const string& hostname,
+      const uint16_t port,
+      const string& server_config,
+      QuicVersion quic_version,
+      StringPiece chlo_hash,
+      const vector<string>& certs,
+      const string& cert_sct,
+      const string& signature,
+      const ProofVerifyContext* context,
+      string* error_details,
+      std::unique_ptr<ProofVerifyDetails>* details,
+      std::unique_ptr<ProofVerifierCallback> callback) override {
     common_name_.clear();
     if (certs.empty()) {
       return QUIC_FAILURE;
@@ -495,7 +496,7 @@
       QuicConnectionPeer::GetHelper(client()->session()->connection())
           ->GetClock();
   QuicTime end_waiting_time =
-      clock->Now().Add(QuicTime::Delta::FromMicroseconds(timeout_us));
+      clock->Now() + QuicTime::Delta::FromMicroseconds(timeout_us);
   while (HaveActiveStream() &&
          (timeout_us < 0 || clock->Now() < end_waiting_time)) {
     client_->WaitForEvents();
@@ -515,7 +516,7 @@
       QuicConnectionPeer::GetHelper(client()->session()->connection())
           ->GetClock();
   QuicTime end_waiting_time =
-      clock->Now().Add(QuicTime::Delta::FromMicroseconds(timeout_us));
+      clock->Now() + QuicTime::Delta::FromMicroseconds(timeout_us);
   while (stream_ != nullptr &&
          !client_->session()->IsClosedStream(stream_->id()) &&
          stream_->stream_bytes_read() == 0 &&
diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h
index b76d1cfc..47e20621 100644
--- a/net/tools/quic/test_tools/quic_test_client.h
+++ b/net/tools/quic/test_tools/quic_test_client.h
@@ -202,6 +202,10 @@
 
   size_t num_responses() const { return num_responses_; }
 
+  void set_server_address(const IPEndPoint& server_address) {
+    client_->set_server_address(server_address);
+  }
+
   // Explicitly set the SNI value for this client, overriding the default
   // behavior which extracts the SNI value from the request URL.
   void OverrideSni(const std::string& sni) {
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 0fdeac11..dd30591 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -722,8 +722,12 @@
 
     // Advertise "br" encoding only if transferred data is opaque to proxy.
     bool advertise_brotli = false;
-    if (request()->context()->enable_brotli())
-      advertise_brotli = request()->url().SchemeIsCryptographic();
+    if (request()->context()->enable_brotli()) {
+      if (request()->url().SchemeIsCryptographic() ||
+          IsLocalhost(request()->url().HostNoBrackets())) {
+        advertise_brotli = true;
+      }
+    }
 
     // Supply Accept-Encoding headers first so that it is more likely that they
     // will be in the first transmitted packet. This can sometimes make it
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h
index f2bbeb22..7b0afbb 100644
--- a/ppapi/proxy/ppapi_messages.h
+++ b/ppapi/proxy/ppapi_messages.h
@@ -1086,9 +1086,11 @@
 // after this message is sent.
 IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBGraphics3D_TakeFrontBuffer,
                     ppapi::HostResource /* graphics_3d */)
-IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBGraphics3D_SwapBuffers,
+IPC_MESSAGE_ROUTED4(PpapiHostMsg_PPBGraphics3D_SwapBuffers,
                     ppapi::HostResource /* graphics_3d */,
-                    gpu::SyncToken /* sync_token */)
+                    gpu::SyncToken /* sync_token */,
+                    int32_t /* width*/,
+                    int32_t /* height*/)
 IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBGraphics3D_EnsureWorkVisible,
                     ppapi::HostResource /* context */)
 
diff --git a/ppapi/proxy/ppb_graphics_3d_proxy.cc b/ppapi/proxy/ppb_graphics_3d_proxy.cc
index 0c21e37..ca29adc 100644
--- a/ppapi/proxy/ppb_graphics_3d_proxy.cc
+++ b/ppapi/proxy/ppb_graphics_3d_proxy.cc
@@ -117,7 +117,9 @@
   return command_buffer_.get();
 }
 
-int32_t Graphics3D::DoSwapBuffers(const gpu::SyncToken& sync_token) {
+int32_t Graphics3D::DoSwapBuffers(const gpu::SyncToken& sync_token,
+                                  int32_t width,
+                                  int32_t height) {
   // A valid sync token would indicate a swap buffer already happened somehow.
   DCHECK(!sync_token.HasData());
 
@@ -135,7 +137,8 @@
   gl->GenSyncTokenCHROMIUM(fence_sync, new_sync_token.GetData());
 
   IPC::Message* msg = new PpapiHostMsg_PPBGraphics3D_SwapBuffers(
-      API_ID_PPB_GRAPHICS_3D, host_resource(), new_sync_token);
+      API_ID_PPB_GRAPHICS_3D, host_resource(), new_sync_token, width,
+      height);
   msg->set_unblock(true);
   PluginDispatcher::GetForResource(this)->Send(msg);
 
@@ -347,13 +350,15 @@
 }
 
 void PPB_Graphics3D_Proxy::OnMsgSwapBuffers(const HostResource& context,
-                                            const gpu::SyncToken& sync_token) {
+                                            const gpu::SyncToken& sync_token,
+                                            int32_t width,
+                                            int32_t height) {
   EnterHostFromHostResourceForceCallback<PPB_Graphics3D_API> enter(
       context, callback_factory_,
       &PPB_Graphics3D_Proxy::SendSwapBuffersACKToPlugin, context);
   if (enter.succeeded())
-    enter.SetResult(
-        enter.object()->SwapBuffersWithSyncToken(enter.callback(), sync_token));
+    enter.SetResult(enter.object()->SwapBuffersWithSyncToken(
+        enter.callback(), sync_token, width, height));
 }
 
 void PPB_Graphics3D_Proxy::OnMsgTakeFrontBuffer(const HostResource& context) {
diff --git a/ppapi/proxy/ppb_graphics_3d_proxy.h b/ppapi/proxy/ppb_graphics_3d_proxy.h
index 2a28fce..9536ee20 100644
--- a/ppapi/proxy/ppb_graphics_3d_proxy.h
+++ b/ppapi/proxy/ppb_graphics_3d_proxy.h
@@ -61,7 +61,9 @@
   // PPB_Graphics3D_Shared overrides.
   gpu::CommandBuffer* GetCommandBuffer() override;
   gpu::GpuControl* GetGpuControl() override;
-  int32_t DoSwapBuffers(const gpu::SyncToken& sync_token) override;
+  int32_t DoSwapBuffers(const gpu::SyncToken& sync_token,
+                        int32_t width,
+                        int32_t height) override;
 
   std::unique_ptr<PpapiCommandBufferProxy> command_buffer_;
 
@@ -110,7 +112,9 @@
       ppapi::proxy::SerializedHandle* transfer_buffer);
   void OnMsgDestroyTransferBuffer(const HostResource& context, int32_t id);
   void OnMsgSwapBuffers(const HostResource& context,
-                        const gpu::SyncToken& sync_token);
+                        const gpu::SyncToken& sync_token,
+                        int32_t width,
+                        int32_t height);
   void OnMsgTakeFrontBuffer(const HostResource& context);
   void OnMsgEnsureWorkVisible(const HostResource& context);
   // Renderer->plugin message handlers.
diff --git a/ppapi/shared_impl/ppb_graphics_3d_shared.cc b/ppapi/shared_impl/ppb_graphics_3d_shared.cc
index af53bfb..0c40b4cb 100644
--- a/ppapi/shared_impl/ppb_graphics_3d_shared.cc
+++ b/ppapi/shared_impl/ppb_graphics_3d_shared.cc
@@ -51,18 +51,22 @@
     return PP_ERROR_BADARGUMENT;
 
   gles2_impl()->ResizeCHROMIUM(width, height, 1.f, true);
+  width_ = width;
+  height_ = height;
   // TODO(alokp): Check if resize succeeded and return appropriate error code.
   return PP_OK;
 }
 
 int32_t PPB_Graphics3D_Shared::SwapBuffers(
     scoped_refptr<TrackedCallback> callback) {
-  return SwapBuffersWithSyncToken(callback, gpu::SyncToken());
+  return SwapBuffersWithSyncToken(callback, gpu::SyncToken(), width_, height_);
 }
 
 int32_t PPB_Graphics3D_Shared::SwapBuffersWithSyncToken(
     scoped_refptr<TrackedCallback> callback,
-    const gpu::SyncToken& sync_token) {
+    const gpu::SyncToken& sync_token,
+    int32_t width,
+    int32_t height) {
   if (HasPendingSwap()) {
     Log(PP_LOGLEVEL_ERROR,
         "PPB_Graphics3D.SwapBuffers: Plugin attempted swap "
@@ -72,7 +76,7 @@
   }
 
   swap_callback_ = callback;
-  return DoSwapBuffers(sync_token);
+  return DoSwapBuffers(sync_token, width, height);
 }
 
 int32_t PPB_Graphics3D_Shared::GetAttribMaxValue(int32_t attribute,
diff --git a/ppapi/shared_impl/ppb_graphics_3d_shared.h b/ppapi/shared_impl/ppb_graphics_3d_shared.h
index 7e11f6c..4c8a1ab6 100644
--- a/ppapi/shared_impl/ppb_graphics_3d_shared.h
+++ b/ppapi/shared_impl/ppb_graphics_3d_shared.h
@@ -43,7 +43,9 @@
   int32_t ResizeBuffers(int32_t width, int32_t height) override;
   int32_t SwapBuffers(scoped_refptr<TrackedCallback> callback) override;
   int32_t SwapBuffersWithSyncToken(scoped_refptr<TrackedCallback> callback,
-                                   const gpu::SyncToken& sync_token) override;
+                                   const gpu::SyncToken& sync_token,
+                                   int32_t width,
+                                   int32_t height) override;
   int32_t GetAttribMaxValue(int32_t attribute, int32_t* value) override;
 
   void* MapTexSubImage2DCHROMIUM(GLenum target,
@@ -70,7 +72,9 @@
 
   virtual gpu::CommandBuffer* GetCommandBuffer() = 0;
   virtual gpu::GpuControl* GetGpuControl() = 0;
-  virtual int32_t DoSwapBuffers(const gpu::SyncToken& sync_token) = 0;
+  virtual int32_t DoSwapBuffers(const gpu::SyncToken& sync_token,
+                                int32_t width,
+                                int32_t height) = 0;
 
   bool HasPendingSwap() const;
   bool CreateGLES2Impl(int32_t command_buffer_size,
@@ -83,6 +87,10 @@
   std::unique_ptr<gpu::TransferBuffer> transfer_buffer_;
   std::unique_ptr<gpu::gles2::GLES2Implementation> gles2_impl_;
 
+  // A local cache of the size of the viewport.
+  int32_t width_ = -1;
+  int32_t height_ = -1;
+
   // Callback that needs to be executed when swap-buffers is completed.
   scoped_refptr<TrackedCallback> swap_callback_;
 
diff --git a/ppapi/shared_impl/test_utils.cc b/ppapi/shared_impl/test_utils.cc
index 2ab8c5a..18bc9e3 100644
--- a/ppapi/shared_impl/test_utils.cc
+++ b/ppapi/shared_impl/test_utils.cc
@@ -213,8 +213,11 @@
 }
 
 std::string StripTestPrefixes(const std::string& test_name) {
-  if (test_name.find("DISABLED_") == 0)
-    return test_name.substr(strlen("DISABLED_"));
+  const char kDisabledPrefix[] = "DISABLED_";
+  if (base::StartsWith(test_name, kDisabledPrefix,
+                       base::CompareCase::SENSITIVE)) {
+    return test_name.substr(sizeof(kDisabledPrefix) - 1);
+  }
   return test_name;
 }
 
diff --git a/ppapi/shared_impl/time_conversion.cc b/ppapi/shared_impl/time_conversion.cc
index 651274a..76946b2d 100644
--- a/ppapi/shared_impl/time_conversion.cc
+++ b/ppapi/shared_impl/time_conversion.cc
@@ -32,9 +32,12 @@
   time.LocalExplode(&exploded);
   time.UTCExplode(&utc_exploded);
   if (exploded.HasValidValues() && utc_exploded.HasValidValues()) {
-    base::Time adj_time = base::Time::FromUTCExploded(exploded);
-    base::Time cur = base::Time::FromUTCExploded(utc_exploded);
-    return (adj_time - cur).InSecondsF();
+    base::Time adj_time;
+    if (base::Time::FromUTCExploded(exploded, &adj_time)) {
+      base::Time cur;
+      if (base::Time::FromUTCExploded(utc_exploded, &cur))
+        return (adj_time - cur).InSecondsF();
+    }
   }
   return 0.0;
 }
diff --git a/ppapi/thunk/ppb_graphics_3d_api.h b/ppapi/thunk/ppb_graphics_3d_api.h
index 845b35f5f..9c2e312 100644
--- a/ppapi/thunk/ppb_graphics_3d_api.h
+++ b/ppapi/thunk/ppb_graphics_3d_api.h
@@ -35,7 +35,9 @@
   virtual int32_t SwapBuffers(scoped_refptr<TrackedCallback> callback) = 0;
   virtual int32_t SwapBuffersWithSyncToken(
       scoped_refptr<TrackedCallback> callback,
-      const gpu::SyncToken& sync_token) = 0;
+      const gpu::SyncToken& sync_token,
+      int32_t width,
+      int32_t height) = 0;
   virtual int32_t GetAttribMaxValue(int32_t attribute, int32_t* value) = 0;
 
   // Graphics3DTrusted API.
diff --git a/sandbox/win/src/win_utils.cc b/sandbox/win/src/win_utils.cc
index c31c25e..8e4da5f 100644
--- a/sandbox/win/src/win_utils.cc
+++ b/sandbox/win/src/win_utils.cc
@@ -132,7 +132,8 @@
 
 bool ResolveRegistryName(base::string16 name, base::string16* resolved_name) {
   for (size_t i = 0; i < arraysize(kKnownKey); ++i) {
-    if (name.find(kKnownKey[i].name) == 0) {
+    if (base::StartsWith(name, kKnownKey[i].name,
+                         base::CompareCase::SENSITIVE)) {
       HKEY key;
       DWORD disposition;
       if (ERROR_SUCCESS != ::RegCreateKeyEx(kKnownKey[i].key, L"", 0, NULL, 0,
diff --git a/services/catalog/catalog.cc b/services/catalog/catalog.cc
index 79acc07..501db2d 100644
--- a/services/catalog/catalog.cc
+++ b/services/catalog/catalog.cc
@@ -18,7 +18,7 @@
 #include "services/catalog/instance.h"
 #include "services/catalog/reader.h"
 #include "services/shell/public/cpp/connection.h"
-#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service_context.h"
 
 namespace catalog {
 namespace {
@@ -92,7 +92,7 @@
 Catalog::Catalog(std::unique_ptr<Store> store)
     : store_(std::move(store)), weak_factory_(this) {
   shell::mojom::ServiceRequest request = GetProxy(&service_);
-  shell_connection_.reset(new shell::ShellConnection(this, std::move(request)));
+  shell_connection_.reset(new shell::ServiceContext(this, std::move(request)));
 }
 
 void Catalog::ScanSystemPackageDir() {
diff --git a/services/catalog/catalog.h b/services/catalog/catalog.h
index 417ac8e9..3dd946e 100644
--- a/services/catalog/catalog.h
+++ b/services/catalog/catalog.h
@@ -29,7 +29,7 @@
 }
 
 namespace shell {
-class ShellConnection;
+class ServiceContext;
 }
 
 namespace catalog {
@@ -85,7 +85,7 @@
   std::unique_ptr<Store> store_;
 
   shell::mojom::ServicePtr service_;
-  std::unique_ptr<shell::ShellConnection> shell_connection_;
+  std::unique_ptr<shell::ServiceContext> shell_connection_;
 
   std::map<std::string, std::unique_ptr<Instance>> instances_;
 
diff --git a/services/navigation/BUILD.gn b/services/navigation/BUILD.gn
index 7031c41..4d84fa5 100644
--- a/services/navigation/BUILD.gn
+++ b/services/navigation/BUILD.gn
@@ -82,7 +82,7 @@
     "//base/test:test_support",
     "//services/navigation/public/interfaces",
     "//services/shell/public/cpp",
-    "//services/shell/public/cpp:shell_test_support",
+    "//services/shell/public/cpp:service_test_support",
     "//services/shell/public/cpp/test:run_all_shelltests",
     "//testing/gtest",
   ]
diff --git a/services/navigation/navigation.h b/services/navigation/navigation.h
index 60efa73..3a731dd6 100644
--- a/services/navigation/navigation.h
+++ b/services/navigation/navigation.h
@@ -9,7 +9,7 @@
 #include "services/navigation/public/interfaces/view.mojom.h"
 #include "services/shell/public/cpp/interface_factory.h"
 #include "services/shell/public/cpp/service.h"
-#include "services/shell/public/cpp/shell_connection_ref.h"
+#include "services/shell/public/cpp/service_context_ref.h"
 
 namespace content {
 class BrowserContext;
@@ -44,8 +44,8 @@
   shell::Connector* connector_ = nullptr;
   std::string client_user_id_;
 
-  shell::ShellConnectionRefFactory ref_factory_;
-  std::set<std::unique_ptr<shell::ShellConnectionRef>> refs_;
+  shell::ServiceContextRefFactory ref_factory_;
+  std::set<std::unique_ptr<shell::ServiceContextRef>> refs_;
 
   mojo::BindingSet<mojom::ViewFactory> bindings_;
 
diff --git a/services/navigation/navigation_unittest.cc b/services/navigation/navigation_unittest.cc
index 11e5dee..a15faa3 100644
--- a/services/navigation/navigation_unittest.cc
+++ b/services/navigation/navigation_unittest.cc
@@ -8,21 +8,21 @@
 #include "base/run_loop.h"
 #include "services/navigation/public/interfaces/view.mojom.h"
 #include "services/shell/public/cpp/service.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_test.h"
 
 namespace navigation {
 
-class NavigationTest : public shell::test::ShellTest,
+class NavigationTest : public shell::test::ServiceTest,
                        public mojom::ViewClient {
  public:
   NavigationTest()
-      : shell::test::ShellTest("exe:navigation_unittests"),
+      : shell::test::ServiceTest("exe:navigation_unittests"),
         binding_(this) {}
   ~NavigationTest() override {}
 
  protected:
    void SetUp() override {
-     shell::test::ShellTest::SetUp();
+     shell::test::ServiceTest::SetUp();
      window_manager_connection_ = connector()->Connect("mojo:test_wm");
    }
 
diff --git a/services/navigation/view_impl.cc b/services/navigation/view_impl.cc
index 8d8af6a..6bb54cf85 100644
--- a/services/navigation/view_impl.cc
+++ b/services/navigation/view_impl.cc
@@ -60,7 +60,7 @@
                    const std::string& client_user_id,
                    mojom::ViewClientPtr client,
                    mojom::ViewRequest request,
-                   std::unique_ptr<shell::ShellConnectionRef> ref)
+                   std::unique_ptr<shell::ServiceContextRef> ref)
     : connector_(connector),
       binding_(this, std::move(request)),
       client_(std::move(client)),
diff --git a/services/navigation/view_impl.h b/services/navigation/view_impl.h
index 2a3fc31..427afa1 100644
--- a/services/navigation/view_impl.h
+++ b/services/navigation/view_impl.h
@@ -14,7 +14,7 @@
 #include "services/navigation/public/interfaces/view.mojom.h"
 #include "services/shell/public/cpp/interface_factory.h"
 #include "services/shell/public/cpp/service.h"
-#include "services/shell/public/cpp/shell_connection_ref.h"
+#include "services/shell/public/cpp/service_context_ref.h"
 #include "services/ui/public/cpp/window_tree_client_delegate.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/views/widget/widget_delegate.h"
@@ -36,7 +36,7 @@
            const std::string& client_user_id,
            mojom::ViewClientPtr client,
            mojom::ViewRequest request,
-           std::unique_ptr<shell::ShellConnectionRef> ref);
+           std::unique_ptr<shell::ServiceContextRef> ref);
   ~ViewImpl() override;
 
  private:
@@ -90,7 +90,7 @@
   shell::Connector* connector_;
   mojo::StrongBinding<mojom::View> binding_;
   mojom::ViewClientPtr client_;
-  std::unique_ptr<shell::ShellConnectionRef> ref_;
+  std::unique_ptr<shell::ServiceContextRef> ref_;
 
   views::WebView* web_view_;
 
diff --git a/services/shell/background/background_shell.cc b/services/shell/background/background_shell.cc
index 1cac7371f..6f743c08 100644
--- a/services/shell/background/background_shell.cc
+++ b/services/shell/background/background_shell.cc
@@ -17,7 +17,7 @@
 #include "services/catalog/store.h"
 #include "services/shell/connect_params.h"
 #include "services/shell/public/cpp/service.h"
-#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service_context.h"
 #include "services/shell/service_manager.h"
 #include "services/shell/standalone/context.h"
 
diff --git a/services/shell/background/tests/background_shell_unittest.cc b/services/shell/background/tests/background_shell_unittest.cc
index 9d9c401..b73c41b 100644
--- a/services/shell/background/tests/background_shell_unittest.cc
+++ b/services/shell/background/tests/background_shell_unittest.cc
@@ -12,7 +12,7 @@
 #include "services/shell/background/tests/test_catalog_store.h"
 #include "services/shell/public/cpp/connector.h"
 #include "services/shell/public/cpp/service.h"
-#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service_context.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace shell {
@@ -62,10 +62,10 @@
   init_params->catalog_store = std::move(store_ptr);
   background_shell.Init(std::move(init_params));
   ServiceImpl service;
-  ShellConnection shell_connection(
+  ServiceContext service_context(
       &service, background_shell.CreateServiceRequest(kTestName));
   mojom::TestServicePtr test_service;
-  shell_connection.connector()->ConnectToInterface(
+  service_context.connector()->ConnectToInterface(
       "mojo:background_shell_test_app", &test_service);
   base::RunLoop run_loop;
   bool got_result = false;
diff --git a/services/shell/public/cpp/BUILD.gn b/services/shell/public/cpp/BUILD.gn
index b116e16..0d8a088 100644
--- a/services/shell/public/cpp/BUILD.gn
+++ b/services/shell/public/cpp/BUILD.gn
@@ -37,12 +37,12 @@
     "lib/interface_registry.cc",
     "lib/names.cc",
     "lib/service.cc",
-    "lib/shell_connection.cc",
-    "lib/shell_connection_ref.cc",
+    "lib/service_context.cc",
+    "lib/service_context_ref.cc",
     "names.h",
     "service.h",
-    "shell_connection.h",
-    "shell_connection_ref.h",
+    "service_context.h",
+    "service_context_ref.h",
   ]
 
   public_deps = [
@@ -68,11 +68,11 @@
     ]
   }
 
-  source_set("shell_test_support") {
+  source_set("service_test_support") {
     testonly = true
     sources = [
-      "lib/shell_test.cc",
-      "shell_test.h",
+      "lib/service_test.cc",
+      "service_test.h",
     ]
 
     public_deps = [
diff --git a/services/shell/public/cpp/application_runner.h b/services/shell/public/cpp/application_runner.h
index bc26b53e..11b2810 100644
--- a/services/shell/public/cpp/application_runner.h
+++ b/services/shell/public/cpp/application_runner.h
@@ -13,7 +13,7 @@
 namespace shell {
 
 class Service;
-class ShellConnection;
+class ServiceContext;
 
 // A utility for running a chromium based mojo Application. The typical use
 // case is to use when writing your MojoMain:
@@ -37,7 +37,7 @@
   void set_message_loop_type(base::MessageLoop::Type type);
 
   // Once the various parameters have been set above, use Run to initialize an
-  // ShellConnection wired to the provided delegate, and run a MessageLoop until
+  // ServiceContext wired to the provided delegate, and run a MessageLoop until
   // the application exits.
   //
   // Iff |init_base| is true, the runner will perform some initialization of
@@ -48,18 +48,18 @@
   // Calls Run above with |init_base| set to |true|.
   MojoResult Run(MojoHandle shell_handle);
 
-  // Allows the caller to shut down the connection with the shell. After the
-  // shell notices the pipe has closed, it will no longer track an instance of
-  // this application, though this application may continue to run and service
-  // requests from others.
-  void DestroyShellConnection();
+  // Allows the caller to shut down the connection with the Service Manager.
+  // After the Service Manager notices the pipe has closed, it will no longer
+  // track an instance of this service, though this service may continue to run
+  // and handle requests from others.
+  void DestroyServiceContext();
 
   // Allows the caller to explicitly quit the application. Must be called from
   // the thread which created the ApplicationRunner.
   void Quit();
 
  private:
-  std::unique_ptr<ShellConnection> connection_;
+  std::unique_ptr<ServiceContext> context_;
   std::unique_ptr<Service> client_;
 
   // MessageLoop type. TYPE_CUSTOM is default (MessagePumpMojo will be used as
diff --git a/services/shell/public/cpp/connection.h b/services/shell/public/cpp/connection.h
index b72bf89..eb49c2c8 100644
--- a/services/shell/public/cpp/connection.h
+++ b/services/shell/public/cpp/connection.h
@@ -38,7 +38,7 @@
 //
 // A Connection returned via Shell::ConnectToApplication() is owned by the
 // caller.
-// An Connection received via AcceptConnection is owned by the ShellConnection.
+// An Connection received via OnConnect is owned by the ServiceContext.
 // To close a connection, call CloseConnection which will destroy this object.
 class Connection {
  public:
diff --git a/services/shell/public/cpp/connector.h b/services/shell/public/cpp/connector.h
index 9db076d..2f26e4c 100644
--- a/services/shell/public/cpp/connector.h
+++ b/services/shell/public/cpp/connector.h
@@ -19,8 +19,8 @@
 // connections between applications are established. Once Connect() is called,
 // this class is bound to the thread the call was made on and it cannot be
 // passed to another thread without calling Clone().
-// An instance of this class is created internally by ShellConnection for use
-// on the thread ShellConnection is instantiated on, and this interface is
+// An instance of this class is created internally by ServiceContext for use
+// on the thread ServiceContext is instantiated on, and this interface is
 // wrapped by the Shell interface.
 // To use this interface on other threads, call Shell::CloneConnector() and
 // pass the result to another thread. To pass to subsequent threads, call
diff --git a/services/shell/public/cpp/lib/application_runner.cc b/services/shell/public/cpp/lib/application_runner.cc
index 51cd8c03..78a8896 100644
--- a/services/shell/public/cpp/lib/application_runner.cc
+++ b/services/shell/public/cpp/lib/application_runner.cc
@@ -11,7 +11,7 @@
 #include "base/process/launch.h"
 #include "base/run_loop.h"
 #include "services/shell/public/cpp/service.h"
-#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service_context.h"
 
 namespace shell {
 
@@ -51,12 +51,12 @@
     std::unique_ptr<base::MessageLoop> loop;
     loop.reset(new base::MessageLoop(message_loop_type_));
 
-    connection_.reset(new ShellConnection(
+    context_.reset(new ServiceContext(
         client_.get(),
         mojo::MakeRequest<mojom::Service>(mojo::MakeScopedHandle(
             mojo::MessagePipeHandle(service_request_handle)))));
     base::RunLoop run_loop;
-    connection_->SetConnectionLostClosure(run_loop.QuitClosure());
+    context_->SetConnectionLostClosure(run_loop.QuitClosure());
     run_loop.Run();
     // It's very common for the client to cache the app and terminate on errors.
     // If we don't delete the client before the app we run the risk of the
@@ -66,7 +66,7 @@
     // client.
     loop.reset();
     client_.reset();
-    connection_.reset();
+    context_.reset();
   }
   return MOJO_RESULT_OK;
 }
@@ -80,8 +80,8 @@
   return Run(service_request_handle, init_base);
 }
 
-void ApplicationRunner::DestroyShellConnection() {
-  connection_.reset();
+void ApplicationRunner::DestroyServiceContext() {
+  context_.reset();
 }
 
 void ApplicationRunner::Quit() {
diff --git a/services/shell/public/cpp/lib/shell_connection.cc b/services/shell/public/cpp/lib/service_context.cc
similarity index 82%
rename from services/shell/public/cpp/lib/shell_connection.cc
rename to services/shell/public/cpp/lib/service_context.cc
index 173f6a3e..e5458dd 100644
--- a/services/shell/public/cpp/lib/shell_connection.cc
+++ b/services/shell/public/cpp/lib/service_context.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 "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service_context.h"
 
 #include "base/bind.h"
 #include "base/logging.h"
@@ -18,10 +18,10 @@
 namespace shell {
 
 ////////////////////////////////////////////////////////////////////////////////
-// ShellConnection, public:
+// ServiceContext, public:
 
-ShellConnection::ShellConnection(shell::Service* client,
-                                 mojom::ServiceRequest request)
+ServiceContext::ServiceContext(shell::Service* client,
+                               mojom::ServiceRequest request)
     : client_(client), binding_(this) {
   mojom::ConnectorPtr connector;
   pending_connector_request_ = GetProxy(&connector);
@@ -31,19 +31,19 @@
   binding_.Bind(std::move(request));
 }
 
-ShellConnection::~ShellConnection() {}
+ServiceContext::~ServiceContext() {}
 
-void ShellConnection::set_initialize_handler(const base::Closure& callback) {
+void ServiceContext::set_initialize_handler(const base::Closure& callback) {
   initialize_handler_ = callback;
 }
 
-void ShellConnection::SetAppTestConnectorForTesting(
+void ServiceContext::SetAppTestConnectorForTesting(
     mojom::ConnectorPtr connector) {
   pending_connector_request_ = nullptr;
   connector_.reset(new ConnectorImpl(std::move(connector)));
 }
 
-void ShellConnection::SetConnectionLostClosure(const base::Closure& closure) {
+void ServiceContext::SetConnectionLostClosure(const base::Closure& closure) {
   connection_lost_closure_ = closure;
   if (should_run_connection_lost_closure_ &&
       !connection_lost_closure_.is_null())
@@ -51,11 +51,11 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// ShellConnection, mojom::Service implementation:
+// ServiceContext, mojom::Service implementation:
 
-void ShellConnection::OnStart(mojom::IdentityPtr identity,
-                              uint32_t id,
-                              const OnStartCallback& callback) {
+void ServiceContext::OnStart(mojom::IdentityPtr identity,
+                             uint32_t id,
+                             const OnStartCallback& callback) {
   identity_ = identity.To<Identity>();
   if (!initialize_handler_.is_null())
     initialize_handler_.Run();
@@ -64,12 +64,12 @@
 
   DCHECK(binding_.is_bound());
   binding_.set_connection_error_handler(
-      base::Bind(&ShellConnection::OnConnectionError, base::Unretained(this)));
+      base::Bind(&ServiceContext::OnConnectionError, base::Unretained(this)));
 
   client_->OnStart(connector_.get(), identity_, id);
 }
 
-void ShellConnection::OnConnect(
+void ServiceContext::OnConnect(
     mojom::IdentityPtr source,
     uint32_t source_id,
     mojom::InterfaceProviderRequest local_interfaces,
@@ -112,9 +112,9 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// ShellConnection, private:
+// ServiceContext, private:
 
-void ShellConnection::OnConnectionError() {
+void ServiceContext::OnConnectionError() {
   // Note that the Service doesn't technically have to quit now, it may live
   // on to service existing connections. All existing Connectors however are
   // invalid.
diff --git a/services/shell/public/cpp/lib/shell_connection_ref.cc b/services/shell/public/cpp/lib/service_context_ref.cc
similarity index 63%
rename from services/shell/public/cpp/lib/shell_connection_ref.cc
rename to services/shell/public/cpp/lib/service_context_ref.cc
index 388c028f..92c7028 100644
--- a/services/shell/public/cpp/lib/shell_connection_ref.cc
+++ b/services/shell/public/cpp/lib/service_context_ref.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 "services/shell/public/cpp/shell_connection_ref.h"
+#include "services/shell/public/cpp/service_context_ref.h"
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
@@ -12,10 +12,10 @@
 
 namespace shell {
 
-class ShellConnectionRefImpl : public ShellConnectionRef {
+class ServiceContextRefImpl : public ServiceContextRef {
  public:
-  ShellConnectionRefImpl(
-      base::WeakPtr<ShellConnectionRefFactory> factory,
+  ServiceContextRefImpl(
+      base::WeakPtr<ServiceContextRefFactory> factory,
       scoped_refptr<base::SingleThreadTaskRunner> service_task_runner)
       : factory_(factory),
         service_task_runner_(service_task_runner) {
@@ -24,7 +24,7 @@
     thread_checker_.DetachFromThread();
   }
 
-  ~ShellConnectionRefImpl() override {
+  ~ServiceContextRefImpl() override {
     DCHECK(thread_checker_.CalledOnValidThread());
 
     if (service_task_runner_->BelongsToCurrentThread() && factory_) {
@@ -32,13 +32,13 @@
     } else {
       service_task_runner_->PostTask(
           FROM_HERE,
-          base::Bind(&ShellConnectionRefFactory::Release, factory_));
+          base::Bind(&ServiceContextRefFactory::Release, factory_));
     }
   }
 
  private:
-  // ShellConnectionRef:
-  std::unique_ptr<ShellConnectionRef> Clone() override {
+  // ServiceContextRef:
+  std::unique_ptr<ServiceContextRef> Clone() override {
     DCHECK(thread_checker_.CalledOnValidThread());
 
     if (service_task_runner_->BelongsToCurrentThread() && factory_) {
@@ -46,40 +46,40 @@
     } else {
       service_task_runner_->PostTask(
           FROM_HERE,
-          base::Bind(&ShellConnectionRefFactory::AddRef, factory_));
+          base::Bind(&ServiceContextRefFactory::AddRef, factory_));
     }
 
     return base::WrapUnique(
-        new ShellConnectionRefImpl(factory_, service_task_runner_));
+        new ServiceContextRefImpl(factory_, service_task_runner_));
   }
 
-  base::WeakPtr<ShellConnectionRefFactory> factory_;
+  base::WeakPtr<ServiceContextRefFactory> factory_;
   scoped_refptr<base::SingleThreadTaskRunner> service_task_runner_;
   base::ThreadChecker thread_checker_;
 
-  DISALLOW_COPY_AND_ASSIGN(ShellConnectionRefImpl);
+  DISALLOW_COPY_AND_ASSIGN(ServiceContextRefImpl);
 };
 
-ShellConnectionRefFactory::ShellConnectionRefFactory(
+ServiceContextRefFactory::ServiceContextRefFactory(
     const base::Closure& quit_closure)
     : quit_closure_(quit_closure), weak_factory_(this) {
   DCHECK(!quit_closure_.is_null());
 }
 
-ShellConnectionRefFactory::~ShellConnectionRefFactory() {}
+ServiceContextRefFactory::~ServiceContextRefFactory() {}
 
-std::unique_ptr<ShellConnectionRef> ShellConnectionRefFactory::CreateRef() {
+std::unique_ptr<ServiceContextRef> ServiceContextRefFactory::CreateRef() {
   AddRef();
   return base::WrapUnique(
-      new ShellConnectionRefImpl(weak_factory_.GetWeakPtr(),
+      new ServiceContextRefImpl(weak_factory_.GetWeakPtr(),
                                  base::ThreadTaskRunnerHandle::Get()));
 }
 
-void ShellConnectionRefFactory::AddRef() {
+void ServiceContextRefFactory::AddRef() {
   ++ref_count_;
 }
 
-void ShellConnectionRefFactory::Release() {
+void ServiceContextRefFactory::Release() {
   if (!--ref_count_)
     quit_closure_.Run();
 }
diff --git a/services/shell/public/cpp/lib/shell_test.cc b/services/shell/public/cpp/lib/service_test.cc
similarity index 65%
rename from services/shell/public/cpp/lib/shell_test.cc
rename to services/shell/public/cpp/lib/service_test.cc
index 6f4f1a7c..30176a1 100644
--- a/services/shell/public/cpp/lib/shell_test.cc
+++ b/services/shell/public/cpp/lib/service_test.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 "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_test.h"
 
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
@@ -13,32 +13,33 @@
 namespace shell {
 namespace test {
 
-ShellTestClient::ShellTestClient(ShellTest* test) : test_(test) {}
-ShellTestClient::~ShellTestClient() {}
+ServiceTestClient::ServiceTestClient(ServiceTest* test) : test_(test) {}
+ServiceTestClient::~ServiceTestClient() {}
 
-void ShellTestClient::OnStart(Connector* connector, const Identity& identity,
+void ServiceTestClient::OnStart(Connector* connector, const Identity& identity,
                               uint32_t id) {
   test_->OnStartCalled(connector, identity.name(), identity.user_id(), id);
 }
 
-ShellTest::ShellTest() {}
-ShellTest::ShellTest(const std::string& test_name) : test_name_(test_name) {}
-ShellTest::~ShellTest() {}
+ServiceTest::ServiceTest() {}
+ServiceTest::ServiceTest(const std::string& test_name)
+    : test_name_(test_name) {}
+ServiceTest::~ServiceTest() {}
 
-void ShellTest::InitTestName(const std::string& test_name) {
+void ServiceTest::InitTestName(const std::string& test_name) {
   DCHECK(test_name_.empty());
   test_name_ = test_name;
 }
 
-std::unique_ptr<Service> ShellTest::CreateService() {
-  return base::WrapUnique(new ShellTestClient(this));
+std::unique_ptr<Service> ServiceTest::CreateService() {
+  return base::WrapUnique(new ServiceTestClient(this));
 }
 
-std::unique_ptr<base::MessageLoop> ShellTest::CreateMessageLoop() {
+std::unique_ptr<base::MessageLoop> ServiceTest::CreateMessageLoop() {
   return base::WrapUnique(new base::MessageLoop);
 }
 
-void ShellTest::OnStartCalled(Connector* connector,
+void ServiceTest::OnStartCalled(Connector* connector,
                               const std::string& name,
                               const std::string& user_id,
                               uint32_t id) {
@@ -49,7 +50,7 @@
   initialize_called_.Run();
 }
 
-void ShellTest::SetUp() {
+void ServiceTest::SetUp() {
   service_ = CreateService();
   message_loop_ = CreateMessageLoop();
   background_shell_.reset(new shell::BackgroundShell);
@@ -62,16 +63,16 @@
       base::MessageLoop::current());
   initialize_called_ = run_loop.QuitClosure();
 
-  shell_connection_.reset(new ShellConnection(
+  service_context_.reset(new ServiceContext(
       service_.get(),
       background_shell_->CreateServiceRequest(test_name_)));
-  connector_ = shell_connection_->connector();
+  connector_ = service_context_->connector();
 
   run_loop.Run();
 }
 
-void ShellTest::TearDown() {
-  shell_connection_.reset();
+void ServiceTest::TearDown() {
+  service_context_.reset();
   background_shell_.reset();
   message_loop_.reset();
   service_.reset();
diff --git a/services/shell/public/cpp/service.h b/services/shell/public/cpp/service.h
index 4e015e4..d79c2ca 100644
--- a/services/shell/public/cpp/service.h
+++ b/services/shell/public/cpp/service.h
@@ -43,7 +43,7 @@
   // Called when the Service Manager has stopped tracking this instance. The
   // service should use this as a signal to exit, and in fact its process may
   // be reaped shortly afterward.
-  // Return true from this method to tell the ShellConnection to run its
+  // Return true from this method to tell the ServiceContext to run its
   // connection lost closure if it has one, false to prevent it from being run.
   // The default implementation returns true.
   // When used in conjunction with ApplicationRunner, returning true here quits
diff --git a/services/shell/public/cpp/shell_connection.h b/services/shell/public/cpp/service_context.h
similarity index 70%
rename from services/shell/public/cpp/shell_connection.h
rename to services/shell/public/cpp/service_context.h
index 8348a21..2cad395 100644
--- a/services/shell/public/cpp/shell_connection.h
+++ b/services/shell/public/cpp/service_context.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 SERVICES_SHELL_PUBLIC_CPP_SHELL_CONNECTION_H_
-#define SERVICES_SHELL_PUBLIC_CPP_SHELL_CONNECTION_H_
+#ifndef SERVICES_SHELL_PUBLIC_CPP_SERVICE_CONTEXT_H_
+#define SERVICES_SHELL_PUBLIC_CPP_SERVICE_CONTEXT_H_
 
 #include <memory>
 #include <utility>
@@ -22,35 +22,35 @@
 
 class Connector;
 
-// Encapsulates a connection to the Mojo Shell in two parts:
-// - a bound InterfacePtr to mojom::Shell, the primary mechanism
-//   by which the instantiating application interacts with other services
-//   brokered by the Mojo Shell.
-// - a bound InterfaceRequest of mojom::Service, an interface
-//   used by the Mojo Shell to inform this application of lifecycle events and
+// Encapsulates a connection to the Service Manager in two parts:
+// - a bound InterfacePtr to mojom::Connector, the primary mechanism
+//   by which the instantiating service connects to other services,
+//   brokered by the Service Manager.
+// - a bound InterfaceRequest of mojom::Service, an interface used by the
+//   Service Manager to inform this service of lifecycle events and
 //   inbound connections brokered by it.
 //
 // This class should be used in two scenarios:
 // - During early startup to bind the mojom::ServiceRequest obtained from
-//   the Mojo Shell, typically in response to either MojoMain() or main().
+//   the Service Manager, typically in response to either MojoMain() or main().
 // - In an implementation of mojom::ServiceFactory to bind the
-//   mojom::ServiceRequest passed via StartApplication. In this scenario
-//   there can be many instances of this class per process.
+//   mojom::ServiceRequest passed via CreateService. In this scenario there can
+//   be many instances of this class per process.
 //
-// Instances of this class are constructed with an implementation of the Shell
-// Client Lib's Service interface. See documentation in service.h
+// Instances of this class are constructed with an implementation of the Service
+// Manager Client Lib's Service interface. See documentation in service.h
 // for details.
 //
-class ShellConnection : public mojom::Service {
+class ServiceContext : public mojom::Service {
  public:
-  // Creates a new ShellConnection bound to |request|. This connection may be
+  // Creates a new ServiceContext bound to |request|. This connection may be
   // used immediately to make outgoing connections via connector().  Does not
   // take ownership of |client|, which must remain valid for the lifetime of
-  // ShellConnection.
-  ShellConnection(shell::Service* client,
-                  mojom::ServiceRequest request);
+  // ServiceContext.
+  ServiceContext(shell::Service* client,
+                 mojom::ServiceRequest request);
 
-  ~ShellConnection() override;
+  ~ServiceContext() override;
 
   Connector* connector() { return connector_.get(); }
   const Identity& identity() { return identity_; }
@@ -87,7 +87,8 @@
   // convenient for the client.
   ScopedVector<Connection> incoming_connections_;
 
-  // A pending Connector request which will eventually be passed to the shell.
+  // A pending Connector request which will eventually be passed to the Service
+  // Manager.
   mojom::ConnectorRequest pending_connector_request_;
 
   shell::Service* client_;
@@ -98,9 +99,9 @@
 
   base::Closure connection_lost_closure_;
 
-  DISALLOW_COPY_AND_ASSIGN(ShellConnection);
+  DISALLOW_COPY_AND_ASSIGN(ServiceContext);
 };
 
 }  // namespace shell
 
-#endif  // SERVICES_SHELL_PUBLIC_CPP_SHELL_CONNECTION_H_
+#endif  // SERVICES_SHELL_PUBLIC_CPP_SERVICE_CONTEXT_H_
diff --git a/services/shell/public/cpp/service_context_ref.h b/services/shell/public/cpp/service_context_ref.h
new file mode 100644
index 0000000..0b81e8d
--- /dev/null
+++ b/services/shell/public/cpp/service_context_ref.h
@@ -0,0 +1,59 @@
+// 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 SERVICES_SHELL_PUBLIC_CPP_SERVICE_CONTEXT_REF_H_
+#define SERVICES_SHELL_PUBLIC_CPP_SERVICE_CONTEXT_REF_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+
+namespace shell {
+
+class ServiceContextRefImpl;
+
+// An interface implementation can keep this object as a member variable to
+// hold a reference to the ServiceContext, keeping it alive as long as the
+// bound implementation exists.
+//
+// This class is safe to use on any thread and instances may be passed to other
+// threads. However, each instance should only be used on one thread at a time,
+// otherwise there'll be races between the AddRef resulting from cloning and
+// destruction.
+class ServiceContextRef {
+ public:
+  virtual ~ServiceContextRef() {}
+
+  virtual std::unique_ptr<ServiceContextRef> Clone() = 0;
+};
+
+class ServiceContextRefFactory {
+ public:
+  // |quit_closure| is called whenever the last ref is destroyed.
+  explicit ServiceContextRefFactory(const base::Closure& quit_closure);
+  ~ServiceContextRefFactory();
+
+  std::unique_ptr<ServiceContextRef> CreateRef();
+
+  bool HasNoRefs() const { return !ref_count_; }
+
+ private:
+  friend ServiceContextRefImpl;
+
+  // Called from ServiceContextRefImpl.
+  void AddRef();
+  void Release();
+
+  const base::Closure quit_closure_;
+  int ref_count_ = 0;
+  base::WeakPtrFactory<ServiceContextRefFactory> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ServiceContextRefFactory);
+};
+
+}  // namespace shell
+
+#endif  // SERVICES_SHELL_PUBLIC_CPP_SERVICE_CONTEXT_REF_H_
diff --git a/services/shell/public/cpp/shell_test.h b/services/shell/public/cpp/service_test.h
similarity index 73%
rename from services/shell/public/cpp/shell_test.h
rename to services/shell/public/cpp/service_test.h
index 452018e..ca3868ef 100644
--- a/services/shell/public/cpp/shell_test.h
+++ b/services/shell/public/cpp/service_test.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 SERVICES_SHELL_PUBLIC_CPP_SHELL_TEST_H_
-#define SERVICES_SHELL_PUBLIC_CPP_SHELL_TEST_H_
+#ifndef SERVICES_SHELL_PUBLIC_CPP_SERVICE_TEST_H_
+#define SERVICES_SHELL_PUBLIC_CPP_SERVICE_TEST_H_
 
 #include <memory>
 
 #include "base/macros.h"
 #include "services/shell/public/cpp/connector.h"
 #include "services/shell/public/cpp/service.h"
-#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service_context.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -23,16 +23,16 @@
 
 namespace test {
 
-class ShellTest;
+class ServiceTest;
 
-// A default implementation of Service for use in ShellTests. Tests wishing
+// A default implementation of Service for use in ServiceTests. Tests wishing
 // to customize this should subclass this class instead of Service,
-// otherwise they will have to call ShellTest::OnStartCalled() to forward
+// otherwise they will have to call ServiceTest::OnStartCalled() to forward
 // metadata from OnStart() to the test.
-class ShellTestClient : public Service {
+class ServiceTestClient : public Service {
  public:
-  explicit ShellTestClient(ShellTest* test);
-  ~ShellTestClient() override;
+  explicit ServiceTestClient(ServiceTest* test);
+  ~ServiceTestClient() override;
 
  protected:
   void OnStart(Connector* connector,
@@ -40,20 +40,20 @@
                uint32_t id) override;
 
  private:
-  ShellTest* test_;
+  ServiceTest* test_;
 
-  DISALLOW_COPY_AND_ASSIGN(ShellTestClient);
+  DISALLOW_COPY_AND_ASSIGN(ServiceTestClient);
 };
 
-class ShellTest : public testing::Test {
+class ServiceTest : public testing::Test {
  public:
-  ShellTest();
+  ServiceTest();
   // Initialize passing the name to use as the identity for the test itself.
   // Once set via this constructor, it cannot be changed later by calling
   // InitTestName(). The test executable must provide a manifest in the
   // appropriate location that specifies this name also.
-  explicit ShellTest(const std::string& test_name);
-  ~ShellTest() override;
+  explicit ServiceTest(const std::string& test_name);
+  ~ServiceTest() override;
 
  protected:
   // See constructor. Can only be called once.
@@ -61,7 +61,7 @@
 
   Connector* connector() { return connector_; }
 
-  // Instance information received from the Shell during OnStart().
+  // Instance information received from the Service Manager during OnStart().
   const std::string& test_name() const { return initialize_name_; }
   const std::string& test_userid() const { return initialize_userid_; }
   uint32_t test_instance_id() const { return initialize_instance_id_; }
@@ -85,13 +85,13 @@
   void TearDown() override;
 
  private:
-  friend ShellTestClient;
+  friend ServiceTestClient;
 
   std::unique_ptr<Service> service_;
 
   std::unique_ptr<base::MessageLoop> message_loop_;
   std::unique_ptr<BackgroundShell> background_shell_;
-  std::unique_ptr<ShellConnection> shell_connection_;
+  std::unique_ptr<ServiceContext> service_context_;
 
   // See constructor.
   std::string test_name_;
@@ -103,10 +103,10 @@
 
   base::Closure initialize_called_;
 
-  DISALLOW_COPY_AND_ASSIGN(ShellTest);
+  DISALLOW_COPY_AND_ASSIGN(ServiceTest);
 };
 
 }  // namespace test
 }  // namespace shell
 
-#endif  // SERVICES_SHELL_PUBLIC_CPP_SHELL_TEST_H_
+#endif  // SERVICES_SHELL_PUBLIC_CPP_SERVICE_TEST_H_
diff --git a/services/shell/public/cpp/shell_connection_ref.h b/services/shell/public/cpp/shell_connection_ref.h
deleted file mode 100644
index b22e12e..0000000
--- a/services/shell/public/cpp/shell_connection_ref.h
+++ /dev/null
@@ -1,59 +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 SERVICES_SHELL_PUBLIC_CPP_SHELL_CONNECTION_REF_H_
-#define SERVICES_SHELL_PUBLIC_CPP_SHELL_CONNECTION_REF_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-
-namespace shell {
-
-class ShellConnectionRefImpl;
-
-// An interface implementation can keep this object as a member variable to
-// hold a reference to the ShellConnection, keeping it alive as long as the
-// bound implementation exists.
-//
-// This class is safe to use on any thread and instances may be passed to other
-// threads. However, each instance should only be used on one thread at a time,
-// otherwise there'll be races between the AddRef resulting from cloning and
-// destruction.
-class ShellConnectionRef {
- public:
-  virtual ~ShellConnectionRef() {}
-
-  virtual std::unique_ptr<ShellConnectionRef> Clone() = 0;
-};
-
-class ShellConnectionRefFactory {
- public:
-  // |quit_closure| is called whenever the last ref is destroyed.
-  explicit ShellConnectionRefFactory(const base::Closure& quit_closure);
-  ~ShellConnectionRefFactory();
-
-  std::unique_ptr<ShellConnectionRef> CreateRef();
-
-  bool HasNoRefs() const { return !ref_count_; }
-
- private:
-  friend ShellConnectionRefImpl;
-
-  // Called from ShellConnectionRefImpl.
-  void AddRef();
-  void Release();
-
-  const base::Closure quit_closure_;
-  int ref_count_ = 0;
-  base::WeakPtrFactory<ShellConnectionRefFactory> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellConnectionRefFactory);
-};
-
-}  // namespace shell
-
-#endif  // SERVICES_SHELL_PUBLIC_CPP_SHELL_CONNECTION_REF_H_
diff --git a/services/shell/runner/child/test_native_main.cc b/services/shell/runner/child/test_native_main.cc
index ded151ab..763b7eb 100644
--- a/services/shell/runner/child/test_native_main.cc
+++ b/services/shell/runner/child/test_native_main.cc
@@ -16,7 +16,7 @@
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/edk/embedder/process_delegate.h"
 #include "services/shell/public/cpp/service.h"
-#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service_context.h"
 #include "services/shell/runner/common/client_util.h"
 #include "services/shell/runner/init.h"
 
@@ -58,7 +58,7 @@
     mojo::edk::SetParentPipeHandleFromCommandLine();
 
     base::MessageLoop loop;
-    shell::ShellConnection impl(service,
+    shell::ServiceContext impl(service,
                                 shell::GetServiceRequestFromCommandLine());
     base::RunLoop().Run();
 
diff --git a/services/shell/service_manager.cc b/services/shell/service_manager.cc
index 90815627..70aca84c 100644
--- a/services/shell/service_manager.cc
+++ b/services/shell/service_manager.cc
@@ -23,7 +23,7 @@
 #include "services/shell/connect_util.h"
 #include "services/shell/public/cpp/connector.h"
 #include "services/shell/public/cpp/names.h"
-#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service_context.h"
 #include "services/shell/public/interfaces/connector.mojom.h"
 #include "services/shell/public/interfaces/service.mojom.h"
 #include "services/shell/public/interfaces/service_manager.mojom.h"
@@ -497,7 +497,7 @@
       Identity(), CreateServiceManagerIdentity(), GetPermissiveCapabilities());
   instance->StartWithService(std::move(service));
   singletons_.insert(kServiceManagerName);
-  shell_connection_.reset(new ShellConnection(this, std::move(request)));
+  service_context_.reset(new ServiceContext(this, std::move(request)));
 
   if (catalog)
     InitCatalog(std::move(catalog));
diff --git a/services/shell/service_manager.h b/services/shell/service_manager.h
index 6a448cf..5357d74 100644
--- a/services/shell/service_manager.h
+++ b/services/shell/service_manager.h
@@ -27,7 +27,7 @@
 #include "services/shell/public/interfaces/service_manager.mojom.h"
 
 namespace shell {
-class ShellConnection;
+class ServiceContext;
 
 // Creates an identity for the Service Manager, used when the Service Manager
 // connects to services.
@@ -154,7 +154,7 @@
   mojo::InterfacePtrSet<mojom::ServiceManagerListener> listeners_;
   base::Callback<void(const Identity&)> instance_quit_callback_;
   std::unique_ptr<NativeRunnerFactory> native_runner_factory_;
-  std::unique_ptr<ShellConnection> shell_connection_;
+  std::unique_ptr<ServiceContext> service_context_;
   base::WeakPtrFactory<ServiceManager> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceManager);
diff --git a/services/shell/shell_public.gyp b/services/shell/shell_public.gyp
index 3cbfa9e..c10db5b 100644
--- a/services/shell/shell_public.gyp
+++ b/services/shell/shell_public.gyp
@@ -59,13 +59,13 @@
       'public/cpp/lib/names.cc',
       'public/cpp/lib/interface_provider.cc',
       'public/cpp/lib/service.cc',
-      'public/cpp/lib/shell_connection.cc',
-      'public/cpp/lib/shell_connection_ref.cc',
+      'public/cpp/lib/service_context.cc',
+      'public/cpp/lib/service_context_ref.cc',
       'public/cpp/names.h',
       'public/cpp/interface_provider.h',
       'public/cpp/service.h',
-      'public/cpp/shell_connection.h',
-      'public/cpp/shell_connection_ref.h',
+      'public/cpp/service_context.h',
+      'public/cpp/service_context_ref.h',
     ],
     'dependencies': [
       'shell_interfaces',
diff --git a/services/shell/tests/connect/BUILD.gn b/services/shell/tests/connect/BUILD.gn
index 00bf944..91fb22cf 100644
--- a/services/shell/tests/connect/BUILD.gn
+++ b/services/shell/tests/connect/BUILD.gn
@@ -16,7 +16,7 @@
     ":interfaces",
     "//base",
     "//base/test:test_support",
-    "//services/shell/public/cpp:shell_test_support",
+    "//services/shell/public/cpp:service_test_support",
     "//services/shell/public/cpp:sources",
     "//services/shell/public/interfaces",
   ]
diff --git a/services/shell/tests/connect/connect_unittest.cc b/services/shell/tests/connect/connect_unittest.cc
index 0b43d40..bfd372d 100644
--- a/services/shell/tests/connect/connect_unittest.cc
+++ b/services/shell/tests/connect/connect_unittest.cc
@@ -15,7 +15,7 @@
 #include "base/test/test_suite.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/shell/public/cpp/names.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_test.h"
 #include "services/shell/public/interfaces/service_manager.mojom.h"
 #include "services/shell/tests/connect/connect_test.mojom.h"
 
@@ -68,11 +68,11 @@
 
 }  // namespace
 
-class ConnectTest : public test::ShellTest,
+class ConnectTest : public test::ServiceTest,
                     public InterfaceFactory<test::mojom::ExposedInterface>,
                     public test::mojom::ExposedInterface {
  public:
-  ConnectTest() : ShellTest("mojo:connect_unittests") {}
+  ConnectTest() : ServiceTest("mojo:connect_unittests") {}
   ~ConnectTest() override {}
 
  protected:
@@ -108,9 +108,9 @@
   }
 
  private:
-  // test::ShellTest:
+  // test::ServiceTest:
   void SetUp() override {
-    test::ShellTest::SetUp();
+    test::ServiceTest::SetUp();
     // We need to connect to the package first to force the shell to read the
     // package app's manifest and register aliases for the applications it
     // provides.
diff --git a/services/shell/tests/lifecycle/BUILD.gn b/services/shell/tests/lifecycle/BUILD.gn
index 3e002e7..498cdbd 100644
--- a/services/shell/tests/lifecycle/BUILD.gn
+++ b/services/shell/tests/lifecycle/BUILD.gn
@@ -16,7 +16,7 @@
     ":interfaces",
     "//base",
     "//base/test:test_support",
-    "//services/shell/public/cpp:shell_test_support",
+    "//services/shell/public/cpp:service_test_support",
     "//services/shell/public/cpp:sources",
     "//services/shell/public/interfaces",
     "//services/shell/runner/common",
diff --git a/services/shell/tests/lifecycle/app_client.cc b/services/shell/tests/lifecycle/app_client.cc
index 4cba823..68ca273 100644
--- a/services/shell/tests/lifecycle/app_client.cc
+++ b/services/shell/tests/lifecycle/app_client.cc
@@ -4,14 +4,14 @@
 
 #include "services/shell/tests/lifecycle/app_client.h"
 
-#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service_context.h"
 
 namespace shell {
 namespace test {
 
 AppClient::AppClient() {}
 AppClient::AppClient(shell::mojom::ServiceRequest request)
-    : connection_(new ShellConnection(this, std::move(request))) {}
+    : context_(new ServiceContext(this, std::move(request))) {}
 AppClient::~AppClient() {}
 
 bool AppClient::OnConnect(Connection* connection) {
@@ -41,7 +41,7 @@
 
 void AppClient::CloseShellConnection() {
   DCHECK(runner_);
-  runner_->DestroyShellConnection();
+  runner_->DestroyServiceContext();
   // Quit the app once the caller goes away.
   bindings_.set_connection_error_handler(
       base::Bind(&AppClient::BindingLost, base::Unretained(this)));
diff --git a/services/shell/tests/lifecycle/app_client.h b/services/shell/tests/lifecycle/app_client.h
index b83a5a27..0dd6c1d 100644
--- a/services/shell/tests/lifecycle/app_client.h
+++ b/services/shell/tests/lifecycle/app_client.h
@@ -20,7 +20,7 @@
 using LifecycleControlRequest = shell::test::mojom::LifecycleControlRequest;
 
 namespace shell {
-class ShellConnection;
+class ServiceContext;
 
 namespace test {
 
@@ -53,7 +53,7 @@
 
   ApplicationRunner* runner_ = nullptr;
   mojo::BindingSet<LifecycleControl> bindings_;
-  std::unique_ptr<ShellConnection> connection_;
+  std::unique_ptr<ServiceContext> context_;
 
   DISALLOW_COPY_AND_ASSIGN(AppClient);
 };
diff --git a/services/shell/tests/lifecycle/lifecycle_unittest.cc b/services/shell/tests/lifecycle/lifecycle_unittest.cc
index 4864275..830d0fc 100644
--- a/services/shell/tests/lifecycle/lifecycle_unittest.cc
+++ b/services/shell/tests/lifecycle/lifecycle_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/process/process.h"
 #include "base/run_loop.h"
 #include "services/shell/public/cpp/identity.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_test.h"
 #include "services/shell/public/interfaces/service_manager.mojom.h"
 #include "services/shell/tests/lifecycle/lifecycle_unittest.mojom.h"
 #include "services/shell/tests/util.h"
@@ -126,21 +126,21 @@
 
 }  // namespace
 
-class LifecycleTest : public test::ShellTest {
+class LifecycleTest : public test::ServiceTest {
  public:
-  LifecycleTest() : ShellTest(kTestName) {}
+  LifecycleTest() : ServiceTest(kTestName) {}
   ~LifecycleTest() override {}
 
  protected:
-  // test::ShellTest:
+  // test::ServiceTest:
   void SetUp() override {
-    test::ShellTest::SetUp();
+    test::ServiceTest::SetUp();
     InitPackage();
     instances_ = TrackInstances();
   }
   void TearDown() override {
     instances_.reset();
-    test::ShellTest::TearDown();
+    test::ServiceTest::TearDown();
   }
 
   bool CanRunCrashTest() {
diff --git a/services/shell/tests/lifecycle/package.cc b/services/shell/tests/lifecycle/package.cc
index cfac449..3250324 100644
--- a/services/shell/tests/lifecycle/package.cc
+++ b/services/shell/tests/lifecycle/package.cc
@@ -10,7 +10,7 @@
 #include "mojo/public/c/system/main.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/shell/public/cpp/application_runner.h"
-#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/cpp/service_context.h"
 #include "services/shell/public/interfaces/service_factory.mojom.h"
 #include "services/shell/tests/lifecycle/app_client.h"
 #include "services/shell/tests/lifecycle/lifecycle_unittest.mojom.h"
@@ -26,7 +26,7 @@
   PackagedApp(shell::mojom::ServiceRequest request,
               const DestructCallback& shell_connection_closed_callback,
               const DestructCallback& destruct_callback)
-      : connection_(new shell::ShellConnection(this, std::move(request))),
+      : connection_(new shell::ServiceContext(this, std::move(request))),
         shell_connection_closed_callback_(shell_connection_closed_callback),
         destruct_callback_(destruct_callback) {
     bindings_.set_connection_error_handler(base::Bind(&PackagedApp::BindingLost,
@@ -75,7 +75,7 @@
       delete this;
   }
 
-  std::unique_ptr<shell::ShellConnection> connection_;
+  std::unique_ptr<shell::ServiceContext> connection_;
   mojo::BindingSet<LifecycleControl> bindings_;
   // Run when this object's connection to the shell is closed.
   DestructCallback shell_connection_closed_callback_;
diff --git a/services/shell/tests/shell/BUILD.gn b/services/shell/tests/shell/BUILD.gn
index d26ff7c..4996253e 100644
--- a/services/shell/tests/shell/BUILD.gn
+++ b/services/shell/tests/shell/BUILD.gn
@@ -18,7 +18,7 @@
     "//base",
     "//base/test:test_config",
     "//mojo/common:common_base",
-    "//services/shell/public/cpp:shell_test_support",
+    "//services/shell/public/cpp:service_test_support",
     "//services/shell/public/cpp:sources",
     "//services/shell/public/interfaces",
   ]
diff --git a/services/shell/tests/shell/shell_unittest.cc b/services/shell/tests/shell/shell_unittest.cc
index d70e7fa..4c740592 100644
--- a/services/shell/tests/shell/shell_unittest.cc
+++ b/services/shell/tests/shell/shell_unittest.cc
@@ -17,7 +17,7 @@
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/shell/public/cpp/interface_factory.h"
 #include "services/shell/public/cpp/service.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_test.h"
 #include "services/shell/public/interfaces/service_manager.mojom.h"
 #include "services/shell/tests/shell/shell_unittest.mojom.h"
 
@@ -26,12 +26,12 @@
 namespace {
 
 class ShellTestClient
-    : public test::ShellTestClient,
+    : public test::ServiceTestClient,
       public InterfaceFactory<test::mojom::CreateInstanceTest>,
       public test::mojom::CreateInstanceTest {
  public:
-  explicit ShellTestClient(test::ShellTest* test)
-      : test::ShellTestClient(test),
+  explicit ShellTestClient(test::ServiceTest* test)
+      : test::ServiceTestClient(test),
         target_id_(shell::mojom::kInvalidInstanceID),
         binding_(this) {}
   ~ShellTestClient() override {}
@@ -39,7 +39,7 @@
   uint32_t target_id() const { return target_id_; }
 
  private:
-  // test::ShellTestClient:
+  // test::ServiceTestClient:
   bool OnConnect(Connection* connection) override {
     connection->AddInterface<test::mojom::CreateInstanceTest>(this);
     return true;
@@ -67,11 +67,11 @@
 
 }  // namespace
 
-class ShellTest : public test::ShellTest,
+class ShellTest : public test::ServiceTest,
                   public mojom::ServiceManagerListener {
  public:
   ShellTest()
-      : test::ShellTest("mojo:shell_unittest"),
+      : test::ServiceTest("mojo:shell_unittest"),
         service_(nullptr),
         binding_(this) {}
   ~ShellTest() override {}
@@ -122,7 +122,7 @@
   }
 
  private:
-  // test::ShellTest:
+  // test::ServiceTest:
   std::unique_ptr<Service> CreateService() override {
     service_ = new ShellTestClient(this);
     return base::WrapUnique(service_);
diff --git a/services/shell/tests/shutdown/BUILD.gn b/services/shell/tests/shutdown/BUILD.gn
index be1661c..e092cb3 100644
--- a/services/shell/tests/shutdown/BUILD.gn
+++ b/services/shell/tests/shutdown/BUILD.gn
@@ -19,7 +19,7 @@
     ":shutdown_service",
     "//base",
     "//base/test:test_config",
-    "//services/shell/public/cpp:shell_test_support",
+    "//services/shell/public/cpp:service_test_support",
     "//services/shell/public/cpp:sources",
     "//services/shell/public/interfaces",
   ]
diff --git a/services/shell/tests/shutdown/shutdown_unittest.cc b/services/shell/tests/shutdown/shutdown_unittest.cc
index ea7faee..93d1c94 100644
--- a/services/shell/tests/shutdown/shutdown_unittest.cc
+++ b/services/shell/tests/shutdown/shutdown_unittest.cc
@@ -4,15 +4,15 @@
 
 #include "base/run_loop.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_test.h"
 #include "services/shell/tests/shutdown/shutdown_unittest.mojom.h"
 
 namespace shell {
 namespace {
 
-class ShutdownTest : public test::ShellTest {
+class ShutdownTest : public test::ServiceTest {
  public:
-  ShutdownTest() : test::ShellTest("mojo:shutdown_unittest") {}
+  ShutdownTest() : test::ServiceTest("mojo:shutdown_unittest") {}
   ~ShutdownTest() override {}
 
  private:
diff --git a/services/ui/clipboard/BUILD.gn b/services/ui/clipboard/BUILD.gn
index 0114a5b5..23044b3 100644
--- a/services/ui/clipboard/BUILD.gn
+++ b/services/ui/clipboard/BUILD.gn
@@ -37,7 +37,7 @@
   deps = [
     "//base",
     "//mojo/common",
-    "//services/shell/public/cpp:shell_test_support",
+    "//services/shell/public/cpp:service_test_support",
     "//services/shell/public/cpp:sources",
     "//services/shell/public/cpp/test:run_all_shelltests",
     "//services/ui/public/interfaces",
diff --git a/services/ui/clipboard/clipboard_unittest.cc b/services/ui/clipboard/clipboard_unittest.cc
index b01951e..a6f287c 100644
--- a/services/ui/clipboard/clipboard_unittest.cc
+++ b/services/ui/clipboard/clipboard_unittest.cc
@@ -9,8 +9,8 @@
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "mojo/common/common_type_converters.h"
-#include "services/shell/public/cpp/shell_connection.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_context.h"
+#include "services/shell/public/cpp/service_test.h"
 #include "services/ui/public/interfaces/clipboard.mojom.h"
 
 using mojo::Array;
@@ -28,14 +28,14 @@
 
 }  // namespace
 
-class ClipboardAppTest : public shell::test::ShellTest {
+class ClipboardAppTest : public shell::test::ServiceTest {
  public:
-  ClipboardAppTest() : ShellTest("exe:mus_clipboard_unittests") {}
+  ClipboardAppTest() : ServiceTest("exe:mus_clipboard_unittests") {}
   ~ClipboardAppTest() override {}
 
-  // Overridden from shell::test::ShellTest:
+  // Overridden from shell::test::ServiceTest:
   void SetUp() override {
-    ShellTest::SetUp();
+    ServiceTest::SetUp();
 
     connector()->ConnectToInterface("mojo:ui", &clipboard_);
     ASSERT_TRUE(clipboard_);
diff --git a/services/ui/common/gpu_type_converters.cc b/services/ui/common/gpu_type_converters.cc
index a09b9590..9ee911a5 100644
--- a/services/ui/common/gpu_type_converters.cc
+++ b/services/ui/common/gpu_type_converters.cc
@@ -31,6 +31,7 @@
   if (platform_file != -1)
     result->socket = mojo::WrapPlatformFile(platform_file);
 #endif
+  result->mojo_handle.reset(handle.mojo_handle);
   return result;
 }
 
@@ -40,6 +41,11 @@
     const ui::mojom::ChannelHandlePtr& handle) {
   if (handle.is_null())
     return IPC::ChannelHandle();
+  if (handle->mojo_handle.is_valid()) {
+    IPC::ChannelHandle channel_handle(handle->mojo_handle.release());
+    channel_handle.name = handle->name;
+    return channel_handle;
+  }
 #if defined(OS_WIN)
   // On windows, a pipe handle Will NOT be marshalled over IPC.
   DCHECK(!handle->socket.is_valid());
diff --git a/services/ui/common/gpu_type_converters_unittest.cc b/services/ui/common/gpu_type_converters_unittest.cc
index 08fc52b2..67b3047 100644
--- a/services/ui/common/gpu_type_converters_unittest.cc
+++ b/services/ui/common/gpu_type_converters_unittest.cc
@@ -57,6 +57,28 @@
     base::ScopedFD socped_fd3(handle.socket.fd);
   }
 #endif
+
+  {
+    const std::string channel_name = "test_channel_name";
+    mojo::MessagePipe message_pipe;
+    mojo::MessagePipeHandle mp_handle = message_pipe.handle0.release();
+    EXPECT_TRUE(mp_handle.is_valid());
+    IPC::ChannelHandle handle(mp_handle);
+    handle.name = channel_name;
+
+    ui::mojom::ChannelHandlePtr mojo_handle =
+        ui::mojom::ChannelHandle::From(handle);
+    ASSERT_EQ(mojo_handle->name, channel_name);
+    ASSERT_EQ(mojo_handle->mojo_handle.get(), mp_handle);
+    EXPECT_FALSE(mojo_handle->socket.is_valid());
+
+    handle = mojo_handle.To<IPC::ChannelHandle>();
+    ASSERT_EQ(handle.name, channel_name);
+    ASSERT_EQ(handle.mojo_handle, mp_handle);
+#if defined(OS_POSIX)
+    ASSERT_EQ(handle.socket.fd, -1);
+#endif
+  }
 }
 
 // Test for mojo TypeConverter of ui::mojom::GpuMemoryBufferHandle
diff --git a/services/ui/public/cpp/tests/BUILD.gn b/services/ui/public/cpp/tests/BUILD.gn
index af29abe..150da06b 100644
--- a/services/ui/public/cpp/tests/BUILD.gn
+++ b/services/ui/public/cpp/tests/BUILD.gn
@@ -40,7 +40,7 @@
   deps = [
     "//base",
     "//base/test:test_config",
-    "//services/shell/public/cpp:shell_test_support",
+    "//services/shell/public/cpp:service_test_support",
     "//services/shell/public/cpp:sources",
     "//services/ui/common:mus_common",
     "//services/ui/public/cpp",
diff --git a/services/ui/public/cpp/tests/window_server_shelltest_base.cc b/services/ui/public/cpp/tests/window_server_shelltest_base.cc
index ee55da4..c34ce7f 100644
--- a/services/ui/public/cpp/tests/window_server_shelltest_base.cc
+++ b/services/ui/public/cpp/tests/window_server_shelltest_base.cc
@@ -10,7 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "services/shell/public/cpp/service.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_test.h"
 #include "services/ui/common/switches.h"
 #include "ui/gl/gl_switches.h"
 
@@ -20,21 +20,21 @@
 
 const char kTestAppName[] = "mojo:mus_ws_unittests_app";
 
-class WindowServerShellTestClient : public shell::test::ShellTestClient {
+class WindowServerServiceTestClient : public shell::test::ServiceTestClient {
  public:
-  explicit WindowServerShellTestClient(WindowServerShellTestBase* test)
-      : ShellTestClient(test), test_(test) {}
-  ~WindowServerShellTestClient() override {}
+  explicit WindowServerServiceTestClient(WindowServerServiceTestBase* test)
+      : ServiceTestClient(test), test_(test) {}
+  ~WindowServerServiceTestClient() override {}
 
  private:
-  // shell::test::ShellTestClient:
+  // shell::test::ServiceTestClient:
   bool OnConnect(shell::Connection* connection) override {
     return test_->OnConnect(connection);
   }
 
-  WindowServerShellTestBase* test_;
+  WindowServerServiceTestBase* test_;
 
-  DISALLOW_COPY_AND_ASSIGN(WindowServerShellTestClient);
+  DISALLOW_COPY_AND_ASSIGN(WindowServerServiceTestClient);
 };
 
 void EnsureCommandLineSwitch(const std::string& name) {
@@ -45,17 +45,17 @@
 
 }  // namespace
 
-WindowServerShellTestBase::WindowServerShellTestBase()
-    : ShellTest(kTestAppName) {
+WindowServerServiceTestBase::WindowServerServiceTestBase()
+    : ServiceTest(kTestAppName) {
   EnsureCommandLineSwitch(switches::kUseTestConfig);
   EnsureCommandLineSwitch(::switches::kOverrideUseGLWithOSMesaForTests);
 }
 
-WindowServerShellTestBase::~WindowServerShellTestBase() {}
+WindowServerServiceTestBase::~WindowServerServiceTestBase() {}
 
 std::unique_ptr<shell::Service>
-WindowServerShellTestBase::CreateService() {
-  return base::WrapUnique(new WindowServerShellTestClient(this));
+WindowServerServiceTestBase::CreateService() {
+  return base::WrapUnique(new WindowServerServiceTestClient(this));
 }
 
 }  // namespace ui
diff --git a/services/ui/public/cpp/tests/window_server_shelltest_base.h b/services/ui/public/cpp/tests/window_server_shelltest_base.h
index 01d9547..ad02871 100644
--- a/services/ui/public/cpp/tests/window_server_shelltest_base.h
+++ b/services/ui/public/cpp/tests/window_server_shelltest_base.h
@@ -7,23 +7,23 @@
 
 #include "base/macros.h"
 #include "services/shell/public/cpp/connection.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_test.h"
 
 namespace ui {
 
-// Base class for all window manager shelltests to perform some common setup.
-class WindowServerShellTestBase : public shell::test::ShellTest {
+// Base class for all window manager ServiceTests to perform some common setup.
+class WindowServerServiceTestBase : public shell::test::ServiceTest {
  public:
-  WindowServerShellTestBase();
-  ~WindowServerShellTestBase() override;
+  WindowServerServiceTestBase();
+  ~WindowServerServiceTestBase() override;
 
   virtual bool OnConnect(shell::Connection* connection) = 0;
 
  private:
-  // shell::test::ShellTest:
+  // shell::test::ServiceTest:
   std::unique_ptr<shell::Service> CreateService() override;
 
-  DISALLOW_COPY_AND_ASSIGN(WindowServerShellTestBase);
+  DISALLOW_COPY_AND_ASSIGN(WindowServerServiceTestBase);
 };
 
 }  // namespace ui
diff --git a/services/ui/public/cpp/tests/window_server_test_base.cc b/services/ui/public/cpp/tests/window_server_test_base.cc
index 40312749..1a72fdc 100644
--- a/services/ui/public/cpp/tests/window_server_test_base.cc
+++ b/services/ui/public/cpp/tests/window_server_test_base.cc
@@ -65,7 +65,7 @@
 }
 
 void WindowServerTestBase::SetUp() {
-  WindowServerShellTestBase::SetUp();
+  WindowServerServiceTestBase::SetUp();
 
   CreateWindowTreeHost(connector(), this, &host_, this);
 
diff --git a/services/ui/public/cpp/tests/window_server_test_base.h b/services/ui/public/cpp/tests/window_server_test_base.h
index 54cf30d..9294305 100644
--- a/services/ui/public/cpp/tests/window_server_test_base.h
+++ b/services/ui/public/cpp/tests/window_server_test_base.h
@@ -22,7 +22,7 @@
 // has been invoked. window_manager() can be used to access the WindowServer
 // established as part of SetUp().
 class WindowServerTestBase
-    : public WindowServerShellTestBase,
+    : public WindowServerServiceTestBase,
       public WindowTreeClientDelegate,
       public WindowManagerDelegate,
       public shell::InterfaceFactory<mojom::WindowTreeClient> {
@@ -62,7 +62,7 @@
   // testing::Test:
   void SetUp() override;
 
-  // WindowServerShellTestBase:
+  // WindowServerServiceTestBase:
   bool OnConnect(shell::Connection* connection) override;
 
   // WindowTreeClientDelegate:
diff --git a/services/ui/public/interfaces/channel_handle.mojom b/services/ui/public/interfaces/channel_handle.mojom
index 5a4136e..a0ffc10 100644
--- a/services/ui/public/interfaces/channel_handle.mojom
+++ b/services/ui/public/interfaces/channel_handle.mojom
@@ -9,5 +9,8 @@
   string name;
 
   // On POSIX, it is one endpoint of a socket pair. On Windows, it is not used.
-  handle socket;
+  handle? socket;
+
+  // Message pipe handle used for ChannelMojo.
+  handle<message_pipe>? mojo_handle;
 };
diff --git a/services/ui/ws/BUILD.gn b/services/ui/ws/BUILD.gn
index 145efa77..60f5477 100644
--- a/services/ui/ws/BUILD.gn
+++ b/services/ui/ws/BUILD.gn
@@ -132,14 +132,17 @@
   ]
 
   if (use_ozone) {
-    sources -= [
-      "platform_screen_impl.cc",
-      "platform_screen_impl.h",
-    ]
-    sources += [
-      "platform_screen_impl_ozone.cc",
-      "platform_screen_impl_ozone.h",
-    ]
+    if (is_chromeos) {
+      sources -= [
+        "platform_screen_impl.cc",
+        "platform_screen_impl.h",
+      ]
+      sources += [
+        "platform_screen_impl_ozone.cc",
+        "platform_screen_impl_ozone.h",
+      ]
+    }
+
     public_deps += [ "//ui/ozone:ozone" ]
   }
 }
@@ -195,6 +198,7 @@
     "event_dispatcher_unittest.cc",
     "event_matcher_unittest.cc",
     "focus_controller_unittest.cc",
+    "frame_generator_unittest.cc",
     "scheduled_animation_group_unittest.cc",
     "server_window_drawn_tracker_unittest.cc",
     "server_window_surface_manager_test_api.cc",
@@ -222,7 +226,7 @@
     "//base/test:test_support",
     "//cc:cc",
     "//mojo/public/cpp/bindings:bindings",
-    "//services/shell/public/cpp:shell_test_support",
+    "//services/shell/public/cpp:service_test_support",
     "//services/shell/public/cpp:sources",
     "//services/shell/public/cpp/test:run_all_shelltests",
     "//services/shell/public/interfaces",
diff --git a/services/ui/ws/frame_generator.cc b/services/ui/ws/frame_generator.cc
index aea380b..d09b0d7 100644
--- a/services/ui/ws/frame_generator.cc
+++ b/services/ui/ws/frame_generator.cc
@@ -4,6 +4,7 @@
 
 #include "services/ui/ws/frame_generator.h"
 
+#include "base/containers/adapters.h"
 #include "cc/output/compositor_frame.h"
 #include "cc/quads/render_pass.h"
 #include "cc/quads/shared_quad_state.h"
@@ -118,11 +119,10 @@
 
   const gfx::Rect absolute_bounds =
       window->bounds() + parent_to_root_origin_offset;
-  std::vector<ServerWindow*> children(window->GetChildren());
-  // TODO(rjkroege, fsamuel): Make sure we're handling alpha correctly.
+  const ServerWindow::Windows& children = window->children();
   const float combined_opacity = opacity * window->opacity();
-  for (auto it = children.rbegin(); it != children.rend(); ++it) {
-    DrawWindowTree(pass, *it, absolute_bounds.OffsetFromOrigin(),
+  for (ServerWindow* child : base::Reversed(children)) {
+    DrawWindowTree(pass, child, absolute_bounds.OffsetFromOrigin(),
                    combined_opacity);
   }
 
@@ -148,7 +148,7 @@
                 bounds_at_origin.size() /* layer_bounds */,
                 bounds_at_origin /* visible_layer_bounds */,
                 bounds_at_origin /* clip_rect */, false /* is_clipped */,
-                window->opacity(), SkXfermode::kSrcOver_Mode,
+                combined_opacity, SkXfermode::kSrcOver_Mode,
                 0 /* sorting-context_id */);
     auto quad = pass->CreateAndAppendDrawQuad<cc::SurfaceDrawQuad>();
     quad->SetAll(sqs, bounds_at_origin /* rect */,
@@ -169,7 +169,7 @@
                 bounds_at_origin.size() /* layer_bounds */,
                 bounds_at_origin /* visible_layer_bounds */,
                 bounds_at_origin /* clip_rect */, false /* is_clipped */,
-                window->opacity(), SkXfermode::kSrcOver_Mode,
+                combined_opacity, SkXfermode::kSrcOver_Mode,
                 0 /* sorting-context_id */);
 
     auto quad = pass->CreateAndAppendDrawQuad<cc::SurfaceDrawQuad>();
diff --git a/services/ui/ws/frame_generator.h b/services/ui/ws/frame_generator.h
index c23e3b7d..1872f1a5 100644
--- a/services/ui/ws/frame_generator.h
+++ b/services/ui/ws/frame_generator.h
@@ -27,6 +27,10 @@
 
 namespace ws {
 
+namespace test {
+class FrameGeneratorTest;
+}
+
 class FrameGeneratorDelegate;
 class ServerWindow;
 
@@ -48,6 +52,8 @@
   bool is_frame_pending() { return frame_pending_; }
 
  private:
+  friend class ui::ws::test::FrameGeneratorTest;
+
   void WantToDraw();
 
   // This method initiates a top level redraw of the display.
diff --git a/services/ui/ws/frame_generator_unittest.cc b/services/ui/ws/frame_generator_unittest.cc
new file mode 100644
index 0000000..0af81b4f
--- /dev/null
+++ b/services/ui/ws/frame_generator_unittest.cc
@@ -0,0 +1,131 @@
+// 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 "services/ui/ws/frame_generator.h"
+
+#include <memory>
+
+#include "base/test/test_message_loop.h"
+#include "cc/quads/render_pass.h"
+#include "cc/quads/shared_quad_state.h"
+#include "services/ui/gles2/gpu_state.h"
+#include "services/ui/ws/platform_display_init_params.h"
+#include "services/ui/ws/server_window.h"
+#include "services/ui/ws/server_window_surface_manager.h"
+#include "services/ui/ws/test_server_window_delegate.h"
+#include "services/ui/ws/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ui {
+namespace ws {
+namespace test {
+namespace {
+
+// Makes the window visible and creates the default surface for it.
+void InitWindow(ServerWindow* window) {
+  window->SetVisible(true);
+  ServerWindowSurfaceManager* surface_manager =
+      window->GetOrCreateSurfaceManager();
+  surface_manager->CreateSurface(mojom::SurfaceType::DEFAULT,
+                                 mojo::InterfaceRequest<mojom::Surface>(),
+                                 mojom::SurfaceClientPtr());
+}
+
+}  // namespace
+
+class FrameGeneratorTest : public testing::Test {
+ public:
+  FrameGeneratorTest() {}
+  ~FrameGeneratorTest() override {}
+
+  // Calls DrawWindowTree() on |frame_generator_|
+  void DrawWindowTree(cc::RenderPass* pass);
+
+  ServerWindow* root_window() {
+    return frame_generator_delegate_->GetRootWindow();
+  }
+
+  TestServerWindowDelegate* test_window_delegate() { return &window_delegate_; }
+
+ private:
+  // testing::Test:
+  void SetUp() override;
+  void TearDown() override;
+
+  std::unique_ptr<FrameGenerator> frame_generator_;
+  std::unique_ptr<TestFrameGeneratorDelegate> frame_generator_delegate_;
+  TestServerWindowDelegate window_delegate_;
+
+  // Needed so that Mojo classes can be initialized for ServerWindow use.
+  base::TestMessageLoop message_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameGeneratorTest);
+};
+
+void FrameGeneratorTest::DrawWindowTree(cc::RenderPass* pass) {
+  frame_generator_->DrawWindowTree(
+      pass, frame_generator_delegate_->GetRootWindow(), gfx::Vector2d(), 1.0f);
+}
+
+void FrameGeneratorTest::SetUp() {
+  testing::Test::SetUp();
+  frame_generator_delegate_.reset(new TestFrameGeneratorDelegate(
+      base::WrapUnique(new ServerWindow(&window_delegate_, WindowId()))));
+  PlatformDisplayInitParams init_params;
+  frame_generator_.reset(new FrameGenerator(frame_generator_delegate_.get(),
+                                            init_params.gpu_state,
+                                            init_params.surfaces_state));
+  InitWindow(root_window());
+}
+
+void FrameGeneratorTest::TearDown() {
+  frame_generator_.reset();
+  frame_generator_delegate_.reset();
+}
+
+// Tests correctness of the SharedQuadStateList generated by
+// FrameGenerator::DrawWindowTree().
+TEST_F(FrameGeneratorTest, DrawWindowTree) {
+  ServerWindow child_window(test_window_delegate(), WindowId());
+  root_window()->Add(&child_window);
+  InitWindow(&child_window);
+  const float root_opacity = .5f;
+  const float child_opacity = .4f;
+  root_window()->SetOpacity(root_opacity);
+  child_window.SetOpacity(child_opacity);
+
+  std::unique_ptr<cc::RenderPass> render_pass = cc::RenderPass::Create();
+  DrawWindowTree(render_pass.get());
+  cc::SharedQuadStateList* quad_state_list =
+      &render_pass->shared_quad_state_list;
+
+  // Both child and root have a DEFAULT Surface and no underlay Surfaces, so
+  // there should be two SharedQuadStates in the list.
+  EXPECT_EQ(2u, quad_state_list->size());
+  cc::SharedQuadState* root_sqs = quad_state_list->back();
+  cc::SharedQuadState* child_sqs = quad_state_list->front();
+  EXPECT_EQ(root_opacity, root_sqs->opacity);
+  // Child's SharedQuadState contains the effective opacity of the child layer,
+  // which should be a product of the child and the parent opacity.
+  EXPECT_EQ(child_opacity * root_opacity, child_sqs->opacity);
+
+  // Create the UNDERLAY Surface for the child window, and confirm that this
+  // creates an extra SharedQuadState in the CompositorFrame.
+  child_window.GetOrCreateSurfaceManager()->CreateSurface(
+      mojom::SurfaceType::UNDERLAY, mojo::InterfaceRequest<mojom::Surface>(),
+      mojom::SurfaceClientPtr());
+
+  render_pass = cc::RenderPass::Create();
+  DrawWindowTree(render_pass.get());
+  quad_state_list = &render_pass->shared_quad_state_list;
+  EXPECT_EQ(3u, quad_state_list->size());
+  auto it = quad_state_list->begin();
+  EXPECT_EQ(child_opacity * root_opacity, (*it)->opacity);
+  EXPECT_EQ(child_opacity * root_opacity, (*++it)->opacity);
+  EXPECT_EQ(root_opacity, (*++it)->opacity);
+}
+
+}  // namespace test
+}  // namespace ws
+}  // namespace ui
diff --git a/services/ui/ws/platform_screen.h b/services/ui/ws/platform_screen.h
index 3ed27930..075dc25 100644
--- a/services/ui/ws/platform_screen.h
+++ b/services/ui/ws/platform_screen.h
@@ -20,6 +20,9 @@
 // attached physical displays.
 class PlatformScreen {
  public:
+  using ConfiguredDisplayCallback =
+      base::Callback<void(int64_t, const gfx::Rect&)>;
+
   virtual ~PlatformScreen() {}
 
   // Creates a PlatformScreen instance.
@@ -28,9 +31,6 @@
   // Initializes platform specific screen resources.
   virtual void Init() = 0;
 
-  using ConfiguredDisplayCallback =
-      base::Callback<void(int64_t, const gfx::Rect&)>;
-
   // ConfigurePhysicalDisplay() configures a single physical display and returns
   // its id and bounds for it via |callback|.
   virtual void ConfigurePhysicalDisplay(
diff --git a/services/ui/ws/platform_screen_impl_ozone.cc b/services/ui/ws/platform_screen_impl_ozone.cc
index 33331d5..498b360 100644
--- a/services/ui/ws/platform_screen_impl_ozone.cc
+++ b/services/ui/ws/platform_screen_impl_ozone.cc
@@ -4,13 +4,14 @@
 
 #include "services/ui/ws/platform_screen_impl_ozone.h"
 
-#include "base/bind.h"
-#include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/sys_info.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/display/types/display_constants.h"
 #include "ui/display/types/display_snapshot.h"
 #include "ui/display/types/native_display_delegate.h"
+#include "ui/gfx/geometry/rect.h"
 #include "ui/ozone/public/ozone_platform.h"
 
 namespace ui {
@@ -18,7 +19,7 @@
 namespace ws {
 namespace {
 
-// TODO(rjkroege): Remove this code once ozone oxygen has the same
+// TODO(rjkroege): Remove this code once ozone headless has the same
 // display creation semantics as ozone drm.
 // Some ozone platforms do not configure physical displays and so do not
 // callback into this class via the implementation of NativeDisplayObserver.
@@ -30,96 +31,65 @@
   callback.Run(1, gfx::Rect(1024, 768));
 }
 
-void GetDisplaysFinished(const std::vector<ui::DisplaySnapshot*>& displays) {
-  // We don't really care about list of displays, we just want the snapshots
-  // held by DrmDisplayManager to be updated. This only only happens when we
-  // call NativeDisplayDelegate::GetDisplays(). Although, this would be a good
-  // place to have PlatformScreen cache the snapshots if need be.
-}
+// Needed for DisplayConfigurator::ForceInitialConfigure.
+const SkColor kChromeOsBootColor = SkColorSetRGB(0xfe, 0xfe, 0xfe);
 
 }  // namespace
 
 // static
 std::unique_ptr<PlatformScreen> PlatformScreen::Create() {
-  return base::WrapUnique(new PlatformScreenImplOzone);
+  return base::MakeUnique<PlatformScreenImplOzone>();
 }
 
-PlatformScreenImplOzone::PlatformScreenImplOzone() : weak_ptr_factory_(this) {}
+PlatformScreenImplOzone::PlatformScreenImplOzone() {}
 
-PlatformScreenImplOzone::~PlatformScreenImplOzone() {}
+PlatformScreenImplOzone::~PlatformScreenImplOzone() {
+  display_configurator_.RemoveObserver(this);
+}
 
 void PlatformScreenImplOzone::Init() {
-  native_display_delegate_ =
-      ui::OzonePlatform::GetInstance()->CreateNativeDisplayDelegate();
-  native_display_delegate_->AddObserver(this);
-  native_display_delegate_->Initialize();
+  display_configurator_.AddObserver(this);
+  display_configurator_.Init(
+      ui::OzonePlatform::GetInstance()->CreateNativeDisplayDelegate(), false);
 }
 
 void PlatformScreenImplOzone::ConfigurePhysicalDisplay(
     const PlatformScreen::ConfiguredDisplayCallback& callback) {
-#if defined(OS_CHROMEOS)
   if (base::SysInfo::IsRunningOnChromeOS()) {
-    // Kick off the configuration of the physical displays comprising the
-    // |PlatformScreenImplOzone|
-
-    DCHECK(native_display_delegate_) << "DefaultDisplayManager::"
-                                        "OnConfigurationChanged requires a "
-                                        "native_display_delegate_ to work.";
-
-    native_display_delegate_->GetDisplays(
-        base::Bind(&PlatformScreenImplOzone::OnDisplaysAquired,
-                   weak_ptr_factory_.GetWeakPtr(), callback));
-
-    return;
+    callback_ = callback;
+    display_configurator_.ForceInitialConfigure(kChromeOsBootColor);
+  } else {
+    // PostTask()ed to maximize control flow similarity with the ChromeOS case.
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&FixedSizeScreenConfiguration, callback));
   }
-#endif  // defined(OS_CHROMEOS)
-  // PostTask()ed to maximize control flow similarity with the ChromeOS case.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(&FixedSizeScreenConfiguration, callback));
 }
 
-void PlatformScreenImplOzone::OnConfigurationChanged() {}
+void PlatformScreenImplOzone::OnDisplayModeChanged(
+    const ui::DisplayConfigurator::DisplayStateList& displays) {
+  // TODO(kylechar): Remove checks when multiple display support is added.
+  CHECK(displays.size() == 1) << "Mus only supports one 1 display";
+  CHECK(!callback_.is_null());
 
-// The display subsystem calls |OnDisplaysAquired| to deliver |displays|
-// describing the attached displays.
-void PlatformScreenImplOzone::OnDisplaysAquired(
-    const ConfiguredDisplayCallback& callback,
-    const std::vector<ui::DisplaySnapshot*>& displays) {
-  DCHECK(native_display_delegate_) << "DefaultDisplayManager::"
-                                      "OnConfigurationChanged requires a "
-                                      "native_display_delegate_ to work.";
-  CHECK(displays.size() == 1) << "Mus only supports one 1 display\n";
   gfx::Point origin;
   for (auto display : displays) {
-    if (!display->native_mode()) {
-      LOG(ERROR) << "Display " << display->display_id()
-                 << " doesn't have a native mode";
-      continue;
-    }
-    // Setup each native display. This places a task on the DRM thread's
-    // runqueue that configures the window size correctly before the call to
-    // Configure.
-    native_display_delegate_->Configure(
-        *display, display->native_mode(), origin,
-        base::Bind(&PlatformScreenImplOzone::OnDisplayConfigured,
-                   weak_ptr_factory_.GetWeakPtr(), callback,
-                   display->display_id(),
-                   gfx::Rect(origin, display->native_mode()->size())));
-    origin.Offset(display->native_mode()->size().width(), 0);
+    const ui::DisplayMode* current_mode = display->current_mode();
+    gfx::Rect bounds(origin, current_mode->size());
+
+    callback_.Run(display->display_id(), bounds);
+
+    // Move the origin so that next display is to the right of current display.
+    origin.Offset(current_mode->size().width(), 0);
   }
+
+  callback_.Reset();
 }
 
-void PlatformScreenImplOzone::OnDisplayConfigured(
-    const ConfiguredDisplayCallback& callback,
-    int64_t id,
-    const gfx::Rect& bounds,
-    bool success) {
-  if (success) {
-    native_display_delegate_->GetDisplays(base::Bind(&GetDisplaysFinished));
-    callback.Run(id, bounds);
-  } else {
-    LOG(FATAL) << "Failed to configure display at " << bounds.ToString();
-  }
+void PlatformScreenImplOzone::OnDisplayModeChangeFailed(
+    const ui::DisplayConfigurator::DisplayStateList& displays,
+    MultipleDisplayState failed_new_state) {
+  LOG(ERROR) << "OnDisplayModeChangeFailed from DisplayConfigurator";
+  callback_.Reset();
 }
 
 }  // namespace ws
diff --git a/services/ui/ws/platform_screen_impl_ozone.h b/services/ui/ws/platform_screen_impl_ozone.h
index f01e16ba..e026bf6 100644
--- a/services/ui/ws/platform_screen_impl_ozone.h
+++ b/services/ui/ws/platform_screen_impl_ozone.h
@@ -10,19 +10,9 @@
 #include <vector>
 
 #include "base/callback.h"
-#include "base/memory/weak_ptr.h"
+#include "base/macros.h"
 #include "services/ui/ws/platform_screen.h"
-#include "ui/display/types/native_display_observer.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace gfx {
-class Rect;
-}
-
-namespace ui {
-class NativeDisplayDelegate;
-class DisplaySnapshot;
-}
+#include "ui/display/chromeos/display_configurator.h"
 
 namespace ui {
 namespace ws {
@@ -30,38 +20,29 @@
 // PlatformScreenImplOzone provides the necessary functionality to configure all
 // attached physical displays on the ozone platform.
 class PlatformScreenImplOzone : public PlatformScreen,
-                                public ui::NativeDisplayObserver {
+                                public ui::DisplayConfigurator::Observer {
  public:
   PlatformScreenImplOzone();
   ~PlatformScreenImplOzone() override;
 
  private:
-  // PlatformScreen
+  // PlatformScreen:
   void Init() override;  // Must not be called until after the ozone platform is
                          // initialized.
   void ConfigurePhysicalDisplay(
       const ConfiguredDisplayCallback& callback) override;
 
-  // TODO(rjkroege): NativeDisplayObserver is misnamed as it tracks changes in
-  // the physical "Screen".  Consider renaming it to NativeScreenObserver.
-  // ui::NativeDisplayObserver:
-  void OnConfigurationChanged() override;
+  // ui::DisplayConfigurator::Observer:
+  void OnDisplayModeChanged(
+      const ui::DisplayConfigurator::DisplayStateList& displays) override;
+  void OnDisplayModeChangeFailed(
+      const ui::DisplayConfigurator::DisplayStateList& displays,
+      MultipleDisplayState failed_new_state) override;
 
-  // Display management callback.
-  void OnDisplaysAquired(const ConfiguredDisplayCallback& callback,
-                         const std::vector<ui::DisplaySnapshot*>& displays);
+  ui::DisplayConfigurator display_configurator_;
 
-  // The display subsystem calls |OnDisplayConfigured| for each display that has
-  // been successfully configured. This in turn calls |callback_| with the
-  // identity and bounds of each physical display.
-  void OnDisplayConfigured(const ConfiguredDisplayCallback& callback,
-                           int64_t id,
-                           const gfx::Rect& bounds,
-                           bool success);
-
-  std::unique_ptr<ui::NativeDisplayDelegate> native_display_delegate_;
-
-  base::WeakPtrFactory<PlatformScreenImplOzone> weak_ptr_factory_;
+  // Callback to called when new displays are configured.
+  ConfiguredDisplayCallback callback_;
 
   DISALLOW_COPY_AND_ASSIGN(PlatformScreenImplOzone);
 };
diff --git a/services/ui/ws/server_window.cc b/services/ui/ws/server_window.cc
index 4b2ab13..834dcd8 100644
--- a/services/ui/ws/server_window.cc
+++ b/services/ui/ws/server_window.cc
@@ -190,19 +190,6 @@
   return delegate_->GetRootWindow(this);
 }
 
-std::vector<const ServerWindow*> ServerWindow::GetChildren() const {
-  std::vector<const ServerWindow*> children;
-  children.reserve(children_.size());
-  for (size_t i = 0; i < children_.size(); ++i)
-    children.push_back(children_[i]);
-  return children;
-}
-
-std::vector<ServerWindow*> ServerWindow::GetChildren() {
-  // TODO(sky): rename to children() and fix return type.
-  return children_;
-}
-
 ServerWindow* ServerWindow::GetChildWindow(const WindowId& window_id) {
   if (id_ == window_id)
     return this;
diff --git a/services/ui/ws/server_window.h b/services/ui/ws/server_window.h
index c59efd8a..6d66668 100644
--- a/services/ui/ws/server_window.h
+++ b/services/ui/ws/server_window.h
@@ -100,8 +100,6 @@
         const_cast<const ServerWindow*>(this)->GetRoot());
   }
 
-  std::vector<const ServerWindow*> GetChildren() const;
-  std::vector<ServerWindow*> GetChildren();
   const Windows& children() const { return children_; }
 
   // Returns the ServerWindow object with the provided |id| if it lies in a
diff --git a/services/ui/ws/test_utils.cc b/services/ui/ws/test_utils.cc
index 36cc25f..e8d648f 100644
--- a/services/ui/ws/test_utils.cc
+++ b/services/ui/ws/test_utils.cc
@@ -108,6 +108,22 @@
   return new TestPlatformDisplay(cursor_id_storage_);
 }
 
+// TestFrameGeneratorDelegate -------------------------------------------------
+
+TestFrameGeneratorDelegate::TestFrameGeneratorDelegate(
+    std::unique_ptr<ServerWindow> root)
+    : root_(std::move(root)) {}
+
+TestFrameGeneratorDelegate::~TestFrameGeneratorDelegate() {}
+
+ServerWindow* TestFrameGeneratorDelegate::GetRootWindow() {
+  return root_.get();
+}
+
+const ViewportMetrics& TestFrameGeneratorDelegate::GetViewportMetrics() {
+  return metrics_;
+}
+
 // WindowTreeTestApi  ---------------------------------------------------------
 
 WindowTreeTestApi::WindowTreeTestApi(WindowTree* tree) : tree_(tree) {}
diff --git a/services/ui/ws/test_utils.h b/services/ui/ws/test_utils.h
index 1162721..18ec321 100644
--- a/services/ui/ws/test_utils.h
+++ b/services/ui/ws/test_utils.h
@@ -244,6 +244,26 @@
 
 // -----------------------------------------------------------------------------
 
+// A stub implementation of FrameGeneratorDelegate.
+class TestFrameGeneratorDelegate : public FrameGeneratorDelegate {
+ public:
+  explicit TestFrameGeneratorDelegate(std::unique_ptr<ServerWindow> root);
+  ~TestFrameGeneratorDelegate() override;
+
+  // FrameGeneratorDelegate:
+  ServerWindow* GetRootWindow() override;
+  void OnCompositorFrameDrawn() override {}
+  const ViewportMetrics& GetViewportMetrics() override;
+
+ private:
+  std::unique_ptr<ServerWindow> root_;
+  ViewportMetrics metrics_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestFrameGeneratorDelegate);
+};
+
+// -----------------------------------------------------------------------------
+
 class TestWindowManager : public mojom::WindowManager {
  public:
   TestWindowManager()
diff --git a/services/ui/ws/window_finder.cc b/services/ui/ws/window_finder.cc
index bbd8737..09be99308 100644
--- a/services/ui/ws/window_finder.cc
+++ b/services/ui/ws/window_finder.cc
@@ -4,6 +4,7 @@
 
 #include "services/ui/ws/window_finder.h"
 
+#include "base/containers/adapters.h"
 #include "services/ui/surfaces/surfaces_state.h"
 #include "services/ui/ws/server_window.h"
 #include "services/ui/ws/server_window_delegate.h"
@@ -25,9 +26,8 @@
 
 ServerWindow* FindDeepestVisibleWindowForEvents(ServerWindow* window,
                                                 gfx::Point* location) {
-  const ServerWindow::Windows children(window->GetChildren());
-  for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
-    ServerWindow* child = *iter;
+  const ServerWindow::Windows& children = window->children();
+  for (ServerWindow* child : base::Reversed(children)) {
     if (!child->visible())
       continue;
 
diff --git a/services/ui/ws/window_tree.cc b/services/ui/ws/window_tree.cc
index 4b5e7498..7b67759 100644
--- a/services/ui/ws/window_tree.cc
+++ b/services/ui/ws/window_tree.cc
@@ -756,7 +756,7 @@
   if (!access_policy_->CanReorderWindow(window, relative_window, direction))
     return false;
 
-  std::vector<const ServerWindow*> children = window->parent()->GetChildren();
+  const ServerWindow::Windows& children = window->parent()->children();
   const size_t child_i =
       std::find(children.begin(), children.end(), window) - children.begin();
   const size_t target_i =
@@ -797,9 +797,9 @@
   window_id_to_client_id_map_[window->id()] = client_window_id;
   if (!access_policy_->CanDescendIntoWindowForWindowTree(window))
     return;
-  std::vector<const ServerWindow*> children(window->GetChildren());
-  for (size_t i = 0; i < children.size(); ++i)
-    GetUnknownWindowsFrom(children[i], windows);
+  const ServerWindow::Windows& children = window->children();
+  for (ServerWindow* child : children)
+    GetUnknownWindowsFrom(child, windows);
 }
 
 bool WindowTree::RemoveFromMaps(const ServerWindow* window) {
@@ -822,9 +822,9 @@
 
   RemoveFromMaps(window);
 
-  std::vector<const ServerWindow*> children = window->GetChildren();
-  for (size_t i = 0; i < children.size(); ++i)
-    RemoveFromKnown(children[i], local_windows);
+  const ServerWindow::Windows& children = window->children();
+  for (ServerWindow* child : children)
+    RemoveFromKnown(child, local_windows);
 }
 
 void WindowTree::RemoveRoot(const ServerWindow* window,
@@ -893,9 +893,9 @@
   if (!access_policy_->CanDescendIntoWindowForWindowTree(window))
     return;
 
-  std::vector<const ServerWindow*> children(window->GetChildren());
-  for (size_t i = 0; i < children.size(); ++i)
-    GetWindowTreeImpl(children[i], windows);
+  const ServerWindow::Windows& children = window->children();
+  for (ServerWindow* child : children)
+    GetWindowTreeImpl(child, windows);
 }
 
 void WindowTree::NotifyDrawnStateChanged(const ServerWindow* window,
@@ -955,9 +955,8 @@
 
 void WindowTree::RemoveChildrenAsPartOfEmbed(ServerWindow* window) {
   CHECK(window);
-  std::vector<ServerWindow*> children = window->GetChildren();
-  for (size_t i = 0; i < children.size(); ++i)
-    window->Remove(children[i]);
+  while (!window->children().empty())
+    window->Remove(window->children().front());
 }
 
 void WindowTree::DispatchInputEventImpl(ServerWindow* target,
diff --git a/services/ui/ws/window_tree_client_unittest.cc b/services/ui/ws/window_tree_client_unittest.cc
index 33dfc4de..31c0d683 100644
--- a/services/ui/ws/window_tree_client_unittest.cc
+++ b/services/ui/ws/window_tree_client_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
-#include "services/shell/public/cpp/shell_test.h"
+#include "services/shell/public/cpp/service_test.h"
 #include "services/ui/public/cpp/tests/window_server_shelltest_base.h"
 #include "services/ui/public/interfaces/window_tree.mojom.h"
 #include "services/ui/public/interfaces/window_tree_host.mojom.h"
@@ -490,7 +490,7 @@
 
 }  // namespace
 
-class WindowTreeClientTest : public WindowServerShellTestBase {
+class WindowTreeClientTest : public WindowServerServiceTestBase {
  public:
   WindowTreeClientTest()
       : client_id_1_(0), client_id_2_(0), root_window_id_(0) {}
@@ -582,7 +582,7 @@
     return client;
   }
 
-  // WindowServerShellTestBase:
+  // WindowServerServiceTestBase:
   bool OnConnect(shell::Connection* connection) override {
     connection->AddInterface(client_factory_.get());
     return true;
@@ -591,7 +591,7 @@
   void SetUp() override {
     client_factory_.reset(new WindowTreeClientFactory());
 
-    WindowServerShellTestBase::SetUp();
+    WindowServerServiceTestBase::SetUp();
 
     mojom::WindowTreeHostFactoryPtr factory;
     connector()->ConnectToInterface("mojo:ui", &factory);
@@ -621,12 +621,12 @@
 
   void TearDown() override {
     // Destroy these before the message loop is destroyed (happens in
-    // WindowServerShellTestBase::TearDown).
+    // WindowServerServiceTestBase::TearDown).
     wt_client1_.reset();
     wt_client2_.reset();
     wt_client3_.reset();
     client_factory_.reset();
-    WindowServerShellTestBase::TearDown();
+    WindowServerServiceTestBase::TearDown();
   }
 
   std::unique_ptr<TestWindowTreeClient> wt_client1_;
diff --git a/styleguide/c++/c++.md b/styleguide/c++/c++.md
index 1b8e307b..e7af38be 100644
--- a/styleguide/c++/c++.md
+++ b/styleguide/c++/c++.md
@@ -11,9 +11,9 @@
 to automatically format C++ code. By policy, Clang's formatting of code should
 always be accepted in code reviews.
 
-You can propose changes to the style guide by sending an email to
-`cxx@chromium.org`. Ideally, the list will arrive at some consensus and the
-wiki page will be updated to mention that consensus. If there's no consensus,
+You can propose changes to this style guide by sending an email to
+`cxx@chromium.org`. Ideally, the list will arrive at some consensus and you can
+request review for a change to this file. If there's no consensus,
 `src/styleguide/c++/OWNERS` get to decide.
 
 Blink code in `third_party/WebKit` uses [Blink
diff --git a/styleguide/c++/c++11.html b/styleguide/c++/c++11.html
index 1ffc465..123ecd8 100644
--- a/styleguide/c++/c++11.html
+++ b/styleguide/c++/c++11.html
@@ -29,12 +29,15 @@
 Guide applies to Chromium and its subprojects. Subprojects can choose to be
 more restrictive if they need to compile on more toolchains than Chromium.</p>
 
+<p>This page comprises part of the more general
+<a href="https://chromium.googlesource.com/chromium/src/+/master/styleguide/c++/c++.md">Chromium C++ style guide</a>.</p>
+
 <p>You can propose to make a feature available or to ban a
 feature by sending an email to <a
 href="https://groups.google.com/a/chromium.org/forum/#!forum/cxx">cxx@chromium.org</a>.
 Ideally include a short blurb on what the feature is, and why you think it
 should or should not be allowed. Ideally, the list will arrive at some
-consensus and the wiki page will be updated to mention that consensus. If
+consensus and you can request review for a change to this file. If
 there's no consensus, <code>src/styleguide/c++/OWNERS</code> get to decide --
 for divisive features, we expect the decision to be to not use the feature yet
 and possibly discuss it again a few months later, when we have more experience
@@ -184,7 +187,7 @@
 <td><code>[<i>captures</i>](<i>params</i>) -&gt; <i>ret</i> { <i>body</i> }</code></td>
 <td>Anonymous functions</td>
 <td><a href="http://en.cppreference.com/w/cpp/language/lambda">Lambda functions</a></td>
-<td>Do not bind or store lambdas outside the lifetime of the stack frame they are defined in; use <code>base::Bind</code> and <code>base::Callback</code> instead, because they offer protection against a large class of object lifetime mistakes. Don't use default captures (<code>[=]</code>, <code>[&amp;]</code> &ndash; <a href="https://google.github.io/styleguide/cppguide.html#Lambda_expressions">Google Style Guide</a>). Lambdas are typically useful as a parameter to methods or functions that will use them immediately, such as those in <code>&lt;algorithm&gt;</code>. <a href="https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/D9UnnxBnciQ">Discussion thread</a></td>
+<td>Do not bind or store capturing lambdas outside the lifetime of the stack frame they are defined in; use captureless lambda with <code>base::Bind</code> and <code>base::Callback</code> instead, because they offer protection against a large class of object lifetime mistakes. Don't use default captures (<code>[=]</code>, <code>[&amp;]</code> &ndash; <a href="https://google.github.io/styleguide/cppguide.html#Lambda_expressions">Google Style Guide</a>). Lambdas are typically useful as a parameter to methods or functions that will use them immediately, such as those in <code>&lt;algorithm&gt;</code>. <a href="https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/D9UnnxBnciQ">Discussion thread</a></td>
 </tr>
 
 <tr>
diff --git a/styleguide/styleguide.md b/styleguide/styleguide.md
index cbe31122..7a9429a 100644
--- a/styleguide/styleguide.md
+++ b/styleguide/styleguide.md
@@ -5,7 +5,7 @@
   * [Chromium C++ style guide](c++/c++.md)
   * [Google Objective-C style guide](https://google.github.io/styleguide/objcguide.xml)
   * [Java style guide for Android](https://sites.google.com/a/chromium.org/dev/developers/coding-style/java)
-  * [GN style guide](https://chromium.googlesource.com/chromium/src/+/master/tool) for build files
+  * [GN style guide](../tools/gn/docs/style_guide.md) for build files
 
 Chromium also uses these languages to a lesser degree:
 
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 8e477cda..6cd6fd4 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -408,6 +408,16 @@
         "test": "base_unittests"
       },
       {
+        "args": [
+          "--override-use-gl-with-osmesa-for-tests",
+          "--run-in-mash",
+          "--test-launcher-filter-file=src/testing/buildbot/filters/mash.browser_tests.filter",
+          "--use-test-config"
+        ],
+        "name": "mash_browser_tests",
+        "test": "browser_tests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 5
diff --git a/testing/buildbot/filters/mash.browser_tests.filter b/testing/buildbot/filters/mash.browser_tests.filter
new file mode 100644
index 0000000..d0e92b9
--- /dev/null
+++ b/testing/buildbot/filters/mash.browser_tests.filter
@@ -0,0 +1 @@
+BrowserTest.Title
diff --git a/testing/buildbot/filters/site-per-process.browser_tests.filter b/testing/buildbot/filters/site-per-process.browser_tests.filter
index c19c6e99..cb143f5e 100644
--- a/testing/buildbot/filters/site-per-process.browser_tests.filter
+++ b/testing/buildbot/filters/site-per-process.browser_tests.filter
@@ -28,6 +28,7 @@
 -ExtensionApiTest.TabMove
 -ExtensionApiTest.TabsOnUpdated
 -ExtensionURLRewriteBrowserTest.NewTabPageURL
+-InputImeApiTest.SendKeyEventsOnNormalPage
 -IsolatedAppTest.CookieIsolation
 -IsolatedAppTest.CrossProcessClientRedirect
 -IsolatedAppTest.IsolatedAppProcessModel
diff --git a/testing/libfuzzer/dictionary_generator.py b/testing/libfuzzer/dictionary_generator.py
new file mode 100755
index 0000000..b720e8e
--- /dev/null
+++ b/testing/libfuzzer/dictionary_generator.py
@@ -0,0 +1,236 @@
+#!/usr/bin/python2
+#
+# 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.
+
+"""Generate a dictionary for libFuzzer or AFL-based fuzzer.
+
+Invoked manually using a fuzzer binary and target format/protocol specification.
+Works better for text formats or protocols. For binary ones may be useless.
+"""
+
+import argparse
+import HTMLParser
+import io
+import logging
+import os
+import re
+import shutil
+import string
+import subprocess
+import sys
+import tempfile
+
+
+ENCODING_TYPES = ['ascii', 'utf_16_be', 'utf_16_le', 'utf_32_be', 'utf_32_le']
+MIN_STRING_LENGTH = 4
+
+
+def DecodeHTML(html_data):
+  """HTML-decoding of the data."""
+  html_parser = HTMLParser.HTMLParser()
+  data = html_parser.unescape(html_data.decode('ascii', 'ignore'))
+  return data.encode('ascii', 'ignore')
+
+
+def EscapeDictionaryElement(element):
+  """Escape all unprintable and control characters in an element."""
+  element_escaped = element.encode('string_escape')
+  # Remove escaping for single quote because it breaks libFuzzer.
+  element_escaped = element_escaped.replace('\\\'', '\'')
+  # Add escaping for double quote.
+  element_escaped = element_escaped.replace('"', '\\"')
+  return element_escaped
+
+
+def ExtractWordsFromBinary(filepath, min_length=MIN_STRING_LENGTH):
+  """Extract words (splitted strings) from a binary executable file."""
+  rodata = PreprocessAndReadRodata(filepath)
+  words = []
+
+  strings_re = re.compile(r'[^\x00-\x1F\x7F-\xFF]{%d,}' % min_length)
+  # Use different encodings for strings extraction.
+  for encoding in ENCODING_TYPES:
+    data = rodata.decode(encoding, 'ignore').encode('ascii', 'ignore')
+    raw_strings = strings_re.findall(data)
+    for splitted_line in map(lambda line: line.split(), raw_strings):
+      words += splitted_line
+
+  return set(words)
+
+
+def ExtractWordsFromLines(lines):
+  """Extract all words from a list of strings."""
+  words = set()
+  for line in lines:
+    for word in line.split():
+      words.add(word)
+
+  return words
+
+
+def ExtractWordsFromSpec(filepath, is_html):
+  """Extract words from a specification."""
+  data = ReadSpecification(filepath, is_html)
+  words = data.split()
+  return set(words)
+
+
+def FindIndentedText(text):
+  """Find space-indented text blocks, e.g. code or data samples in RFCs."""
+  lines = text.split('\n')
+  indented_blocks = []
+  current_block = ''
+  previous_number_of_spaces = 0
+
+  # Go through every line and concatenate space-indented blocks into lines.
+  for i in xrange(0, len(lines), 1):
+    if not lines[i]:
+      # Ignore empty lines.
+      continue
+
+    # Space-indented text blocks have more leading spaces than regular text.
+    n = FindNumberOfLeadingSpaces(lines[i])
+
+    if n > previous_number_of_spaces:
+      # Beginning of a space-indented text block, start concatenation.
+      current_block = lines[i][n : ]
+    elif n == previous_number_of_spaces and current_block:
+      # Or continuation of a space-indented text block, concatenate lines.
+      current_block += '\n' + lines[i][n : ]
+
+    if n < previous_number_of_spaces and current_block:
+      # Current line is not indented, save previously concatenated lines.
+      indented_blocks.append(current_block)
+      current_block = ''
+
+    previous_number_of_spaces = n
+
+  return indented_blocks
+
+
+def FindNumberOfLeadingSpaces(line):
+  """Calculate number of leading whitespace characters in the string."""
+  n = 0
+  while n < len(line) and line[n].isspace():
+    n += 1
+
+  return n
+
+
+def GenerateDictionary(path_to_binary, path_to_spec, strategy, is_html=False):
+  """Generate a dictionary for given pair of fuzzer binary and specification."""
+  for filepath in [path_to_binary, path_to_spec]:
+    if not os.path.exists(filepath):
+      logging.error('%s doesn\'t exist. Exit.', filepath)
+      sys.exit(1)
+
+  words_from_binary = ExtractWordsFromBinary(path_to_binary)
+  words_from_spec = ExtractWordsFromSpec(path_to_spec, is_html)
+
+  dictionary_words = set()
+
+  if 'i' in strategy:
+    # Strategy i: only words which are common for binary and for specification.
+    dictionary_words = words_from_binary.intersection(words_from_spec)
+
+  if 'q' in strategy:
+    # Strategy q: add words from all quoted strings from specification.
+    # TODO(mmoroz): experimental and very noisy. Not recommended to use.
+    spec_data = ReadSpecification(path_to_spec, is_html)
+    quoted_strings = FindIndentedText(spec_data)
+    quoted_words = ExtractWordsFromLines(quoted_strings)
+    dictionary_words = dictionary_words.union(quoted_words)
+
+  if 'u' in strategy:
+    # Strategy u: add all uppercase words from specification.
+    uppercase_words = set(w for w in words_from_spec if w.isupper())
+    dictionary_words = dictionary_words.union(uppercase_words)
+
+  return dictionary_words
+
+
+def PreprocessAndReadRodata(filepath):
+  """Create a stripped copy of the binary and extract .rodata section."""
+  stripped_file = tempfile.NamedTemporaryFile(prefix='.stripped_')
+  stripped_filepath = stripped_file.name
+  shutil.copyfile(filepath, stripped_filepath)
+
+  # Strip all symbols to reduce amount of redundant strings.
+  strip_cmd = ['strip', '--strip-all', stripped_filepath]
+  result = subprocess.call(strip_cmd)
+  if result:
+    logging.warning('Failed to strip the binary. Using the original version.')
+    stripped_filepath = filepath
+
+  # Extract .rodata section to reduce amount of redundant strings.
+  rodata_file = tempfile.NamedTemporaryFile(prefix='.rodata_')
+  rodata_filepath = rodata_file.name
+  objcopy_cmd = ['objcopy', '-j', '.rodata', stripped_filepath, rodata_filepath]
+
+  # Hide output from stderr since objcopy prints a warning.
+  with open(os.devnull, 'w') as devnull:
+    result = subprocess.call(objcopy_cmd, stderr=devnull)
+
+  if result:
+    logging.warning('Failed to extract .rodata section. Using the whole file.')
+    rodata_filepath = stripped_filepath
+
+  with open(rodata_filepath) as file_handle:
+    data = file_handle.read()
+
+  stripped_file.close()
+  rodata_file.close()
+
+  return data
+
+
+def ReadSpecification(filepath, is_html):
+  """Read a specification file and return its contents."""
+  with open(filepath, 'r') as file_handle:
+    data = file_handle.read()
+
+  if is_html:
+    data = DecodeHTML(data)
+
+  return data
+
+
+def WriteDictionary(dictionary_path, dictionary):
+  """Write given dictionary to a file."""
+  with open(dictionary_path, 'wb') as file_handle:
+    file_handle.write('# This is an automatically generated dictionary.\n')
+    for word in dictionary:
+      if not word:
+        continue
+      line = '"%s"\n' % EscapeDictionaryElement(word)
+      file_handle.write(line)
+
+
+def main():
+  parser = argparse.ArgumentParser(description="Generate fuzzer dictionary.")
+  parser.add_argument('--fuzzer', required=True,
+                      help='Path to a fuzzer binary executable. It is '
+                      'recommended to use a binary built with '
+                      '"use_libfuzzer=false is_asan=false" to get a better '
+                      'dictionary with fewer number of redundant elements.')
+  parser.add_argument('--spec', required=True,
+                      help='Path to a target specification (in textual form).')
+  parser.add_argument('--html', default=0,
+                      help='Decode HTML [01] (0 is default value): '
+                      '1 - if specification has HTML entities to be decoded.')
+  parser.add_argument('--out', required=True,
+                      help='Path to a file to write a dictionary into.')
+  parser.add_argument('--strategy', default='iu',
+                      help='Generation strategy [iqu] ("iu" is default value): '
+                      'i - intersection, q - quoted, u - uppercase.')
+  args = parser.parse_args()
+
+  dictionary = GenerateDictionary(args.fuzzer, args.spec, args.strategy,
+                                  is_html=bool(args.html))
+  WriteDictionary(args.out, dictionary)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/testing/libfuzzer/fuzzers/BUILD.gn b/testing/libfuzzer/fuzzers/BUILD.gn
index 92d89fa..e39b6065 100644
--- a/testing/libfuzzer/fuzzers/BUILD.gn
+++ b/testing/libfuzzer/fuzzers/BUILD.gn
@@ -132,6 +132,7 @@
     "//base:i18n",
     "//url:url",
   ]
+  dict = "dicts/generated/url_parse_fuzzer.dict"
 }
 
 fuzzer_test("usrsctp_fuzzer") {
@@ -189,7 +190,7 @@
   deps = [
     "//third_party/sqlite",
   ]
-  dict = "dicts/sql.dict"
+  dict = "dicts/generated/sqlite3_prepare_v2_fuzzer.dict"
 }
 
 fuzzer_test("libxml_xml_read_memory_fuzzer") {
@@ -199,7 +200,7 @@
   deps = [
     "//third_party/libxml:libxml",
   ]
-  dict = "dicts/xml.dict"
+  dict = "dicts/generated/libxml_xml_read_memory_fuzzer.dict"
 }
 
 fuzzer_test("libpng_read_fuzzer") {
@@ -218,7 +219,7 @@
   deps = [
     "//v8:parser_fuzzer",
   ]
-  dict = "dicts/js.dict"
+  dict = "dicts/generated/v8_script_parser_fuzzer.dict"
   seed_corpus = "//v8/test/mjsunit/regress/"
 }
 
diff --git a/testing/libfuzzer/fuzzers/dicts/generated/libxml_xml_read_memory_fuzzer.dict b/testing/libfuzzer/fuzzers/dicts/generated/libxml_xml_read_memory_fuzzer.dict
new file mode 100644
index 0000000..6257038
--- /dev/null
+++ b/testing/libfuzzer/fuzzers/dicts/generated/libxml_xml_read_memory_fuzzer.dict
@@ -0,0 +1,663 @@
+#
+# AFL dictionary for XML
+# ----------------------
+#
+# Several basic syntax elements and attributes, modeled on libxml2.
+#
+# Created by Michal Zalewski <lcamtuf@google.com>
+#
+
+attr_encoding=" encoding=\"1\""
+attr_generic=" a=\"1\""
+attr_href=" href=\"1\""
+attr_standalone=" standalone=\"no\""
+attr_version=" version=\"1\""
+attr_xml_base=" xml:base=\"1\""
+attr_xml_id=" xml:id=\"1\""
+attr_xml_lang=" xml:lang=\"1\""
+attr_xml_space=" xml:space=\"1\""
+attr_xmlns=" xmlns=\"1\""
+
+entity_builtin="&lt;"
+entity_decimal="&#1;"
+entity_external="&a;"
+entity_hex="&#x1;"
+
+string_any="ANY"
+string_brackets="[]"
+string_cdata="CDATA"
+string_col_fallback=":fallback"
+string_col_generic=":a"
+string_col_include=":include"
+string_dashes="--"
+string_empty="EMPTY"
+string_empty_dblquotes="\"\""
+string_empty_quotes="''"
+string_entities="ENTITIES"
+string_entity="ENTITY"
+string_fixed="#FIXED"
+string_id="ID"
+string_idref="IDREF"
+string_idrefs="IDREFS"
+string_implied="#IMPLIED"
+string_nmtoken="NMTOKEN"
+string_nmtokens="NMTOKENS"
+string_notation="NOTATION"
+string_parentheses="()"
+string_pcdata="#PCDATA"
+string_percent="%a"
+string_public="PUBLIC"
+string_required="#REQUIRED"
+string_schema=":schema"
+string_system="SYSTEM"
+string_ucs4="UCS-4"
+string_utf16="UTF-16"
+string_utf8="UTF-8"
+string_xmlns="xmlns:"
+
+tag_attlist="<!ATTLIST"
+tag_cdata="<![CDATA["
+tag_close="</a>"
+tag_doctype="<!DOCTYPE"
+tag_element="<!ELEMENT"
+tag_entity="<!ENTITY"
+tag_ignore="<![IGNORE["
+tag_include="<![INCLUDE["
+tag_notation="<!NOTATION"
+tag_open="<a>"
+tag_open_close="<a />"
+tag_open_exclamation="<!"
+tag_open_q="<?"
+tag_sq2_close="]]>"
+tag_xml_q="<?xml?>"
+"http://docboo"
+"http://www.w"
+"UTF-16LE"
+"xmlns"
+"he30"
+"he2"
+"IET"
+"FDF-10"
+"aDUCS-4OPveb:"
+"a>"
+"UT"
+"xMl"
+"/usr/share/sg"
+"ha07"
+"http://www.oa"
+"cle"
+
+
+# This part has been generated with testing/libfuzzer/dictionary_generator.py
+# using libxml_xml_read_memory_fuzzer binary and XML 1.0 W3C Recommendation.
+"WG"
+"all"
+"code"
+"TC2."
+"text"
+"forbidden"
+"supported"
+"(UAX"
+"by"
+"syntax"
+"notations"
+"area"
+"SGML,"
+"/"
+"Content"
+"conditional"
+"follow"
+"Document"
+"find"
+"MUST"
+"with,"
+"removed"
+"based"
+"("
+"V.,"
+"outside"
+"should"
+"to"
+"only"
+"'('"
+"W3C."
+"8"
+"quotation"
+"local"
+"(E)."
+"do"
+"QUESTION"
+"FULL"
+"WIDTH"
+"string"
+"notation"
+"without"
+"':'"
+"between"
+"space,"
+"Value"
+"choice"
+"'INCLUDE'"
+"cannot"
+"JIS"
+"NO-BREAK"
+"E62"
+"ending"
+"(URI):"
+"(#PCDATA"
+"LAO"
+"resource"
+"embedded"
+"called"
+"'&#60;!ENTITY"
+"Conditional"
+"list"
+"Entity"
+"large"
+"(GI),"
+"contain"
+"small"
+"&MAY;"
+"->"
+"ASCII"
+"available"
+"abbreviated"
+"set"
+"3986\">IETF"
+"\"REC\">"
+"reference"
+"##"
+"etc."
+"DTD,"
+"direct"
+"module"
+"sign"
+"zero"
+"Version"
+"M."
+"are"
+"3C"
+"UTF-8,"
+"3F"
+"canonical"
+"&SGML;"
+"font"
+"incompatible"
+"B+,"
+"EMPTY>"
+"section"
+"ID,"
+"label"
+"state"
+"version"
+"enumerated"
+"apos"
+"above"
+"capital"
+"new"
+"(ASCII)"
+"PI"
+"'='"
+"public"
+"body"
+"C"
+"full"
+"escaping"
+"parent"
+"UAX"
+"error"
+"component"
+"here"
+"ranges"
+"MIDDLE"
+"objects"
+"address"
+"path"
+"Identifier"
+"UTF-16,"
+"change"
+"V2.1"
+"last"
+"2141\">IETF"
+"root"
+"ISO-10646-UCS-2"
+"equal"
+"against"
+"[A-Z]"
+"connection"
+"2781\">IETF"
+"attributes"
+"Attribute"
+"error,"
+"comment"
+"among"
+"named"
+"LINE"
+"point"
+"color"
+"character"
+"marked"
+"names"
+"FF"
+"table"
+"BCP"
+"DOT"
+"once"
+"use"
+"from"
+"stream"
+"entities"
+"MARK,"
+"P."
+"contains"
+"two"
+"'ANY'"
+"symbol"
+"few"
+"duplicate"
+"CDATA,"
+"call"
+"UCS-4,"
+"scope"
+"type"
+"empty"
+"more"
+"XML"
+"field"
+"XSLT"
+"Default"
+"Markup"
+"validity"
+"ZERO"
+"Space"
+"normalized"
+"child"
+"')*'"
+"%YN;\""
+"(MUST,"
+"must"
+"#IMPLIED>"
+"sample"
+"6F"
+"GREEK"
+"this"
+"Text"
+"expanded"
+"single"
+"value"
+"will"
+"(UCS)"
+"FEED"
+"paragraph"
+"values"
+"three"
+"many"
+"following"
+"closing"
+"property"
+"'}'"
+"F."
+"LOW"
+"control"
+"ASCII,"
+"2119\">IETF"
+"L."
+"links"
+"YN"
+"process"
+"attribute"
+"is"
+"in"
+"accept"
+"parse"
+"middle"
+"tag"
+"MIME"
+"allowed"
+"X-0208-1997."
+"UTF-7"
+"']'"
+"absolute"
+"information"
+"different"
+"end"
+"PI."
+"Notation"
+"quot"
+"generic"
+"unparsed"
+"charset"
+"namespace"
+"same"
+"(CDATA)"
+"write"
+"read"
+"ISO/IEC"
+"H"
+"units"
+"8879\">ISO"
+"document"
+"parameter"
+"start"
+"A"
+"product"
+"Resource"
+"description"
+"see"
+"may"
+"stop"
+"after"
+"'IGNORE'"
+"U+FEFF,"
+"HTML."
+"possible"
+"user"
+"characters"
+"such"
+"on"
+"data"
+"compatibility"
+"STACS"
+"a"
+"All"
+"I"
+"undefined"
+"rules"
+"expression"
+"markup"
+"author"
+"well"
+"-MSM"
+"element"
+"')'"
+")"
+"xml:lang"
+"y"
+"position"
+"the"
+"first"
+"left"
+"decl"
+"S."
+"MA,"
+"BB"
+"less"
+"<body>"
+"storage"
+"';'"
+"entity"
+"symbols"
+"10646\">ISO"
+"stored"
+"nbsp"
+"COLON,"
+"THAI"
+"(FAMILY"
+"R."
+"before"
+"HTML"
+"MIME),"
+"MIME)."
+"group"
+"trying"
+"No"
+"had"
+"except"
+"detected"
+"valid"
+"usage"
+"input"
+"(double-hyphen)"
+"has"
+"match"
+"(('X'"
+"identical"
+"..."
+"V2.5"
+"3023\">IETF"
+"combination"
+"format"
+"fragment"
+"URN"
+"URI"
+"symbol,"
+"SHOULD,"
+"declared"
+"logical"
+"not"
+"using"
+"bit"
+"NDATA"
+"like"
+"sequence,"
+"term"
+"name"
+"Encoding"
+"B,"
+"decimal"
+"B)"
+"JC)"
+"(#PCDATA)"
+"token"
+"10744\">ISO"
+"steps"
+"ENTITY)"
+"found"
+"8879:1986(E)."
+"|"
+"FE"
+"subset"
+"profile"
+"right"
+"(W3C)"
+"p"
+"bytes"
+"creation"
+"(('#FIXED'"
+"HH"
+"elements"
+"escape"
+"proper"
+"et"
+"FINAL"
+"out"
+"predefined"
+"provided"
+"declaration"
+"XML."
+"container"
+"network"
+"'"
+"space"
+"SPACE"
+"preserve"
+"SGML"
+"per"
+"content"
+"method"
+"does"
+"XML),"
+"occurs"
+"be"
+"HTTP"
+"8879:1986(E)"
+"10646:2000\">ISO"
+"B"
+"'{'"
+"RFC"
+"step"
+"base"
+"references"
+"output"
+"\"MUST"
+"permitted"
+"definition"
+"EDIT:"
+"language"
+"standalone"
+"column"
+"of"
+"could"
+"Tags"
+"mdash"
+"recognized"
+"times"
+"range"
+"due"
+"'#PCDATA'"
+"hexadecimal"
+"or"
+"'PUBLIC'"
+"N.B."
+"','"
+"A,"
+"encoding"
+"xml:space"
+"within"
+"STOP"
+"number"
+"one"
+"&MAY;,"
+"Internal"
+"ISO"
+"construct"
+"operator"
+"RETURN"
+"mark"
+"Empty"
+"IANA"
+"doesn't"
+"(#PCDATA)>"
+"long"
+"checked"
+"(C"
+"indicate"
+"IETF"
+"unknown"
+"there"
+"system"
+"wrapper"
+"HYPHEN-MINUS,"
+"needed"
+"2"
+"too"
+"literal"
+"white"
+"<!--"
+"was"
+"final"
+"function"
+"D."
+"T."
+"'?>'"
+"option"
+"form"
+"enough"
+"D21"
+"collapsed"
+"(XML)"
+"but"
+"selector"
+"ampersand,"
+"part"
+"scripts,"
+"DTD."
+"EBCDIC"
+"UTF-16LE,"
+"line"
+"DTD"
+"with"
+"than"
+"MAY"
+"relative"
+"Set"
+"target"
+"keyword"
+"default"
+"double"
+"SA,"
+"tree"
+"return,"
+"'['"
+"carriage"
+"computer"
+"to,"
+">"
+"similar"
+"declare"
+"result"
+"and"
+"files"
+"UTF-16BE,"
+"ISBN"
+"semicolon"
+"up"
+"defined"
+"parser"
+"CHARACTER"
+"E14"
+"an"
+"UTF-8."
+"as"
+"warning"
+"exist"
+"at"
+"file"
+"New"
+"need"
+"check"
+"('M'"
+"conversion"
+"angle"
+"no"
+"#IMPLIED\">"
+"-"
+"validating"
+"invalid"
+"A."
+"EUC,"
+"instance"
+"internal"
+"A7"
+"XHTML"
+"registered"
+"'|'"
+"node"
+"added"
+"multiple"
+"Name"
+"XML,"
+"quote"
+"preceding"
+"object"
+"AM"
+"W3C"
+"(WG)."
+"Element"
+"('L'"
+"class"
+"generated"
+"letter"
+"SARA"
+"inserted"
+"model"
+"structure"
+"'\\'"
+"building"
+"'NDATA'"
+"backward"
+"less-than"
+"for"
+"E11"
+"failure"
+"FFFE,"
+"required"
+"rule"
+"(EBNF)"
+"CARRIAGE"
+"bracket"
+"link"
+"%"
+"requires"
+"external"
+
diff --git a/testing/libfuzzer/fuzzers/dicts/generated/sqlite3_prepare_v2_fuzzer.dict b/testing/libfuzzer/fuzzers/dicts/generated/sqlite3_prepare_v2_fuzzer.dict
new file mode 100644
index 0000000..691b961a
--- /dev/null
+++ b/testing/libfuzzer/fuzzers/dicts/generated/sqlite3_prepare_v2_fuzzer.dict
@@ -0,0 +1,909 @@
+#
+# AFL dictionary for SQL
+# ----------------------
+#
+# Modeled based on SQLite documentation, contains some number of SQLite
+# extensions. Other dialects of SQL may benefit from customized dictionaries.
+#
+# If you append @1 to the file name when loading this dictionary, afl-fuzz
+# will also additionally load a selection of pragma keywords that are very
+# specific to SQLite (and are probably less interesting from the security
+# standpoint, because they are usually not allowed in non-privileged
+# contexts).
+#
+# Created by Michal Zalewski <lcamtuf@google.com>
+#
+
+function_abs=" abs(1)"
+function_avg=" avg(1)"
+function_changes=" changes()"
+function_char=" char(1)"
+function_coalesce=" coalesce(1,1)"
+function_count=" count(1)"
+function_date=" date(1,1,1)"
+function_datetime=" datetime(1,1,1)"
+function_decimal=" decimal(1,1)"
+function_glob=" glob(1,1)"
+function_group_concat=" group_concat(1,1)"
+function_hex=" hex(1)"
+function_ifnull=" ifnull(1,1)"
+function_instr=" instr(1,1)"
+function_julianday=" julianday(1,1,1)"
+function_last_insert_rowid=" last_insert_rowid()"
+function_length=" length(1)"
+function_like=" like(1,1)"
+function_likelihood=" likelihood(1,1)"
+function_likely=" likely(1)"
+function_load_extension=" load_extension(1,1)"
+function_lower=" lower(1)"
+function_ltrim=" ltrim(1,1)"
+function_max=" max(1,1)"
+function_min=" min(1,1)"
+function_nullif=" nullif(1,1)"
+function_printf=" printf(1,1)"
+function_quote=" quote(1)"
+function_random=" random()"
+function_randomblob=" randomblob(1)"
+function_replace=" replace(1,1,1)"
+function_round=" round(1,1)"
+function_rtrim=" rtrim(1,1)"
+function_soundex=" soundex(1)"
+function_sqlite_compileoption_get=" sqlite_compileoption_get(1)"
+function_sqlite_compileoption_used=" sqlite_compileoption_used(1)"
+function_sqlite_source_id=" sqlite_source_id()"
+function_sqlite_version=" sqlite_version()"
+function_strftime=" strftime(1,1,1,1)"
+function_substr=" substr(1,1,1)"
+function_sum=" sum(1)"
+function_time=" time(1,1,1)"
+function_total=" total(1)"
+function_total_changes=" total_changes()"
+function_trim=" trim(1,1)"
+function_typeof=" typeof(1)"
+function_unicode=" unicode(1)"
+function_unlikely=" unlikely(1)"
+function_upper=" upper(1)"
+function_varchar=" varchar(1)"
+function_zeroblob=" zeroblob(1)"
+
+keyword_ABORT="ABORT"
+keyword_ACTION="ACTION"
+keyword_ADD="ADD"
+keyword_AFTER="AFTER"
+keyword_ALL="ALL"
+keyword_ALTER="ALTER"
+keyword_ANALYZE="ANALYZE"
+keyword_AND="AND"
+keyword_AS="AS"
+keyword_ASC="ASC"
+keyword_ATTACH="ATTACH"
+keyword_AUTOINCREMENT="AUTOINCREMENT"
+keyword_BEFORE="BEFORE"
+keyword_BEGIN="BEGIN"
+keyword_BETWEEN="BETWEEN"
+keyword_BY="BY"
+keyword_CASCADE="CASCADE"
+keyword_CASE="CASE"
+keyword_CAST="CAST"
+keyword_CHECK="CHECK"
+keyword_COLLATE="COLLATE"
+keyword_COLUMN="COLUMN"
+keyword_COMMIT="COMMIT"
+keyword_CONFLICT="CONFLICT"
+keyword_CONSTRAINT="CONSTRAINT"
+keyword_CREATE="CREATE"
+keyword_CROSS="CROSS"
+keyword_CURRENT_DATE="CURRENT_DATE"
+keyword_CURRENT_TIME="CURRENT_TIME"
+keyword_CURRENT_TIMESTAMP="CURRENT_TIMESTAMP"
+keyword_DATABASE="DATABASE"
+keyword_DEFAULT="DEFAULT"
+keyword_DEFERRABLE="DEFERRABLE"
+keyword_DEFERRED="DEFERRED"
+keyword_DELETE="DELETE"
+keyword_DESC="DESC"
+keyword_DETACH="DETACH"
+keyword_DISTINCT="DISTINCT"
+keyword_DROP="DROP"
+keyword_EACH="EACH"
+keyword_ELSE="ELSE"
+keyword_END="END"
+keyword_ESCAPE="ESCAPE"
+keyword_EXCEPT="EXCEPT"
+keyword_EXCLUSIVE="EXCLUSIVE"
+keyword_EXISTS="EXISTS"
+keyword_EXPLAIN="EXPLAIN"
+keyword_FAIL="FAIL"
+keyword_FOR="FOR"
+keyword_FOREIGN="FOREIGN"
+keyword_FROM="FROM"
+keyword_FULL="FULL"
+keyword_GLOB="GLOB"
+keyword_GROUP="GROUP"
+keyword_HAVING="HAVING"
+keyword_IF="IF"
+keyword_IGNORE="IGNORE"
+keyword_IMMEDIATE="IMMEDIATE"
+keyword_IN="IN"
+keyword_INDEX="INDEX"
+keyword_INDEXED="INDEXED"
+keyword_INITIALLY="INITIALLY"
+keyword_INNER="INNER"
+keyword_INSERT="INSERT"
+keyword_INSTEAD="INSTEAD"
+keyword_INTERSECT="INTERSECT"
+keyword_INTO="INTO"
+keyword_IS="IS"
+keyword_ISNULL="ISNULL"
+keyword_JOIN="JOIN"
+keyword_KEY="KEY"
+keyword_LEFT="LEFT"
+keyword_LIKE="LIKE"
+keyword_LIMIT="LIMIT"
+keyword_MATCH="MATCH"
+keyword_NATURAL="NATURAL"
+keyword_NO="NO"
+keyword_NOT="NOT"
+keyword_NOTNULL="NOTNULL"
+keyword_NULL="NULL"
+keyword_OF="OF"
+keyword_OFFSET="OFFSET"
+keyword_ON="ON"
+keyword_OR="OR"
+keyword_ORDER="ORDER"
+keyword_OUTER="OUTER"
+keyword_PLAN="PLAN"
+keyword_PRAGMA="PRAGMA"
+keyword_PRIMARY="PRIMARY"
+keyword_QUERY="QUERY"
+keyword_RAISE="RAISE"
+keyword_RECURSIVE="RECURSIVE"
+keyword_REFERENCES="REFERENCES"
+#keyword_REGEXP="REGEXP"
+keyword_REINDEX="REINDEX"
+keyword_RELEASE="RELEASE"
+keyword_RENAME="RENAME"
+keyword_REPLACE="REPLACE"
+keyword_RESTRICT="RESTRICT"
+keyword_RIGHT="RIGHT"
+keyword_ROLLBACK="ROLLBACK"
+keyword_ROW="ROW"
+keyword_SAVEPOINT="SAVEPOINT"
+keyword_SELECT="SELECT"
+keyword_SET="SET"
+keyword_TABLE="TABLE"
+keyword_TEMP="TEMP"
+keyword_TEMPORARY="TEMPORARY"
+keyword_THEN="THEN"
+keyword_TO="TO"
+keyword_TRANSACTION="TRANSACTION"
+keyword_TRIGGER="TRIGGER"
+keyword_UNION="UNION"
+keyword_UNIQUE="UNIQUE"
+keyword_UPDATE="UPDATE"
+keyword_USING="USING"
+keyword_VACUUM="VACUUM"
+keyword_VALUES="VALUES"
+keyword_VIEW="VIEW"
+keyword_VIRTUAL="VIRTUAL"
+keyword_WHEN="WHEN"
+keyword_WHERE="WHERE"
+keyword_WITH="WITH"
+keyword_WITHOUT="WITHOUT"
+
+operator_concat=" || "
+operator_ebove_eq=" >="
+
+snippet_1eq1=" 1=1"
+snippet_at=" @1"
+snippet_backticks=" `a`"
+snippet_blob=" blob"
+snippet_brackets=" [a]"
+snippet_colon=" :1"
+snippet_comment=" /* */"
+snippet_date="2001-01-01"
+snippet_dollar=" $1"
+snippet_dotref=" a.b"
+snippet_fmtY="%Y"
+snippet_int=" int"
+snippet_neg1=" -1"
+snippet_pair=" a,b"
+snippet_parentheses=" (1)"
+snippet_plus2days="+2 days"
+snippet_qmark=" ?1"
+snippet_semicolon=" ;"
+snippet_star=" *"
+snippet_string_pair=" \"a\",\"b\""
+
+string_dbl_q=" \"a\""
+string_escaped_q=" 'a''b'"
+string_single_q=" 'a'"
+
+pragma_application_id@1=" application_id"
+pragma_auto_vacuum@1=" auto_vacuum"
+pragma_automatic_index@1=" automatic_index"
+pragma_busy_timeout@1=" busy_timeout"
+pragma_cache_size@1=" cache_size"
+pragma_cache_spill@1=" cache_spill"
+pragma_case_sensitive_like@1=" case_sensitive_like"
+pragma_checkpoint_fullfsync@1=" checkpoint_fullfsync"
+pragma_collation_list@1=" collation_list"
+pragma_compile_options@1=" compile_options"
+pragma_count_changes@1=" count_changes"
+pragma_data_store_directory@1=" data_store_directory"
+pragma_database_list@1=" database_list"
+pragma_default_cache_size@1=" default_cache_size"
+pragma_defer_foreign_keys@1=" defer_foreign_keys"
+pragma_empty_result_callbacks@1=" empty_result_callbacks"
+pragma_encoding@1=" encoding"
+pragma_foreign_key_check@1=" foreign_key_check"
+pragma_foreign_key_list@1=" foreign_key_list"
+pragma_foreign_keys@1=" foreign_keys"
+pragma_freelist_count@1=" freelist_count"
+pragma_full_column_names@1=" full_column_names"
+pragma_fullfsync@1=" fullfsync"
+pragma_ignore_check_constraints@1=" ignore_check_constraints"
+pragma_incremental_vacuum@1=" incremental_vacuum"
+pragma_index_info@1=" index_info"
+pragma_index_list@1=" index_list"
+pragma_integrity_check@1=" integrity_check"
+pragma_journal_mode@1=" journal_mode"
+pragma_journal_size_limit@1=" journal_size_limit"
+pragma_legacy_file_format@1=" legacy_file_format"
+pragma_locking_mode@1=" locking_mode"
+pragma_max_page_count@1=" max_page_count"
+pragma_mmap_size@1=" mmap_size"
+pragma_page_count@1=" page_count"
+pragma_page_size@1=" page_size"
+pragma_parser_trace@1=" parser_trace"
+pragma_query_only@1=" query_only"
+pragma_quick_check@1=" quick_check"
+pragma_read_uncommitted@1=" read_uncommitted"
+pragma_recursive_triggers@1=" recursive_triggers"
+pragma_reverse_unordered_selects@1=" reverse_unordered_selects"
+pragma_schema_version@1=" schema_version"
+pragma_secure_delete@1=" secure_delete"
+pragma_short_column_names@1=" short_column_names"
+pragma_shrink_memory@1=" shrink_memory"
+pragma_soft_heap_limit@1=" soft_heap_limit"
+pragma_stats@1=" stats"
+pragma_synchronous@1=" synchronous"
+pragma_table_info@1=" table_info"
+pragma_temp_store@1=" temp_store"
+pragma_temp_store_directory@1=" temp_store_directory"
+pragma_threads@1=" threads"
+pragma_user_version@1=" user_version"
+pragma_vdbe_addoptrace@1=" vdbe_addoptrace"
+pragma_vdbe_debug@1=" vdbe_debug"
+pragma_vdbe_listing@1=" vdbe_listing"
+pragma_vdbe_trace@1=" vdbe_trace"
+pragma_wal_autocheckpoint@1=" wal_autocheckpoint"
+pragma_wal_checkpoint@1=" wal_checkpoint"
+pragma_writable_schema@1=" writable_schema"
+
+
+# This part has been generated with testing/libfuzzer/dictionary_generator.py
+# using sqlite3_prepare_v2_fuzzer binary and ISO/IEC FCD 9075-1.
+"all"
+"code"
+"BE"
+"text"
+"TP2,"
+"supported"
+"GR4)"
+"syntax"
+"S151,"
+"S043,"
+"\xe2\x80\x9cCR\xe2\x80\x9d"
+"(SQL/PSM)"
+"query"
+"expressions"
+"TP2;"
+"row"
+"[ISO9075-14],"
+"BNF."
+"<SQL"
+"parameters"
+"title"
+"S211,"
+"ISO/IEC:"
+"BNF,"
+"SQL_FEATURES"
+"should"
+"to"
+"only"
+"program"
+"present"
+"T211,"
+"G,"
+"local"
+"NY"
+"columns"
+"END."
+"do"
+"OBJECT"
+"rollback"
+"string"
+"FEAT2."
+"get"
+"H"
+"P001,"
+"between"
+"RI."
+"[ISO9075-11]"
+"cannot"
+"entries"
+"referencing"
+"datetime"
+"[UCS]."
+"BNF"
+"MINUTE"
+"(BNF"
+"IEC,"
+"False"
+"OF,"
+"level"
+"did"
+"W."
+"list"
+"large"
+"SQL)"
+"PSM."
+"(ISO/IEC"
+"SQL,"
+"SQL-"
+"SQL."
+"small"
+"x"
+"DEFINITION_SCHEMA;"
+"view"
+"Index"
+"[ISO9075-3])."
+"set"
+"S024,"
+"CHANGE."
+"reference"
+"T1,"
+"OLAP."
+"direct"
+"(SQL/XML)."
+"LARGE"
+"likely"
+"result"
+"T341,"
+"ST"
+"ISO/JTC"
+"INSERT,"
+"PKG004"
+"index"
+"PKG006"
+"PKG007"
+"PKG001"
+"PKG002"
+"PKG008"
+"supplied"
+"T611,"
+"access"
+"3"
+"version"
+"NULL."
+"routine"
+"[ISO9075-10])."
+"S1"
+"[UCS],"
+"P003,"
+"C"
+"terms"
+"(SQL/MED)"
+"JTC1/SC32"
+"K"
+"(SQL/JRT)"
+"modify"
+"reported"
+"S"
+"objects"
+"32N1821"
+"SECOND."
+"key"
+"UNDER"
+"(ANSI)"
+"rows"
+"come"
+"(CALL"
+"change"
+"P-"
+"both"
+"search"
+"SQLSTATE,"
+"[ISO9075-"
+"[ISO9075-14]."
+"many"
+"changed"
+"foreign"
+"Symbols"
+"S023,"
+"connection"
+"SQL\xe2\x80\x9d),"
+"context"
+"delete"
+"changes"
+"REFERENCES,"
+"page."
+"named"
+"point"
+"UPDATE."
+"S2"
+"UPDATE,"
+"[ISO9075-13]"
+"Y\xe2\x80\x9d"
+"replace"
+"\xe2\x80\x9cPSM\xe2\x80\x9d"
+"SERIALIZABLE,"
+"names"
+"E"
+"PUBLIC."
+"table"
+"REF"
+"INFORMATION_SCHEMA"
+"C1."
+"ID."
+"use"
+"[ISO9075-2]."
+"from"
+"USA"
+"0"
+"distinct"
+"create"
+"contains"
+"due"
+"ISO."
+"few"
+"duplicate"
+"trigger"
+"call"
+"S111,"
+"expected"
+"REPEATABLE"
+"C1"
+"DOCUMENT"
+"type"
+"authorization"
+"more"
+"XML"
+"[ISO9075-3],"
+"<A>,"
+"P"
+"on"
+"initial"
+"name,"
+"[ISO9075-11]),"
+"QE,"
+"STANDARD"
+"PKG010"
+"TRIGGER,"
+"V"
+"CS"
+"SQL\xe2\x80\x9d:"
+"IEC"
+"Expression"
+"F521,"
+"sequence:"
+"must"
+"none"
+"SR3)"
+"word"
+"INTERNATIONAL"
+"ANSI"
+"this"
+"PSM"
+"PUBLIC),"
+"modified"
+"value"
+"<"
+"descriptor"
+"while"
+"paragraph"
+"values"
+"resources"
+"error"
+"exceptions"
+"IT"
+"F,"
+"CO,"
+"[ISO9075-4],"
+"control"
+"type,"
+"reserved"
+"SQL:"
+"<C>"
+"[ISO9075-2])."
+"F052,"
+"attribute"
+"is"
+"type:"
+"level,"
+"it"
+"[ISO9075-2],"
+"incremental"
+"MONTH,"
+"dropped"
+"MONTH."
+"allowed"
+"S241,"
+"\xe2\x80\x9cSQL"
+"TIMESTAMP"
+"failed"
+"SC"
+"end"
+"Format"
+"ST."
+"permission"
+"V,"
+"length"
+"same"
+"[ISO10646]."
+"write"
+"arguments"
+"F555,"
+"F671,"
+"<C>,"
+"<C>."
+"parameter"
+"NATIONAL"
+"Types"
+"A"
+"Insert"
+"32/WG"
+"used"
+"temporary"
+"\xe2\x80\x9cOLAP\xe2\x80\x9d"
+"(FCD)"
+"may"
+"after"
+"(SQL/OLB)"
+"THIS"
+"Q"
+"SQL/CLI"
+"levels"
+"two"
+"characters"
+"date"
+"such"
+"[ISO9075-9]"
+"data"
+"stack"
+"single"
+"a"
+"FEAT,"
+"lower"
+"transaction"
+"in"
+"database"
+"EXTRACT)"
+"expression"
+"32N1963"
+"CD"
+"without"
+"QE."
+"1"
+"CALL"
+"F"
+"[ISO9075-4])."
+"entry"
+"the"
+"SUBJECT"
+"N1968;"
+"order"
+"left"
+"FEAT1,"
+"FEAT1."
+"S081,"
+"YEAR"
+"READ,"
+"SQL;"
+"A,"
+"symbols"
+"S161,"
+"[ISO9075-10]"
+"already"
+"identify"
+"V."
+"during"
+"differs"
+"(UCS)."
+"Final"
+"before"
+"tables"
+"[UCS]"
+"Multiple"
+"integer"
+"NT,"
+"character"
+","
+"ID\xe2\x80\x9d"
+"(INFORMATION_SCHEMA)"
+"source"
+"add"
+"other"
+"TP1"
+"SQLSTATE"
+"has"
+"match"
+"KEY."
+"real"
+"On"
+"C1,"
+"D"
+"[ISO14651]"
+"views"
+"read"
+"\xe2\x80\x9cGR\xe2\x80\x9d"
+"L"
+"primary"
+"TB1."
+"qualified"
+"(SUBSTRING,"
+"T"
+"compound"
+"not"
+"using"
+"unique"
+"LOB"
+"name"
+"term"
+"sorting"
+"like"
+"B,"
+"[ISO9075-1]"
+"RESULT,"
+"Numeric"
+"MONTH"
+"PURPOSES."
+"[ISO9075-11]."
+"mode"
+"(DEFINITION_SCHEMA)."
+"SQL"
+"ISO"
+"page"
+"constraints"
+"\xc2\xa9ISO/IEC"
+"right"
+"Java"
+"sequence"
+"TB1"
+"TB2"
+"P002,"
+"DAY,"
+"extended"
+"(SQL/CLI)"
+"X"
+"specified"
+"S051,"
+"clauses"
+"operation"
+"FEAT"
+"out"
+"E,"
+"XML."
+"for"
+"space"
+"support"
+"T041,"
+"[ISO9075-4]"
+"content"
+"I"
+"does"
+"STUDY"
+"CHARACTER,"
+"B1"
+"T212,"
+"be"
+"object"
+"[ISO9075-11],"
+"G"
+"ZONE,"
+"S2."
+"collations"
+"[ISO9075-2]:"
+"<A>"
+"O"
+"standard"
+"[ISO9075-2]"
+"base"
+"W"
+"collation"
+"HOUR,"
+"UNDER,"
+"JTC"
+"C."
+"definition"
+"Square"
+"\xe2\x80\x9cSR\xe2\x80\x9d"
+"extension"
+"constraint"
+"column"
+"of"
+"C,"
+"F701,"
+"(SQL/CLI)."
+"T191,"
+"range"
+"GR"
+"1,"
+"constructor"
+"commit"
+"or"
+"first"
+"referenced"
+"statements"
+"encoding"
+"B1."
+"clause"
+"variables"
+"within"
+"number"
+"one"
+"NT"
+"variable"
+"because"
+"references"
+"another"
+"blank"
+"operator"
+"RETURN"
+"COMMITTED,"
+"9075-1:2011(E)"
+"[ISO9075-14]"
+"(SQL/OLB)."
+"D1"
+"exists"
+"REFERENCE"
+"area"
+"S041,"
+"unknown"
+"Symbol"
+"there"
+"system"
+"long"
+"ID"
+"start"
+"returns"
+"2"
+"authorized"
+"statement"
+"X2"
+"FCD"
+"STILL"
+"S231,"
+"final"
+"READ"
+"schema"
+"function"
+"DELETE,"
+"B"
+"TC\xe2\x80\x9d."
+"declare"
+"month"
+"Deprecated"
+"exactly"
+"[ISO10646]"
+"JTC1"
+"but"
+"9075-1:2010(E)"
+"part"
+"T201,"
+"D2."
+"<B>,"
+"attempt"
+"line"
+"with"
+"than"
+"<B>"
+"BEFORE,"
+"DAY."
+"DATE"
+"default"
+"EXECUTE."
+"B1,"
+"F191,"
+"tree"
+"second"
+"SHOULD"
+"[ISO9075-13],"
+"A1,"
+"1/SC"
+"VARYING,"
+"<B>."
+"SQL/CLI,"
+"were"
+"1)"
+"<A>."
+"CLI,"
+"called"
+"are"
+"and"
+"(SQL/MED)."
+"[ISO9075-4]:"
+"associated"
+"\xe2\x80\x9cAR\xe2\x80\x9d"
+"defined"
+"(SQL/XML)"
+"CHARACTER"
+"argument"
+"an"
+"[ISO9075-4])"
+"non-deterministic"
+"as"
+"Other"
+"at"
+"have"
+"[ISO9075-4]."
+"CS."
+"\xe2\x80\x9cV\xe2\x80\x9d"
+"Y."
+"null"
+"any"
+"CLI"
+"Function"
+"NOTE"
+"functions"
+"UCS"
+"returned"
+"F411,"
+"no"
+"TIME"
+"that"
+"-"
+"RETURN),"
+"A1"
+"OLAP"
+"internal"
+"S071,"
+"[ISO9075-10],"
+"T431,"
+"A1."
+"\xe2\x80\x9cONLY"
+"Y"
+"SS"
+"UNCOMMITTED,"
+"multiple"
+"Name"
+"truncate"
+"normal"
+"symbol"
+"literal"
+"M"
+"\xe2\x80\x9c<SQL"
+"prepared"
+"most"
+"ATOMIC,"
+"E."
+"U"
+"letter"
+"PUBLIC"
+"identical"
+"F491,"
+"N"
+"inserted"
+"Page"
+"(SQL/JRT)."
+"D,"
+"SELECT,"
+"USED"
+"lead"
+"Sequence"
+"FEAT1"
+"into"
+"required"
+"[ISO9075-9],"
+"USAGE,"
+"2nd"
+"depth"
+"R"
+"ISO,"
+"time"
+"SQL\xe2\x80\x9d,"
+"FEAT2"
+"[ISO9075-3]"
+"(SQL/PSM)."
+"ISO/IEC"
diff --git a/testing/libfuzzer/fuzzers/dicts/generated/url_parse_fuzzer.dict b/testing/libfuzzer/fuzzers/dicts/generated/url_parse_fuzzer.dict
new file mode 100644
index 0000000..302f590
--- /dev/null
+++ b/testing/libfuzzer/fuzzers/dicts/generated/url_parse_fuzzer.dict
@@ -0,0 +1,403 @@
+# 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.
+
+# This file has been generated with testing/libfuzzer/dictionary_generator.py
+# using url_parse_fuzzer binary and RFC 3986.
+"DNS"
+"text"
+"TCP"
+"\"%D3%81%87%A4%95%81@%C2%85%81%83%88\"."
+"[RFC2234]"
+"F.,"
+"FORCE"
+"SOCIETY"
+"implementation"
+"TASK"
+"cache"
+"WINS,"
+"D.1."
+"to"
+"only"
+"HTML"
+"SPONSORED"
+"[RFC1630]."
+"D.,"
+"[RFC1123]"
+"resources"
+"(STD"
+"[RFC1808],"
+"string"
+"returning"
+"=="
+"H"
+"HEREIN"
+"[BCP35]"
+"SP)"
+"SCTP)"
+"(NUL)"
+"THE"
+"(URI):"
+"REPRESENTS"
+"resource"
+"A.,"
+"EXPRESS"
+"list"
+"(%2E),"
+"WILL"
+"J."
+"INCLUDING"
+"segment."
+"[RFC2732]"
+"(URL)\","
+"set"
+"HTTP"
+"IANA"
+"INFORMATION"
+"(%41-%5A"
+"[RFC2518]"
+"M."
+"direct"
+"(IDNA)\","
+"Only"
+"Version"
+"are"
+"allowed."
+"\"X\""
+"(SP)."
+"2DIGIT"
+"section"
+"BUT"
+"\"UTF-8,"
+"3"
+"version"
+"[RFC1034]"
+"probably"
+"[RFC2732]."
+"metadata"
+"Y.,"
+"C"
+"WWW\""
+"FOR"
+"0X"
+"S"
+"address"
+"INPUT"
+"["
+"P."
+"WWW:"
+"AND"
+"WWW"
+"[BCP35]."
+"MA"
+"\"AS"
+"\"%\""
+"NOT"
+"ANY"
+"[RFC1808]"
+"WARRANTY"
+"useful"
+"[RFC1737]."
+"[STD63],"
+"\"HTTP\""
+"(MIME)"
+"TELNET"
+"[RFC1630]"
+"S."
+"D.2."
+"B.,"
+"[RFC2234]."
+"[RFC2234],"
+"BCP"
+"[STD63];"
+"use"
+"LATIN"
+"from"
+"C."
+"0"
+"WARRANTIES"
+"(MHTML)\","
+"ENGINEERING"
+"URI;"
+"few"
+"(DNS)."
+"expected"
+"USENET"
+"type"
+"empty"
+"XML"
+"URL?\","
+"W3C/MIT"
+"F"
+"CA"
+"STD:"
+"SMTP"
+"[RFC2141],"
+"N"
+"A),"
+"NOTE:"
+"CR"
+"MHTML"
+"must"
+"ANY),"
+"ALL"
+"[STD63]"
+"RIGHTS"
+"HE/SHE"
+"SP"
+"[BCP19]"
+"value"
+"INFRINGE"
+"while"
+"KATAKANA"
+"US-ASCII"
+"W3C/IETF"
+"loop"
+"J.,"
+"2E:"
+"L."
+"have"
+"%61-%7A),"
+"is"
+"PARTICULAR"
+"thus"
+"URI,"
+"parse"
+"STEP"
+"MIME"
+"UTF-8"
+"in"
+"failed"
+"LF"
+"binary"
+"ISO/IEC"
+"\"A"
+"(%5F),"
+")"
+"HTTP,"
+"get"
+"\"A\","
+"[RFC2141]"
+"BUFFER"
+"ABNF"
+"[RFC2557]."
+"I."
+"WARRANTIES,"
+"URN"
+"EBCDIC"
+"A"
+"used"
+"http"
+"may"
+"IP"
+"IS"
+"after"
+"L"
+"Q"
+"'A'"
+"running"
+"HEXDIG"
+"such"
+"EBCDIC,"
+"data"
+"[ASCII]"
+"a"
+"P"
+"[ASCII]."
+"M.,"
+"Names"
+"the"
+"[RFC0952]."
+"[RFC3490]"
+"US-ASCII."
+"2C:"
+"THAT"
+"E.,"
+"(%2D),"
+"\"URL:\""
+"WITH"
+"BY"
+"[UCS],"
+"tables"
+"[UCS]"
+"TO"
+"BNF"
+"internal"
+"P.,"
+"ORGANIZATION"
+"\"HTTP"
+"URI."
+"it,"
+"D"
+"format"
+"URL"
+"(0"
+"URI\""
+"URI"
+"K."
+"URI:"
+"T"
+"D.W."
+"not"
+"R."
+"LIMITED"
+"\"%3A\")"
+"name"
+"OF"
+"B."
+"[RFC1736]"
+"(R),"
+"IPR"
+"[RFC1738];"
+"OUTPUT"
+"LALR"
+"OR"
+"STD"
+"[RFC3513]"
+"because"
+"bytes"
+"DNS,"
+"back"
+"(URI)"
+"*DIGIT"
+"[RFC2046]"
+"[RFC3305]"
+"W3C"
+"E."
+"for"
+"space"
+"ABNF\","
+"[RFC1535]."
+"DQUOTE"
+"I"
+"does"
+"'F'"
+"[RFC2396]"
+"be"
+"K.,"
+"DISCLAIM"
+"G"
+"(UTF-16),"
+"This"
+"M"
+"INTERNET"
+"RFC"
+"X3.4,"
+"base"
+"(T):"
+"IMPLIED,"
+"by"
+"\"URL\""
+"on"
+"DIGIT"
+"(ABNF)"
+"WEBDAV\","
+"of"
+"could"
+"R.,"
+"(ABNF:"
+"S.,"
+"1*4HEXDIG"
+"CAPITAL"
+"number"
+"one"
+"ISO"
+"FITNESS"
+"\"%7E\""
+"open"
+"ANSI"
+"[BCP19],"
+"\"%C3%80\","
+"IETF"
+"support"
+"\"URN"
+"[RFC1123]."
+"long"
+"[RFC0952]"
+":"
+"was"
+"[RFC3513]."
+"[RFC2718]"
+"B"
+"N."
+"that"
+"IDNA"
+"OCTET"
+"but"
+"R"
+"POSIX"
+"LETTER"
+"CONTRIBUTOR,"
+"[RFC1738]"
+"(C)"
+"with"
+"\"URI\""
+"16"
+"default"
+"double"
+"\"URN\""
+"[RFC2557]"
+"up"
+"TCP,"
+"PURPOSE."
+"MERCHANTABILITY"
+"1)"
+"IS\""
+"\"IANA"
+"(URN)"
+"and"
+"USE"
+"false"
+"(IF"
+"USA"
+"URL,"
+"an"
+"To"
+"as"
+"(%7E)"
+"at"
+"file"
+"need"
+"any"
+"\"%E3%82%A2\"."
+"physical"
+"1*HEXDIG"
+"no"
+"[RFC1737]"
+"-"
+"invalid"
+"A."
+"application"
+"valid"
+"take"
+"which"
+"test"
+"[RFC2732],"
+"you"
+"="
+"GRAVE"
+"<URI>"
+"[RFC2396],"
+"2B:"
+"period,"
+"UDP,"
+"[RFC1535]"
+"T."
+"(UCS)\","
+"U"
+"A-F."
+"T.,"
+"]"
+"[RFC2718]."
+"D."
+"persistent"
+"traditional"
+"L.,"
+"As"
+"IMPLIED"
+"(URL)"
+"ALPHA"
+"[RFC3305]."
+"H.,"
+"\"MIME"
+
diff --git a/testing/libfuzzer/fuzzers/dicts/generated/v8_script_parser_fuzzer.dict b/testing/libfuzzer/fuzzers/dicts/generated/v8_script_parser_fuzzer.dict
new file mode 100644
index 0000000..b4d536c
--- /dev/null
+++ b/testing/libfuzzer/fuzzers/dicts/generated/v8_script_parser_fuzzer.dict
@@ -0,0 +1,1656 @@
+#
+# AFL dictionary for JavaScript
+# -----------------------------
+#
+# Contains basic reserved keywords and syntax building blocks.
+#
+# Created by Michal Zalewski <lcamtuf@google.com>
+#
+
+keyword_arguments="arguments"
+keyword_break="break"
+keyword_case="case"
+keyword_catch="catch"
+keyword_const="const"
+keyword_continue="continue"
+keyword_debugger="debugger"
+keyword_decodeURI="decodeURI"
+keyword_default="default"
+keyword_delete="delete"
+keyword_do="do"
+keyword_else="else"
+keyword_escape="escape"
+keyword_eval="eval"
+keyword_export="export"
+keyword_finally="finally"
+keyword_for="for (a=0;a<2;a++)"
+keyword_function="function"
+keyword_if="if"
+keyword_in="in"
+keyword_instanceof="instanceof"
+keyword_isNaN="isNaN"
+keyword_let="let"
+keyword_new="new"
+keyword_parseInt="parseInt"
+keyword_return="return"
+keyword_super="super"
+keyword_switch="switch"
+keyword_this="this"
+keyword_throw="throw"
+keyword_try="try"
+keyword_typeof="typeof"
+keyword_var="var"
+keyword_void="void"
+keyword_while="while"
+keyword_with="with"
+
+misc_1=" 1"
+misc_a="a"
+misc_array=" [1]"
+misc_assign=" a=1"
+misc_code_block=" {1}"
+misc_colon_num=" 1:"
+misc_colon_string=" 'a':"
+misc_comma=" ,"
+misc_comment_block=" /* */"
+misc_comment_line=" //"
+misc_cond=" 1?2:3"
+misc_dec=" --"
+misc_div=" /"
+misc_equals=" ="
+misc_fn=" a()"
+misc_identical=" ==="
+misc_inc=" ++"
+misc_minus=" -"
+misc_modulo=" %"
+misc_parentheses=" ()"
+misc_parentheses_1=" (1)"
+misc_parentheses_1x4=" (1,1,1,1)"
+misc_parentheses_a=" (a)"
+misc_period="."
+misc_plus=" +"
+misc_plus_assign=" +="
+misc_regex=" /a/g"
+misc_rol=" <<<"
+misc_semicolon=" ;"
+misc_serialized_object=" {'a': 1}"
+misc_string=" 'a'"
+misc_unicode=" '\\u0001'"
+misc_shl=" <<"
+misc_shr=" >>"
+misc_sae=" >>>"
+misc_bit_or=" |"
+misc_bit_and=" &"
+misc_bit_xor=" ^"
+misc_bit_not=" ~"
+
+object_Array=" Array"
+object_Boolean=" Boolean"
+object_Date=" Date"
+object_Function=" Function"
+object_Infinity=" Infinity"
+object_Int8Array=" Int8Array"
+object_Math=" Math"
+object_NaN=" NaN"
+object_Number=" Number"
+object_Object=" Object"
+object_RegExp=" RegExp"
+object_String=" String"
+object_Symbol=" Symbol"
+object_false=" false"
+object_null=" null"
+object_true=" true"
+
+prop_charAt=".charAt"
+prop_concat=".concat"
+prop_constructor=".constructor"
+prop_destructor=".destructor"
+prop_length=".length"
+prop_match=".match"
+prop_proto=".__proto__"
+prop_prototype=".prototype"
+prop_slice=".slice"
+prop_toCode=".toCode"
+prop_toString=".toString"
+prop_valueOf=".valueOf"
+
+
+# This part has been generated with testing/libfuzzer/dictionary_generator.py
+# using v8_script_parser_fuzzer binary and ECMA-262 standard 6.0.
+"all"
+"ECMA-404."
+"contexts."
+"Date.prototype.setHours"
+"IsConstructor"
+"forbidden"
+"dynamic"
+"month"
+"(exclusive)"
+"(OOPSLA"
+"arguments)"
+"consists"
+"expressions"
+"(which"
+"(in"
+"WeakSet"
+"whose"
+"iterator"
+"PATENT"
+"(for"
+"equivalence"
+"including"
+"to"
+"tail"
+"program"
+"under"
+"immutable"
+"started"
+"@"
+"digit"
+"returned"
+"very"
+"activation"
+"'UA-32577963-1']);"
+"Classes"
+"every"
+"updates"
+"U+200C"
+"(URI):"
+"condition"
+"(QUOTATION"
+"exponential"
+"Reference"
+"EXPRESS"
+"list"
+"prefix"
+"non-extensible"
+"large"
+"INDIRECT,"
+"NY,"
+"enclosing"
+"small"
+"abbreviated"
+"built-in"
+"range."
+"BUSINESS"
+"C++,"
+"translating"
+"surrounding"
+"second"
+"Version"
+"pass"
+"UTF-8."
+"invariant"
+"(LINE"
+"implemented"
+"INFRINGE"
+"Z."
+"Latin"
+"incompatible"
+"section"
+"selected"
+"supplied"
+"decoding"
+"version"
+"run"
+"above"
+"Int8Array"
+"method"
+"\"BSD"
+"full"
+"escaping"
+"Undefined"
+"compilation"
+"never"
+"component"
+"here"
+"ranges"
+"reported"
+"U+007D"
+"operations."
+"active"
+"path"
+"placeholder"
+"8601:2004(E)"
+"search"
+"White_Space"
+"U+10FFFF,"
+"changed"
+"allows"
+"(see"
+"SOLIDUS)"
+"prior"
+"real"
+"successors"
+"error,"
+"error."
+"proxy"
+"prints"
+"via"
+"shorthand"
+"divide"
+"replace"
+"Object.defineProperties"
+"Instance"
+"TO"
+"S,"
+"SUCH"
+"total"
+"unit"
+"languages"
+"executable"
+"takes"
+"would"
+"U+003A"
+"contains"
+"negative"
+"URI;"
+"call"
+"JTC"
+"6"
+"type"
+"until"
+"more"
+"Date.prototype.setMinutes"
+"GOODS"
+"EXEMPLARY,"
+"expose"
+"SIGN)"
+"flag"
+"U+000A"
+"V"
+"Representation"
+"Alphabetic"
+"hold"
+"finalization"
+"must"
+"Array.prototype"
+"PROVIDED"
+"none"
+"word"
+"U+000D"
+"hour"
+"SV"
+"(REVERSE"
+"paragraph"
+"ms"
+"v"
+"exceptions"
+"COMMA,"
+"root"
+"could"
+"defer"
+"compare"
+"type."
+"(with"
+"JavaScript"
+"states"
+"minimum"
+"numbers"
+"keep"
+"SEPARATOR),"
+"absolute"
+"information"
+"end"
+"recursive"
+"Format"
+"provide"
+"DataView"
+"HOWEVER"
+"maps"
+"reject"
+"Promise"
+"IMPLIED"
+"<CR>"
+"A"
+"description"
+"binary"
+"Arrays"
+"typed"
+"after"
+"variant"
+"mapping"
+"U+0024"
+"hoisting"
+"reflect"
+"SPECIAL,"
+"types"
+"All"
+"short"
+"(CHARACTER"
+"postfix"
+"ID_Start"
+"map,"
+"blocks."
+")"
+"LICENSING"
+"QUOTATION"
+"order"
+"DAMAGES"
+"operations"
+"executed"
+"interpretation"
+"V,"
+"over"
+"NO-BREAK"
+"expects"
+"through"
+"LINE"
+"its"
+"before"
+"byteLength"
+"style"
+"20"
+"(V,"
+"CreateIterResultObject"
+","
+"writing"
+"detected"
+"verifies"
+"SUBSTITUTE"
+"might"
+"then"
+"them"
+"skipped"
+"combination"
+"strings."
+"URI"
+"number"
+"of:"
+"nested"
+"operation."
+"[~U]"
+"always"
+"decimal"
+"Date.prototype.setMonth"
+"token"
+"API"
+"twice."
+"arrow"
+"each"
+"types."
+"side"
+"(but"
+"GetSuperConstructor"
+"directly"
+"Zone"
+"UTC"
+"FITNESS"
+"numeric"
+"expect"
+"RegExp"
+"loops"
+"operation"
+"scope)"
+"Type"
+"Reflect.ownKeys"
+"More"
+"WILL"
+"by"
+"mark-up"
+"restricted"
+"since"
+"BMP"
+"7"
+"newly"
+"Super"
+"Class"
+"Must"
+"loop."
+"Extension"
+"found"
+"free"
+"standard"
+"reason"
+"base"
+"byteOffset"
+"Constructor"
+"put"
+"Block"
+"thrown"
+"definition"
+"pairs"
+"unresolved"
+"created"
+"starts"
+"filter"
+"uses"
+"assign"
+"already"
+"features"
+">>"
+"encoding"
+"SYMBOL"
+"TC39"
+"SameValue"
+"primary"
+"system"
+"Maps"
+"Handler"
+"done"
+"notify"
+"another"
+"RETURN),"
+"SMALL"
+"Date.prototype.setSeconds"
+"script"
+"top"
+"least"
+"ToString"
+"needed"
+"SymbolDescriptiveString"
+"too"
+"statement"
+"store"
+"passed"
+"Language"
+"OrdinaryHasInstance"
+"Named"
+"immediate"
+"direct"
+"tokens"
+"execution."
+"BRACKET)."
+"translation"
+"to:"
+"kind"
+"Code"
+"keyword"
+"double"
+"enabled"
+"zero"
+"normalizing"
+"Reflect.getOwnPropertyDescriptor"
+"(NOTE"
+"minus"
+"debugging"
+"script."
+"constructors"
+"bitwise"
+"randomly"
+"UTC,"
+"Reflect.has"
+"initialized"
+"U+005D"
+"null"
+"ARISING"
+"UTF-8,"
+"contents"
+"option"
+"forced"
+"Power"
+"-"
+"eagerly"
+"indexes"
+"also"
+"internal"
+"(LEFT"
+"Date.prototype.setYear"
+"ARE"
+"REGARDING"
+"added"
+"object"
+"most"
+"optimized"
+"regular"
+"rejected"
+"letter"
+"scripts"
+"Date.prototype.setDate"
+"The"
+"<ZWNJ>"
+"brackets"
+"flow"
+"traditional"
+"Single"
+"Boolean"
+"place"
+"parenthesis"
+"Native"
+"+"
+"heuristics"
+"radix"
+"SyntaxError"
+"(N,"
+"syntax"
+"attempts"
+"O,"
+"relation"
+"find"
+"(COMMA)."
+"access"
+"(COMMA),"
+"parameters"
+"THAT"
+"HTML"
+"8"
+"exports"
+"dependent"
+"account"
+"Value"
+"(P)"
+"ToLength"
+"non-integer"
+"report"
+"during"
+"target"
+"runs"
+"resolve"
+"THIS"
+"fields"
+"bytes"
+"remove"
+"twice"
+"common"
+"CET,"
+"parameter,"
+"parameter."
+"automatic"
+"ToObject"
+"set"
+"reference"
+"locale"
+"testing"
+"<ZWNBSP>"
+"Tail"
+"are"
+"arg"
+"hash"
+"(CARRIAGE"
+"stringify"
+"said"
+"currently"
+"BUT"
+"future"
+"various"
+"OWNERSHIP"
+"consecutive"
+"conditions"
+"available"
+"C"
+"1))"
+"creating"
+"missing"
+"modify"
+"weak"
+"zone,"
+"PROCUREMENT"
+"succeed"
+"IS\""
+"interface"
+"IMPLEMENT"
+"AND"
+"both"
+"c"
+"TypeError"
+"last"
+"SHALL"
+"false,"
+"against"
+"became"
+"PURPOSE"
+"context"
+"receiver"
+"exceeds"
+"(MV),"
+"finds"
+"WARRANTY"
+"point"
+"header"
+"globals"
+"written"
+"slots"
+"Method"
+"iterable"
+"Wide"
+"Date.prototype.toDateString"
+"C,"
+"format,"
+"create"
+"Processing"
+"(SV,"
+"been"
+"accessor"
+"Early"
+"TORT"
+"JSON"
+"UTF-16."
+"basic"
+"expected"
+"C0"
+"empty"
+"Date.prototype.setUTCMilliseconds"
+"CLEF)."
+"precision"
+"N"
+"TV,"
+"assigning"
+"exception"
+"Date.prototype.setMilliseconds"
+"frozen"
+"Uint16Array"
+"deferred"
+"optimization"
+"replaced"
+"Object.defineProperty"
+"error"
+"property"
+"EVENT"
+"loop"
+"resolved"
+"USE,"
+"Both"
+"is"
+"binding"
+"it"
+"encountered"
+"itself"
+"[[Handler]]"
+"containing"
+"U+005F"
+"ISO/IEC"
+"Boolean.prototype.toString"
+"flag."
+"make"
+"NaN"
+"shorter"
+"(PARAGRAPH"
+"(MV,"
+"split"
+"9"
+"AT&T"
+"U+005B"
+"(TV)"
+"used"
+"keys"
+"assignment"
+"LIABILITY,"
+"NOT"
+"levels"
+"moving"
+"user"
+"characters"
+"CONDUCT"
+"stack"
+"normalization"
+"early"
+"lower"
+"surrogate"
+"changes"
+"ZERO),"
+"flags"
+"Names"
+"y"
+"entry"
+"the"
+"encodeURIComponent"
+"ECMA"
+"left"
+"construct"
+"quoted"
+"sentence"
+"||"
+"overflows"
+"SERVICES;"
+"(F,"
+"Inherited"
+"followed"
+"32"
+"yet"
+"previous"
+"tables"
+"Assignment"
+"LEFT-TO-RIGHT"
+"character"
+"source"
+"n"
+"collections"
+"found,"
+"input"
+"has"
+"remaining"
+"..."
+"format"
+"lexically"
+"big"
+"(O,"
+"possible"
+"marked"
+"integer"
+"bit"
+"enumerable"
+"formal"
+"ON"
+"d"
+"OF"
+"ignore"
+"steps"
+"Date.prototype.toISOString"
+"table."
+"OR"
+"right"
+"old"
+"Reflect.set"
+"<PS>"
+"creation"
+"back"
+"Numeric"
+"apply"
+"indirect"
+"encodeURI"
+"sourceText"
+"String"
+"for"
+"notification"
+"subclass"
+"<LF>"
+"track"
+"Let"
+"eliminate"
+"either"
+"be"
+"<LS>"
+"algorithmic"
+"Calls"
+"processing"
+"O"
+"step"
+"RIGHT-TO-LEFT"
+"ToNumber"
+"BMP."
+"method."
+"from"
+"Property"
+"properties"
+"<ZWJ>,"
+"Abstract"
+"Argument"
+"range"
+"extensions"
+"value."
+"runtime"
+"automatically"
+"Common"
+"IANA"
+"primitive"
+"statements"
+"constructor."
+"garbage"
+"CAUSED"
+"into"
+"within"
+"bound"
+"ACM"
+"parsing"
+"Literal"
+"Java"
+"Reflect.get"
+"IsRegExp"
+"32-bit"
+"U+005C"
+"Keys"
+"intrinsic"
+"support"
+"initial"
+"handles"
+"long"
+"ReferenceError"
+"RangeError"
+"array."
+"Variable"
+"perform"
+"analyze"
+"was"
+"(i.e."
+"form"
+"memory"
+"failure"
+"decodeURIComponent"
+"CONTRACT,"
+"statement."
+"objects."
+"true"
+"objects)"
+"Left"
+"arrays"
+"inside"
+"caller"
+"maximum"
+"...,"
+"annotations"
+"LEFT"
+"called"
+"constant"
+"defined"
+"Deseret"
+"iterator,"
+"To"
+"single"
+"Arguments"
+"floating"
+"check"
+"Map"
+"Only"
+"no"
+"TV"
+"binding."
+"when"
+"Possible"
+"invalid"
+"A."
+"application"
+"points"
+"Proxy"
+"Scripts"
+"test"
+"Reflect.isExtensible"
+"arithmetic"
+"node"
+"elements"
+"update"
+"prepared"
+"class"
+"AT"
+"variable"
+"structure"
+"for-in"
+"required"
+"modules"
+"An"
+"NOTE"
+"logical"
+"time"
+"PROFITS;"
+"code)"
+"requires"
+"CreateDataProperty"
+"non-writable"
+"once"
+"code"
+"partial"
+"FEED),"
+"chain"
+"FEED)."
+"(MUSICAL"
+"global"
+"existing"
+"WIDTH"
+"signatures"
+"per"
+"computation"
+"SOLIDUS),"
+"U+017F"
+"CLEF"
+"millisecond"
+"aligned"
+"U+007B"
+"zone"
+"default,"
+"Object"
+"environment"
+"0"
+"Array.prototype.concat"
+"stable"
+"include"
+"resources"
+"uninitialized"
+"division"
+"string"
+"LOSS"
+"(LATIN"
+"(INCLUDING,"
+"Tagged"
+"Keyed"
+"P"
+"ObjectDefineProperties"
+"anonymous"
+"entries"
+"specific"
+"minute"
+"level"
+"did"
+"positions"
+"Global"
+"EvalError"
+"round"
+"Canonical"
+"prevent"
+"CODE"
+"HTTP"
+"INFORMATION"
+"M,"
+"M."
+"object."
+"initializer"
+"non-strict"
+"manipulating"
+"Date.prototype.setUTCMinutes"
+"index"
+"adds"
+"appear"
+"TO,"
+"MUSICAL"
+"current"
+"Float64Array"
+"lazily"
+"template"
+"shared"
+";"
+"filled"
+"body"
+"(SOLIDUS)"
+"U+2028"
+"U+2029"
+"Descriptor"
+"objects"
+"(FORM"
+"["
+"UTF-16,"
+"implicit"
+"change"
+"convert"
+"\"AS"
+"shift"
+"31"
+"Date.prototype.setUTCSeconds"
+"queue"
+"MV"
+"weekday"
+"(MV)"
+"{"
+"Null"
+"named"
+"tasks"
+"GetOwnPropertyKeys"
+"extra"
+"When"
+"Construct"
+"modifying"
+"Languages"
+"names"
+"(DIGIT"
+"marker"
+"Import"
+"bindings"
+"use"
+"additive"
+"handled"
+"&"
+"illegal"
+"value,"
+"value)"
+"next"
+"few"
+"duplicate"
+"handler"
+"Date.prototype.setUTCFullYear"
+"attribute"
+"scope"
+"String.prototype"
+"F"
+"Default"
+"trail"
+"Time"
+"cases"
+"ID_Continue"
+"\"CODE\","
+"NON-JOINER)"
+"lowercase"
+"RIGHTS"
+"ObjectCreate"
+"modified"
+"MARK"
+"descriptor"
+"tag"
+"values"
+"can"
+"executor"
+"following"
+"meet"
+"detached"
+"F,"
+"control"
+"FTP)"
+"reserved"
+"stream"
+"escapes"
+"process"
+"lock"
+"escaped"
+"incremental"
+"UTF-8"
+"allowed"
+"unhandled"
+"block."
+"for-of"
+"requirements"
+"UTF-32"
+"means"
+"write"
+"INTERNATIONAL"
+"instead"
+"WARRANTIES,"
+"parameter"
+"attributes,"
+"circular"
+"map"
+"may"
+"clone"
+"(PLUS"
+"collection"
+"DISCLAIMS"
+"produce"
+"preferred"
+"Prologue"
+"date"
+"representations"
+"Int16Array"
+"data"
+"annotation"
+"ambiguous"
+"USA,"
+"computations"
+"bind"
+"lines"
+"element"
+"q"
+"rather"
+"block"
+"allow"
+"representation"
+"terminating"
+"__proto__"
+"(COLON),"
+"tagged"
+"@@toPrimitive"
+"Uint32Array"
+"Generator"
+"move"
+"Use"
+"years"
+"symbols"
+"comma"
+"differs"
+"INCIDENTAL,"
+"THE"
+"non-zero"
+"1"
+"(LF)"
+"group"
+"Rules"
+"platform"
+"Using"
+"main"
+"defining"
+"<"
+"pending"
+"Date.prototype.toUTCString"
+"non"
+"greater"
+"views"
+"%JSON%"
+"(FULL"
+"BRACKET)"
+"EVEN"
+"Extensions"
+"subtraction"
+"SameValueZero"
+"not"
+"(P,"
+"now"
+"nor"
+"execute"
+"name"
+"Iterator"
+"U+1D11E"
+"(LOW"
+"unrepresentable"
+"trap"
+"Eliminating"
+"identifier"
+"|"
+"subset"
+"(the"
+"8,"
+"Generic"
+"non-object"
+"U+0000"
+"static"
+"(HYPHEN-MINUS)"
+"year"
+"operand"
+"U+0008"
+"transitions"
+"Parameter"
+"special"
+"out"
+"space"
+"REQUIRED"
+"RegExpExec"
+"Set"
+"Float32Array"
+"Throw"
+"index."
+"G"
+"state"
+"column"
+"RFC"
+"completely"
+"Used"
+"x"
+"IMPLIED,"
+"byte"
+"remainder"
+"log"
+"DATA,"
+"backwards"
+"unescape"
+"language"
+"ArrayBuffer"
+"@@hasInstance"
+"times"
+"STRICT"
+"length"
+"separator"
+"isView"
+"hexadecimal"
+"first"
+"clause"
+"variables"
+"one"
+"INTERRUPTION)"
+"ISO"
+"suspended"
+"JOINER)"
+"reached"
+"array"
+"size"
+"given"
+"Runtime"
+"checked"
+"CURLY"
+"start"
+"ordering"
+"Symbol"
+"Date.prototype.setFullYear"
+"Uint8Array"
+"grow"
+"their"
+"SEE"
+"2"
+"Date"
+"TypedArray"
+"bits"
+"final"
+"HasProperty"
+"destructuring"
+"that"
+"completed"
+"exactly"
+"R"
+"closures"
+"LETTER"
+"variable."
+"PDF"
+"copy"
+"than"
+"specify"
+"==="
+"relative"
+"later."
+":"
+"1;"
+"depends"
+"accesses"
+"WHETHER"
+"r"
+"were"
+"1)"
+"accessed"
+"GeneratorFunction"
+"URIError"
+"1,"
+"ArrayBuffer.prototype.slice"
+"result"
+"and"
+"Executable"
+"false"
+"NEGLIGENCE"
+"explicit"
+"argument"
+"generalization"
+"Field"
+"Other"
+"Call"
+"have"
+"String.prototype.charAt"
+"any"
+"conversion"
+"Date.prototype.setUTCMonth"
+"min"
+"LINE)"
+"(no"
+"instance"
+"which"
+"="
+"TRV."
+"begin"
+"multiple"
+"Name"
+"normal"
+"buffer"
+"callable"
+"connected"
+"comparison"
+"inserted"
+"pages"
+"RIGHT"
+"considered"
+"request"
+"Module"
+"Date.prototype.toString"
+"OUT"
+"Date.prototype.setUTCHours"
+"Export"
+"ECMA-404"
+"STOP),"
+"Array"
+"}"
+"selection"
+"text"
+"supported"
+"POSSIBILITY"
+"BRACKET,"
+"Reflect.setPrototypeOf"
+"ECMA-402"
+"line"
+"Math"
+"slot"
+"We"
+"based"
+"("
+"cache"
+"3"
+"should"
+"only"
+"unable"
+"invocation"
+"SEPARATOR)"
+"b"
+"local"
+"WARRANTIES"
+"handle"
+"get"
+"=="
+"space,"
+"HEREIN"
+"cannot"
+"words"
+"progress"
+"quantifier"
+"interpreted"
+"neither"
+"secondary"
+"closure"
+"Right"
+"resource"
+"upper"
+"encounters"
+"yield"
+"keyed"
+"EST,"
+"Date.prototype.getYear"
+"INCLUDING"
+"contain"
+"Reflect.preventExtensions"
+"fixed"
+"where"
+"view"
+"SOFTWARE,"
+"declared"
+"declarations"
+"RETURN"
+"computed"
+"exists"
+"we"
+"module"
+"up"
+"writable"
+"Source"
+"(BACKSPACE),"
+"legacy"
+"truncating"
+"receiver."
+"THEORY"
+"invoked"
+"attribute,"
+"U+001F"
+"pattern"
+"lexical"
+"label"
+"outside"
+"toString"
+"closed"
+"between"
+"Reflect.getPrototypeOf"
+"import"
+"boundary"
+"reading"
+"checks"
+"AVAILABLE"
+"FOR"
+"<NUL>"
+"S"
+"key"
+"Identifier"
+"valid"
+"P,"
+"observable"
+"revoked"
+"many"
+"equal"
+"Month"
+"propagation"
+"s"
+"Unicode"
+"Escape"
+"values)"
+"MapIterator"
+"expression"
+"values,"
+"Boolean.prototype.valueOf"
+"comment"
+"(HYPHEN-MINUS),"
+"color"
+"pos"
+"adding"
+"table"
+"allocated"
+"array-like"
+"IS"
+"addition"
+"]"
+"MARK)"
+"mark"
+"(SPACE),"
+"literal"
+"(SPACE)."
+"non-configurable"
+"U+200D"
+"prototype"
+">"
+"enable"
+"(S,"
+"restrictions"
+"instantiated"
+"Function.prototype.apply"
+"external"
+"WAY"
+"declaration"
+"CONSEQUENTIAL"
+"folding"
+"Date.prototype"
+"an"
+"E),"
+"present"
+"IsArray"
+"/"
+"contexts"
+"Number"
+"value"
+"will"
+"(UCS)"
+"J.UCS"
+"ADVISED"
+"unpaired"
+"FEED"
+"ECMA-402:"
+"architecture."
+"parse"
+"Strict"
+"PARTICULAR"
+"IEEE"
+"comments"
+"capture"
+"different"
+"Return"
+"compiling"
+"generic"
+"Typed"
+"same"
+"configurable"
+"member"
+"Regular"
+"mode."
+"events"
+"Types"
+"SOFTWARE"
+"string."
+"extended"
+"infinity"
+"again"
+"initialization"
+"LIABLE"
+"effect"
+"running"
+"IN"
+"changing"
+"validate"
+"ACM,"
+"U+002D"
+"IF"
+"//"
+"undefined"
+"String.prototype.trim"
+"argument."
+"argument,"
+"UTC)"
+"UTC."
+"It"
+"<table"
+"ANY"
+"patterns"
+"without"
+"extensible"
+"In"
+"String.prototype.charCodeAt"
+"position"
+"(ZERO"
+"bodies"
+"If"
+"BE"
+"(UTC)"
+"less"
+"being"
+"captures"
+"ToInteger"
+"numbering"
+"rest"
+"unary"
+"R,"
+"unicode"
+"BY"
+"captured"
+"U+212A"
+"generator"
+"hint"
+"supply"
+"unsigned"
+"add"
+"setting"
+"extends"
+"4"
+"usage"
+"lookup"
+"(A"
+"match"
+"Labelled"
+"identical"
+"Control"
+"rules"
+"DIRECT,"
+"(inclusive)"
+"non-null"
+"[U]"
+"immediately"
+"execution"
+"left-hand"
+"desc"
+"LIMITED"
+"(EQUALS"
+"missing."
+"B."
+"user-defined"
+"Bitwise"
+"MATTERS"
+"BRACKET"
+"t"
+"CLAIMS"
+"multiplicative"
+"output"
+"OTHERWISE)"
+"page"
+"replacement"
+"specifies"
+"because"
+"sequence"
+"uppercase"
+"conditional"
+"searching"
+"calling"
+"INCLUDING,"
+"specified"
+"proper"
+"New"
+"Date.prototype.toTimeString"
+"literals"
+"lead"
+"[+U]"
+"avoid"
+"results:"
+"leap"
+"does"
+"\"B\","
+"CreateListFromArrayLike"
+"?"
+"mode"
+"SQUARE"
+"power"
+"compiler"
+"WeakMap"
+"(TRV)"
+"A-Z"
+"offset"
+"regexp"
+"TRV"
+"ALL"
+"on"
+"actual"
+"extension"
+"Date.prototype.valueOf"
+"of"
+"Date.prototype.setTime"
+"recognized"
+"(SV)"
+"(U+00DF)"
+"FL,"
+"constructor"
+"or"
+"Int32Array"
+"referenced"
+"letters"
+"No"
+"Internal"
+"promise"
+"Function.prototype.toString"
+"Reflect.defineProperty"
+"operator"
+"Empty"
+"Week"
+"(U+017F)"
+"Infinity"
+"additional"
+"prepare"
+"NO"
+"*"
+"ECMA-262"
+"decode"
+"strict"
+"context."
+"SIGPLAN"
+"N,"
+"triggered"
+"enough"
+"TABULATION),"
+"DISCLAIMED."
+"ToPrimitive"
+"but"
+"repeated"
+"construction"
+"Error"
+"(RIGHT"
+"N2"
+"promote"
+"(C,"
+"longer"
+"count"
+"1024"
+"UTF-16"
+"embedded"
+"U+002F"
+"using"
+"signed"
+"U+002C"
+"below"
+"converted"
+"limit"
+"MERCHANTABILITY"
+"<BS>"
+"define"
+"detailed"
+"USE"
+"<CR><LF>"
+"Space"
+"exhausted"
+"combining"
+"FIFO"
+"general"
+"as"
+"optionally"
+"at"
+"file"
+"Reflect.deleteProperty"
+"trailing"
+"Function"
+"parameters."
+"functions"
+"beyond"
+"Date.prototype.setUTCDate"
+"virtual"
+"Reflect"
+"field"
+"other"
+"5"
+"details"
+"<<"
+"requested"
+"repeat"
+"Uint8ClampedArray"
+"separate"
+"symbol"
+"Remove"
+"U"
+"functions)"
+"(DOLLAR"
+"Object.prototype"
+"calls"
+"code,"
+"(INCLUDING"
+"rule"
+"strings"
+"code."
+"Year"
+"(URL),"
+"validation"
+"starting"
+"function,"
diff --git a/testing/libfuzzer/fuzzers/dicts/js.dict b/testing/libfuzzer/fuzzers/dicts/js.dict
deleted file mode 100644
index f3a0f6c5..0000000
--- a/testing/libfuzzer/fuzzers/dicts/js.dict
+++ /dev/null
@@ -1,115 +0,0 @@
-#
-# AFL dictionary for JavaScript
-# -----------------------------
-#
-# Contains basic reserved keywords and syntax building blocks.
-#
-# Created by Michal Zalewski <lcamtuf@google.com>
-#
-
-keyword_arguments="arguments"
-keyword_break="break"
-keyword_case="case"
-keyword_catch="catch"
-keyword_const="const"
-keyword_continue="continue"
-keyword_debugger="debugger"
-keyword_decodeURI="decodeURI"
-keyword_default="default"
-keyword_delete="delete"
-keyword_do="do"
-keyword_else="else"
-keyword_escape="escape"
-keyword_eval="eval"
-keyword_export="export"
-keyword_finally="finally"
-keyword_for="for (a=0;a<2;a++)"
-keyword_function="function"
-keyword_if="if"
-keyword_in="in"
-keyword_instanceof="instanceof"
-keyword_isNaN="isNaN"
-keyword_let="let"
-keyword_new="new"
-keyword_parseInt="parseInt"
-keyword_return="return"
-keyword_super="super"
-keyword_switch="switch"
-keyword_this="this"
-keyword_throw="throw"
-keyword_try="try"
-keyword_typeof="typeof"
-keyword_var="var"
-keyword_void="void"
-keyword_while="while"
-keyword_with="with"
-
-misc_1=" 1"
-misc_a="a"
-misc_array=" [1]"
-misc_assign=" a=1"
-misc_code_block=" {1}"
-misc_colon_num=" 1:"
-misc_colon_string=" 'a':"
-misc_comma=" ,"
-misc_comment_block=" /* */"
-misc_comment_line=" //"
-misc_cond=" 1?2:3"
-misc_dec=" --"
-misc_div=" /"
-misc_equals=" ="
-misc_fn=" a()"
-misc_identical=" ==="
-misc_inc=" ++"
-misc_minus=" -"
-misc_modulo=" %"
-misc_parentheses=" ()"
-misc_parentheses_1=" (1)"
-misc_parentheses_1x4=" (1,1,1,1)"
-misc_parentheses_a=" (a)"
-misc_period="."
-misc_plus=" +"
-misc_plus_assign=" +="
-misc_regex=" /a/g"
-misc_rol=" <<<"
-misc_semicolon=" ;"
-misc_serialized_object=" {'a': 1}"
-misc_string=" 'a'"
-misc_unicode=" '\\u0001'"
-misc_shl=" <<"
-misc_shr=" >>"
-misc_sae=" >>>"
-misc_bit_or=" |"
-misc_bit_and=" &"
-misc_bit_xor=" ^"
-misc_bit_not=" ~"
-
-object_Array=" Array"
-object_Boolean=" Boolean"
-object_Date=" Date"
-object_Function=" Function"
-object_Infinity=" Infinity"
-object_Int8Array=" Int8Array"
-object_Math=" Math"
-object_NaN=" NaN"
-object_Number=" Number"
-object_Object=" Object"
-object_RegExp=" RegExp"
-object_String=" String"
-object_Symbol=" Symbol"
-object_false=" false"
-object_null=" null"
-object_true=" true"
-
-prop_charAt=".charAt"
-prop_concat=".concat"
-prop_constructor=".constructor"
-prop_destructor=".destructor"
-prop_length=".length"
-prop_match=".match"
-prop_proto=".__proto__"
-prop_prototype=".prototype"
-prop_slice=".slice"
-prop_toCode=".toCode"
-prop_toString=".toString"
-prop_valueOf=".valueOf"
diff --git a/testing/libfuzzer/fuzzers/dicts/sql.dict b/testing/libfuzzer/fuzzers/dicts/sql.dict
deleted file mode 100644
index bf522cc4..0000000
--- a/testing/libfuzzer/fuzzers/dicts/sql.dict
+++ /dev/null
@@ -1,282 +0,0 @@
-#
-# AFL dictionary for SQL
-# ----------------------
-#
-# Modeled based on SQLite documentation, contains some number of SQLite
-# extensions. Other dialects of SQL may benefit from customized dictionaries.
-#
-# If you append @1 to the file name when loading this dictionary, afl-fuzz
-# will also additionally load a selection of pragma keywords that are very
-# specific to SQLite (and are probably less interesting from the security
-# standpoint, because they are usually not allowed in non-privileged
-# contexts).
-#
-# Created by Michal Zalewski <lcamtuf@google.com>
-#
-
-function_abs=" abs(1)"
-function_avg=" avg(1)"
-function_changes=" changes()"
-function_char=" char(1)"
-function_coalesce=" coalesce(1,1)"
-function_count=" count(1)"
-function_date=" date(1,1,1)"
-function_datetime=" datetime(1,1,1)"
-function_decimal=" decimal(1,1)"
-function_glob=" glob(1,1)"
-function_group_concat=" group_concat(1,1)"
-function_hex=" hex(1)"
-function_ifnull=" ifnull(1,1)"
-function_instr=" instr(1,1)"
-function_julianday=" julianday(1,1,1)"
-function_last_insert_rowid=" last_insert_rowid()"
-function_length=" length(1)"
-function_like=" like(1,1)"
-function_likelihood=" likelihood(1,1)"
-function_likely=" likely(1)"
-function_load_extension=" load_extension(1,1)"
-function_lower=" lower(1)"
-function_ltrim=" ltrim(1,1)"
-function_max=" max(1,1)"
-function_min=" min(1,1)"
-function_nullif=" nullif(1,1)"
-function_printf=" printf(1,1)"
-function_quote=" quote(1)"
-function_random=" random()"
-function_randomblob=" randomblob(1)"
-function_replace=" replace(1,1,1)"
-function_round=" round(1,1)"
-function_rtrim=" rtrim(1,1)"
-function_soundex=" soundex(1)"
-function_sqlite_compileoption_get=" sqlite_compileoption_get(1)"
-function_sqlite_compileoption_used=" sqlite_compileoption_used(1)"
-function_sqlite_source_id=" sqlite_source_id()"
-function_sqlite_version=" sqlite_version()"
-function_strftime=" strftime(1,1,1,1)"
-function_substr=" substr(1,1,1)"
-function_sum=" sum(1)"
-function_time=" time(1,1,1)"
-function_total=" total(1)"
-function_total_changes=" total_changes()"
-function_trim=" trim(1,1)"
-function_typeof=" typeof(1)"
-function_unicode=" unicode(1)"
-function_unlikely=" unlikely(1)"
-function_upper=" upper(1)"
-function_varchar=" varchar(1)"
-function_zeroblob=" zeroblob(1)"
-
-keyword_ABORT="ABORT"
-keyword_ACTION="ACTION"
-keyword_ADD="ADD"
-keyword_AFTER="AFTER"
-keyword_ALL="ALL"
-keyword_ALTER="ALTER"
-keyword_ANALYZE="ANALYZE"
-keyword_AND="AND"
-keyword_AS="AS"
-keyword_ASC="ASC"
-keyword_ATTACH="ATTACH"
-keyword_AUTOINCREMENT="AUTOINCREMENT"
-keyword_BEFORE="BEFORE"
-keyword_BEGIN="BEGIN"
-keyword_BETWEEN="BETWEEN"
-keyword_BY="BY"
-keyword_CASCADE="CASCADE"
-keyword_CASE="CASE"
-keyword_CAST="CAST"
-keyword_CHECK="CHECK"
-keyword_COLLATE="COLLATE"
-keyword_COLUMN="COLUMN"
-keyword_COMMIT="COMMIT"
-keyword_CONFLICT="CONFLICT"
-keyword_CONSTRAINT="CONSTRAINT"
-keyword_CREATE="CREATE"
-keyword_CROSS="CROSS"
-keyword_CURRENT_DATE="CURRENT_DATE"
-keyword_CURRENT_TIME="CURRENT_TIME"
-keyword_CURRENT_TIMESTAMP="CURRENT_TIMESTAMP"
-keyword_DATABASE="DATABASE"
-keyword_DEFAULT="DEFAULT"
-keyword_DEFERRABLE="DEFERRABLE"
-keyword_DEFERRED="DEFERRED"
-keyword_DELETE="DELETE"
-keyword_DESC="DESC"
-keyword_DETACH="DETACH"
-keyword_DISTINCT="DISTINCT"
-keyword_DROP="DROP"
-keyword_EACH="EACH"
-keyword_ELSE="ELSE"
-keyword_END="END"
-keyword_ESCAPE="ESCAPE"
-keyword_EXCEPT="EXCEPT"
-keyword_EXCLUSIVE="EXCLUSIVE"
-keyword_EXISTS="EXISTS"
-keyword_EXPLAIN="EXPLAIN"
-keyword_FAIL="FAIL"
-keyword_FOR="FOR"
-keyword_FOREIGN="FOREIGN"
-keyword_FROM="FROM"
-keyword_FULL="FULL"
-keyword_GLOB="GLOB"
-keyword_GROUP="GROUP"
-keyword_HAVING="HAVING"
-keyword_IF="IF"
-keyword_IGNORE="IGNORE"
-keyword_IMMEDIATE="IMMEDIATE"
-keyword_IN="IN"
-keyword_INDEX="INDEX"
-keyword_INDEXED="INDEXED"
-keyword_INITIALLY="INITIALLY"
-keyword_INNER="INNER"
-keyword_INSERT="INSERT"
-keyword_INSTEAD="INSTEAD"
-keyword_INTERSECT="INTERSECT"
-keyword_INTO="INTO"
-keyword_IS="IS"
-keyword_ISNULL="ISNULL"
-keyword_JOIN="JOIN"
-keyword_KEY="KEY"
-keyword_LEFT="LEFT"
-keyword_LIKE="LIKE"
-keyword_LIMIT="LIMIT"
-keyword_MATCH="MATCH"
-keyword_NATURAL="NATURAL"
-keyword_NO="NO"
-keyword_NOT="NOT"
-keyword_NOTNULL="NOTNULL"
-keyword_NULL="NULL"
-keyword_OF="OF"
-keyword_OFFSET="OFFSET"
-keyword_ON="ON"
-keyword_OR="OR"
-keyword_ORDER="ORDER"
-keyword_OUTER="OUTER"
-keyword_PLAN="PLAN"
-keyword_PRAGMA="PRAGMA"
-keyword_PRIMARY="PRIMARY"
-keyword_QUERY="QUERY"
-keyword_RAISE="RAISE"
-keyword_RECURSIVE="RECURSIVE"
-keyword_REFERENCES="REFERENCES"
-#keyword_REGEXP="REGEXP"
-keyword_REINDEX="REINDEX"
-keyword_RELEASE="RELEASE"
-keyword_RENAME="RENAME"
-keyword_REPLACE="REPLACE"
-keyword_RESTRICT="RESTRICT"
-keyword_RIGHT="RIGHT"
-keyword_ROLLBACK="ROLLBACK"
-keyword_ROW="ROW"
-keyword_SAVEPOINT="SAVEPOINT"
-keyword_SELECT="SELECT"
-keyword_SET="SET"
-keyword_TABLE="TABLE"
-keyword_TEMP="TEMP"
-keyword_TEMPORARY="TEMPORARY"
-keyword_THEN="THEN"
-keyword_TO="TO"
-keyword_TRANSACTION="TRANSACTION"
-keyword_TRIGGER="TRIGGER"
-keyword_UNION="UNION"
-keyword_UNIQUE="UNIQUE"
-keyword_UPDATE="UPDATE"
-keyword_USING="USING"
-keyword_VACUUM="VACUUM"
-keyword_VALUES="VALUES"
-keyword_VIEW="VIEW"
-keyword_VIRTUAL="VIRTUAL"
-keyword_WHEN="WHEN"
-keyword_WHERE="WHERE"
-keyword_WITH="WITH"
-keyword_WITHOUT="WITHOUT"
-
-operator_concat=" || "
-operator_ebove_eq=" >="
-
-snippet_1eq1=" 1=1"
-snippet_at=" @1"
-snippet_backticks=" `a`"
-snippet_blob=" blob"
-snippet_brackets=" [a]"
-snippet_colon=" :1"
-snippet_comment=" /* */"
-snippet_date="2001-01-01"
-snippet_dollar=" $1"
-snippet_dotref=" a.b"
-snippet_fmtY="%Y"
-snippet_int=" int"
-snippet_neg1=" -1"
-snippet_pair=" a,b"
-snippet_parentheses=" (1)"
-snippet_plus2days="+2 days"
-snippet_qmark=" ?1"
-snippet_semicolon=" ;"
-snippet_star=" *"
-snippet_string_pair=" \"a\",\"b\""
-
-string_dbl_q=" \"a\""
-string_escaped_q=" 'a''b'"
-string_single_q=" 'a'"
-
-pragma_application_id@1=" application_id"
-pragma_auto_vacuum@1=" auto_vacuum"
-pragma_automatic_index@1=" automatic_index"
-pragma_busy_timeout@1=" busy_timeout"
-pragma_cache_size@1=" cache_size"
-pragma_cache_spill@1=" cache_spill"
-pragma_case_sensitive_like@1=" case_sensitive_like"
-pragma_checkpoint_fullfsync@1=" checkpoint_fullfsync"
-pragma_collation_list@1=" collation_list"
-pragma_compile_options@1=" compile_options"
-pragma_count_changes@1=" count_changes"
-pragma_data_store_directory@1=" data_store_directory"
-pragma_database_list@1=" database_list"
-pragma_default_cache_size@1=" default_cache_size"
-pragma_defer_foreign_keys@1=" defer_foreign_keys"
-pragma_empty_result_callbacks@1=" empty_result_callbacks"
-pragma_encoding@1=" encoding"
-pragma_foreign_key_check@1=" foreign_key_check"
-pragma_foreign_key_list@1=" foreign_key_list"
-pragma_foreign_keys@1=" foreign_keys"
-pragma_freelist_count@1=" freelist_count"
-pragma_full_column_names@1=" full_column_names"
-pragma_fullfsync@1=" fullfsync"
-pragma_ignore_check_constraints@1=" ignore_check_constraints"
-pragma_incremental_vacuum@1=" incremental_vacuum"
-pragma_index_info@1=" index_info"
-pragma_index_list@1=" index_list"
-pragma_integrity_check@1=" integrity_check"
-pragma_journal_mode@1=" journal_mode"
-pragma_journal_size_limit@1=" journal_size_limit"
-pragma_legacy_file_format@1=" legacy_file_format"
-pragma_locking_mode@1=" locking_mode"
-pragma_max_page_count@1=" max_page_count"
-pragma_mmap_size@1=" mmap_size"
-pragma_page_count@1=" page_count"
-pragma_page_size@1=" page_size"
-pragma_parser_trace@1=" parser_trace"
-pragma_query_only@1=" query_only"
-pragma_quick_check@1=" quick_check"
-pragma_read_uncommitted@1=" read_uncommitted"
-pragma_recursive_triggers@1=" recursive_triggers"
-pragma_reverse_unordered_selects@1=" reverse_unordered_selects"
-pragma_schema_version@1=" schema_version"
-pragma_secure_delete@1=" secure_delete"
-pragma_short_column_names@1=" short_column_names"
-pragma_shrink_memory@1=" shrink_memory"
-pragma_soft_heap_limit@1=" soft_heap_limit"
-pragma_stats@1=" stats"
-pragma_synchronous@1=" synchronous"
-pragma_table_info@1=" table_info"
-pragma_temp_store@1=" temp_store"
-pragma_temp_store_directory@1=" temp_store_directory"
-pragma_threads@1=" threads"
-pragma_user_version@1=" user_version"
-pragma_vdbe_addoptrace@1=" vdbe_addoptrace"
-pragma_vdbe_debug@1=" vdbe_debug"
-pragma_vdbe_listing@1=" vdbe_listing"
-pragma_vdbe_trace@1=" vdbe_trace"
-pragma_wal_autocheckpoint@1=" wal_autocheckpoint"
-pragma_wal_checkpoint@1=" wal_checkpoint"
-pragma_writable_schema@1=" writable_schema"
diff --git a/testing/libfuzzer/zip_sources.py b/testing/libfuzzer/zip_sources.py
index 5220262..946a7de 100755
--- a/testing/libfuzzer/zip_sources.py
+++ b/testing/libfuzzer/zip_sources.py
@@ -6,7 +6,7 @@
 
 """Archive all source files that are references in binary debug info.
 
-Invoked by libfuzzer buildbots. Executes llvm-dwarfdump to parse debug info.
+Invoked by libfuzzer buildbots. Executes dwarfdump to parse debug info.
 """
 
 from __future__ import print_function
@@ -18,7 +18,7 @@
 import zipfile
 
 compile_unit_re = re.compile('.*DW_TAG_compile_unit.*')
-at_name_re = re.compile('.*DW_AT_name.*debug_str\[.*\] = "(.*)".*')
+at_name_re = re.compile('.*DW_AT_name.*"(.*)".*')
 
 
 def main():
@@ -27,15 +27,17 @@
           help='binary file to read')
   parser.add_argument('--workdir', required=True,
           help='working directory to use to resolve relative paths')
+  parser.add_argument('--srcdir', required=True,
+          help='sources root directory to calculate zip entry names')
   parser.add_argument('--output', required=True,
           help='output zip file name')
-  parser.add_argument('--llvm-dwarfdump', required=False,
-          default='llvm-dwarfdump', help='path to llvm-dwarfdump utility')
+  parser.add_argument('--dwarfdump', required=False,
+          default='dwarfdump', help='path to dwarfdump utility')
   args = parser.parse_args()
 
   # Dump .debug_info section.
   out = subprocess.check_output(
-          [args.llvm_dwarfdump, '-debug-dump=info', args.binary])
+          [args.dwarfdump, '-i', args.binary])
 
   looking_for_unit = True
   compile_units = set()
@@ -55,7 +57,7 @@
     for compile_unit in sorted(compile_units):
       src_file = os.path.abspath(os.path.join(args.workdir, compile_unit))
       print(src_file)
-      z.write(src_file, compile_unit)
+      z.write(src_file, os.path.relpath(src_file, args.srcdir))
 
 
 if __name__ == '__main__':
diff --git a/testing/variations/fieldtrial_testing_config_linux.json b/testing/variations/fieldtrial_testing_config_linux.json
index 8d935a4..053e69a 100644
--- a/testing/variations/fieldtrial_testing_config_linux.json
+++ b/testing/variations/fieldtrial_testing_config_linux.json
@@ -128,6 +128,14 @@
             "group_name": "Enabled"
         }
     ],
+    "NonValidatingReloadOnNormalReload": [
+        {
+            "enable_features": [
+                "NonValidatingReloadOnNormalReload"
+            ],
+            "group_name": "Enabled"
+        }
+    ],
     "OfferUploadCreditCards": [
         {
             "group_name": "Enabled"
diff --git a/testing/variations/fieldtrial_testing_config_mac.json b/testing/variations/fieldtrial_testing_config_mac.json
index d79521bd..a7d2d8f3 100644
--- a/testing/variations/fieldtrial_testing_config_mac.json
+++ b/testing/variations/fieldtrial_testing_config_mac.json
@@ -165,6 +165,14 @@
             "group_name": "Enabled"
         }
     ],
+    "NonValidatingReloadOnNormalReload": [
+        {
+            "enable_features": [
+                "NonValidatingReloadOnNormalReload"
+            ],
+            "group_name": "Enabled"
+        }
+    ],
     "OfferUploadCreditCards": [
         {
             "group_name": "Enabled"
diff --git a/testing/variations/fieldtrial_testing_config_win.json b/testing/variations/fieldtrial_testing_config_win.json
index a30a5cc..72b2a5c 100644
--- a/testing/variations/fieldtrial_testing_config_win.json
+++ b/testing/variations/fieldtrial_testing_config_win.json
@@ -203,6 +203,14 @@
             "group_name": "Enabled"
         }
     ],
+    "NonValidatingReloadOnNormalReload": [
+        {
+            "enable_features": [
+                "NonValidatingReloadOnNormalReload"
+            ],
+            "group_name": "Enabled"
+        }
+    ],
     "OfferUploadCreditCards": [
         {
             "group_name": "Enabled"
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
index 5d35887..63162016 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
@@ -11,10 +11,7 @@
   fast/forms/xss-auditor-doesnt-crash-on-post-submit.html [ Timeout ]
   fast/loader/form-state-restore-with-frames.html [ Failure ]
   http/tests/history/back-to-post.html [ Timeout ]
-  http/tests/history/post-replace-state-reload.html [ Crash Failure ]
-  http/tests/navigation/location-reload-after-post.php [ Crash Failure ]
   http/tests/navigation/post-goback-same-url.html [ Failure ]
-  http/tests/security/xssAuditor/script-tag-post-redirect.html [ Failure ]
 
 # Failing due to error page supression in layout tests
   fast/xmlhttprequest/null-document-xmlhttprequest-open.html [ Crash Timeout ]
@@ -46,6 +43,7 @@
   fast/history/same-document-iframes-changing-pushstate.html [ Failure ]
   http/tests/history/cross-origin-redirect-on-back.html [ Crash ]
   http/tests/navigation/back-to-dynamic-iframe.html [ Failure Crash ]
+  http/tests/navigation/back-to-redirect-with-frame.php [ Failure ]
   http/tests/navigation/history-back-across-form-submission-to-fragment.html [ Timeout ]
   http/tests/navigation/redirect-on-reload-updates-history-item.html [ Failure ]
   http/tests/navigation/same-and-different-back.html [ Crash ]
@@ -84,23 +82,34 @@
   http/tests/w3c/webperf/submission/Intel/resource-timing/test_resource_timing_same_origin_redirect.html [ Timeout ]
   imported/wpt/web-animations/animation-timeline/document-timeline.html [ Failure ]
 
+# https://crbug.com/625765: Need to solve duplicate output from
+# WebFrameTestClient::willSendRequest() that causes text failures.
+  http/tests/history/post-replace-state-reload.html [ Failure ]
+  http/tests/navigation/location-reload-after-post.php [ Failure ]
+  http/tests/security/xssAuditor/script-tag-post-redirect.html [ Failure ]
+  http/tests/security/XFrameOptions/x-frame-options-allowall.html [ Failure ]
+  http/tests/security/XFrameOptions/x-frame-options-deny.html [ Failure ]
+  http/tests/security/XFrameOptions/x-frame-options-invalid.html [ Failure ]
+  http/tests/security/XFrameOptions/x-frame-options-multiple-headers-conflict.html [ Failure ]
+  http/tests/security/XFrameOptions/x-frame-options-multiple-headers-sameorigin-allow.html [ Failure ]
+  http/tests/security/XFrameOptions/x-frame-options-none.html [ Failure ]
+  http/tests/security/XFrameOptions/x-frame-options-parent-same-origin-allow.html [ Failure ]
+  fast/loader/main-document-url-for-non-http-loads.html [ Failure ]
+  http/tests/cache/iframe-304-crash.html [ Failure ]
+  http/tests/security/frame-loading-via-document-write.html [ Failure ]
+  imported/wpt/shadow-dom/untriaged/html-elements-in-shadow-trees/html-forms/test-003.html [ Failure ]
+  mhtml/multi_frames_contentid.mht [ Timeout Failure ]
+
 # https://crbug.com/555418: Move `X-Frame-Options` and CSP's `frame-ancestor`
 # checks up out of the renderer.
   http/tests/security/contentSecurityPolicy/1.1/child-src/frame-redirect-blocked.html [ Timeout ]
   http/tests/security/contentSecurityPolicy/1.1/form-action-src-redirect-blocked.html [ Failure ]
   http/tests/security/contentSecurityPolicy/frame-src-redirect-blocked.html [ Timeout ]
   http/tests/security/contentSecurityPolicy/redirect-does-not-match-paths.html [ Timeout ]
-  http/tests/security/XFrameOptions/x-frame-options-allowall.html [ Failure ]
   http/tests/security/XFrameOptions/x-frame-options-deny-meta-tag-in-body.html [ Failure ]
   http/tests/security/XFrameOptions/x-frame-options-deny-meta-tag-parent-same-origin-allow.html [ Failure ]
   http/tests/security/XFrameOptions/x-frame-options-deny-meta-tag-parent-same-origin-deny.html [ Failure ]
   http/tests/security/XFrameOptions/x-frame-options-deny-meta-tag.html [ Failure ]
-  http/tests/security/XFrameOptions/x-frame-options-deny.html [ Failure Crash ]
-  http/tests/security/XFrameOptions/x-frame-options-invalid.html [ Failure ]
-  http/tests/security/XFrameOptions/x-frame-options-multiple-headers-conflict.html [ Failure Crash ]
-  http/tests/security/XFrameOptions/x-frame-options-multiple-headers-sameorigin-allow.html [ Failure Crash ]
-  http/tests/security/XFrameOptions/x-frame-options-none.html [ Failure ]
-  http/tests/security/XFrameOptions/x-frame-options-parent-same-origin-allow.html [ Failure ]
 
 # https://crbug.com/576270: Move mixed-content checks that happen during
 # navigation to the browser
@@ -119,13 +128,10 @@
 
 # Untriaged navigation
   compositing/gestures/gesture-tapHighlight-simple-navigate.html [ Failure ]
-  fast/dom/location-new-window-no-crash.html [ Crash ]
   fast/loader/document-destruction-within-unload.html [ Crash ]
-  fast/loader/main-document-url-for-non-http-loads.html [ Failure ]
   fast/loader/scroll-position-restored-on-reload-at-load-event.html [ Failure ]
   fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html [ Crash Timeout ]
   fast/loader/subframe-removes-itself.html [ Failure ]
-  http/tests/cache/iframe-304-crash.html [ Crash Failure ]
   http/tests/cache/smil-usecounter-in-cached-image.html [ Failure ]
   http/tests/cookies/same-site/popup-same-site-post.html [ Failure ]
   http/tests/cookies/same-site/popup-same-site.html [ Failure ]
@@ -139,7 +145,6 @@
   http/tests/loading/redirect-with-no-location-crash.html [ Failure ]
   http/tests/loading/slow-parsing-subframe.html [ Failure ]
   http/tests/loading/text-content-type-with-binary-extension.html [ Timeout Failure ]
-  http/tests/navigation/back-to-redirect-with-frame.php [ Failure ]
   http/tests/navigation/cross-origin-fragment-navigation-is-async.html [ Failure ]
   http/tests/navigation/forward-to-fragment-fires-onload.html [ Timeout ]
   http/tests/navigation/response204.html [ Timeout ]
@@ -150,7 +155,6 @@
   http/tests/navigation/scrollstate-after-location-reload.html [ Timeout ]
 
 # Untriaged security
-  http/tests/security/frame-loading-via-document-write.html [ Failure ]
   http/tests/security/isolatedWorld/bypass-main-world-csp-iframes.html [ Failure ]
 
 # Untriaged other
@@ -169,8 +173,6 @@
   http/tests/misc/window-dot-stop.html [ Failure ]
   http/tests/misc/window-open-then-write.html [ Timeout ]
   imported/wpt/html/semantics/embedded-content/the-object-element/object-attributes.html [ Failure ]
-  imported/wpt/shadow-dom/untriaged/html-elements-in-shadow-trees/html-forms/test-003.html [ Failure ]
-  mhtml/multi_frames_contentid.mht [ Timeout Failure ]
   plugins/object-onfocus-mutation-crash.html [ Timeout ]
   svg/custom/anchor-on-use.svg [ Failure ]
   svg/dynamic-updates/SVGAElement-dom-href-attr.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
index 74ca9aa..9d84010 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -302,8 +302,8 @@
 compositing/masks/masked-ancestor.html [ Failure ]
 compositing/masks/multiple-masks.html [ Failure ]
 compositing/masks/simple-composited-mask.html [ Failure ]
-compositing/overflow-trumps-transform-style.html [ Failure ]
 compositing/overflow/accelerated-overflow-scroll-should-not-affect-perspective.html [ Failure ]
+compositing/overflow/accelerated-scrolling-with-clip-path-text.html [ Failure ]
 compositing/overflow/accelerated-scrolling-with-clip-path.html [ Failure ]
 compositing/overflow/ancestor-with-clip-path.html [ Failure ]
 compositing/overflow/avoid-ancestor-clip-for-scroll-children.html [ Failure ]
@@ -326,8 +326,6 @@
 compositing/overflow/overflow-scaled-descendant-overlapping.html [ Crash Timeout ]
 compositing/overflow/overflow-scroll-with-pointer-events-toggle.html [ Failure ]
 compositing/overflow/overflow-scrollbar-layers.html [ Failure ]
-compositing/overflow/reflected-overlay-scrollbars-should-appear-without-compositing.html [ Crash ]
-compositing/overflow/reflected-overlay-scrollbars-should-respect-ancestor-clip.html [ Crash ]
 compositing/overflow/reparented-scrollbars-non-sc-anc.html [ Failure ]
 compositing/overflow/resize-painting.html [ Failure ]
 compositing/overflow/scroll-ancestor-update.html [ Failure ]
@@ -340,48 +338,40 @@
 compositing/overflow/selection-gaps-after-removing-scrolling-contents.html [ Failure ]
 compositing/overflow/selection-gaps-toggling-with-scrolling-contents.html [ Failure ]
 compositing/overflow/selection-gaps-toggling.html [ Failure ]
-compositing/overflow/text-color-change.html [ Failure ]
 compositing/overflow/text-match-highlight.html [ Failure ]
 compositing/overflow/textarea-scroll-touch.html [ Failure ]
 compositing/overflow/universal-accelerated-overflow-scroll.html [ Failure ]
-compositing/overflow/update-widget-positions-on-nested-frames-and-scrollers.html [ Crash ]
 compositing/overflow/updating-scrolling-container-and-content.html [ Failure ]
-compositing/overflow/updating-scrolling-container.html [ Failure ]
 compositing/overflow/updating-scrolling-content.html [ Failure ]
-compositing/overlap-blending/reflection-opacity-huge.html [ Crash ]
 compositing/overlap-test-with-filter.html [ Failure ]
 compositing/perpendicular-layer-sorting.html [ Failure ]
-compositing/plugins/webplugin-reflection.html [ Crash ]
+compositing/plugins/webplugin-reflection.html [ Failure ]
 compositing/preserve-3d-toggle.html [ Failure ]
-compositing/reflections/animation-inside-reflection.html [ Crash ]
-compositing/reflections/backface-hidden-reflection.html [ Crash ]
-compositing/reflections/become-simple-composited-reflection.html [ Crash ]
-compositing/reflections/compositing-change-inside-reflection.html [ Crash ]
-compositing/reflections/deeply-nested-reflections.html [ Crash ]
-compositing/reflections/empty-reflection-with-mask.html [ Crash ]
-compositing/reflections/enable-disable-compositing-reflection.html [ Crash ]
-compositing/reflections/load-video-in-reflection.html [ Crash ]
-compositing/reflections/masked-reflection-on-composited.html [ Crash ]
-compositing/reflections/nested-reflection-anchor-point.html [ Crash ]
-compositing/reflections/nested-reflection-animated.html [ Crash ]
-compositing/reflections/nested-reflection-mask-change.html [ Crash ]
-compositing/reflections/nested-reflection-on-overflow.html [ Crash ]
-compositing/reflections/nested-reflection-opacity.html [ Crash ]
-compositing/reflections/nested-reflection-size-change.html [ Crash ]
-compositing/reflections/nested-reflection-transformed.html [ Crash ]
-compositing/reflections/nested-reflection-transformed2.html [ Crash ]
-compositing/reflections/nested-reflection-transition.html [ Crash ]
-compositing/reflections/nested-reflection.html [ Crash ]
-compositing/reflections/reflection-in-composited.html [ Crash ]
-compositing/reflections/reflection-on-composited.html [ Crash ]
-compositing/reflections/reflection-opacity.html [ Crash ]
-compositing/reflections/reflection-ordering.html [ Crash ]
-compositing/reflections/reflection-positioning.html [ Crash ]
-compositing/reflections/reflection-positioning2.html [ Crash ]
-compositing/reflections/remove-add-reflection.html [ Crash ]
-compositing/reflections/remove-reflection.html [ Crash ]
-compositing/reflections/simple-composited-reflections.html [ Crash ]
-compositing/reflections/transform-inside-reflection.html [ Crash ]
+compositing/reflections/animation-inside-reflection.html [ Failure ]
+compositing/reflections/compositing-change-inside-reflection.html [ Failure ]
+compositing/reflections/deeply-nested-reflections.html [ Failure ]
+compositing/reflections/enable-disable-compositing-reflection.html [ Failure ]
+compositing/reflections/load-video-in-reflection.html [ Failure ]
+compositing/reflections/masked-reflection-on-composited.html [ Failure ]
+compositing/reflections/nested-reflection-anchor-point.html [ Failure ]
+compositing/reflections/nested-reflection-animated.html [ Failure ]
+compositing/reflections/nested-reflection-mask-change.html [ Failure ]
+compositing/reflections/nested-reflection-on-overflow.html [ Failure ]
+compositing/reflections/nested-reflection-opacity.html [ Failure ]
+compositing/reflections/nested-reflection-size-change.html [ Failure ]
+compositing/reflections/nested-reflection-transformed.html [ Failure ]
+compositing/reflections/nested-reflection-transformed2.html [ Failure ]
+compositing/reflections/nested-reflection-transition.html [ Failure ]
+compositing/reflections/nested-reflection.html [ Failure ]
+compositing/reflections/reflection-in-composited.html [ Failure ]
+compositing/reflections/reflection-on-composited.html [ Failure ]
+compositing/reflections/reflection-opacity.html [ Failure ]
+compositing/reflections/reflection-ordering.html [ Failure ]
+compositing/reflections/reflection-positioning.html [ Failure ]
+compositing/reflections/reflection-positioning2.html [ Failure ]
+compositing/reflections/remove-add-reflection.html [ Failure ]
+compositing/reflections/simple-composited-reflections.html [ Failure ]
+compositing/reflections/transform-inside-reflection.html [ Failure ]
 compositing/render-surface-alpha-blending.html [ Failure ]
 compositing/rendering-contexts.html [ Failure ]
 compositing/repaint/become-overlay-composited-layer.html [ Failure ]
@@ -465,16 +455,13 @@
 compositing/squashing/squash-transform-repainting-child.html [ Failure ]
 compositing/squashing/squash-transform-repainting-transformed-child.html [ Failure ]
 compositing/squashing/squash-transform.html [ Failure ]
-compositing/squashing/squash-with-ancestor-reflection.html [ Crash ]
 compositing/squashing/squashed-layer-loses-graphicslayer.html [ Failure ]
 compositing/squashing/squashed-repaints.html [ Failure ]
 compositing/squashing/squashing-inside-perspective.html [ Failure ]
 compositing/squashing/squashing-inside-preserve-3d-element.html [ Failure ]
 compositing/squashing/squashing-print.html [ Crash Timeout ]
-compositing/squashing/squashing-reflection-disallowed.html [ Crash ]
 compositing/squashing/squashing-sparsity-heuristic.html [ Failure ]
 compositing/squashing/tricky-element-removal-crash.html [ Failure ]
-compositing/squashing/vertical-writing-mode-squashed.html [ Failure ]
 compositing/tiled-layers-hidpi.html [ Failure ]
 compositing/transitions/scale-transition-no-start.html [ Failure ]
 compositing/update-paint-phases.html [ Failure ]
@@ -491,13 +478,12 @@
 compositing/visibility/visibility-simple-webgl-layer.html [ Failure ]
 compositing/webgl/webgl-no-alpha.html [ Failure ]
 compositing/webgl/webgl-nonpremultiplied-blend.html [ Failure ]
-compositing/webgl/webgl-reflection.html [ Crash ]
+compositing/webgl/webgl-reflection.html [ Failure ]
 compositing/webgl/webgl-repaint.html [ Failure ]
 compositing/webgl/webgl-with-accelerated-background-color.html [ Failure ]
 compositing/will-change/composited-layers.html [ Failure ]
 compositing/will-change/containing-block-added.html [ Failure ]
 compositing/will-change/containing-block-removed.html [ Failure ]
-compositing/writing-mode-rl-overflow.html [ Failure ]
 fast/backgrounds/animated-svg-as-mask.html [ Failure ]
 fast/backgrounds/background-inherit-color-bug.html [ Failure ]
 fast/backgrounds/background-leakage-transforms.html [ Failure ]
@@ -1703,44 +1689,22 @@
 svg/animations/animateMotion-accumulate-2a.svg [ Failure ]
 svg/animations/animateMotion-accumulate-2b.svg [ Failure ]
 svg/animations/filter-primitive-region.html [ Failure ]
-svg/animations/mozilla/animateMotion-by-1.svg [ Failure ]
-svg/animations/mozilla/animateMotion-from-to-1.svg [ Failure ]
-svg/as-background-image/animated-svg-as-background.html [ Crash ]
 svg/as-background-image/svg-transformed-background.html [ Failure ]
 svg/as-background-image/tiled-background-image.html [ Crash Timeout ]
-svg/as-image/animated-svg-as-image-visited-link.html [ Crash ]
 svg/as-image/default-font-settings-external.html [ Failure ]
 svg/as-image/default-font-size.html [ Failure ]
 svg/as-image/default-monospace-font.html [ Failure ]
 svg/as-image/default-sans-serif-font.html [ Failure ]
-svg/as-image/image-change-with-equal-sizes.html [ Crash ]
 svg/as-image/image-preserveAspectRatio-all.svg [ Failure ]
 svg/as-image/image-respects-pageScaleFactor.html [ Crash Timeout ]
 svg/as-image/img-preserveAspectRatio-support-1.html [ Failure ]
 svg/as-image/img-preserveAspectRatio-support-2.html [ Failure ]
-svg/as-image/smil-usecounter-in-css-image.html [ Crash ]
-svg/as-image/svg-as-image-canvas.html [ Crash ]
-svg/as-image/svg-as-image-intrinsic-size.html [ Crash ]
 svg/as-image/svg-as-image-object-fit-cover.html [ Failure ]
-svg/as-image/svg-as-image-with-relative-size.html [ Failure ]
-svg/as-image/svg-canvas-link-not-colored.html [ Crash ]
-svg/as-image/svg-canvas-not-tainted.html [ Crash ]
-svg/as-image/svg-canvas-svg-with-image-with-link-tainted.html [ Crash ]
-svg/as-image/svg-canvas-xhtml-tainted.html [ Crash ]
-svg/as-image/svg-image-leak-cached-data.html [ Crash ]
-svg/as-image/svg-image-with-css-animation.html [ Crash ]
-svg/as-image/svg-image-with-data-uri.html [ Failure ]
-svg/as-image/svg-image-with-nested-data-uri.html [ Crash Failure ]
 svg/as-image/svgview-references.html [ Failure ]
-svg/as-list-image/svg-list-image-intrinsic-size-zoom.html [ Crash ]
-svg/as-object/deep-nested-embedded-svg-size-changes-no-layout-triggers-1.html [ Failure ]
-svg/as-object/deep-nested-embedded-svg-size-changes-no-layout-triggers-2.html [ Failure ]
 svg/as-object/embedded-svg-immediate-offsetWidth-query.html [ Failure ]
-svg/as-object/embedded-svg-size-changes-no-layout-triggers.html [ Failure ]
 svg/as-object/embedded-svg-size-changes.html [ Failure ]
 svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-1.html [ Failure ]
 svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-2.html [ Failure ]
-svg/as-object/nested-embedded-svg-size-changes.html [ Failure ]
 svg/as-object/object-box-sizing-no-width-height.html [ Failure ]
 svg/batik/filters/feTile.svg [ Failure ]
 svg/batik/filters/filterRegions.svg [ Failure ]
@@ -1751,7 +1715,7 @@
 svg/batik/paints/patternRegions-positioned-objects.svg [ Failure ]
 svg/batik/paints/patternRegions.svg [ Failure ]
 svg/batik/text/longTextOnPath.svg [ Failure Timeout ]
-svg/batik/text/smallFonts.svg [ Failure ]
+svg/batik/text/smallFonts.svg [ Failure Timeout ]
 svg/batik/text/textAnchor.svg [ Failure ]
 svg/batik/text/textAnchor2.svg [ Failure ]
 svg/batik/text/textAnchor3.svg [ Failure ]
@@ -1778,14 +1742,7 @@
 svg/batik/text/verticalText.svg [ Failure ]
 svg/batik/text/verticalTextOnPath.svg [ Failure ]
 svg/batik/text/xmlSpace.svg [ Failure ]
-svg/canvas/canvas-default-object-sizing.html [ Crash ]
-svg/canvas/canvas-draw-image-globalalpha.html [ Crash ]
-svg/canvas/canvas-draw-image-size.html [ Crash ]
-svg/canvas/canvas-draw-image-svg-fragment.html [ Crash ]
-svg/canvas/canvas-draw-pattern-size.html [ Crash ]
 svg/canvas/canvas-draw-pattern-svg-fragment.html [ Crash Timeout ]
-svg/canvas/canvas-pattern-svg.html [ Crash ]
-svg/canvas/image-svg-intrinsic-size.html [ Crash ]
 svg/carto.net/button.svg [ Failure ]
 svg/carto.net/colourpicker.svg [ Failure ]
 svg/carto.net/combobox.svg [ Failure ]
@@ -1844,7 +1801,6 @@
 svg/clip-path/nested-clip-in-mask-path-based-clipping.svg [ Failure ]
 svg/clip-path/opacity-assertion.svg [ Failure ]
 svg/clip-path/transformed-clip.svg [ Failure ]
-svg/css/css-box-min-width.html [ Failure ]
 svg/css/path-gradient-stroke-shadow.svg [ Failure ]
 svg/css/rect-gradient-stroke-shadow.svg [ Failure ]
 svg/css/svg-resource-fragment-identifier-img-src.html [ Crash Timeout ]
@@ -1899,7 +1855,6 @@
 svg/custom/font-face-cascade-order.svg [ Failure ]
 svg/custom/foreign-object-skew.svg [ Failure ]
 svg/custom/foreignObject-crash-on-hover.xml [ Failure ]
-svg/custom/foreignObject-font-size-on-zoom.html [ Failure ]
 svg/custom/fractional-rects.svg [ Failure ]
 svg/custom/getscreenctm-in-scrollable-div-area-nested.xhtml [ Failure ]
 svg/custom/getscreenctm-in-scrollable-div-area.xhtml [ Failure ]
@@ -1915,15 +1870,11 @@
 svg/custom/grayscale-gradient-mask.svg [ Failure ]
 svg/custom/group-opacity.svg [ Failure ]
 svg/custom/hit-test-unclosed-subpaths.svg [ Failure ]
-svg/custom/hit-test-with-br.xhtml [ Failure ]
 svg/custom/image-parent-translation.xhtml [ Failure ]
-svg/custom/image-rescale.svg [ Failure ]
 svg/custom/image-small-width-height.svg [ Failure ]
-svg/custom/image-with-aspect-ratio-stretch.svg [ Failure ]
 svg/custom/image-with-preserveAspectRatio-none.html [ Failure ]
 svg/custom/image-with-transform-clip-filter.svg [ Failure ]
 svg/custom/inline-svg-in-xhtml.xml [ Failure ]
-svg/custom/intersection-list-transforms.svg [ Failure ]
 svg/custom/invalid-css.svg [ Failure ]
 svg/custom/invalid-fill-hex.svg [ Failure ]
 svg/custom/invalid-gradient-with-xlink.svg [ Failure ]
@@ -1941,13 +1892,11 @@
 svg/custom/js-late-mask-creation.svg [ Failure ]
 svg/custom/js-late-pattern-and-object-creation.svg [ Failure ]
 svg/custom/js-late-pattern-creation.svg [ Failure ]
-svg/custom/js-repaint-rect-on-path-with-stroke.svg [ Failure ]
 svg/custom/js-update-bounce.svg [ Failure ]
 svg/custom/js-update-container.svg [ Failure ]
 svg/custom/js-update-stop-linked-gradient.svg [ Failure ]
 svg/custom/junk-data.svg [ Failure ]
 svg/custom/lazy-attach-use.html [ Failure ]
-svg/custom/linking-a-03-b-all.svg [ Failure ]
 svg/custom/linking-a-03-b-preserveAspectRatio.svg [ Failure ]
 svg/custom/linking-a-03-b-transform.svg [ Failure ]
 svg/custom/linking-a-03-b-viewBox-transform.svg [ Failure ]
@@ -1979,12 +1928,10 @@
 svg/custom/mouse-move-on-svg-container.xhtml [ Failure ]
 svg/custom/mouse-move-on-svg-root-standalone.svg [ Failure ]
 svg/custom/mouse-move-on-svg-root.xhtml [ Failure ]
-svg/custom/no-fixed-in-svg-assert.html [ Crash ]
 svg/custom/no-inherited-dashed-stroke.xhtml [ Failure ]
 svg/custom/non-circular-marker-reference.svg [ Failure ]
 svg/custom/non-opaque-filters.svg [ Failure ]
 svg/custom/non-scaling-stroke.svg [ Failure ]
-svg/custom/object-sizing-no-width-height-change-content-box-size.xhtml [ Failure ]
 svg/custom/object-sizing-no-width-height.xhtml [ Failure ]
 svg/custom/object-sizing.xhtml [ Failure ]
 svg/custom/path-bad-data.svg [ Failure ]
@@ -1994,7 +1941,6 @@
 svg/custom/pattern-cycle-detection.svg [ Failure ]
 svg/custom/pattern-deep-referencing.svg [ Failure ]
 svg/custom/pattern-incorrect-tiling.svg [ Failure ]
-svg/custom/pattern-no-pixelation.svg [ Failure ]
 svg/custom/pattern-rotate-gaps.svg [ Failure ]
 svg/custom/pattern-rotate.svg [ Failure ]
 svg/custom/pattern-scaling.svg [ Failure ]
@@ -2003,7 +1949,7 @@
 svg/custom/pointer-events-image-css-transform.svg [ Failure ]
 svg/custom/pointer-events-image.svg [ Failure ]
 svg/custom/pointer-events-path.svg [ Failure ]
-svg/custom/pointer-events-text-css-transform.svg [ Crash ]
+svg/custom/pointer-events-text-css-transform.svg [ Crash Timeout ]
 svg/custom/pointer-events-text.svg [ Failure ]
 svg/custom/preserve-aspect-ratio-syntax.svg [ Failure ]
 svg/custom/recursive-clippath.svg [ Failure ]
@@ -2012,16 +1958,12 @@
 svg/custom/recursive-mask.svg [ Failure ]
 svg/custom/recursive-pattern.svg [ Failure ]
 svg/custom/relative-sized-content-with-resources.xhtml [ Failure ]
-svg/custom/relative-sized-content.xhtml [ Failure ]
-svg/custom/relative-sized-deep-shadow-tree-content.xhtml [ Failure ]
-svg/custom/relative-sized-image.xhtml [ Failure ]
 svg/custom/relative-sized-inner-svg.xhtml [ Failure ]
-svg/custom/relative-sized-shadow-tree-content-with-symbol.xhtml [ Failure ]
-svg/custom/relative-sized-shadow-tree-content.xhtml [ Failure ]
 svg/custom/relative-sized-use-on-symbol.xhtml [ Failure ]
 svg/custom/relative-sized-use-without-attributes-on-symbol.xhtml [ Failure ]
 svg/custom/repaint-moving-svg-and-div.xhtml [ Failure ]
 svg/custom/repaint-shadow.svg [ Failure ]
+svg/custom/resource-client-removal.svg [ Failure ]
 svg/custom/resource-invalidate-on-target-update.svg [ Failure ]
 svg/custom/resources-css-scaled.html [ Failure ]
 svg/custom/root-container-opacity-clip-viewBox.svg [ Failure ]
@@ -2037,18 +1979,10 @@
 svg/custom/stroked-pattern.svg [ Failure ]
 svg/custom/style-attribute-font-size.svg [ Failure ]
 svg/custom/subpaths-moveto-only-rendering.svg [ Failure ]
-svg/custom/svg-float-border-padding.xml [ Failure ]
-svg/custom/svg-image-container-size.html [ Failure ]
-svg/custom/svg-image-initial-size.html [ Failure ]
 svg/custom/svg-image-par-none-no-intrinsic-size.html [ Failure ]
-svg/custom/svg-image-par-resize.html [ Crash ]
 svg/custom/svg-overflow-types.svg [ Failure ]
-svg/custom/svg-root-padding-border-margin.html [ Failure ]
 svg/custom/SVGMatrix-interface.svg [ Failure ]
-svg/custom/SVGNumber-interface.svg [ Failure ]
-svg/custom/SVGPoint-interface.svg [ Failure ]
 svg/custom/SVGPoint-matrixTransform.svg [ Failure ]
-svg/custom/SVGRect-interface.svg [ Failure ]
 svg/custom/text-clip.svg [ Failure ]
 svg/custom/text-ctm.svg [ Failure ]
 svg/custom/text-decoration-visibility.svg [ Failure ]
@@ -2069,14 +2003,12 @@
 svg/custom/text-x-override-in-tspan-child.svg [ Failure ]
 svg/custom/text-xy-updates-SVGList.xhtml [ Failure ]
 svg/custom/text-xy-updates.svg [ Failure ]
-svg/custom/transform-scale-parse.svg [ Failure ]
 svg/custom/transformed-outlines.svg [ Failure ]
 svg/custom/transformed-pattern-clamp-svg-root.svg [ Failure ]
 svg/custom/transformed-text-pattern.html [ Failure ]
 svg/custom/transformedMaskFails.svg [ Failure ]
 svg/custom/use-attribute-invalidations.html [ Failure ]
 svg/custom/use-clipped-hit.svg [ Failure ]
-svg/custom/use-clipped-transform.svg [ Failure ]
 svg/custom/use-css-no-effect-on-shadow-tree.svg [ Failure ]
 svg/custom/use-detach.svg [ Failure ]
 svg/custom/use-disappears-after-style-update.svg [ Failure ]
@@ -2084,18 +2016,12 @@
 svg/custom/use-event-handler-on-referenced-element.svg [ Failure ]
 svg/custom/use-event-handler-on-use-element.svg [ Failure ]
 svg/custom/use-events-crash.svg [ Failure ]
-svg/custom/use-extern-href.svg [ Failure ]
 svg/custom/use-font-face-crash.svg [ Failure ]
 svg/custom/use-forward-refs.svg [ Failure ]
-svg/custom/use-href-null-ns-precedence-dynamic.html [ Failure ]
-svg/custom/use-image-in-g.svg [ Failure ]
-svg/custom/use-in-symbol-with-offset.svg [ Failure ]
 svg/custom/use-modify-container-in-target.svg [ Failure ]
 svg/custom/use-modify-target-container.svg [ Failure ]
 svg/custom/use-modify-target-symbol.svg [ Failure ]
-svg/custom/use-nested-sibling-symbols.html [ Failure ]
 svg/custom/use-nested-transform.svg [ Failure ]
-svg/custom/use-nested.svg [ Failure ]
 svg/custom/use-on-clip-path-with-transformation.svg [ Failure ]
 svg/custom/use-on-disallowed-foreign-object-1.svg [ Failure ]
 svg/custom/use-on-disallowed-foreign-object-2.svg [ Failure ]
@@ -2103,8 +2029,6 @@
 svg/custom/use-on-disallowed-foreign-object-4.svg [ Failure ]
 svg/custom/use-on-disallowed-foreign-object-5.svg [ Failure ]
 svg/custom/use-on-disallowed-foreign-object-6.svg [ Failure ]
-svg/custom/use-on-g-containing-foreignObject-and-image.svg [ Failure ]
-svg/custom/use-on-g-containing-symbol.html [ Failure ]
 svg/custom/use-on-g-containing-use.svg [ Failure ]
 svg/custom/use-on-g.svg [ Failure ]
 svg/custom/use-on-non-svg-namespaced-element.svg [ Failure ]
@@ -2121,13 +2045,6 @@
 svg/custom/use-recursion-4.svg [ Failure ]
 svg/custom/use-referencing-nonexisting-symbol.svg [ Failure ]
 svg/custom/use-setAttribute-crash.svg [ Failure ]
-svg/custom/use-symbol-overflow.svg [ Failure ]
-svg/custom/use-transfer-width-height-properties-to-svg.svg [ Failure ]
-svg/custom/use-transfer-width-height-properties-to-svg1.svg [ Failure ]
-svg/custom/use-transfer-width-height-properties-to-svg2.svg [ Failure ]
-svg/custom/use-transfer-width-height-properties-to-symbol.svg [ Failure ]
-svg/custom/use-transfer-width-height-properties-to-symbol1.svg [ Failure ]
-svg/custom/use-transfer-width-height-properties-to-symbol2.svg [ Failure ]
 svg/custom/use-transform.svg [ Failure ]
 svg/custom/viewBox-hit.svg [ Failure ]
 svg/custom/viewbox-syntax.svg [ Failure ]
@@ -2506,6 +2423,7 @@
 svg/filters/filter-hidden-content.svg [ Failure ]
 svg/filters/filter-huge-clamping.svg [ Failure ]
 svg/filters/filter-on-filter-for-text.svg [ Failure ]
+svg/filters/filter-on-svg-root-w-layer.html [ Failure ]
 svg/filters/filter-on-tspan.svg [ Failure ]
 svg/filters/filter-placement-issue.svg [ Failure ]
 svg/filters/filter-refresh.svg [ Failure ]
@@ -2522,6 +2440,9 @@
 svg/filters/subRegion-in-userSpace.svg [ Failure ]
 svg/filters/subRegion-one-effect.svg [ Failure ]
 svg/filters/subRegion-two-effects.svg [ Failure ]
+svg/filters/svg-element-invalid-filter.html [ Failure ]
+svg/filters/svg-filter-child-box-reflect.html [ Failure ]
+svg/filters/svg-filter-root-box-reflect.html [ Failure ]
 svg/foreignObject/clip.html [ Failure ]
 svg/foreignObject/filter-repaint.svg [ Failure ]
 svg/foreignObject/filter.html [ Failure ]
@@ -2529,7 +2450,6 @@
 svg/foreignObject/svg-document-as-direct-child.svg [ Failure ]
 svg/foreignObject/svg-document-in-html-document.svg [ Failure ]
 svg/foreignObject/transformed-text-invalidation.html [ Failure ]
-svg/hittest/singular-transform-3.html [ Crash ]
 svg/hixie/data-types/001.xml [ Failure ]
 svg/hixie/dynamic/002.xml [ Failure ]
 svg/hixie/error/002.xml [ Failure ]
@@ -2552,6 +2472,7 @@
 svg/hixie/perf/003.xml [ Failure ]
 svg/hixie/perf/004.xml [ Failure ]
 svg/hixie/perf/005.xml [ Failure ]
+svg/hixie/perf/006.xml [ Failure ]
 svg/hixie/perf/007.xml [ Failure ]
 svg/hixie/text/001.xml [ Crash Timeout ]
 svg/hixie/text/002.xml [ Failure ]
@@ -2561,12 +2482,10 @@
 svg/hixie/viewbox/preserveAspectRatio/002.xml [ Failure ]
 svg/in-html/circle.html [ Failure ]
 svg/in-html/overflow-repaint.html [ Failure ]
-svg/markers/marker-orientation-02.svg [ Failure ]
 svg/markers/marker-orientation-minus-one.html [ Failure ]
 svg/masking/mask-type-alpha.svg [ Failure ]
 svg/masking/mask-type-luminance.svg [ Failure ]
 svg/masking/mask-type-not-set.svg [ Failure ]
-svg/overflow/overflow-on-foreignObject.svg [ Failure ]
 svg/overflow/overflow-on-inner-svg-element-defaults.svg [ Failure ]
 svg/overflow/overflow-on-inner-svg-element.svg [ Failure ]
 svg/overflow/overflow-on-outermost-svg-element-defaults.svg [ Failure ]
@@ -2578,10 +2497,6 @@
 svg/overflow/overflow-on-outermost-svg-element-in-xhtml-scroll.xhtml [ Failure ]
 svg/overflow/overflow-x-hidden-on-outermost-svg-element.svg [ Failure ]
 svg/overflow/overflow-y-hidden-on-outermost-svg-element.svg [ Failure ]
-svg/parser/svg-parser-argument-whitespace.html [ Failure ]
-svg/repaint/buffered-rendering-dynamic-image.html [ Crash ]
-svg/repaint/buffered-rendering-static-image.html [ Crash ]
-svg/repaint/container-repaint.svg [ Failure ]
 svg/repaint/filter-child-repaint.svg [ Failure ]
 svg/repaint/filter-repaint.svg [ Failure ]
 svg/repaint/focus-element.html [ Failure ]
@@ -2600,7 +2515,6 @@
 svg/repaint/text-pattern-update.html [ Failure ]
 svg/repaint/tspan-pattern-update.html [ Failure ]
 svg/stroke/non-scaling-stroke-gradient-text.html [ Failure ]
-svg/stroke/non-scaling-stroke-paintserver-same-as-fill.html [ Failure ]
 svg/stroke/non-scaling-stroke-text-decoration.html [ Failure ]
 svg/stroke/non-scaling-stroke-text.html [ Failure ]
 svg/stroke/non-scaling-stroke-zero-length-subpath-linecaps.html [ Failure ]
@@ -2624,7 +2538,6 @@
 svg/text/ligature-queries.html [ Failure ]
 svg/text/modify-text-node-in-tspan.html [ Failure ]
 svg/text/non-bmp-positioning-lists.svg [ Failure ]
-svg/text/non-invertible-matrix-text.svg [ Failure ]
 svg/text/obb-paintserver.html [ Failure ]
 svg/text/remove-text-node-from-tspan.html [ Failure ]
 svg/text/remove-tspan-from-text.html [ Failure ]
@@ -2702,14 +2615,12 @@
 svg/text/tspan-dynamic-positioning.svg [ Failure ]
 svg/text/tspan-multiple-outline.svg [ Failure ]
 svg/transforms/animated-path-inside-transformed-html.xhtml [ Failure ]
-svg/transforms/change-transform-origin-css.xhtml [ Failure ]
-svg/transforms/change-transform-origin-presentation-attribute.xhtml [ Failure ]
-svg/transforms/change-transform-to-none-text.html [ Crash ]
+svg/transforms/change-transform-to-none-text.html [ Failure ]
 svg/transforms/svg-css-transforms-clip-path.xhtml [ Failure ]
 svg/transforms/svg-css-transforms.xhtml [ Failure ]
 svg/transforms/text-with-mask-with-svg-transform.svg [ Failure ]
 svg/transforms/text-with-pattern-inside-transformed-html.xhtml [ Failure ]
-svg/transforms/transform-origin-css-property.xhtml [ Failure ]
+svg/transforms/text-with-pattern-with-svg-transform.svg [ Failure ]
 svg/transforms/transformed-text-fill-gradient.html [ Failure ]
 svg/transforms/transformed-text-fill-pattern.html [ Failure ]
 svg/transforms/will-change-transform.svg [ Failure ]
@@ -2863,6 +2774,7 @@
 svg/W3C-SVG-1.1/coords-trans-05-t.svg [ Failure ]
 svg/W3C-SVG-1.1/coords-trans-06-t.svg [ Failure ]
 svg/W3C-SVG-1.1/coords-units-01-b.svg [ Failure ]
+svg/W3C-SVG-1.1/coords-units-02-b.svg [ Failure ]
 svg/W3C-SVG-1.1/coords-viewattr-01-b.svg [ Failure ]
 svg/W3C-SVG-1.1/coords-viewattr-02-b.svg [ Failure ]
 svg/W3C-SVG-1.1/coords-viewattr-03-b.svg [ Failure ]
@@ -3055,7 +2967,6 @@
 svg/zoom/page/absolute-sized-document-no-scrollbars.svg [ Failure ]
 svg/zoom/page/absolute-sized-document-scrollbars.svg [ Failure ]
 svg/zoom/page/relative-sized-document-scrollbars.svg [ Failure ]
-svg/zoom/page/zoom-background-image-tiled.html [ Crash ]
 svg/zoom/page/zoom-clip-path.html [ Failure ]
 svg/zoom/page/zoom-coords-viewattr-01-b.svg [ Failure ]
 svg/zoom/page/zoom-foreign-content.svg [ Failure ]
@@ -3065,10 +2976,7 @@
 svg/zoom/page/zoom-img-preserveAspectRatio-support-1.html [ Crash Failure Timeout ]
 svg/zoom/page/zoom-mask-with-percentages.svg [ Failure ]
 svg/zoom/page/zoom-replaced-intrinsic-ratio-001.htm [ Failure ]
-svg/zoom/page/zoom-svg-as-background-with-relative-size-and-viewBox.html [ Crash ]
-svg/zoom/page/zoom-svg-as-image.html [ Crash ]
 svg/zoom/page/zoom-svg-as-object.html [ Failure ]
-svg/zoom/page/zoom-svg-as-relative-image.html [ Crash ]
 svg/zoom/page/zoom-svg-float-border-padding.xml [ Failure ]
 svg/zoom/page/zoom-svg-through-object-with-absolute-size-2.xhtml [ Failure ]
 svg/zoom/page/zoom-svg-through-object-with-absolute-size.xhtml [ Failure ]
@@ -3077,7 +2985,6 @@
 svg/zoom/page/zoom-svg-through-object-with-override-size.html [ Failure ]
 svg/zoom/page/zoom-svg-through-object-with-percentage-size.xhtml [ Failure ]
 svg/zoom/text/zoom-coords-viewattr-01-b.svg [ Failure ]
-svg/zoom/text/zoom-em-units.html [ Failure ]
 svg/zoom/text/zoom-foreignObject.svg [ Failure ]
 svg/zoom/text/zoom-hixie-mixed-008.xml [ Failure ]
 svg/zoom/text/zoom-hixie-mixed-009.xml [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests
index 60ec6db..e280da8 100644
--- a/third_party/WebKit/LayoutTests/NeverFixTests
+++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -62,6 +62,7 @@
 
 # Mac does not have menu key.
 [ Mac ] editing/spelling/spelling-on-context-menu-key.html [ WontFix ]
+[ Mac ] fast/events/context-menu-key-shift-f10-modifiers.html [ WontFix ]
 [ Mac ] fast/events/menu-key-context-menu-document.html [ WontFix ]
 [ Mac ] fast/events/menu-key-context-menu.html [ WontFix ]
 [ Mac ] fast/events/menu-key-context-menu-position.html [ WontFix ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 0d0e9b15..2f1c133 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -130,6 +130,8 @@
 crbug.com/410974 virtual/threaded/fast/scroll-behavior/scroll-customization/scrollstate-distribute-to-scroll-chain-descendant.html [ Pass Failure ]
 crbug.com/410974 virtual/threaded/fast/scroll-behavior/scroll-customization/touch-scroll-customization.html [ Pass Failure ]
 
+crbug.com/620618 svg/custom/alignment-baseline-modes.svg [ NeedsRebaseline ]
+
 crbug.com/381730 http/tests/navigation/pending-location-change-assert.html [ Failure Pass ]
 crbug.com/518883 crbug.com/390452 http/tests/security/isolatedWorld/media-query-wrapper-leaks.html [ Failure Pass Timeout ]
 crbug.com/518987 http/tests/xmlhttprequest/navigation-abort-detaches-frame.html [ Pass Timeout ]
@@ -850,7 +852,8 @@
 
 crbug.com/600087 virtual/gpu-rasterization/fast/images/pixel-crack-image-background-webkit-transform-scale.html [ Timeout ]
 
-crbug.com/624233 [ Win10 ] virtual/gpu-rasterization/fast/images/color-profile-background-clip-text.html [ Failure ]
+# Flaky on Win10 and Win7
+crbug.com/624233 [ Win ] virtual/gpu-rasterization/fast/images/color-profile-background-clip-text.html [ Failure ]
 
 crbug.com/385014 crbug.com/410145 accessibility/canvas-fallback-content-2.html [ Pass Failure Timeout ]
 
@@ -905,77 +908,58 @@
 
 crbug.com/482229 compositing/layer-creation/fixed-position-under-transform.html [ Failure ]
 
-crbug.com/613672 [ Mac ] imported/wpt/pointerevents/pointerevent_change-touch-action-onpointerdown_touch-manual.html [ Skip ]
+
 # These fail in the leak detector: http://crbug.com/612924#c4
-crbug.com/612924 [ Linux ] imported/wpt/pointerevents/pointerevent_change-touch-action-onpointerdown_touch-manual.html [ Skip ]
+crbug.com/619060 [ Linux ] imported/wpt/pointerevents/pointerevent_change-touch-action-onpointerdown_touch-manual.html [ Skip ]
+crbug.com/619060 [ Linux ] imported/wpt/pointerevents/pointerevent_pointerout_after_pointercancel_touch-manual.html [ Skip ]
 
-# Probably needs a rebaseline, marking as failing for now: http://crbug.com/612924#c6
-# Feature owner needs to investigate.
-crbug.com/471824 imported/wpt/pointerevents/pointerevent_button_attribute_mouse-manual.html  [ Failure Timeout ]
+# The commented lines here for Mac is due to the fact that there is a more
+# generic skip rule in the next block of rules. However, when they get fixed
+# these should be uncommented as there is no touch support on Mac.
+crbug.com/613672 [ Mac ] imported/wpt/pointerevents/pointerevent_change-touch-action-onpointerdown_touch-manual.html [ Skip ]
+# crbug.com/613672 [ Mac ] imported/wpt/pointerevents/pointerevent_pointerenter_nohover-manual.html [ Skip ]
+# crbug.com/613672 [ Mac ] imported/wpt/pointerevents/pointerevent_pointerleave_after_pointerup_nohover-manual.html [ Skip ]
+# crbug.com/613672 [ Mac ] imported/wpt/pointerevents/pointerevent_pointerleave_after_pointercancel_touch-manual.html [ Skip ]
+# crbug.com/613672 [ Mac ] imported/wpt/pointerevents/pointerevent_pointercancel_touch-manual.html [ Skip ]
+# crbug.com/613672 [ Mac ] imported/wpt/pointerevents/pointerevent_pointerout_after_pointerup_nohover-manual.html [ Skip ]
+# crbug.com/613672 [ Mac ] imported/wpt/pointerevents/pointerevent_pointertype_touch-manual.html [ Skip ]
+# crbug.com/613672 [ Mac ] imported/wpt/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch-manual.html [ Skip ]
+crbug.com/613672 [ Mac ] imported/wpt/pointerevents/pointerevent_pointerout_after_pointercancel_touch-manual.html [ Skip ]
+# crbug.com/613672 [ Mac ] imported/wpt/pointerevents/pointerevent_pointerleave_touch-manual.html [ Skip ]
 
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_capture_mouse-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_capture_suppressing_mouse-manual.html  [ Skip ]
-crbug.com/471824 imported/wpt/pointerevents/pointerevent_constructor.html  [ Failure ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_gotpointercapture_before_first_pointerevent-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_lostpointercapture_is_first-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointercancel_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerdown-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerenter_does_not_bubble-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerenter-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerenter_nohover-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerleave_after_pointercancel_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerleave_after_pointerup_nohover-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerleave_descendant_over-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerleave_descendants-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerleave_does_not_bubble-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerleave_mouse-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerleave_pen-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerleave_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointermove_isprimary_same_as_pointerdown-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointermove-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointermove_pointertype-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerout_after_pointercancel_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerout_after_pointerup_nohover-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerout-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerout_pen-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerout_received_once-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerover-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointertype_mouse-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointertype_pen-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointertype_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerup_isprimary_same_as_pointerdown-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerup-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_pointerup_pointertype-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_releasepointercapture_invalid_pointerid-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_releasepointercapture_onpointerup_mouse-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_setpointercapture_disconnected-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_setpointercapture_inactive_button_mouse-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_setpointercapture_invalid_pointerid-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_setpointercapture_relatedtarget-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-auto-css_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-button-test_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-illegal.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-keyboard-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-mouse-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-none-css_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-span-test_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-table-test_touch-manual.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_touch-action-verification.html  [ Skip ]
-crbug.com/612924 imported/wpt/pointerevents/pointerevent_properties_mouse-manual.html [ Skip ]
+# These are crashing on Linux debug builds and timing out on Mac as it doesn't support touch
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_pointertype_touch-manual.html [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_pointerout_after_pointerup_nohover-manual.html [ Skip ]
+
+crbug.com/619060 imported/wpt/pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual.html  [ Skip ]
+crbug.com/619060 imported/wpt/pointerevents/pointerevent_lostpointercapture_is_first-manual.html  [ Skip ]
+crbug.com/619060 imported/wpt/pointerevents/pointerevent_pointercancel_touch-manual.html  [ Skip ]
+crbug.com/619060 imported/wpt/pointerevents/pointerevent_pointerenter_nohover-manual.html  [ Skip ]
+crbug.com/619060 imported/wpt/pointerevents/pointerevent_pointerleave_after_pointercancel_touch-manual.html  [ Skip ]
+crbug.com/619060 imported/wpt/pointerevents/pointerevent_pointerleave_after_pointerup_nohover-manual.html  [ Skip ]
+crbug.com/619060 imported/wpt/pointerevents/pointerevent_pointerleave_touch-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_properties_mouse-manual.html [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_touch-action-auto-css_touch-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_touch-action-button-test_touch-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_touch-action-keyboard-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_touch-action-none-css_touch-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y_touch-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_touch-action-span-test_touch-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html  [ Skip ]
+crbug.com/620236 imported/wpt/pointerevents/pointerevent_touch-action-table-test_touch-manual.html  [ Skip ]
+
+crbug.com/583413 imported/wpt/pointerevents/pointerevent_pointerleave_pen-manual.html  [ Failure ]
+
 
 # These testcases are incorrect, mark them as failing until they're fixed in the testsuite.
 # https://lists.w3.org/Archives/Public/www-style/2016Jan/0275.html
@@ -1247,8 +1231,6 @@
 
 crbug.com/399951 http/tests/mime/javascript-mimetype-usecounters.html [ Pass Failure ]
 
-crbug.com/602193 inspector/extensions/extensions-resources.html [ Pass Failure ]
-
 crbug.com/579493 http/tests/security/xss-DENIED-xsl-document-securityOrigin.xml [ Timeout ]
 
 crbug.com/572723 [ Linux Mac10.9 ] inspector/sources/debugger/debugger-disable-enable.html [ Pass Failure Timeout ]
@@ -1260,8 +1242,6 @@
 
 crbug.com/577380 [ Linux Debug ] http/tests/serviceworker/chromium/registration-stress.html [ Failure ]
 
-crbug.com/607101 [ Mac ] fast/text/first-letter-bad-line-boxes-crash.html [ Timeout Pass ]
-
 crbug.com/587136 [ Linux Debug ] http/tests/security/xss-DENIED-cross-origin-stack-overflow.html [ Timeout Pass ]
 
 crbug.com/587593 [ Android ] fast/js/pic/cached-single-entry-transition.html [ Pass Failure ]
@@ -1380,6 +1360,10 @@
 crbug.com/621892 css3/filters/effect-saturate-hw.html [ Pass Failure ]
 crbug.com/621892 css3/filters/effect-sepia-hw.html [ Pass Failure ]
 
+crbug.com/612278 svg/as-background-image/background-repeat.html [ NeedsRebaseline ]
+crbug.com/612278 ietestcenter/css3/bordersbackgrounds/background-size-aspect-ratio.htm [ NeedsRebaseline ]
+crbug.com/612278 fast/backgrounds/background-repeat-with-background-color.html [ NeedsRebaseline ]
+
 crbug.com/622672 [ Mac ] virtual/threaded/fast/scroll-behavior/overflow-interrupted-scroll.html [ Pass Failure ]
 
 crbug.com/624430 [ Win10 ] fast/text/font-features/caps-casemapping.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/css3/background/background-repeat-round-auto1-expected.html b/third_party/WebKit/LayoutTests/css3/background/background-repeat-round-auto1-expected.html
index 80c929d..c1e9397 100644
--- a/third_party/WebKit/LayoutTests/css3/background/background-repeat-round-auto1-expected.html
+++ b/third_party/WebKit/LayoutTests/css3/background/background-repeat-round-auto1-expected.html
@@ -9,7 +9,7 @@
                 padding: 50px;
                 border: 50px solid transparent;
                 background-image: url(resources/circle.png);
-                background-size: 111px 84px;
+                background-size: 111px 88px;
                 background-repeat: repeat;
                 background-origin: border-box;
                 background-clip: border-box;
diff --git a/third_party/WebKit/LayoutTests/css3/background/background-repeat-round-auto2-expected.html b/third_party/WebKit/LayoutTests/css3/background/background-repeat-round-auto2-expected.html
index 10069941..a59eca2 100644
--- a/third_party/WebKit/LayoutTests/css3/background/background-repeat-round-auto2-expected.html
+++ b/third_party/WebKit/LayoutTests/css3/background/background-repeat-round-auto2-expected.html
@@ -9,7 +9,7 @@
                 padding: 50px;
                 border: 50px solid transparent;
                 background-image: url(resources/circle.png);
-                background-size: 123px 100px;
+                background-size: 125px 100px;
                 background-repeat: repeat;
                 background-origin: border-box;
                 background-clip: border-box;
diff --git a/third_party/WebKit/LayoutTests/css3/masking/mask-repeat-round-auto1-expected.html b/third_party/WebKit/LayoutTests/css3/masking/mask-repeat-round-auto1-expected.html
index 70c05ec..6cb020b 100644
--- a/third_party/WebKit/LayoutTests/css3/masking/mask-repeat-round-auto1-expected.html
+++ b/third_party/WebKit/LayoutTests/css3/masking/mask-repeat-round-auto1-expected.html
@@ -14,7 +14,7 @@
                 border: 50px solid blue;
                 padding: 50px;
                 -webkit-mask-image: url(resources/circle.png);
-                -webkit-mask-size: 111px 84px;
+                -webkit-mask-size: 111px 88px;
                 -webkit-mask-repeat: repeat;
                 -webkit-mask-origin: border-box;
                 -webkit-mask-clip: border-box;
diff --git a/third_party/WebKit/LayoutTests/css3/masking/mask-repeat-round-auto2-expected.html b/third_party/WebKit/LayoutTests/css3/masking/mask-repeat-round-auto2-expected.html
index 7d1cf43..e2ef0054 100644
--- a/third_party/WebKit/LayoutTests/css3/masking/mask-repeat-round-auto2-expected.html
+++ b/third_party/WebKit/LayoutTests/css3/masking/mask-repeat-round-auto2-expected.html
@@ -14,7 +14,7 @@
                 border: 50px solid blue;
                 padding: 50px;
                 -webkit-mask-image: url(resources/circle.png);
-                -webkit-mask-size: 123px 100px;
+                -webkit-mask-size: 125px 100px;
                 -webkit-mask-repeat: repeat;
                 -webkit-mask-origin: border-box;
                 -webkit-mask-clip: border-box;
diff --git a/third_party/WebKit/LayoutTests/custom-elements/spec/custom-elements-registry/when_defined.html b/third_party/WebKit/LayoutTests/custom-elements/spec/custom-elements-registry/when_defined.html
index 133c512b..649c339 100644
--- a/third_party/WebKit/LayoutTests/custom-elements/spec/custom-elements-registry/when_defined.html
+++ b/third_party/WebKit/LayoutTests/custom-elements/spec/custom-elements-registry/when_defined.html
@@ -2,6 +2,7 @@
 <title>Custom Elements: CustomElementsRegistry.whenDefined</title>
 <script src="../../../resources/testharness.js"></script>
 <script src="../../../resources/testharnessreport.js"></script>
+<script src="../resources/custom-elements-helpers.js"></script>
 <body>
 <div id="log"></div>
 <script>
@@ -58,6 +59,43 @@
       assert_true(afterDefined, 'promise after defined should be resolved.');
       assert_true(notDefined, 'promise for not defined name should not be resolved.');
     }).catch(reason => { throw reason }));
+
+  // Calling whenDefined() with invalid names should throw "SyntaxError"DOMException
+  // https://html.spec.whatwg.org/multipage/scripting.html#valid-custom-element-name
+  let invalid_names = [
+    'annotation-xml',
+    'color-profile',
+    'font-face',
+    'font-face-src',
+    'font-face-uri',
+    'font-face-format',
+    'font-face-name',
+    'missing-glyph',
+    'div', 'p',
+    'nothtmlbutnohyphen',
+    '-not-initial-a-z', '0not-initial-a-z', 'Not-initial-a-z',
+    'intermediate-UPPERCASE-letters',
+    'bad-\u00b6', 'bad-\u00b8', 'bad-\u00bf', 'bad-\u00d7', 'bad-\u00f7',
+    'bad-\u037e', 'bad-\u037e', 'bad-\u2000', 'bad-\u200e', 'bad-\u203e',
+    'bad-\u2041', 'bad-\u206f', 'bad-\u2190', 'bad-\u2bff', 'bad-\u2ff0',
+    'bad-\u3000', 'bad-\ud800', 'bad-\uf8ff', 'bad-\ufdd0', 'bad-\ufdef',
+    'bad-\ufffe', 'bad-\uffff', 'bad-' + String.fromCodePoint(0xf0000)
+  ];
+
+  invalid_names.forEach((name) => {
+    promise_test((t) => {
+      return create_window_in_test(t)
+      .then((w) => {
+        return promise_rejects_with_dom_exception_syntax_error(w, t, w.customElements.whenDefined(name));
+      });
+    }, 'whenDefined() called with invalid name ' + name + ' should throw "SyntaxError"DOMException');
+  });
+
+  function promise_rejects_with_dom_exception_syntax_error(global_context, test, promise, description) {
+    return promise.then(test.unreached_func("Should have rejected: " + description)).catch(function(e) {
+        assert_throws_dom_exception(global_context, 'SYNTAX_ERR', function () { throw e; })         
+      });
+    }  
 })();
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/custom-elements/spec/define-element.html b/third_party/WebKit/LayoutTests/custom-elements/spec/define-element.html
index 8021adb..3dd01c67 100644
--- a/third_party/WebKit/LayoutTests/custom-elements/spec/define-element.html
+++ b/third_party/WebKit/LayoutTests/custom-elements/spec/define-element.html
@@ -12,19 +12,6 @@
 
 'use strict';
 
-function assert_throws_dom_exception(global_context, code, func, description) {
-  let exception;
-  assert_throws(code, () => {
-    try {
-      func.call(this);
-    } catch(e) {
-      exception = e;
-      throw e;
-    }
-  }, description);
-  assert_true(exception instanceof global_context.DOMException, 'DOMException on the appropriate window');
-}
-
 test_with_window((w) => {
   assert_throws(TypeError.prototype, () => {
     w.customElements.define('a-a', 42);
diff --git a/third_party/WebKit/LayoutTests/custom-elements/spec/resources/custom-elements-helpers.js b/third_party/WebKit/LayoutTests/custom-elements/spec/resources/custom-elements-helpers.js
index 885677d..c4a9e6c 100644
--- a/third_party/WebKit/LayoutTests/custom-elements/spec/resources/custom-elements-helpers.js
+++ b/third_party/WebKit/LayoutTests/custom-elements/spec/resources/custom-elements-helpers.js
@@ -20,3 +20,16 @@
     });
   }, name);
 }
+
+function assert_throws_dom_exception(global_context, code, func, description) {
+  let exception;
+  assert_throws(code, () => {
+    try {
+      func.call(this);
+    } catch(e) {
+      exception = e;
+      throw e;
+    }
+  }, description);
+  assert_true(exception instanceof global_context.DOMException, 'DOMException on the appropriate window');
+}
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/editing/assert_selection.html b/third_party/WebKit/LayoutTests/editing/assert_selection.html
index 324ba8c7..1dc66d6 100644
--- a/third_party/WebKit/LayoutTests/editing/assert_selection.html
+++ b/third_party/WebKit/LayoutTests/editing/assert_selection.html
@@ -2,7 +2,6 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="assert_selection.js"></script>
-<div id="log"></div>
 <script>
 function checked_assert_selection(input, command, output) {
     try {
diff --git a/third_party/WebKit/LayoutTests/editing/assert_selection.js b/third_party/WebKit/LayoutTests/editing/assert_selection.js
index 014aa440..2ee74145 100644
--- a/third_party/WebKit/LayoutTests/editing/assert_selection.js
+++ b/third_party/WebKit/LayoutTests/editing/assert_selection.js
@@ -509,6 +509,8 @@
   constructor(sampleText) {
     /** @const @type {!HTMLIFame} */
     this.iframe_ = document.createElement('iframe');
+    if (!document.body)
+        document.body = document.createElement("body");
     document.body.appendChild(this.iframe_);
     /** @const @type {!HTMLDocument} */
     this.document_ = this.iframe_.contentDocument;
diff --git a/third_party/WebKit/LayoutTests/editing/inserting/insert-div-018.html b/third_party/WebKit/LayoutTests/editing/inserting/insert-div-018.html
index e0db6ad2..580ff06 100644
--- a/third_party/WebKit/LayoutTests/editing/inserting/insert-div-018.html
+++ b/third_party/WebKit/LayoutTests/editing/inserting/insert-div-018.html
@@ -1,44 +1,24 @@
-<html> 
-<head>
-
-<style>
-body {
-    font-size: 24px; 
-}
-.editing { 
-    border: 2px solid red; 
-    padding: 12px; 
-}
-div {
-    border: 2px solid blue; 
-    padding: 12px; 
-}
-
-</style>
-<script src=../editing.js language="JavaScript" type="text/JavaScript" ></script>
-
+<!doctype html>
+<body>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../assert_selection.js"></script>
 <script>
-
-function editingTest() {
-    moveSelectionBackwardByCharacterCommand();
-    insertParagraphCommand();
-}
-
+test(() => {
+    assert_selection(
+        [
+            '<div contenteditable>',
+            '<div style="height:12px"></div>',
+            'bar|<div>baz</div>',
+            '</div>',
+        ].join(''),
+        'insertParagraph',
+        [
+            '<div contenteditable>',
+            '<div style="height:12px"></div>',
+            'bar<div>|<br><div>baz</div></div>',
+            '</div>',
+        ].join(''),
+        'Insert BR befor <div>baz</div>');
+});
 </script>
-
-<title>Editing Test</title> 
-</head> 
-<body contenteditable id="root">
-
-Test inserting paragraphs: should see an empty blue box below "bar"
-
-<div style="border: none; height: 12px"></div>
-
-bar<div class="editing" id="test">baz</div>
-
-<script>
-runEditingTest();
-</script>
-
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/background-repeat-with-background-color.html b/third_party/WebKit/LayoutTests/fast/backgrounds/background-repeat-with-background-color.html
index adc7e1c..ea85b19 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/background-repeat-with-background-color.html
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/background-repeat-with-background-color.html
@@ -4,7 +4,7 @@
 <style>
 div {
   display: inline-block;
-  width: 110px;
+  width: 130px;
   height: 110px;
   margin: 10px;
   background-color: green;
diff --git a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/getComputedStyle-resolved-values-expected.txt b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/getComputedStyle-resolved-values-expected.txt
index f35339b..ea819be 100644
--- a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/getComputedStyle-resolved-values-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/getComputedStyle-resolved-values-expected.txt
@@ -484,6 +484,75 @@
 padding-left: 20px
 
 
+Resolved values for element "ruby" with display "block":
+line-height: normal
+width: 452px
+height: 0px
+top: 0px
+right: -50px
+bottom: 0px
+left: 50px
+margin-top: 0px
+margin-right: 0px
+margin-bottom: 0px
+margin-left: 0px
+padding-top: 0px
+padding-right: 0px
+padding-bottom: 0px
+padding-left: 0px
+
+Resolved values for element "ruby" with display "inline":
+line-height: normal
+width: auto
+height: auto
+top: 0px
+right: auto
+bottom: 0px
+left: 10%
+margin-top: 0px
+margin-right: 0px
+margin-bottom: 0px
+margin-left: 0px
+padding-top: 0px
+padding-right: 0px
+padding-bottom: 0px
+padding-left: 0px
+
+Resolved values for element "ruby" with display "inline-block":
+line-height: normal
+width: 0px
+height: 0px
+top: 0px
+right: -50px
+bottom: 0px
+left: 50px
+margin-top: 0px
+margin-right: 0px
+margin-bottom: 0px
+margin-left: 0px
+padding-top: 0px
+padding-right: 0px
+padding-bottom: 0px
+padding-left: 0px
+
+Resolved values for element "ruby" with display "none":
+line-height: normal
+width: auto
+height: auto
+top: auto
+right: auto
+bottom: auto
+left: 10%
+margin-top: 0px
+margin-right: 0px
+margin-bottom: 0px
+margin-left: 0px
+padding-top: 0px
+padding-right: 0px
+padding-bottom: 0px
+padding-left: 0px
+
+
 Fixed
 Percents
 EMs
@@ -491,3 +560,4 @@
 Mixed
 Relative Positioned
 Absolute Positioned
+
diff --git a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/getComputedStyle-resolved-values.html b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/getComputedStyle-resolved-values.html
index 806dc5d..842b5f9 100644
--- a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/getComputedStyle-resolved-values.html
+++ b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/getComputedStyle-resolved-values.html
@@ -101,6 +101,11 @@
             padding: 20px;
         }
 
+        #ruby {
+            left: 10%;
+            position: relative;
+        }
+
     </style>
     
     <script>
@@ -163,6 +168,7 @@
             test('mixed');
             test('rel_positioned');
             test('abs_positioned');
+            test('ruby');
         }
     </script>
 </head>
@@ -195,5 +201,8 @@
     <div class="outer" id="abs_container">
         <div class="testbox" id="abs_positioned">Absolute Positioned</div>
     </div>
+    <div class="outer">
+        <ruby class="testbox" id="ruby"></ruby>
+    </div>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-html-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-html-crash-expected.txt
new file mode 100644
index 0000000..7d8d089
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-html-crash-expected.txt
@@ -0,0 +1 @@
+This test should not crash
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-html-crash.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-html-crash.html
new file mode 100644
index 0000000..db8ae5f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-html-crash.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<style>
+html {
+    position: sticky;
+}
+</style>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+</script>
+</head>
+<p>This test should not crash</p>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/HTMLDialogElement/dialog-autofocus-multiple-times.html b/third_party/WebKit/LayoutTests/fast/dom/HTMLDialogElement/dialog-autofocus-multiple-times.html
index fa02a005..6abf6df 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/HTMLDialogElement/dialog-autofocus-multiple-times.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/HTMLDialogElement/dialog-autofocus-multiple-times.html
@@ -33,6 +33,9 @@
 <body>
 <button id="outer-button" autofocus></button>
 <dialog id="dlg">
+    <!-- Unfocusable elements with [autofocus] should be ignored. -->
+    <input autofocus disabled>
+    <textarea autofocus hidden></textarea>
     <input id="input1"></input>
     <input id="input2" autofocus></input>
 </dialog>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/HTMLDialogElement/dialog-autofocus.html b/third_party/WebKit/LayoutTests/fast/dom/HTMLDialogElement/dialog-autofocus.html
index ff093fa..421f7f0c2 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/HTMLDialogElement/dialog-autofocus.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/HTMLDialogElement/dialog-autofocus.html
@@ -51,6 +51,9 @@
 <button id="outer-button" autofocus></button>
 <dialog id="dialog">
     <button></button>
+    <!-- Unfocusable elements with [autofocus] should be ignored. -->
+    <input autofocus disabled>
+    <textarea autofocus hidden></textarea>
     <dialog>
         <button autofocus></button>
     </dialog>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/focus-navigation-in-plugin.html b/third_party/WebKit/LayoutTests/fast/dom/focus-navigation-in-plugin.html
new file mode 100644
index 0000000..2512dcb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dom/focus-navigation-in-plugin.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<input id="outer-before">
+<object data="resources/plugin-focus-subframe.html" type="text/html" id="obj"></object>
+<embed src="resources/plugin-focus-subframe.html" type="text/html" id="emb"></embed>
+<input id="outer-after">
+<script>
+function PressTab() {
+    eventSender.keyDown('\t');
+}
+
+function PressShiftTab() {
+    eventSender.keyDown('\t', ['shiftKey']);
+}
+
+function testFocusNavigation() {
+    test(() => {
+      var before = document.querySelector('#outer-before');
+      var after = document.querySelector('#outer-after');
+
+      before.focus();
+
+      // 'plugin-focus-subframe.html' has 2 focus areas.
+      var expected = ['outer-before', 'obj', 'obj', 'emb', 'emb', 'outer-after'];
+
+      var i;
+      for (i = 0; i < 5; ++i) {
+          assert_equals(document.activeElement.id, expected[i]);
+          PressTab();
+      }
+      assert_equals(document.activeElement, after, '#after');
+
+      expected.reverse();
+      for (i = 0; i < 5; ++i) {
+          assert_equals(document.activeElement.id, expected[i]);
+          PressShiftTab();
+      }
+      assert_equals(document.activeElement, before, '#before');
+
+    }, "Focus should navigate to <option>/<embed>");
+}
+
+if (window.testRunner) {
+    window.addEventListener('load', testFocusNavigation, false);
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/resources/plugin-focus-subframe.html b/third_party/WebKit/LayoutTests/fast/dom/resources/plugin-focus-subframe.html
new file mode 100644
index 0000000..1a0a9e2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dom/resources/plugin-focus-subframe.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+  <input placeholder="subframe-before">
+  <input placeholder="subframe-after">
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/events/context-menu-key-shift-f10-modifiers.html b/third_party/WebKit/LayoutTests/fast/events/context-menu-key-shift-f10-modifiers.html
new file mode 100644
index 0000000..4d57740
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/context-menu-key-shift-f10-modifiers.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>Test Context Menu Key, Shift+F10 with Modifiers</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<a href="#" id="anchor">Anchor</a>
+<script>
+test(function() {
+    assert_not_equals(window.eventSender, undefined, 'This test requires eventSender.');
+
+    var contextMenuFired = false;
+    var anchor = document.getElementById('anchor');
+    anchor.addEventListener('contextmenu', () => contextMenuFired = true);
+
+    function testContextMenuEvent(key, modifiers, shouldFire) {
+        contextMenuFired = false;
+        anchor.focus();
+        eventSender.keyDown(key, modifiers);
+        // Esc key to hide context menu
+        eventSender.keyDown("Escape");
+        assert_equals(contextMenuFired, shouldFire, `${key}+${modifiers} opens Context Menu:${shouldFire}.`);
+    }
+
+    testContextMenuEvent('ContextMenu', [], true);
+    testContextMenuEvent('ContextMenu', ['numLockOn'], true);
+    testContextMenuEvent('ContextMenu', ['capsLockOn'], true);
+    testContextMenuEvent('ContextMenu', ['altKey'], false);
+    testContextMenuEvent('ContextMenu', ['ctrlKey'], false);
+    testContextMenuEvent('ContextMenu', ['shiftKey'], false);
+
+    testContextMenuEvent('F10', ['shiftKey'], true);
+    testContextMenuEvent('F10', ['shiftKey', 'numLockOn'], true);
+    testContextMenuEvent('F10', ['shiftKey', 'capsLockOn'], true);
+    testContextMenuEvent('F10', ['shiftKey', 'altKey'], false);
+    testContextMenuEvent('F10', ['shiftKey', 'ctrlKey'], false);
+}, 'Context Menu keys should allow NumLock/CapsLock/etc but not other modifiers.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/events/inputevents/before-input-data.html b/third_party/WebKit/LayoutTests/fast/events/inputevents/before-input-data.html
deleted file mode 100644
index a704bdb..0000000
--- a/third_party/WebKit/LayoutTests/fast/events/inputevents/before-input-data.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title>InputEvent: beforeinput data</title>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-</head>
-<body>
-<input type="text" id="txt">
-<script>
-test(function() {
-    var lastData = '';
-    var txt = document.getElementById('txt');
-    txt.addEventListener('beforeinput', function(event) {
-        lastData = event.data;
-    });
-    if (!window.eventSender) {
-        document.write('This test requires eventSender');
-    } else {
-        function testKeyDownData(key, modifiers, data) {
-            eventSender.keyDown(key, modifiers);
-            assert_equals(lastData, data, `${modifiers.toString()}+${key} should produce data: ${data}`);
-        }
-
-        txt.focus();
-        // Typing
-        testKeyDownData('a', [], 'a');
-        testKeyDownData('4', [], '4');
-        testKeyDownData('Backspace', [], '');
-        // TODO(chongz): eventSender.keyDown('a', ['shiftKey']) should produce shifted character.
-        // https://crbug.com/604488
-        // testKeyDownData('l', ['shiftKey'], 'L');
-        // testKeyDownData('6', ['shiftKey'], '^');
-        testKeyDownData(' ', [], ' ');
-    }
-}, 'Testing beforeinput data');
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/events/inputevents/inputevent-data-keyboard.html b/third_party/WebKit/LayoutTests/fast/events/inputevents/inputevent-data-keyboard.html
new file mode 100644
index 0000000..edeb17c9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/inputevents/inputevent-data-keyboard.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>InputEvent: data field from keyboard</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+</head>
+<body>
+<p id="txt" contenteditable></p>
+<script>
+test(function() {
+    assert_not_equals(window.eventSender, undefined, 'This test requires eventSender.');
+
+    const NOT_FIRED = 'NOT_FIRED';
+    var beforeinputData = NOT_FIRED;
+    var inputData = NOT_FIRED;
+
+    var txt = document.getElementById('txt');
+    txt.addEventListener('beforeinput', event => beforeinputData = event.data);
+    txt.addEventListener('input', event => inputData = event.data);
+
+    function testKeyDownData(key, modifiers, data) {
+        beforeinputData = NOT_FIRED;
+        inputData = NOT_FIRED;
+        eventSender.keyDown(key, modifiers);
+        assert_equals(beforeinputData, data, `${modifiers.toString()}+${key} should produce beforeinput data: ${data}`);
+        assert_equals(inputData, data, `${modifiers.toString()}+${key} should produce input data: ${data}`);
+    }
+
+    txt.focus();
+    // Typing
+    testKeyDownData('a', [], 'a');
+    testKeyDownData('4', [], '4');
+    testKeyDownData('Backspace', [], '');
+    testKeyDownData('L', ['shiftKey'], 'L');
+    testKeyDownData('^', ['shiftKey'], '^');
+    testKeyDownData(' ', [], ' ');
+}, 'Testing data field from keyboard');
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/events/offsetX-offsetY-svg.html b/third_party/WebKit/LayoutTests/fast/events/offsetX-offsetY-svg.html
new file mode 100644
index 0000000..586ed89
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/offsetX-offsetY-svg.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<title>MouseEvent.offsetX/offsetY for an SVG element is always relative to the outermost &lt;svg> CSS layout box</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<style>
+svg {
+    border: 10px solid blue;
+    border-width: 20px 40px 30px 10px;
+}
+</style>
+<svg width="400" height="400" viewBox="0 0 400000 400000">
+  <rect x="40000" y="60000" width="80000" height="80000" fill="blue"/>
+  <rect x="160000" y="180000" width="80000" height="80000" fill="blue" stroke="lightblue" stroke-width="10000"/>
+</svg>
+<script>
+function check_offset(test, element, clientX, clientY, expectedOffsetX, expectedOffsetY) {
+    element.onclick = test.step_func(function(event) {
+        assert_equals(event.offsetX, expectedOffsetX, 'offsetX');
+        assert_equals(event.offsetY, expectedOffsetY, 'offsetY');
+    });
+    var mouseEvent = new MouseEvent('click', { clientX: clientX, clientY: clientY });
+    element.dispatchEvent(mouseEvent);
+}
+
+test(function(t) {
+    var rects = document.querySelectorAll('rect');
+    var svgBoundingRect = document.querySelector('svg').getBoundingClientRect();
+    var offsetBase = { x: svgBoundingRect.left + 10, y: svgBoundingRect.top + 20 };
+    check_offset(t, rects[0], offsetBase.x + 80, offsetBase.y + 100, 80, 100);
+    check_offset(t, rects[1], offsetBase.x + 200, offsetBase.y + 220, 200, 220);
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-global.html b/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-global.html
index 5f8c979c..d41a66b6 100644
--- a/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-global.html
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-global.html
@@ -27,14 +27,14 @@
   // With a global handler, no other handlers should matter
   var elements = [document.getElementById('description'), element, document.getElementById('tests')];
   for (var i = 0; i < elements.length; i++)
-    elements[i].addEventListener('touchmove', listener, false);
+    elements[i].addEventListener('touchmove', listener, {passive: false});
 
   if (window.internals)
     internals.forceCompositingUpdate(document);
   logRects(name, true);
 
   for (var i = 0; i < elements.length; i++)
-    elements[i].removeEventListener('touchmove', listener, false);
+    elements[i].removeEventListener('touchmove', listener, {passive: false});
 }
 
 function runOverlayTest() {
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/resources/compositor-touch-hit-rects-iframe-doc.html b/third_party/WebKit/LayoutTests/fast/events/touch/resources/compositor-touch-hit-rects-iframe-doc.html
index f012a4e..f7987a8 100644
--- a/third_party/WebKit/LayoutTests/fast/events/touch/resources/compositor-touch-hit-rects-iframe-doc.html
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/resources/compositor-touch-hit-rects-iframe-doc.html
@@ -24,7 +24,7 @@
 
   function handler() {};
   frameElement.addHandlers = function() {
-    document.addEventListener('touchstart', handler, false);
+    document.addEventListener('touchstart', handler, {passive: false});
   }
   frameElement.removeHandlers = function() {
     document.removeEventListener('touchstart', handler, false);
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/resources/compositor-touch-hit-rects.js b/third_party/WebKit/LayoutTests/fast/events/touch/resources/compositor-touch-hit-rects.js
index 99892127..6b827a7 100644
--- a/third_party/WebKit/LayoutTests/fast/events/touch/resources/compositor-touch-hit-rects.js
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/resources/compositor-touch-hit-rects.js
@@ -28,7 +28,7 @@
 var preRunHandlerForTest = {};
 
 function testElement(element) {
-    element.addEventListener('touchstart', listener, false);
+    element.addEventListener('touchstart', listener, {passive: false});
 
     // Run any test-specific handler AFTER adding the touch event listener
     // (which itself causes rects to be recomputed).
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/touch-event-cancelable.html b/third_party/WebKit/LayoutTests/fast/events/touch/touch-event-cancelable.html
index 5d972836..0691cfa 100644
--- a/third_party/WebKit/LayoutTests/fast/events/touch/touch-event-cancelable.html
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/touch-event-cancelable.html
@@ -15,7 +15,7 @@
     shouldBeFalse('touchEvent.defaultPrevented');
     console.log('Calling preventDefault on TouchEvent with cancelable=' + event.cancelable);
     touchEvent.preventDefault();
-}, false);
+}, {passive: false});
 
 if (window.eventSender) {
     eventSender.addTouchPoint(152, 152);
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/touch-target-move-documents.html b/third_party/WebKit/LayoutTests/fast/events/touch/touch-target-move-documents.html
index c7eca01..eea9092 100644
--- a/third_party/WebKit/LayoutTests/fast/events/touch/touch-target-move-documents.html
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/touch-target-move-documents.html
@@ -32,7 +32,7 @@
 var events = ['touchstart', 'touchmove', 'touchend'];
 for (var i = 0; i < events.length; i++) {
   for (var j = 0; j < targets.length; j++) {
-    targets[j].addEventListener(events[i], logEvent);
+    targets[j].addEventListener(events[i], logEvent, {passive: false});
   }
 }
 
diff --git a/third_party/WebKit/LayoutTests/fast/scrolling/set-root-scroller.html b/third_party/WebKit/LayoutTests/fast/scrolling/set-root-scroller.html
index ca9cdd4..177d339 100644
--- a/third_party/WebKit/LayoutTests/fast/scrolling/set-root-scroller.html
+++ b/third_party/WebKit/LayoutTests/fast/scrolling/set-root-scroller.html
@@ -20,7 +20,13 @@
     overflow: auto;
   }
 
-  #spacer {
+  #parent {
+    width: 100%;
+    height: 100%;
+    overflow: auto;
+  }
+
+  .spacer {
     width: 2000px;
     height: 2000px;
   }
@@ -35,10 +41,13 @@
   }
 </style>
 
-<div id="container">
-  <div id="spacer">
-    <span id="spanner">TEST</span>
+<div id="parent">
+  <div id="container">
+    <div class="spacer">
+      <span id="spanner">TEST</span>
+    </div>
   </div>
+  <div class="spacer"></div>
 </div>
 <div id="rootspacer"></div>
 
@@ -46,77 +55,112 @@
 <script src="../../resources/testharnessreport.js"></script>
 
 <script>
+  var parentScroller = document.querySelector('#parent');
+  var container = document.querySelector('#container');
+  var spanner = document.querySelector('#spanner');
+
   test(function() {
       assert_false(typeof document.rootScroller === 'undefined');
   }, 'setRootScroller API enabled');
 
-  // TODO(bokan): Break this test up, failing asserts are hard to find.
   test(function() {
-    // Setting the container object should succeed.
-    assert_equals(document.rootScroller, null);
-    var container = document.querySelector('#container');
-    document.rootScroller = container;
-    assert_equals(document.rootScroller, container);
+      // Setting the container object should succeed.
+      assert_equals(document.rootScroller, null);
+      document.rootScroller = container;
+      assert_equals(document.rootScroller, container);
+      document.rootScroller = null;
+      assert_equals(document.rootScroller, null);
+  }, 'Setter and getter on a valid element works');
 
-    // Trying to set the <span> should succeed even though it's not a valid
-    // scroller.
-    var spanner = document.querySelector('#spanner');
-    document.rootScroller = spanner;
-    assert_equals(document.rootScroller, spanner);
+  test(function() {
+      // Trying to set the <span> should succeed even though it's not a valid
+      // scroller.
+      document.rootScroller = spanner;
+      assert_equals(document.rootScroller, spanner);
+  }, 'Can set a non-scrolling element as the rootScroller');
 
-    // Scroll the container <div> past the end. The scrolls should not chain
-    // past the rootScroller to the scrollingElement.
-    document.rootScroller = container;
-    if (typeof eventSender !== 'undefined') {
-        eventSender.gestureScrollBegin(500, 500);
-        eventSender.gestureScrollUpdate(-300, -300);
-        eventSender.gestureScrollEnd(0, 0);
-        eventSender.gestureScrollBegin(500, 500);
-        eventSender.gestureScrollUpdate(-300, -300);
-        eventSender.gestureScrollEnd(0, 0);
-        eventSender.gestureScrollBegin(500, 500);
-        eventSender.gestureScrollUpdate(-300, -300);
-        eventSender.gestureScrollEnd(0, 0);
-        eventSender.gestureScrollBegin(500, 500);
-        eventSender.gestureScrollUpdate(-300, -300);
-        eventSender.gestureScrollUpdate(-300, -300);
-        eventSender.gestureScrollUpdate(-300, -300);
-        eventSender.gestureScrollEnd(0, 0);
+  test(function() {
+      // Scroll the container <div> past the end. The scrolls should not chain
+      // past the rootScroller to the parentScroller element.
+      document.rootScroller = container;
+      if (typeof eventSender !== 'undefined') {
+          eventSender.gestureScrollBegin(500, 500);
+          eventSender.gestureScrollUpdate(-300, -300);
+          eventSender.gestureScrollEnd(0, 0);
+          eventSender.gestureScrollBegin(500, 500);
+          eventSender.gestureScrollUpdate(-300, -300);
+          eventSender.gestureScrollEnd(0, 0);
+          eventSender.gestureScrollBegin(500, 500);
+          eventSender.gestureScrollUpdate(-300, -300);
+          eventSender.gestureScrollEnd(0, 0);
+          eventSender.gestureScrollBegin(500, 500);
+          eventSender.gestureScrollUpdate(-300, -300);
+          eventSender.gestureScrollUpdate(-300, -300);
 
-        assert_equals(container.scrollTop, 2000 - 600);
-        assert_equals(container.scrollLeft, 2000 - 800);
-        assert_equals(document.scrollingElement.scrollTop, 0);
-        assert_equals(document.scrollingElement.scrollLeft, 0);
-    }
+          assert_equals(container.scrollTop, 2000 - 600);
+          assert_equals(container.scrollLeft, 2000 - 800);
 
-    // Making the current rootScroller an invalid scroller should fallback to
-    // the default element, the documentElement, but the rootScroller property
-    // should remain the same.
-    container.style.width = "95%";
-    assert_equals(document.rootScroller, container);
+          // The container is now fully scrolled. Normally, further scroll
+          // events would chain up to the parent element but, because the
+          // container is the root scroller, we shouldn't chain up past it.
+          eventSender.gestureScrollUpdate(-300, -300);
+          eventSender.gestureScrollEnd(0, 0);
+          eventSender.gestureScrollBegin(500, 500);
+          eventSender.gestureScrollUpdate(-300, -300);
+          eventSender.gestureScrollEnd(0, 0);
 
-    // Now scrolling over the <div> should scroll the scrollingElement since the
-    // rootElement is invalid (doesn't fill the viewport).
-    if (typeof eventSender !== 'undefined') {
-        eventSender.gestureScrollBegin(500, 500);
-        eventSender.gestureScrollUpdate(-300, -300);
-        eventSender.gestureScrollEnd(0, 0);
-        eventSender.gestureScrollBegin(500, 500);
-        eventSender.gestureScrollUpdate(-300, -300);
-        eventSender.gestureScrollEnd(0, 0);
-        eventSender.gestureScrollBegin(500, 500);
-        eventSender.gestureScrollUpdate(-300, -300);
-        eventSender.gestureScrollEnd(0, 0);
-        eventSender.gestureScrollBegin(500, 500);
-        eventSender.gestureScrollUpdate(-300, -300);
-        eventSender.gestureScrollEnd(0, 0);
+          assert_equals(container.scrollTop, 2000 - 600);
+          assert_equals(container.scrollLeft, 2000 - 800);
+          assert_equals(parentScroller.scrollTop, 0);
+          assert_equals(parentScroller.scrollLeft, 0);
+      }
+  }, "Scrolls don't chain past root scroller element");
 
-        assert_equals(document.scrollingElement.scrollTop, 400);
-        assert_equals(document.scrollingElement.scrollLeft, 200);
-    }
+  test(function() {
+      document.rootScroller = container;
+      container.scrollTop = 999;
+      container.scrollLeft = 998;
 
-    // Don't output the text in spanner.
-    document.querySelector('#spanner').style.display = 'none';
+      // Window.scrollX and scrollY should reflect the scroll offset of the
+      // rootScroller
+      assert_equals(container.scrollTop, 999);
+      assert_equals(container.scrollLeft, 998);
+      assert_equals(window.scrollY, container.scrollTop);
+      assert_equals(window.scrollX, container.scrollLeft);
+      assert_equals(document.scrollingElement.scrollTop, container.scrollTop);
+      assert_equals(document.scrollingElement.scrollLeft, container.scrollLeft);
 
-  }, 'Test the setRootScroller API basic functionality');
+  }, "document.scrollingElement and window scroll API reflect rootScroller offsets");
+
+  test(function() {
+      // Making the current rootScroller an invalid scroller (by making it not
+      // fill the viewport) should fallback to the default element, the
+      // documentElement, but the rootScroller property should remain the same.
+      document.rootScroller = container;
+      container.style.width = "95%";
+      assert_equals(document.rootScroller, container);
+
+      // Reset parentScroller's offsets, make container fully scrolled.
+      parentScroller.scrollTop = 0;
+      parentScroller.scrollLeft = 0;
+      container.scrollTop = 10000;
+      container.scrollLeft = 10000;
+
+      // Now scrolling over the container should scroll the scrollingElement
+      // since the rootElement is invalid (doesn't fill the viewport).
+      if (typeof eventSender !== 'undefined') {
+          eventSender.gestureScrollBegin(500, 500);
+          eventSender.gestureScrollUpdate(-300, -300);
+          eventSender.gestureScrollEnd(0, 0);
+          eventSender.gestureScrollBegin(500, 500);
+          eventSender.gestureScrollUpdate(-300, -300);
+          eventSender.gestureScrollEnd(0, 0);
+          eventSender.gestureScrollBegin(500, 500);
+          eventSender.gestureScrollUpdate(-300, -300);
+          eventSender.gestureScrollEnd(0, 0);
+
+          assert_equals(parentScroller.scrollTop, 900);
+          assert_equals(parentScroller.scrollLeft, 900);
+      }
+    }, "Setting an invalid rootScroller should reset to using the documentElement.");
 </script>
diff --git a/third_party/WebKit/LayoutTests/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls.html b/third_party/WebKit/LayoutTests/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls.html
index 5c9f28c..c81fdcb 100644
--- a/third_party/WebKit/LayoutTests/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls.html
+++ b/third_party/WebKit/LayoutTests/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls.html
@@ -18,7 +18,7 @@
     testRunner.dumpAsText();
 
 window.onload = function () {
-    document.addEventListener('touchstart', function() { });
+    document.addEventListener('touchstart', function() { }, {passive: false});
 
     consoleWrite("Should have single rect on document before fullscreen");
     window.internals.forceCompositingUpdate(document);
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/extensions-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/extensions-test.js
index b5d0b04..29bcfbe 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/extensions-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/extensions-test.js
@@ -12,7 +12,7 @@
 var initialize_ExtensionsTest = function()
 {
 
-WebInspector.extensionServer._overridePlatformExtensionAPIForTest = function(extensionInfo, inspectedTabId)
+WebInspector.extensionServer._overridePlatformExtensionAPIForTest = function(extensionInfo, inspectedTabId, themeName)
 {
     WebInspector.extensionServer._registerHandler("evaluateForTestInFrontEnd", onEvaluate);
 
@@ -20,6 +20,7 @@
     {
         window.webInspector = coreAPI;
         window._extensionServerForTests = extensionServer;
+        coreAPI.panels.themeName = "themeNameForTest";
     }
     return platformExtensionAPI.toString();
 }
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
index 56701bf..c21526c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
@@ -962,9 +962,9 @@
         InspectorTest.WorkerAgent = target.workerAgent();
 
         InspectorTest.consoleModel = target.consoleModel;
-        InspectorTest.networkManager = target.networkManager;
+        InspectorTest.networkManager = WebInspector.NetworkManager.fromTarget(target);
         InspectorTest.resourceTreeModel = target.resourceTreeModel;
-        InspectorTest.networkLog = target.networkLog;
+        InspectorTest.networkLog = WebInspector.NetworkLog.fromTarget(target);
         InspectorTest.debuggerModel = WebInspector.DebuggerModel.fromTarget(target);
         InspectorTest.runtimeModel = target.runtimeModel;
         InspectorTest.domModel = WebInspector.DOMModel.fromTarget(target);
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-choose-preview-view.html b/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-choose-preview-view.html
index 28ab6ef..8939041 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-choose-preview-view.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-choose-preview-view.html
@@ -8,7 +8,7 @@
     function createNetworkRequest(mimeType, content, statusCode)
     {
         InspectorTest.addResult("Creating a NetworkRequest with mimeType: " + mimeType);
-        var request = new WebInspector.NetworkRequest(WebInspector.mainTarget, 0, 'http://localhost');
+        var request = new WebInspector.NetworkRequest(WebInspector.targetManager.mainTarget(), 0, 'http://localhost');
         InspectorTest.addResult("Content: " + content.replace(/\0/g, "**NULL**"));
         request.mimeType = mimeType;
         request._content = content;
@@ -85,4 +85,4 @@
 <body onload="runTest()">
 <p>Tests to make sure the proper view is used for the data that is received in network panel.</p>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/security/security-explanation-ordering-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/security/security-explanation-ordering-expected.txt
new file mode 100644
index 0000000..bdfdf97
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/security/security-explanation-ordering-expected.txt
@@ -0,0 +1,52 @@
+Tests that info explanations are placed after regular explanations.
+
+<DIV class=security-explanation security-explanation-secure >
+    <DIV class=security-property security-property-secure >
+    </DIV>
+    <DIV class=security-explanation-text >
+        <DIV class=security-explanation-title >
+Valid Certificate
+        </DIV>
+        <DIV >
+The connection to this site is using a valid, trusted server certificate.
+        </DIV>
+        <BUTTON is=text-button type=button class=security-certificate-button >
+View certificate
+            <#document-fragment >
+                <STYLE type=text/css >
+                </STYLE>
+                <STYLE type=text/css >
+                </STYLE>
+                <STYLE type=text/css >
+                </STYLE>
+                <CONTENT >
+                </CONTENT>
+            </#document-fragment>
+        </BUTTON>
+    </DIV>
+</DIV>
+<DIV class=security-explanation security-explanation-secure >
+    <DIV class=security-property security-property-secure >
+    </DIV>
+    <DIV class=security-explanation-text >
+        <DIV class=security-explanation-title >
+Secure Resources
+        </DIV>
+        <DIV >
+All resources on this page are served securely.
+        </DIV>
+    </DIV>
+</DIV>
+<DIV class=security-explanation security-explanation-info >
+    <DIV class=security-property security-property-info >
+    </DIV>
+    <DIV class=security-explanation-text >
+        <DIV class=security-explanation-title >
+Public-Key Pinning Bypassed
+        </DIV>
+        <DIV >
+Public-key pinning was bypassed by a local root certificate.
+        </DIV>
+    </DIV>
+</DIV>
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/security/security-explanation-ordering.html b/third_party/WebKit/LayoutTests/http/tests/inspector/security/security-explanation-ordering.html
new file mode 100644
index 0000000..686b363
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/security/security-explanation-ordering.html
@@ -0,0 +1,42 @@
+<html>
+<head>
+<script src="../inspector-test.js"></script>
+<script src="../security-test.js"></script>
+<script>
+function test()
+{
+    var mixedContentStatus = { ranInsecureContent: false, displayedInsecureContent: false};
+
+    // Explanations from https://cbc.badssl.com/ as of 2016-06-13.
+    // We explicitly place the explanation with the security state "info"
+    // first to make sure it gets reordered.
+    var explanations = [
+        {
+            "description": "Public-key pinning was bypassed by a local root certificate.",
+            "securityState": "info",
+            "summary": "Public-Key Pinning Bypassed"
+        },
+        {
+            "certificateId": 1,
+            "description": "The connection to this site is using a valid, trusted server certificate.",
+            "securityState": "secure",
+            "summary": "Valid Certificate"
+        }
+    ];
+
+    InspectorTest.mainTarget.model(WebInspector.SecurityModel).dispatchEventToListeners(WebInspector.SecurityModel.EventTypes.SecurityStateChanged, new WebInspector.PageSecurityState(SecurityAgent.SecurityState.Secure, explanations, mixedContentStatus, true));
+
+    var request = new WebInspector.NetworkRequest(InspectorTest.mainTarget, 0, "http://foo.test", "https://foo.test", 0, 0, null);
+    InspectorTest.dispatchRequestFinished(request);
+
+    var explanations = WebInspector.SecurityPanel._instance()._mainView.contentElement.getElementsByClassName("security-explanation");
+    for (var i = 0; i < explanations.length; i++)
+        InspectorTest.dumpDeepInnerHTML(explanations[i]);
+    InspectorTest.completeTest();
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Tests that info explanations are placed after regular explanations.</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/media/media-source/mediasource-initsegmentreceived-alg.html b/third_party/WebKit/LayoutTests/http/tests/media/media-source/mediasource-initsegmentreceived-alg.html
index c7aa122d..69ff7bc 100644
--- a/third_party/WebKit/LayoutTests/http/tests/media/media-source/mediasource-initsegmentreceived-alg.html
+++ b/third_party/WebKit/LayoutTests/http/tests/media/media-source/mediasource-initsegmentreceived-alg.html
@@ -107,6 +107,46 @@
                 loadMediaAndVerifyAddedTracks(test, mediaElement, segmentInfo, sourceBuffer, mediaData, expectedAudioTrackInfo, expectedVideoTrackInfo, test.step_func_done());
             }, "Track defaults processing in the init segment algorithm (no bytestream ids)");
 
+            mediasource_test(function(test, mediaElement, mediaSource)
+            {
+                var subType = MediaSourceUtil.getSubType(MediaSourceUtil.AUDIO_VIDEO_TYPE);
+                var manifestFilenameA = subType + '/test-a-128k-44100Hz-1ch-manifest.json';
+                var manifestFilenameV = subType + '/test-v-128k-320x240-30fps-10kfr-manifest.json';
+
+                MediaSourceUtil.fetchManifestAndData(test, manifestFilenameA, function(typeA, dataA)
+                {
+                    MediaSourceUtil.fetchManifestAndData(test, manifestFilenameV, function(typeV, dataV)
+                    {
+                        var sourceBufferA = mediaSource.addSourceBuffer(typeA);
+                        var sourceBufferV = mediaSource.addSourceBuffer(typeV);
+                        sourceBufferA.trackDefaults = new TrackDefaultList([new TrackDefault("audio", "", "audio-label-for-track-bsid1", ["main"], "1")]);
+                        sourceBufferV.trackDefaults = new TrackDefaultList([new TrackDefault("video", "", "video-label-for-track-bsid1", ["main"], "1")]);
+
+                        test.expectEvent(mediaElement.audioTracks, "addtrack", "mediaElement.audioTracks addtrack event");
+                        test.expectEvent(mediaElement, "loadedmetadata", "loadedmetadata done.");
+                        test.expectEvent(sourceBufferA, "updateend", "initSegment append ended.");
+                        test.expectEvent(sourceBufferV, "updateend", "initSegment append ended.");
+                        sourceBufferA.appendBuffer(dataA);
+                        sourceBufferV.appendBuffer(dataV);
+                        test.waitForExpectedEvents(function()
+                        {
+                            assert_equals(mediaElement.audioTracks.length, 1, "mediaElement.audioTracks.length");
+                            assert_equals(mediaElement.videoTracks.length, 1, "mediaElement.audioTracks.length");
+                            assert_equals(sourceBufferA.audioTracks.length, 1, "sourceBufferA.audioTracks.length");
+                            assert_equals(sourceBufferA.videoTracks.length, 0, "sourceBufferA.videoTracks.length");
+                            assert_equals(sourceBufferV.audioTracks.length, 0, "sourceBufferV.audioTracks.length");
+                            assert_equals(sourceBufferV.videoTracks.length, 1, "sourceBufferV.videoTracks.length");
+                            // Verify that audio track bytestream id == video track bytestream id == "1"
+                            assert_equals(sourceBufferA.audioTracks[0].label, "audio-label-for-track-bsid1", "audio track bytestream id is 1");
+                            assert_equals(sourceBufferV.videoTracks[0].label, "video-label-for-track-bsid1", "video track bytestream id is 1");
+                            // Track ids generated for media tracks must be unique, even though the tracks have identical bytestream ids.
+                            assert_not_equals(sourceBufferA.audioTracks[0].id, sourceBufferV.videoTracks[0].id, "track ids must be unique");
+                            test.done();
+                        });
+                    });
+                });
+            }, "Two source buffers with clashing bytestream track ids");
+
         </script>
     </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/update-worker.php b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/update-worker.php
index 1f2ebbbc..81bdd1bf 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/update-worker.php
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/update-worker.php
@@ -8,6 +8,8 @@
 header("Cache-Control: no-cache, must-revalidate");
 header("Pragma: no-cache");
 
+$extra_body = '';
+
 if ($mode == 'init') {
   // Set a normal mimetype.
   // Set cookie value to 'normal' so the next fetch will work in 'normal' mode.
@@ -20,11 +22,21 @@
   setcookie('mode', 'error');
 } else if ($mode == 'error') {
   // Set a disallowed mimetype.
-  // Unset and delete cookie to clean up the test setting.
+  // Set cookie value to 'syntax-error' so the next fetch will work in 'syntax-error' mode.
   header('Content-Type:text/html');
+  setcookie('mode', 'syntax-error');
+} else if ($mode == 'syntax-error') {
+  // Set cookie value to 'throw-install' so the next fetch will work in 'throw-install' mode.
+  header('Content-Type:application/javascript');
+  setcookie('mode', 'throw-install');
+  $extra_body = 'badsyntax(isbad;';
+} else if ($mode == 'throw-install') {
+  // Unset and delete cookie to clean up the test setting.
+  header('Content-Type:application/javascript');
   unset($_COOKIE['mode']);
   setcookie('mode', '', time() - 3600);
+  $extra_body = "addEventListener('install', function(e) { throw new Error('boom'); });";
 }
 // Return a different script for each access.
-echo '// ' . microtime();
+echo '/* ', microtime(), ' */ ', $extra_body;
 ?>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/update.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/update.html
index 61a8a2df..82db192 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/update.html
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/update.html
@@ -9,7 +9,6 @@
     var worker_url = 'resources/update-worker.php';
     var expected_url = normalizeURL(worker_url);
     var registration;
-
     return service_worker_unregister_and_register(t, worker_url, scope)
       .then(function(r) {
           registration = r;
@@ -69,7 +68,52 @@
                         'promise reject with a SecurityError.');
           assert_equals(registration.active.scriptURL, expected_url,
                         'active should still exist after update failure.');
-          return service_worker_unregister_and_done(t, scope);
+
+          // A new worker(generated by update-worker.py) should be found.
+          // The returned promise should reject as update-worker.py returns
+          // a worker script with a syntax error.
+          return registration.update();
+        })
+      .then(
+        function() { assert_unreached("update() should reject."); },
+        function(e) {
+          assert_throws({name: 'TypeError'}, function () { throw e; },
+                        'A script syntax error should make update() ' +
+                        'promise reject with a TypeError.');
+          assert_equals(registration.active.scriptURL, expected_url,
+                        'active should still exist after update failure.');
+
+          // A new worker(generated by update-worker.py) should be found.
+          // The returned promise should not reject, even though
+          // update-worker.py returns a worker script that throws in the
+          // install event handler.
+          return Promise.all([registration.update(),
+                              wait_for_update(t, registration)]);
+        })
+      .then(function() {
+          assert_equals(registration.installing.scriptURL, expected_url,
+                        'installing should be set after update resolves (throw-install).');
+          assert_equals(registration.waiting, null,
+                        'waiting should still be null after update resolves (throw-install).');
+          assert_equals(registration.active.scriptURL, expected_url,
+                        'active should still exist after update found (throw-install).');
+
+          // We need to hold a client alive so that unregister() below doesn't
+          // remove the registration before update() has had a chance to look
+          // at the pending uninstall flag.
+          return with_iframe(scope);
+        })
+      .then(function(frame) {
+          return Promise.all([registration.unregister(),
+                              registration.update()]);
+        })
+      .then(
+        function() { assert_unreached("update() should reject."); },
+        function(e) {
+          assert_throws({name: 'TypeError'}, function () { throw e; },
+                        'Calling update() while the uninstalling flag is ' +
+                        'set should return a promise that rejects with an ' +
+                        'TypeError.');
         });
   }, 'Update a registration.');
 </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 7ec0c9fe..e495d128 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -370,6 +370,7 @@
 interface IDBObserver
     method constructor
     method observe
+    method unobserve
 interface IDBObserverChangesRecord
     getter key
     getter type
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/embedded-content/the-img-element/update-the-source-set-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/embedded-content/the-img-element/update-the-source-set-expected.txt
index 264f086..21a14ab5 100644
--- a/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/embedded-content/the-img-element/update-the-source-set-expected.txt
+++ b/third_party/WebKit/LayoutTests/imported/wpt/html/semantics/embedded-content/the-img-element/update-the-source-set-expected.txt
@@ -1,8 +1,8 @@
 CONSOLE WARNING: <source src> with a <picture> parent is invalid and therefore ignored. Please use <source srcset> instead.
 CONSOLE ERROR: Failed parsing 'srcset' attribute value since it has multiple 'x' descriptors or a mix of 'x' and 'w'/'h' descriptors.
 CONSOLE ERROR: Dropped srcset candidate data:,b
-CONSOLE ERROR: line 128: Failed parsing 'srcset' attribute value since it has multiple 'x' descriptors or a mix of 'x' and 'w'/'h' descriptors.
-CONSOLE ERROR: line 128: Dropped srcset candidate data:,b
+CONSOLE ERROR: line 138: Failed parsing 'srcset' attribute value since it has multiple 'x' descriptors or a mix of 'x' and 'w'/'h' descriptors.
+CONSOLE ERROR: line 138: Dropped srcset candidate data:,b
 This is a testharness.js-based test.
 PASS <img data-expect=""> 
 PASS <img src="" data-expect=""> 
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/resources/testharnessreport.js b/third_party/WebKit/LayoutTests/imported/wpt/resources/testharnessreport.js
index 64c08a9..0dba6f20 100644
--- a/third_party/WebKit/LayoutTests/imported/wpt/resources/testharnessreport.js
+++ b/third_party/WebKit/LayoutTests/imported/wpt/resources/testharnessreport.js
@@ -66,9 +66,19 @@
         return !!document.querySelector('script[src*="/resources/testharness"]');
     }
 
+
     function injectSyntheticInput() {
         var path = window.location.pathname;
         if (path.match(/imported\/wpt\/.*\.html$/)) {
+            // Set a global variable for the address of automated input script if they need to use it.
+            var automated_input_scripts_folder = path.replace(/imported\/wpt\/(.*)\.html$/, 'imported/wpt_automation');
+
+            importAutomationScript = function(relativePath) {
+              var common_script = document.createElement('script');
+              common_script.setAttribute('src', automated_input_scripts_folder + relativePath);
+              document.head.appendChild(common_script);
+            }
+
             path = path.replace(/imported\/wpt\/(.*)\.html$/, "imported/wpt_automation/$1-input.js");
             var input_script = document.createElement('script');
             input_script.setAttribute('src', path);
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_button_attribute_mouse-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_button_attribute_mouse-manual-input.js
index 2948039..d8ef5a6 100644
--- a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_button_attribute_mouse-manual-input.js
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_button_attribute_mouse-manual-input.js
@@ -1,2 +1,6 @@
-if (window.eventSender)
-  eventSender.mouseMoveTo(200, 220);
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseClickInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_capture_mouse-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_capture_mouse-manual-input.js
new file mode 100644
index 0000000..2c681ca2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_capture_mouse-manual-input.js
@@ -0,0 +1,10 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseMoveIntoTarget('target0');
+  mouseMoveIntoTarget('target1');
+  mouseDragInTargets(['btnCapture', 'target1', 'target0']);
+
+  // To handle delayed capturing
+  mouseMoveIntoTarget('target0');
+}
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_capture_suppressing_mouse-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_capture_suppressing_mouse-manual-input.js
new file mode 100644
index 0000000..44ed0d0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_capture_suppressing_mouse-manual-input.js
@@ -0,0 +1,11 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseMoveIntoTarget('target0');
+  mouseMoveIntoTarget('target1');
+  mouseDragInTargets(['btnCapture', 'target1', 'target0', 'target1']);
+
+  // To handle delayed capturing
+  mouseMoveIntoTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_common_input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_common_input.js
new file mode 100644
index 0000000..2604f69
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_common_input.js
@@ -0,0 +1,106 @@
+// This file contains the commonly used functions in pointerevent tests.
+
+// Mouse actions
+function mouseMoveToDocument() {
+  if (window.eventSender)
+    eventSender.mouseMoveTo(0, 0);
+}
+
+function mouseMoveIntoTarget(targetId) {
+  if (window.eventSender) {
+    var target = document.getElementById(targetId);
+    var targetRect = target.getBoundingClientRect();
+    eventSender.mouseMoveTo(targetRect.left+5, targetRect.top+5);
+  }
+}
+
+function mouseClickInTarget(targetId) {
+  if (window.eventSender) {
+    mouseMoveIntoTarget(targetId);
+    eventSender.mouseDown(0);
+    eventSender.mouseUp(0);
+  }
+}
+
+function mouseDragInTargets(targetIdList) {
+  if (window.eventSender) {
+    var target = document.getElementById(targetIdList[0]);
+    mouseMoveIntoTarget(targetIdList[0]);
+    eventSender.mouseDown(0);
+    for (var i=1; i<targetIdList.length; i++)
+      mouseMoveIntoTarget(targetIdList[i]);
+    eventSender.mouseUp(0);
+  }
+}
+
+function mouseDragInTarget(targetId) {
+  if (window.eventSender) {
+    var target = document.getElementById(targetId);
+    mouseMoveIntoTarget(targetId);
+    eventSender.mouseDown(0);
+    mouseMoveIntoTarget(targetId);
+    eventSender.mouseUp(0);
+  }
+}
+
+function mouseScrollUp() {
+  if (window.eventSender)
+    eventSender.continuousMouseScrollBy(-50, 0);
+
+}
+
+function mouseScrollLeft() {
+  if (window.eventSender)
+    eventSender.continuousMouseScrollBy(0, -50);
+}
+
+// Touch actions
+function touchTapInTarget(targetId) {
+  if (window.chrome && chrome.gpuBenchmarking) {
+    var target = document.getElementById(targetId);
+    var targetRect = target.getBoundingClientRect();
+    chrome.gpuBenchmarking.tap(targetRect.left+5, targetRect.top+5);
+  }
+}
+
+function touchScrollUpInTarget(targetId) {
+  if (window.chrome && chrome.gpuBenchmarking) {
+    var target = document.getElementById(targetId);
+    var targetRect = target.getBoundingClientRect();
+    chrome.gpuBenchmarking.smoothDrag(targetRect.left, targetRect.bottom-5, targetRect.left, targetRect.top+5);
+  }
+}
+
+function touchScrollLeftInTarget(targetId) {
+  if (window.chrome && chrome.gpuBenchmarking) {
+    var target = document.getElementById(targetId);
+    var targetRect = target.getBoundingClientRect();
+    chrome.gpuBenchmarking.smoothDrag(targetRect.right-5, targetRect.top+5, targetRect.left+5, targetRect.top+5);
+  }
+}
+
+// Pen actions
+function penMoveIntoTarget(target) {
+  var targetRect = target.getBoundingClientRect();
+  eventSender.mouseMoveTo(targetRect.left+5, targetRect.top+5, [], "pen", 0);
+}
+
+function penClickIntoTarget(target) {
+  penMoveIntoTarget(target);
+  eventSender.mouseDown(0, [], "pen", 0);
+  eventSender.mouseUp(0, [], "pen", 0);
+}
+
+// Keyboard actions
+function keyboardScrollUp() {
+  if (window.eventSender)
+    eventSender.keyDown('downArrow');
+}
+
+function keyboardScrollLeft() {
+  if (window.eventSender)
+    eventSender.keyDown('rightArrow');
+}
+
+// Defined in every test
+inject_input();
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_gotpointercapture_before_first_pointerevent-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_gotpointercapture_before_first_pointerevent-manual-input.js
new file mode 100644
index 0000000..d8ef5a6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_gotpointercapture_before_first_pointerevent-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseClickInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual-input.js
new file mode 100644
index 0000000..18b1ecc0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseDragInTarget('btnCapture');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_lostpointercapture_is_first-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_lostpointercapture_is_first-manual-input.js
new file mode 100644
index 0000000..744912c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_lostpointercapture_is_first-manual-input.js
@@ -0,0 +1,9 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseClickInTarget('btnCapture');
+
+  // To handle delayed capturing
+  mouseMoveIntoTarget('btnCapture');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointercancel_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointercancel_touch-manual-input.js
new file mode 100644
index 0000000..14dd4b5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointercancel_touch-manual-input.js
@@ -0,0 +1,7 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+}
+
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerdown-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerdown-manual-input.js
new file mode 100644
index 0000000..d8ef5a6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerdown-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseClickInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerenter-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerenter-manual-input.js
new file mode 100644
index 0000000..c08ae78
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerenter-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseMoveIntoTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerenter_does_not_bubble-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerenter_does_not_bubble-manual-input.js
new file mode 100644
index 0000000..316468b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerenter_does_not_bubble-manual-input.js
@@ -0,0 +1,7 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseMoveIntoTarget('target0');
+  mouseMoveToDocument();
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerenter_nohover-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerenter_nohover-manual-input.js
new file mode 100644
index 0000000..05cf1b1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerenter_nohover-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchTapInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_after_pointercancel_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_after_pointercancel_touch-manual-input.js
new file mode 100644
index 0000000..14dd4b5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_after_pointercancel_touch-manual-input.js
@@ -0,0 +1,7 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+}
+
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_after_pointerup_nohover-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_after_pointerup_nohover-manual-input.js
new file mode 100644
index 0000000..05cf1b1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_after_pointerup_nohover-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchTapInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_descendant_over-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_descendant_over-manual-input.js
new file mode 100644
index 0000000..8fbc0a6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_descendant_over-manual-input.js
@@ -0,0 +1,7 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseMoveIntoTarget('target0');
+  mouseClickInTarget('target1');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_descendants-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_descendants-manual-input.js
new file mode 100644
index 0000000..a159a18
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_descendants-manual-input.js
@@ -0,0 +1,9 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseMoveIntoTarget('target0');
+  if (window.eventSender)
+    eventSender.mouseMoveTo(100, 200);
+  mouseMoveToDocument();
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_does_not_bubble-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_does_not_bubble-manual-input.js
new file mode 100644
index 0000000..316468b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_does_not_bubble-manual-input.js
@@ -0,0 +1,7 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseMoveIntoTarget('target0');
+  mouseMoveToDocument();
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_mouse-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_mouse-manual-input.js
new file mode 100644
index 0000000..316468b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_mouse-manual-input.js
@@ -0,0 +1,7 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseMoveIntoTarget('target0');
+  mouseMoveToDocument();
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_pen-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_pen-manual-input.js
new file mode 100644
index 0000000..66bffa4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_pen-manual-input.js
@@ -0,0 +1,10 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  if (window.eventSender) {
+    var target0 = document.getElementById('target0');
+    penMoveIntoTarget(target0);
+    eventSender.mouseMoveTo(0, 0, [], "pen", 0);
+  }
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_touch-manual-input.js
new file mode 100644
index 0000000..05cf1b1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerleave_touch-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchTapInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointermove-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointermove-manual-input.js
new file mode 100644
index 0000000..c08ae78
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointermove-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseMoveIntoTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointermove_isprimary_same_as_pointerdown-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointermove_isprimary_same_as_pointerdown-manual-input.js
new file mode 100644
index 0000000..0c31fb73
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointermove_isprimary_same_as_pointerdown-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseDragInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointermove_pointertype-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointermove_pointertype-manual-input.js
new file mode 100644
index 0000000..ebbe93e3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointermove_pointertype-manual-input.js
@@ -0,0 +1,7 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseClickInTarget('target0');
+  mouseMoveIntoTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerout-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerout-manual-input.js
new file mode 100644
index 0000000..316468b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerout-manual-input.js
@@ -0,0 +1,7 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseMoveIntoTarget('target0');
+  mouseMoveToDocument();
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerout_after_pointercancel_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerout_after_pointercancel_touch-manual-input.js
new file mode 100644
index 0000000..d73a444
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerout_after_pointercancel_touch-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerout_after_pointerup_nohover-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerout_after_pointerup_nohover-manual-input.js
new file mode 100644
index 0000000..05cf1b1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerout_after_pointerup_nohover-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchTapInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerout_pen-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerout_pen-manual-input.js
new file mode 100644
index 0000000..66bffa4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerout_pen-manual-input.js
@@ -0,0 +1,10 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  if (window.eventSender) {
+    var target0 = document.getElementById('target0');
+    penMoveIntoTarget(target0);
+    eventSender.mouseMoveTo(0, 0, [], "pen", 0);
+  }
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerout_received_once-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerout_received_once-manual-input.js
new file mode 100644
index 0000000..316468b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerout_received_once-manual-input.js
@@ -0,0 +1,7 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseMoveIntoTarget('target0');
+  mouseMoveToDocument();
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerover-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerover-manual-input.js
new file mode 100644
index 0000000..c08ae78
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerover-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseMoveIntoTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointertype_mouse-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointertype_mouse-manual-input.js
new file mode 100644
index 0000000..d8ef5a6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointertype_mouse-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseClickInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointertype_pen-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointertype_pen-manual-input.js
new file mode 100644
index 0000000..cb9da76
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointertype_pen-manual-input.js
@@ -0,0 +1,9 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  if (window.chrome && chrome.gpuBenchmarking) {
+    var target0 = document.getElementById('target0');
+    penClickIntoTarget(target0);
+  }
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointertype_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointertype_touch-manual-input.js
new file mode 100644
index 0000000..05cf1b1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointertype_touch-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchTapInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerup-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerup-manual-input.js
new file mode 100644
index 0000000..d8ef5a6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerup-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseClickInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerup_isprimary_same_as_pointerdown-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerup_isprimary_same_as_pointerdown-manual-input.js
new file mode 100644
index 0000000..d8ef5a6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerup_isprimary_same_as_pointerdown-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseClickInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerup_pointertype-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerup_pointertype-manual-input.js
new file mode 100644
index 0000000..d8ef5a6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_pointerup_pointertype-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseClickInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual-input.js
new file mode 100644
index 0000000..0c31fb73
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseDragInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_releasepointercapture_invalid_pointerid-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_releasepointercapture_invalid_pointerid-manual-input.js
new file mode 100644
index 0000000..0c31fb73
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_releasepointercapture_invalid_pointerid-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseDragInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch-manual-input.js
new file mode 100644
index 0000000..d73a444
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_releasepointercapture_onpointerup_mouse-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_releasepointercapture_onpointerup_mouse-manual-input.js
new file mode 100644
index 0000000..dae01ba
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_releasepointercapture_onpointerup_mouse-manual-input.js
@@ -0,0 +1,9 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseClickInTarget('btnCapture');
+
+  // To Handle delayed capturing
+  mouseMoveIntoTarget('btnCapture');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_setpointercapture_disconnected-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_setpointercapture_disconnected-manual-input.js
new file mode 100644
index 0000000..d8ef5a6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_setpointercapture_disconnected-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseClickInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_setpointercapture_inactive_button_mouse-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_setpointercapture_inactive_button_mouse-manual-input.js
new file mode 100644
index 0000000..316468b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_setpointercapture_inactive_button_mouse-manual-input.js
@@ -0,0 +1,7 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseMoveIntoTarget('target0');
+  mouseMoveToDocument();
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_setpointercapture_invalid_pointerid-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_setpointercapture_invalid_pointerid-manual-input.js
new file mode 100644
index 0000000..d8ef5a6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_setpointercapture_invalid_pointerid-manual-input.js
@@ -0,0 +1,6 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseClickInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_setpointercapture_relatedtarget-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_setpointercapture_relatedtarget-manual-input.js
new file mode 100644
index 0000000..3ccadf2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_setpointercapture_relatedtarget-manual-input.js
@@ -0,0 +1,7 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseMoveIntoTarget('target1');
+  mouseDragInTargets(['btnCapture', 'target0']);
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-auto-css_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-auto-css_touch-manual-input.js
new file mode 100644
index 0000000..4fffdcf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-auto-css_touch-manual-input.js
@@ -0,0 +1,7 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+  touchScrollLeftInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-button-test_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-button-test_touch-manual-input.js
new file mode 100644
index 0000000..d972b5a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-button-test_touch-manual-input.js
@@ -0,0 +1,8 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+  touchScrollLeftInTarget('target0');
+  touchTapInTarget('btnComplete');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual-input.js
new file mode 100644
index 0000000..d972b5a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual-input.js
@@ -0,0 +1,8 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+  touchScrollLeftInTarget('target0');
+  touchTapInTarget('btnComplete');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual-input.js
new file mode 100644
index 0000000..d972b5a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual-input.js
@@ -0,0 +1,8 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+  touchScrollLeftInTarget('target0');
+  touchTapInTarget('btnComplete');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual-input.js
new file mode 100644
index 0000000..d972b5a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual-input.js
@@ -0,0 +1,8 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+  touchScrollLeftInTarget('target0');
+  touchTapInTarget('btnComplete');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual-input.js
new file mode 100644
index 0000000..d972b5a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual-input.js
@@ -0,0 +1,8 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+  touchScrollLeftInTarget('target0');
+  touchTapInTarget('btnComplete');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch-manual-input.js
new file mode 100644
index 0000000..4fffdcf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch-manual-input.js
@@ -0,0 +1,7 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+  touchScrollLeftInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual-input.js
new file mode 100644
index 0000000..d972b5a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual-input.js
@@ -0,0 +1,8 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+  touchScrollLeftInTarget('target0');
+  touchTapInTarget('btnComplete');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-keyboard-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-keyboard-manual-input.js
new file mode 100644
index 0000000..ba21768
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-keyboard-manual-input.js
@@ -0,0 +1,8 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseClickInTarget('target0');
+  keyboardScrollUp();
+  keyboardScrollLeft();
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-mouse-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-mouse-manual-input.js
new file mode 100644
index 0000000..71eafbc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-mouse-manual-input.js
@@ -0,0 +1,8 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  mouseClickInTarget('target0');
+  mouseScrollUp();
+  mouseScrollLeft();
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-none-css_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-none-css_touch-manual-input.js
new file mode 100644
index 0000000..d972b5a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-none-css_touch-manual-input.js
@@ -0,0 +1,8 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+  touchScrollLeftInTarget('target0');
+  touchTapInTarget('btnComplete');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual-input.js
new file mode 100644
index 0000000..d972b5a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual-input.js
@@ -0,0 +1,8 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+  touchScrollLeftInTarget('target0');
+  touchTapInTarget('btnComplete');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual-input.js
new file mode 100644
index 0000000..d972b5a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual-input.js
@@ -0,0 +1,8 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+  touchScrollLeftInTarget('target0');
+  touchTapInTarget('btnComplete');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-pan-x-pan-y_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-pan-x-pan-y_touch-manual-input.js
new file mode 100644
index 0000000..4fffdcf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-pan-x-pan-y_touch-manual-input.js
@@ -0,0 +1,7 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+  touchScrollLeftInTarget('target0');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual-input.js
new file mode 100644
index 0000000..d972b5a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual-input.js
@@ -0,0 +1,8 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+  touchScrollLeftInTarget('target0');
+  touchTapInTarget('btnComplete');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-span-test_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-span-test_touch-manual-input.js
new file mode 100644
index 0000000..d972b5a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-span-test_touch-manual-input.js
@@ -0,0 +1,8 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+  touchScrollLeftInTarget('target0');
+  touchTapInTarget('btnComplete');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-svg-test_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-svg-test_touch-manual-input.js
new file mode 100644
index 0000000..d972b5a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-svg-test_touch-manual-input.js
@@ -0,0 +1,8 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+  touchScrollLeftInTarget('target0');
+  touchTapInTarget('btnComplete');
+}
+
diff --git a/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-table-test_touch-manual-input.js b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-table-test_touch-manual-input.js
new file mode 100644
index 0000000..d972b5a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/wpt_automation/pointerevents/pointerevent_touch-action-table-test_touch-manual-input.js
@@ -0,0 +1,8 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+
+function inject_input() {
+  touchScrollUpInTarget('target0');
+  touchScrollLeftInTarget('target0');
+  touchTapInTarget('btnComplete');
+}
+
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/input/emulateTouchFromMouseEvent.html b/third_party/WebKit/LayoutTests/inspector-protocol/input/emulateTouchFromMouseEvent.html
index f141e8c..802f29f 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/input/emulateTouchFromMouseEvent.html
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/input/emulateTouchFromMouseEvent.html
@@ -3,9 +3,9 @@
 <script type="text/javascript" src="../../http/tests/inspector-protocol/inspector-protocol-test.js"></script>
 <script>
 
-window.addEventListener("touchstart", logEvent);
+window.addEventListener("touchstart", logEvent, {passive: false});
+window.addEventListener("touchmove", logEvent, {passive: false});
 window.addEventListener("touchend", logEvent);
-window.addEventListener("touchmove", logEvent);
 window.addEventListener("touchcancel", logEvent);
 
 function logEvent(event)
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/resources/styles-do-not-detach-sourcemap-on-edits.css b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/resources/styles-do-not-detach-sourcemap-on-edits.css
new file mode 100644
index 0000000..c1b4b8b1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/resources/styles-do-not-detach-sourcemap-on-edits.css
@@ -0,0 +1,2 @@
+@media (min-width: 6px){#container{border:1px solid blue;color:blue}}
+/*# sourceMappingURL=styles-do-not-detach-sourcemap-on-edits.css.map */
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/resources/styles-do-not-detach-sourcemap-on-edits.css.map b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/resources/styles-do-not-detach-sourcemap-on-edits.css.map
new file mode 100644
index 0000000..c932ea4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/resources/styles-do-not-detach-sourcemap-on-edits.css.map
@@ -0,0 +1,7 @@
+{
+"version": 3,
+"mappings": "AAAA,uBAAwB,CACpB,UAAW,CACP,MAAM,CAAE,cAAc,CACtB,KAAK,CAAE,IAAI",
+"sources": ["styles-do-not-detach-sourcemap-on-edits.scss"],
+"names": [],
+"file": "styles-do-not-detach-sourcemap-on-edits.css"
+}
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/resources/styles-do-not-detach-sourcemap-on-edits.scss b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/resources/styles-do-not-detach-sourcemap-on-edits.scss
new file mode 100644
index 0000000..9b7eeef
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/resources/styles-do-not-detach-sourcemap-on-edits.scss
@@ -0,0 +1,6 @@
+@media (min-width: 6px) {
+    #container {
+        border: 1px solid blue;
+        color: blue;
+    }
+}
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-do-not-detach-sourcemap-on-edits-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-do-not-detach-sourcemap-on-edits-expected.txt
new file mode 100644
index 0000000..c0e5b1e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-do-not-detach-sourcemap-on-edits-expected.txt
@@ -0,0 +1,82 @@
+Tests that source map is not detached on edits. crbug.com/257778
+
+container.
+
+Running: editProperty
+[expanded] 
+element.style { ()
+
+[expanded] 
+@media (min-width: 6px)
+#container { (styles-do-not-d…n-edits.scss:2 -> styles-do-not-detach-sourcemap-on-edits.scss:2:5)
+    border: 1px solid blue;
+    color: blue;
+
+[expanded] 
+div { (user agent stylesheet)
+    display: block;
+
+
+Running: editSelector
+[expanded] 
+element.style { ()
+
+[expanded] 
+@media (min-width: 6px)
+#container { (styles-do-not-d…n-edits.scss:2 -> styles-do-not-detach-sourcemap-on-edits.scss:2:5)
+    border: 1px solid blue;
+/-- overloaded --/     NAME: VALUE;
+
+[expanded] 
+div { (user agent stylesheet)
+    display: block;
+
+
+Running: editMedia
+[expanded] 
+element.style { ()
+
+[expanded] 
+@media (min-width: 6px)
+#container, SELECTOR { (styles-do-not-d…n-edits.scss:2 -> styles-do-not-detach-sourcemap-on-edits.scss:2:5)
+    border: 1px solid blue;
+/-- overloaded --/     NAME: VALUE;
+
+[expanded] 
+div { (user agent stylesheet)
+    display: block;
+
+
+Running: addRule
+[expanded] 
+element.style { ()
+
+[expanded] 
+@media (max-width: 9999999px)
+#container, SELECTOR { (styles-do-not-d…n-edits.scss:2 -> styles-do-not-detach-sourcemap-on-edits.scss:2:5)
+    border: 1px solid blue;
+/-- overloaded --/     NAME: VALUE;
+
+[expanded] 
+div { (user agent stylesheet)
+    display: block;
+
+
+Running: finish
+[expanded] 
+element.style { ()
+
+[expanded] [no-affect] 
+NEW-RULE { (styles-do-not-d…n-edits.scss:4 -> styles-do-not-detach-sourcemap-on-edits.scss:4:20)
+
+[expanded] 
+@media (max-width: 9999999px)
+#container, SELECTOR { (styles-do-not-d…n-edits.scss:2 -> styles-do-not-detach-sourcemap-on-edits.scss:2:5)
+    border: 1px solid blue;
+/-- overloaded --/     NAME: VALUE;
+
+[expanded] 
+div { (user agent stylesheet)
+    display: block;
+
+
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-do-not-detach-sourcemap-on-edits.html b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-do-not-detach-sourcemap-on-edits.html
new file mode 100644
index 0000000..1a4fedc5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-do-not-detach-sourcemap-on-edits.html
@@ -0,0 +1,89 @@
+<html>
+<head>
+
+<link rel="stylesheet" href="./resources/styles-do-not-detach-sourcemap-on-edits.css">
+<script src="../../../http/tests/inspector/debugger-test.js"></script>
+<script src="../../../http/tests/inspector/elements-test.js"></script>
+<script src="../../../http/tests/inspector/inspector-test.js"></script>
+<script>
+
+function test()
+{
+    InspectorTest.waitForScriptSource("styles-do-not-detach-sourcemap-on-edits.scss", onSourceMapLoaded);
+
+    function onSourceMapLoaded()
+    {
+        InspectorTest.selectNodeAndWaitForStyles("container", onNodeSelected);
+    }
+
+    function onNodeSelected()
+    {
+        InspectorTest.runTestSuite(testSuite);
+    }
+
+    var testSuite = [
+        function editProperty(next)
+        {
+            InspectorTest.dumpSelectedElementStyles(true, false, true);
+
+            var treeItem = InspectorTest.getMatchedStylePropertyTreeItem("color");
+            treeItem.applyStyleText("NAME: VALUE", true);
+            InspectorTest.waitForStyles("container", next);
+        },
+
+        function editSelector(next)
+        {
+            InspectorTest.dumpSelectedElementStyles(true, false, true);
+
+            var section = InspectorTest.firstMatchedStyleSection();
+            section.startEditingSelector();
+            section._selectorElement.textContent = "#container, SELECTOR";
+            InspectorTest.waitForSelectorCommitted(next);
+            section._selectorElement.dispatchEvent(InspectorTest.createKeyEvent("Enter"));
+        },
+
+        function editMedia(next)
+        {
+            InspectorTest.dumpSelectedElementStyles(true, false, true);
+
+            var section = InspectorTest.firstMatchedStyleSection();
+            var mediaTextElement = InspectorTest.firstMediaTextElementInSection(section);
+            mediaTextElement.click();
+            mediaTextElement.textContent = "(max-width: 9999999px)";
+            InspectorTest.waitForMediaTextCommitted(next);
+            mediaTextElement.dispatchEvent(InspectorTest.createKeyEvent("Enter"));
+        },
+
+        function addRule(next)
+        {
+            InspectorTest.dumpSelectedElementStyles(true, false, true);
+
+            var styleSheetHeader = InspectorTest.cssModel.styleSheetHeaders().find(header => header.resourceURL().indexOf("styles-do-not-detach-sourcemap-on-edits.css") !== -1);
+            if (!styleSheetHeader) {
+                InspectorTest.addResult("ERROR: failed to find style sheet!");
+                InspectorTest.completeTest();
+                return;
+            }
+            InspectorTest.addNewRuleInStyleSheet(styleSheetHeader, "NEW-RULE", next);
+        },
+
+        function finish(next)
+        {
+            InspectorTest.dumpSelectedElementStyles(true, false, true);
+            next();
+        },
+    ];
+}
+
+</script>
+</head>
+
+<body onload="runTest()">
+<p>
+Tests that source map is not detached on edits. crbug.com/257778
+</p>
+
+<div id="container">container.</div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-edit-property-after-invalid-rule.html b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-edit-property-after-invalid-rule.html
index ce787fd..fbdd285 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-edit-property-after-invalid-rule.html
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-edit-property-after-invalid-rule.html
@@ -19,17 +19,17 @@
 function test()
 {
       InspectorTest.selectNodeAndWaitForStyles("container", step1);
-    
+
       function step1()
       {
           InspectorTest.addResult("Initial value");
           InspectorTest.dumpSelectedElementStyles(true, false, true);
-    
+
           var treeItem = InspectorTest.getMatchedStylePropertyTreeItem("padding");
           treeItem.applyStyleText("padding: 20px", false);
           InspectorTest.waitForStyles("container", step2);
       }
-    
+
       function step2()
       {
           InspectorTest.addResult("After changing property");
diff --git a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-api-expected.txt b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-api-expected.txt
index ae39265..47c994c4 100644
--- a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-api-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-api-expected.txt
@@ -46,6 +46,7 @@
                 removeListener : <function>
             }
         }
+        themeName : "themeNameForTest"
     }
     resources : {
         onFinished : {
diff --git a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-panel-expected.txt b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-panel-expected.txt
index 20afde0b..6ad7ff8 100644
--- a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-panel-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-panel-expected.txt
@@ -69,5 +69,7 @@
 status bar item 0, icon: ".../inspector/resources/button1-updated.png", tooltip: 'Button One tooltip', disabled: false
 status bar item 1, icon: ".../inspector/resources/button2.png", tooltip: 'Button Two updated tooltip', disabled: false
 button2 clicked
+RUNNING TEST: extension_testThemeName
+Theme name: themeNameForTest
 All tests done.
 
diff --git a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-panel.html b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-panel.html
index e9d6010..9e4b20a 100644
--- a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-panel.html
+++ b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-panel.html
@@ -120,6 +120,12 @@
     }
 }
 
+function extension_testThemeName(nextTest)
+{
+    output("Theme name: " + webInspector.panels.themeName);
+    nextTest();
+}
+
 function extension_testCreatePanel(nextTest)
 {
     var expectOnShown = false;
@@ -215,7 +221,7 @@
         panel.onSearch.addListener(callback);
 
         extension_showPanel("extension");
-        
+
         function performSearch(query)
         {
             var panel = WebInspector.inspectorView.currentPanel();
diff --git a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-resources.html b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-resources.html
index 117e222..31573919 100644
--- a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-resources.html
+++ b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-resources.html
@@ -4,7 +4,6 @@
 <script src="../../http/tests/inspector/console-test.js"></script>
 <script src="../../http/tests/inspector/extensions-test.js"></script>
 <script src="../../http/tests/inspector/debugger-test.js"></script>
-
 <script type="text/javascript">
 function loadFrame(callback)
 {
@@ -25,8 +24,10 @@
 InspectorTest.clickOnURL = function()
 {
     WebInspector.ConsolePanel.show();
+    WebInspector.ConsoleView.instance()._updateMessageList();
     var xpathResult = document.evaluate("//a[starts-with(., 'test-script.js')]",
-                                        WebInspector.panels.console.element, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null);
+                                        WebInspector.ConsoleView.instance().element, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null);
+
     var click = document.createEvent("MouseEvent");
     click.initMouseEvent("click", true, true);
     xpathResult.singleNodeValue.dispatchEvent(click);
diff --git a/third_party/WebKit/LayoutTests/inspector/input-event-warning-expected.txt b/third_party/WebKit/LayoutTests/inspector/input-event-warning-expected.txt
index 4ced2c4..51d6c697 100644
--- a/third_party/WebKit/LayoutTests/inspector/input-event-warning-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/input-event-warning-expected.txt
@@ -1,7 +1,7 @@
 Tests that console warnings are issued for a blocked event listener and that there is no crash when an offending listener is removed by the handler.
 
 There should be no warnings above this line
-Handling of 'wheel' input event was delayed for <number> ms due to main thread being busy. Consider marking event handler as 'passive' to make the page more responive.
-Handling of 'touchstart' input event was delayed for <number> ms due to main thread being busy. Consider marking event handler as 'passive' to make the page more responive.
-Handling of 'touchmove' input event was delayed for <number> ms due to main thread being busy. Consider marking event handler as 'passive' to make the page more responive.
+Handling of 'wheel' input event was delayed for <number> ms due to main thread being busy. Consider marking event handler as 'passive' to make the page more responsive.
+Handling of 'touchstart' input event was delayed for <number> ms due to main thread being busy. Consider marking event handler as 'passive' to make the page more responsive.
+Handling of 'touchmove' input event was delayed for <number> ms due to main thread being busy. Consider marking event handler as 'passive' to make the page more responsive.
 
diff --git a/third_party/WebKit/LayoutTests/inspector/network/network-status-non-http.html b/third_party/WebKit/LayoutTests/inspector/network/network-status-non-http.html
index 84eb6c51..0ece6db 100644
--- a/third_party/WebKit/LayoutTests/inspector/network/network-status-non-http.html
+++ b/third_party/WebKit/LayoutTests/inspector/network/network-status-non-http.html
@@ -16,7 +16,7 @@
         var urls = document.evaluate("//tbody/tr/td[position()=1]/@title", dataGrid, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
         var outputStrings = [];
 
-        for (var request of WebInspector.targetManager.mainTarget().networkLog._requests) {
+        for (var request of WebInspector.NetworkLog.fromTarget(WebInspector.targetManager.mainTarget())._requests) {
             var line = request.displayName + ":" + request.statusCode + " " + request.statusText
             if (request.failed)
                 line += "(failed)";
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/breakpoint-manager.js b/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/breakpoint-manager.js
index c52f23a..5fcd616 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/breakpoint-manager.js
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/breakpoint-manager.js
@@ -48,6 +48,8 @@
         return this._target;
     },
 
+    _targetDisposed: function() { },
+
     debuggerEnabled: function()
     {
         return true;
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/function-generator-details-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/function-generator-details-expected.txt
index e043b9d2..0ad0a51 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/function-generator-details-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/function-generator-details-expected.txt
@@ -3,41 +3,70 @@
 
 Running: testIterNotStarted
 iterNotStarted: type = object, subtype = generator
-functionName: "gen"
-lineNumber: 14
-columnNumber: 13
-scriptId is valid: true
-status: suspended
+[[GeneratorStatus]] = suspended
+[[GeneratorFunction]] = function* gen()
+{
+    yield 1;
+    yield 2;
+    yield 3;
+}
+[[GeneratorReceiver]] = Window
+lineNumber = 13
+columnNumber = 13
+script is valid: yes
 
 Running: testIterSuspended
 iterSuspended: type = object, subtype = generator
-functionName: "gen"
-lineNumber: 16
-columnNumber: 4
-scriptId is valid: true
-status: suspended
+[[GeneratorStatus]] = suspended
+[[GeneratorFunction]] = function* gen()
+{
+    yield 1;
+    yield 2;
+    yield 3;
+}
+[[GeneratorReceiver]] = Window
+lineNumber = 15
+columnNumber = 4
+script is valid: yes
 
 Running: testIterClosed
 iterClosed: type = object, subtype = generator
-functionName: "gen"
-lineNumber: 14
-columnNumber: 13
-scriptId is valid: true
-status: closed
+[[GeneratorStatus]] = closed
+[[GeneratorFunction]] = function* gen()
+{
+    yield 1;
+    yield 2;
+    yield 3;
+}
+[[GeneratorReceiver]] = Window
+lineNumber = 13
+columnNumber = 13
+script is valid: yes
 
 Running: testIterObjGenerator
 iterObjGenerator: type = object, subtype = generator
-functionName: "generator"
-lineNumber: 25
-columnNumber: 8
-scriptId is valid: true
-status: suspended
+[[GeneratorStatus]] = suspended
+[[GeneratorFunction]] = function* ()
+    {
+        yield 11;
+        yield 12;
+        yield 13;
+    }
+[[GeneratorReceiver]] = Object
+lineNumber = 24
+columnNumber = 8
+script is valid: yes
 
 Running: testAnonymousGenIter
 anonymousGenIter: type = object, subtype = generator
-functionName: ""
-lineNumber: 39
-columnNumber: 4
-scriptId is valid: true
-status: suspended
+[[GeneratorStatus]] = suspended
+[[GeneratorFunction]] = function* () {
+    yield 21;
+    yield 22;
+    yield 23;
+}
+[[GeneratorReceiver]] = Window
+lineNumber = 38
+columnNumber = 4
+script is valid: yes
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/function-generator-details.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/function-generator-details.html
index 5f5af6d8..a63a2f3 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/function-generator-details.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/function-generator-details.html
@@ -42,15 +42,6 @@
 
 function test()
 {
-    function dumpGeneratorObjectDetails(details)
-    {
-        InspectorTest.addResult("functionName: \"" + details.functionName + "\"");
-        InspectorTest.addResult("lineNumber: " + (details.location.lineNumber + 1));
-        InspectorTest.addResult("columnNumber: " + details.location.columnNumber);
-        InspectorTest.addResult("scriptId is valid: " + !!details.location.scriptId);
-        InspectorTest.addResult("status: " + details.status);
-    }
-
     function performStandardTestCase(pageExpression, next)
     {
         InspectorTest.evaluateInPage(pageExpression, didEvaluate);
@@ -58,15 +49,27 @@
         function didEvaluate(remote)
         {
             InspectorTest.addResult(pageExpression + ": type = " + remote.type + ", subtype = " + remote.subtype);
-            InspectorTest.DebuggerAgent.getGeneratorObjectDetails(remote.objectId, didGetDetails);
+            remote.getOwnPropertiesPromise().then(dumpInternalProperties);
         }
 
-        function didGetDetails(error, response)
+        function dumpInternalProperties(properties)
         {
-            InspectorTest.assertTrue(!error, "FAIL: " + error);
-            dumpGeneratorObjectDetails(response);
+            InspectorTest.assertTrue(properties && properties.internalProperties, "FAIL: no properties");
+            for (var prop of properties.internalProperties) {
+                if (prop.name !== "[[GeneratorLocation]]")
+                    InspectorTest.addResult(prop.name + " = " + prop.value.description);
+                else
+                    dumpLocation(prop.value.value);
+            }
             next();
         }
+
+        function dumpLocation(location)
+        {
+            InspectorTest.addResult("lineNumber = " + location.lineNumber);
+            InspectorTest.addResult("columnNumber = " + location.columnNumber);
+            InspectorTest.addResult("script is valid: " + (location.scriptId ? "yes" : "no"));
+        }
     }
 
     var expressions = [
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/script-snippet-model-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/script-snippet-model-expected.txt
index 155411e..7a147a3 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/script-snippet-model-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/script-snippet-model-expected.txt
@@ -69,3 +69,5 @@
 Last evaluation source url for snippet: snippets:///1_1
 Snippet execution result: 4
 
+Running: testDangerousNames
+
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/script-snippet-model.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/script-snippet-model.html
index 82678cd..4f2a1bd 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/script-snippet-model.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/script-snippet-model.html
@@ -281,6 +281,30 @@
                 evaluateSnippetAndDumpEvaluationDetails(uiSourceCode, context, next);
             }
         },
+
+        function testDangerousNames(next)
+        {
+            resetSnippetsSettings();
+
+            WebInspector.scriptSnippetModel.project().createFile("", null, "", step2.bind(this));
+
+            function step2(uiSourceCode)
+            {
+                uiSourceCode.rename("toString", function() { });
+                InspectorTest.showUISourceCode(uiSourceCode,step3.bind(this));
+            }
+
+            function step3()
+            {
+                WebInspector.scriptSnippetModel.project().createFile("", null, "", step4.bind(this));
+            }
+
+            function step4(uiSourceCode)
+            {
+                uiSourceCode.rename("myfile.toString", function() { });
+                InspectorTest.showUISourceCode(uiSourceCode,next);
+            }
+        }
     ]);
 };
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/show-generator-location.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/show-generator-location.html
index 6c41f6c..2a159f4 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/show-generator-location.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/show-generator-location.html
@@ -35,7 +35,19 @@
 
         function didEvaluate(remote)
         {
-            panel._showGeneratorLocation(remote);
+            remote.getOwnPropertiesPromise().then(revealLocation.bind(null, remote));
+        }
+
+        function revealLocation(remote, properties)
+        {
+            var loc;
+            for (var prop of properties.internalProperties) {
+                if (prop.name === "[[GeneratorLocation]]") {
+                    loc = prop.value.value;
+                    break;
+                }
+            }
+            WebInspector.Revealer.reveal(remote.debuggerModel().createRawLocationByScriptId(loc.scriptId, loc.lineNumber, loc.columnNumber));
         }
 
         function showUISourceCodeHook(uiSourceCode, lineNumber, columnNumber, forceShowInPanel)
diff --git a/third_party/WebKit/LayoutTests/media/video-defaultmuted-expected.txt b/third_party/WebKit/LayoutTests/media/video-defaultmuted-expected.txt
deleted file mode 100644
index d718364..0000000
--- a/third_party/WebKit/LayoutTests/media/video-defaultmuted-expected.txt
+++ /dev/null
@@ -1,72 +0,0 @@
-Test 'muted' content attribute
-
-
-
-*** Test with 'muted' content attribute
-
-RUN(video = document.createElement('video'))
-RUN(video.setAttribute('controls', 'controls'))
-RUN(video.setAttribute('muted', 'muted'))
-
-*** Test before setting src, IDL attribute should default to false
-EXPECTED (video.muted == 'false') OK
-EXPECTED (video.defaultMuted == 'true') OK
-
-EVENT(loadedmetadata)
-
-*** After setting url, content attribute should have set IDL attribute
-EXPECTED (video.muted == 'true') OK
-EXPECTED (video.defaultMuted == 'true') OK
-
-*** Change 'defaultMuted', IDL attribute should not change but content attribute should.
-RUN(video.defaultMuted = false)
-EXPECTED (video.muted == 'true') OK
-EXPECTED (video.defaultMuted == 'false') OK
-EXPECTED (video.hasAttribute('muted') == 'false') OK
-
-*** Change 'muted' IDL attribute, content attribute should not change
-RUN(video.muted = false)
-EXPECTED (video.muted == 'false') OK
-EXPECTED (video.defaultMuted == 'false') OK
-EXPECTED (video.hasAttribute('muted') == 'false') OK
-
-*** Remove 'muted' content attribute, it should have no effect on IDL attribute
-RUN(video.removeAttribute('muted'))
-EXPECTED (video.muted == 'false') OK
-EXPECTED (video.defaultMuted == 'false') OK
-
-
-*** Test without 'muted' content attribute
-
-RUN(video = document.createElement('video'))
-RUN(video.setAttribute('controls', 'controls'))
-
-*** Test before setting src, IDL attribute should default to false
-EXPECTED (video.muted == 'false') OK
-EXPECTED (video.defaultMuted == 'false') OK
-
-EVENT(loadedmetadata)
-
-*** After setting url, content attribute should have set IDL attribute
-EXPECTED (video.muted == 'false') OK
-EXPECTED (video.defaultMuted == 'false') OK
-
-*** Change 'defaultMuted', IDL attribute should not change but content attribute should.
-RUN(video.defaultMuted = true)
-EXPECTED (video.muted == 'false') OK
-EXPECTED (video.defaultMuted == 'true') OK
-EXPECTED (video.hasAttribute('muted') == 'true') OK
-
-*** Change 'muted' IDL attribute, content attribute should not change
-RUN(video.muted = false)
-EXPECTED (video.muted == 'false') OK
-EXPECTED (video.defaultMuted == 'true') OK
-EXPECTED (video.hasAttribute('muted') == 'true') OK
-
-*** Add 'muted' content attribute, it should have no effect on IDL attribute
-RUN(video.setAttribute('muted', 'muted'))
-EXPECTED (video.muted == 'false') OK
-EXPECTED (video.defaultMuted == 'true') OK
-
-END OF TEST
-
diff --git a/third_party/WebKit/LayoutTests/media/video-defaultmuted.html b/third_party/WebKit/LayoutTests/media/video-defaultmuted.html
index f58e5ce8..67623dd 100644
--- a/third_party/WebKit/LayoutTests/media/video-defaultmuted.html
+++ b/third_party/WebKit/LayoutTests/media/video-defaultmuted.html
@@ -1,92 +1,38 @@
-<!doctype html>
-<html>
-    <head>
-        <!-- TODO(foolip): Convert test to testharness.js. crbug.com/588956
-             (Please avoid writing new tests using video-test.js) -->
-        <script src=video-test.js></script>
-        <script src=media-file.js></script>
-        <script>
-            var index = 0;
+<!DOCTYPE html>
+<title>Test "defaultMuted" IDL, "muted" IDL and content attributes.</title>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="media-file.js"></script>
+<script>
+test(function() {
+    var video = document.createElement("video");
+    // Test that "defaultMuted" IDL attribute reflects "muted" content attribute and
+    // that "muted" IDL attribute is not affected by content attribute.
+    assert_false(video.muted);
+    assert_false(video.defaultMuted);
+    video.setAttribute("muted", "muted");
+    assert_false(video.muted);
+    assert_true(video.defaultMuted);
+    video.removeAttribute("muted", "muted");
+    assert_false(video.muted);
+    assert_false(video.defaultMuted);
 
-            function testMuted(expectedMuted, expectedDefaultMuted)
-            {
-                testExpected("video.muted", expectedMuted);
-                testExpected("video.defaultMuted", expectedDefaultMuted);
-            }
+    // Test that "muted" IDL attribute is not affected by "defaultMuted" IDL attribute.
+    video.defaultMuted = true;
+    assert_false(video.muted);
+}, "Test 'defaultMuted' and 'muted' IDL attributes");
 
-            function test(defaultMuted)
-            {
-                consoleWrite("<br><br><b>*** Test <em>" + (defaultMuted ? "with" : "without") + "</em> 'muted' content attribute</b><br>");
+async_test(function(t) {
+    var video = document.createElement("video");
+    // Set "muted" content attribute and it should set "muted" IDL attribute on video load.
+    // This is wrong per spec. See https://crbug.com/350303 for details.
+    video.setAttribute("muted", "muted");
 
-                run("video = document.createElement('video')");
-                run("video.setAttribute('controls', 'controls')");
-                video.setAttribute('width', '300');
-                if (defaultMuted)
-                    run("video.setAttribute('muted', 'muted')");
-                document.getElementById('parent').appendChild(video);
+    video.onloadedmetadata = t.step_func_done(function() {
+        // "muted" IDL attribute should have been set.
+        assert_true(video.muted);
+    });
 
-                consoleWrite("<br>*** Test before setting src, IDL attribute should default to false");
-                testMuted(false, defaultMuted);
-
-                var loadedmetadata = function(evt)
-                {
-                    consoleWrite("<br>EVENT(" + evt.type + ")");
-
-                    consoleWrite("<br>*** After setting url, content attribute should have set IDL attribute");
-                    testMuted(defaultMuted, defaultMuted);
-
-                    consoleWrite("<br>*** Change 'defaultMuted', IDL attribute should not change but content attribute should.");
-                    var newDefaultMuted = !defaultMuted;
-                    run("video.defaultMuted = " + newDefaultMuted);
-                    testMuted(defaultMuted, newDefaultMuted);
-                    testExpected("video.hasAttribute('muted')", newDefaultMuted);
-
-                    consoleWrite("<br>*** Change 'muted' IDL attribute, content attribute should not change");
-                    run("video.muted = false");
-                    testMuted(false, newDefaultMuted);
-                    testExpected("video.hasAttribute('muted')", newDefaultMuted);
-
-                    var action = defaultMuted ? "Remove" : "Add";
-                    consoleWrite("<br>*** " + action + " 'muted' content attribute, it should have no effect on IDL attribute");
-                    if (defaultMuted)
-                        run("video.removeAttribute('muted')");
-                    else
-                        run("video.setAttribute('muted', 'muted')");
-                    testMuted(false, video.hasAttribute('muted'));
-
-                    runNextTest();
-                }
-                video.addEventListener('loadedmetadata', loadedmetadata);
-                video.src = findMediaFile("audio", "content/test");
-            }
-
-            function runNextTest()
-            {
-                if (video) {
-                    video.parentNode.removeChild(video);
-                    video = null;
-                }
-
-                switch (++index)
-                {
-                case 1:
-                    test(true);
-                    break;
-                case 2:
-                    test(false);
-                    break;
-                case 3:
-                    consoleWrite("");
-                    endTest();
-                    break;
-                }
-            }
-
-        </script>
-    </head>
-
-    <body onload="runNextTest()">
-        <div id="parent"></div>
-        <p>Test 'muted' content attribute<p>
-    </body>
-</html>
+    video.src = findMediaFile("audio", "content/test");
+}, "Test 'muted' content and IDL attributes on video load");
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/video-double-seek-currentTime-expected.txt b/third_party/WebKit/LayoutTests/media/video-double-seek-currentTime-expected.txt
deleted file mode 100644
index 2cf8a59..0000000
--- a/third_party/WebKit/LayoutTests/media/video-double-seek-currentTime-expected.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-Test currentTime values when setting from seeking event.
-
-
-loadedmetadata()
-doNextSeek() 0
-doNextSeek() seeking to 1.00
-seeking 1.00
-doNextSeek() 1
-doNextSeek() seeking to 1.50
-seeking 1.50
-doNextSeek() 2
-doNextSeek() seeking to 1.50
-seeking 1.50
-doNextSeek() 3
-seeked 1.50
-END OF TEST
-
diff --git a/third_party/WebKit/LayoutTests/media/video-double-seek-currentTime.html b/third_party/WebKit/LayoutTests/media/video-double-seek-currentTime.html
index b125afdc..fe5e533 100644
--- a/third_party/WebKit/LayoutTests/media/video-double-seek-currentTime.html
+++ b/third_party/WebKit/LayoutTests/media/video-double-seek-currentTime.html
@@ -1,84 +1,32 @@
 <!DOCTYPE html>
-<html>
-    <head>
-        <script src=media-file.js></script>
-        <!-- TODO(foolip): Convert test to testharness.js. crbug.com/588956
-             (Please avoid writing new tests using video-test.js) -->
-        <script src=video-test.js></script>
-        <script>
-            var seekCount = 0;
-            var expectedSeek = 0;
-            var video;
+<title>Test double seek currentTime.</title>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="media-file.js"></script>
+<video></video>
+<script>
+// Seek to same time twice and make sure "seeking" is fired twice and that
+// "seeked" is fired only once with the "currentTime" being the time set.
+async_test(function(t) {
+    var timeToTest = 1.5;
+    var video = document.querySelector("video");
 
-            function seeking(e)
-            {
-                consoleWrite("seeking " + e.target.currentTime.toFixed(2));
+    var watcher = new EventWatcher(t, video, ["loadedmetadata", "seeking", "seeked"]);
+    watcher.wait_for("loadedmetadata").then(t.step_func(function() {
+        video.currentTime = 1.0;
+        return watcher.wait_for("seeking");
+    })).then(t.step_func(function() {
+        video.currentTime = timeToTest;
+        return watcher.wait_for("seeking");
+    })).then(t.step_func(function() {
+        video.currentTime = timeToTest;
+        return watcher.wait_for("seeking");
+    })).then(t.step_func(function() {
+        return watcher.wait_for("seeked");
+    })).then(t.step_func_done(function() {
+        assert_equals(video.currentTime, timeToTest);
+    }));
 
-                doNextSeek(e.target);
-            }
-
-            function seeked(e)
-            {
-                consoleWrite("seeked " + e.target.currentTime.toFixed(2));
-
-                video = e.target;
-                var now = e.target.currentTime.toFixed(2);
-                var expected = expectedSeek.toFixed(2);
-                if (now != expected) {
-                    failTest("Expected " + expectedSeek + " got " + now);
-                    return;
-                }
-                endTest();
-            }
-
-            function doNextSeek(video)
-            {
-                consoleWrite("doNextSeek() " + seekCount);
-
-                var newSeekPoint = -1;
-                switch (seekCount) {
-                case 0:
-                    newSeekPoint = 1;
-                    break;
-                case 1:
-                    newSeekPoint = 1.5;
-                    break;
-                case 2:
-                    newSeekPoint = 1.5;
-                    break;
-                };
-
-                if (newSeekPoint >= 0) {
-                    consoleWrite('doNextSeek() seeking to ' + newSeekPoint.toFixed(2));
-                    expectedSeek = newSeekPoint;
-                    video.currentTime = newSeekPoint;
-                }
-                seekCount++;
-            }
-
-            function loadedmetadata(e)
-            {
-                consoleWrite("loadedmetadata()");
-                doNextSeek(e.target);
-            }
-
-            function onWindowLoad(e)
-            {
-                video = document.getElementById('video');
-
-                video.src = findMediaFile("video", "content/test");
-                video.addEventListener('seeking', seeking);
-                video.addEventListener('seeked', seeked);
-                video.addEventListener('loadedmetadata', loadedmetadata);
-                video.load();
-            }
-
-            window.addEventListener('load', onWindowLoad, false);
-        </script>
-    </head>
-    <body>
-        <video controls id="video"></video>
-        <p>Test currentTime values when setting from seeking event.</p>
-        <br/>
-    </body>
-</html>
+    video.src = findMediaFile("video", "content/test");
+});
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/video-loop-expected.txt b/third_party/WebKit/LayoutTests/media/video-loop-expected.txt
deleted file mode 100644
index 2e5fa75..0000000
--- a/third_party/WebKit/LayoutTests/media/video-loop-expected.txt
+++ /dev/null
@@ -1,63 +0,0 @@
-Test looping by:
-
-Play to end with 'loop' set to true.
-When 'seeked' event fires, verify that time has jumped back and movie is playing.
-Set 'loop' to false and play again.
-Verify that 'ended' event fires.
-++ Test setting/removing the attribute.
-EXPECTED (video.getAttribute('loop') == 'null') OK
-EXPECTED (video.loop == 'false') OK
-RUN(video.loop = true)
-EXPECTED (video.loop == 'true') OK
-EXPECTED (video.getAttribute('loop') != 'null') OK
-RUN(video.removeAttribute('loop'))
-EXPECTED (video.loop == 'false') OK
-
-++ Set 'loop' to true and begin playing.
-RUN(video.loop = true)
-
-EVENT(play)
-
-++ seek to near the end, wait for 'seeked' event to announce loop.
-EXPECTED (video.paused == 'false') OK
-RUN(video.pause())
-RUN(video.currentTime = video.duration - 0.4)
-
-EVENT(pause)
-EVENT(seeked)
-
-++ first seek completed, beginning playback.
-EXPECTED (video.paused == 'true') OK
-EXPECTED (video.ended == 'false') OK
-RUN(video.play())
-
-EVENT(play)
-EVENT(seeked)
-
-++ second seek completed because video looped, toggle 'loop' and seek to near end again.
-EXPECTED (video.paused == 'false') OK
-EXPECTED (video.ended == 'false') OK
-RUN(video.pause())
-EXPECTED (mediaElement.currentTime >= '0') OK
-EXPECTED (mediaElement.currentTime < 'mediaElement.duration') OK
-RUN(video.loop = false)
-RUN(video.currentTime = video.duration - 0.4)
-
-EVENT(pause)
-EVENT(seeked)
-
-++ third seek completed, beginning playback for the last time.
-EXPECTED (video.paused == 'true') OK
-EXPECTED (video.ended == 'false') OK
-RUN(video.play())
-
-EVENT(play)
-EVENT(pause)
-EVENT(ended)
-
-++ played to end and stopped.
-EXPECTED (video.ended == 'true') OK
-EXPECTED (mediaElement.currentTime == 'mediaElement.duration') OK
-
-END OF TEST
-
diff --git a/third_party/WebKit/LayoutTests/media/video-loop-from-ended-expected.txt b/third_party/WebKit/LayoutTests/media/video-loop-from-ended-expected.txt
deleted file mode 100644
index 37d35a6..0000000
--- a/third_party/WebKit/LayoutTests/media/video-loop-from-ended-expected.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-Test looping edge case to verify http://crbug.com/364442. Steps:
-
-Seek toward end of video (for faster testing).
-Play video to end with 'loop' set to false.
-Once ended, set 'loop' to true.
-Call play.
-Verify that 'seeked' event fires, seeking back to the beginning.
-Pause video and end test.
-
-++ Video is initially paused and 'loop' unset.
-EXPECTED (video.paused == 'true') OK
-EXPECTED (video.loop == 'false') OK
-
-++ Seek to just before the end of the video and play.
-RUN(video.currentTime = video.duration - .5)
-RUN(video.play())
-
-EVENT(play)
-EVENT(ended)
-
-++ Verify played to end and stopped.
-EXPECTED (video.ended == 'true') OK
-EXPECTED (video.paused == 'true') OK
-EXPECTED (video.currentTime == 'video.duration') OK
-
-++ With playback ended, set 'loop' attribute. This will cause ended == false; looping video cannot be 'ended', only paused.
-EXPECTED (video.loop == 'false') OK
-RUN(video.loop = true)
-EXPECTED (video.loop == 'true') OK
-EXPECTED (video.ended == 'false') OK
-EXPECTED (video.paused == 'true') OK
-
-++ Play video with 'loop' set. Expect seek back to start.
-RUN(video.play())
-
-EVENT(play)
-EVENT(seeked)
-
-++ Observed seek. Verify current time decreased and still playing.
-EXPECTED (video.loop == 'true') OK
-EXPECTED (video.paused == 'false') OK
-EXPECTED (video.ended == 'false') OK
-EXPECTED (video.currentTime < 'video.duration') OK
-
-++ Pausing now that test is over to prevent additional unwanted looping.
-RUN(video.pause())
-
-END OF TEST
-
diff --git a/third_party/WebKit/LayoutTests/media/video-loop-from-ended.html b/third_party/WebKit/LayoutTests/media/video-loop-from-ended.html
index bc4b771..a441d48 100644
--- a/third_party/WebKit/LayoutTests/media/video-loop-from-ended.html
+++ b/third_party/WebKit/LayoutTests/media/video-loop-from-ended.html
@@ -1,89 +1,55 @@
 <!DOCTYPE html>
-<html>
-    <head>
-        <script src=media-file.js></script>
-        <!-- TODO(foolip): Convert test to testharness.js. crbug.com/588956
-             (Please avoid writing new tests using video-test.js) -->
-        <script src=video-test.js></script>
+<title>Test looping edge case to verify http://crbug.com/364442.</title>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="media-file.js"></script>
+<video></video>
+<script>
+// Seek towards end of video (for faster testing).
+// Play video to end with "loop" set to false.
+// Once ended, set "loop" to true. Call play.
+// Verify that "seeked" event fires, seeking back to the beginning.
+// Pause video and end test.
+async_test(function(t) {
+    var video = document.querySelector("video");
 
-        <script>
-            function start()
-            {
-                findMediaElement();
-                var mediaFile = findMediaFile("video", "content/test");
-                video.src = mediaFile;
+    video.onloadedmetadata = t.step_func(function() {
+        // Video is initially paused and "loop" unset.
+        assert_true(video.paused);
+        assert_false(video.loop);
+        // Seek to just before the end of the video and play.
+        video.currentTime = video.duration - 0.5;
+        video.onended = t.step_func(function() {
+            // Verify played to end and stopped.
+            assert_true(video.ended);
+            assert_true(video.paused);
+            assert_equals(video.currentTime, video.duration);
 
-                consoleWrite("<br><em>++ Video is initially paused and 'loop' unset.</em>");
-                testExpected("video.paused", true)
-                testExpected("video.loop", false);
+            // With playback ended, set "loop" attribute. This will cause ended == false.
+            // looping video cannot be "ended", only paused.
+            assert_false(video.loop);
+            video.loop = true;
+            assert_true(video.loop);
+            assert_false(video.ended);
+            assert_true(video.paused);
 
-                seekThenPlayWhenReady();
-            }
+            video.onseeked = t.step_func_done(function() {
+                // Observed seek. Verify current time decreased and still playing.
+                assert_true(video.loop)
+                assert_false(video.paused);
+                assert_false(video.ended);
+                assert_less_than(video.currentTime, video.duration);
+                // Pausing now that test is over to prevent additional unwanted looping.
+                video.pause();
+            });
 
-            function seekThenPlayWhenReady() {
-                if (video.readyState < HTMLMediaElement.HAVE_METADATA) {
-                    setTimeout(seekThenPlayWhenReady, 100);
-                    return;
-                }
+            // Play video with "loop" set. Expect seek back to start.
+            video.play();
+        });
 
-                consoleWrite("<br><em>++ Seek to just before the end of the video and play.</em>");
-                run("video.currentTime = video.duration - .5");
-                waitForEvent("play");
-                waitForEvent("ended", ended);
-                run("video.play()");
-                consoleWrite("");
-            }
+        video.play();
+    });
 
-            function ended()
-            {
-                consoleWrite("<br><em>++ Verify played to end and stopped.</em>");
-                testExpected("video.ended", true);
-                testExpected("video.paused", true);
-                // Using reportExpected to avoid logging floating point value which may differ across engines.
-                reportExpected(video.currentTime == video.duration, "video.currentTime", "==", "video.duration", video.currentTime);
-
-                consoleWrite("<br><em>++ With playback ended, set 'loop' attribute. This will cause ended == false; looping video cannot be 'ended', only paused.</em>");
-                testExpected("video.loop", false);
-                run("video.loop = true");
-                testExpected("video.loop", true);
-                testExpected("video.ended", false);
-                testExpected("video.paused", true);
-
-                consoleWrite("<br><em>++ Play video with 'loop' set. Expect seek back to start.<em>");
-                waitForEvent("seeked", seeked);
-                run("video.play()");
-                consoleWrite("");
-            }
-
-            function seeked()
-            {
-                consoleWrite("<br><em>++ Observed seek. Verify current time decreased and still playing.</em>");
-                testExpected("video.loop", true);
-                testExpected("video.paused", false);
-                testExpected("video.ended", false);
-                // Using reportExpected to avoid logging floating point value which may differ across engines.
-                reportExpected(video.currentTime < video.duration, "video.currentTime", "<", "video.duration", video.currentTime);
-
-                consoleWrite("<br><em>++ Pausing now that test is over to prevent additional unwanted looping.</em>");
-                run("video.pause()");
-                consoleWrite("");
-                endTest();
-            }
-        </script>
-
-    </head>
-    <body>
-        <video controls></video>
-        <p><b>Test looping edge case to verify http://crbug.com/364442. Steps:</b>
-        <ol>
-            <li>Seek toward end of video (for faster testing).</li>
-            <li>Play video to end with 'loop' set to false.</li>
-            <li>Once ended, set 'loop' to true.</li>
-            <li>Call play.</li>
-            <li>Verify that 'seeked' event fires, seeking back to the beginning.</li>
-            <li>Pause video and end test.</li>
-        </ol>
-        </p>
-        <script>start()</script>
-    </body>
-</html>
+    video.src = findMediaFile("video", "content/test");
+});
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/video-loop.html b/third_party/WebKit/LayoutTests/media/video-loop.html
index 3cdfbda3..4aee3df 100644
--- a/third_party/WebKit/LayoutTests/media/video-loop.html
+++ b/third_party/WebKit/LayoutTests/media/video-loop.html
@@ -1,124 +1,73 @@
 <!DOCTYPE html>
-<html>
-    <head>
-        <script src=media-file.js></script>
-        <!-- TODO(foolip): Convert test to testharness.js. crbug.com/588956
-             (Please avoid writing new tests using video-test.js) -->
-        <script src=video-test.js></script>
+<title>Test video looping.</title>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="media-file.js"></script>
+<video autoplay></video>
+<script>
+// Test looping by:
+// Play to end with "loop" set to true.
+// When "seeked" event fires, verify that time has jumped back and movie is playing.
+// Set "loop" to false and play again.
+// Verify that "ended" event fires.
+async_test(function(t) {
+    var video = document.querySelector("video");
+    // Test setting/removing the attribute.
+    assert_equals(video.getAttribute("loop"), null);
+    assert_false(video.loop);
 
-        <script>
-            var seekCount = 0;
-            var playCount = 0;
+    video.loop = true;
+    assert_true(video.loop);
+    assert_not_equals(video.getAttribute("loop"), null);
 
-            function play()
-            {
-                if (video.readyState < HTMLMediaElement.HAVE_METADATA) {
-                    setTimeout(play, 100);
-                    return;
-                }
+    video.removeAttribute("loop");
+    assert_false(video.loop);
 
-                if (++playCount > 1)
-                    return;
+    video.onplay = t.step_func(function() {
+        video.onplay = null;
+        assert_false(video.paused);
 
-                consoleWrite("<br><em>++ seek to near the end, wait for 'seeked' event to announce loop.</em>");
-                testExpected("video.paused", false);
-
-                // Pause playback so the movie can't possibly loop before the seeked event fires
-                run("video.pause()");
-                waitForEvent("seeked", seeked);
-                run("video.currentTime = video.duration - 0.4");
-                consoleWrite("");
+        // Pause playback so the movie can't possibly loop before the seeked event fires.
+        video.pause();
+        // seek to near the end, wait for "seeked" event to announce loop.
+        var seekCount = 0;
+        video.onseeked = t.step_func(function() {
+            switch (++seekCount) {
+            case 1:
+                // first seek completed, beginning playback.
+                assert_true(video.paused);
+                assert_false(video.ended);
+                video.play();
+                break;
+            case 2:
+                // second seek completed because video looped, toggle "loop" and seek to near end again.
+                assert_false(video.paused);
+                assert_false(video.ended);
+                video.pause();
+                assert_greater_than_equal(video.currentTime, 0);
+                assert_less_than(video.currentTime, video.duration);
+                video.loop = false;
+                video.currentTime = video.duration - 0.4;
+                break;
+            case 3:
+                // third seek completed, beginning playback for the last time.
+                assert_true(video.paused);
+                assert_false(video.ended);
+                video.play();
+                break;
             }
+        });
 
-            function seeked()
-            {
-                switch (++seekCount)
-                {
-                    case 1:
-                        consoleWrite("<br><em>++ first seek completed, beginning playback.</em>");
-                        testExpected("video.paused", true);
-                        testExpected("video.ended", false);
-                        run("video.play()");
-                        consoleWrite("");
-                        break;
-                    case 2:
-                        consoleWrite("<br><em>++ second seek completed because video looped, toggle 'loop' and seek to near end again.</em>");
-                        testExpected("video.paused", false);
-                        testExpected("video.ended", false);
-                        run("video.pause()");
+        video.currentTime = video.duration - 0.4;
+    });
 
-                        testExpected("mediaElement.currentTime", 0, '>=');
+    video.onended = t.step_func_done(function() {
+        assert_true(video.ended);
+        assert_equals(video.currentTime, video.duration);
+    });
 
-                        // don't use "testExpected()" so we won't log the actual duration as the floating point result may differ with different engines
-                        reportExpected(mediaElement.currentTime < mediaElement.duration, "mediaElement.currentTime", "<", "mediaElement.duration", mediaElement.currentTime);
-                        run("video.loop = false");
-                        run("video.currentTime = video.duration - 0.4");
-                        consoleWrite("");
-                        break;
-                    case 3:
-                        consoleWrite("<br><em>++ third seek completed, beginning playback for the last time.</em>");
-                        testExpected("video.paused", true);
-                        testExpected("video.ended", false);
-                        run("video.play()");
-                        consoleWrite("");
-                        break;
-                    default:
-                        failTest("Video should have only seeked three times.");
-                        break;
-
-                }
-            }
-
-            function ended()
-            {
-                consoleWrite("<br><em>++ played to end and stopped.</em>");
-                testExpected("video.ended", true);
-
-                // don't use "testExpected()" so we won't log the actual duration as the floating point result may differ with different engines
-                reportExpected(mediaElement.currentTime == mediaElement.duration, "mediaElement.currentTime", "==", "mediaElement.duration", mediaElement.currentTime);
-
-                consoleWrite("");
-                endTest();
-            }
-
-            function start()
-            {
-                findMediaElement();
-
-                consoleWrite("<em>++ Test setting/removing the attribute.</em>");
-                testExpected("video.getAttribute('loop')", null);
-                testExpected("video.loop", false);
-
-                run("video.loop = true");
-                testExpected("video.loop", true);
-                testExpected("video.getAttribute('loop')", null, "!=");
-
-                run("video.removeAttribute('loop')");
-                testExpected("video.loop", false);
-
-                waitForEvent('pause');
-                waitForEvent('play', play);
-                waitForEvent("ended", ended);
-
-                consoleWrite("<br><em>++ Set 'loop' to true and begin playing.</em>");
-                var mediaFile = findMediaFile("video", "content/test");
-                run("video.loop = true");
-                video.src = mediaFile;
-                consoleWrite("");
-            }
-        </script>
-
-    </head>
-    <body>
-        <video controls autoplay ></video>
-        <p><b>Test looping by:</b>
-        <ol>
-            <li>Play to end with 'loop' set to true.</li>
-            <li>When 'seeked' event fires, verify that time has jumped back and movie is playing.</li>
-            <li>Set 'loop' to false and play again.</li>
-            <li>Verify that 'ended' event fires.</li>
-        </ol>
-        </p>
-        <script>start()</script>
-    </body>
-</html>
+    // Set "loop" to true and begin playing.
+    video.loop = true;
+    video.src = findMediaFile("video", "content/test");
+});
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/video-size-expected.txt b/third_party/WebKit/LayoutTests/media/video-size-expected.txt
deleted file mode 100644
index 8e19077..0000000
--- a/third_party/WebKit/LayoutTests/media/video-size-expected.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-Test <video> element size with and without 'src' and 'poster' attributes.
-
-Testing movie with no 'src' and no 'poster', with 'width' and 'height' attributes.
-EXPECTED (video.clientWidth == '640') OK
-EXPECTED (video.clientHeight == '480') OK
-EXPECTED (video.videoWidth == '0') OK
-EXPECTED (video.videoHeight == '0') OK
-
-Removing 'width' and 'height' attributes.
-Testing movie with no 'src' and no 'poster', with NO 'width' and 'height' attributes, should be default size.
-EXPECTED (video.clientWidth == '300') OK
-EXPECTED (video.clientHeight == '150') OK
-EXPECTED (video.videoWidth == '0') OK
-EXPECTED (video.videoHeight == '0') OK
-
-Setting 'poster' to "content/abe.png"
-Testing movie with 'poster' but no 'src', should be image size.
-EXPECTED (video.clientWidth == '76') OK
-EXPECTED (video.clientHeight == '103') OK
-EXPECTED (video.videoWidth == '0') OK
-EXPECTED (video.videoHeight == '0') OK
-
-Setting 'src' to "content/test.[extension]" 
-Testing movie with 'poster' and 'src', should be <video> size.
-EXPECTED (video.clientWidth == '320') OK
-EXPECTED (video.clientHeight == '240') OK
-EXPECTED (video.videoWidth == '320') OK
-EXPECTED (video.videoHeight == '240') OK
-
-Setting 'src' to "content/bogus.[extension]" 'poster' to "content/greenbox.png"
-Testing movie with 'poster' and invalid 'src', should be image size.
-EXPECTED (video.clientWidth == '25') OK
-EXPECTED (video.clientHeight == '25') OK
-EXPECTED (video.videoWidth == '0') OK
-EXPECTED (video.videoHeight == '0') OK
-
-END OF TEST
-
diff --git a/third_party/WebKit/LayoutTests/media/video-size.html b/third_party/WebKit/LayoutTests/media/video-size.html
index 9446d96d..462bddd 100644
--- a/third_party/WebKit/LayoutTests/media/video-size.html
+++ b/third_party/WebKit/LayoutTests/media/video-size.html
@@ -1,131 +1,97 @@
-<html>
-    <head>
-        <title>&lt;video&gt; element size and resize test</title>
-        <!-- TODO(foolip): Convert test to testharness.js. crbug.com/588956
-             (Please avoid writing new tests using video-test.js) -->
-        <script src=video-test.js></script>
-        <script src=media-file.js></script>
+<!DOCTYPE html>
+<title>Test "video" element size with and without "src" and "poster" attributes.</title>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="media-file.js"></script>
+<body>
+<script>
+var movieInfo = [
+    {
+        src: null,
+        poster: null,
+        description: "no 'src' and no 'poster', with 'width' and 'height' attributes",
+        width: 640,
+        height: 480,
+        videoWidth: 0,
+        videoHeight: 0,
+        setSize: true
+    },
+    {
+        src: null,
+        poster: null,
+        description: "no 'src' and no 'poster', with no 'width' and 'height' attributes, should be default size",
+        width: 300,
+        height: 150,
+        videoWidth: 0,
+        videoHeight: 0
+    },
+    {
+        src: null,
+        poster: "content/abe.png",
+        description: "'poster' but no 'src', should be 'poster' size",
+        width: 76,
+        height: 103,
+        videoWidth: 0,
+        videoHeight: 0
+    },
+    {
+        src: "content/test",
+        poster: "content/abe.png",
+        description: "'poster' and 'src', should be 'video' size",
+        width: 320,
+        height: 240,
+        videoWidth: 320,
+        videoHeight: 240
+    },
+    {
+        src: "content/bogus",
+        poster: "content/greenbox.png",
+        description: "'poster' and invalid 'src', should be 'poster' size",
+        width: 25,
+        height: 25,
+        videoWidth: 0,
+        videoHeight: 0
+    }
+];
 
-        <script>
-            var movieInfo =
-            {
-                current:0,
-                movies:
-                [
-                    {
-                        src:null,
-                        poster:null,
-                        description:"no 'src' and no 'poster', with 'width' and 'height' attributes",
-                        width:640,
-                        height:480,
-                        videoWidth:0,
-                        videoHeight:0
-                    },
-                    {
-                        src:null,
-                        poster:null,
-                        description:"no 'src' and no 'poster', with NO 'width' and 'height' attributes, should be default size",
-                        width:300,
-                        height:150,
-                        videoWidth:0,
-                        videoHeight:0
-                    },
-                    {
-                        src:null,
-                        poster:"content/abe.png",
-                        description:"'poster' but no  'src', should be image size",
-                        width:76,
-                        height:103,
-                        videoWidth:0,
-                        videoHeight:0
-                    },
-                    {
-                        src:"content/test",
-                        poster:"content/abe.png",
-                        description:"'poster' and  'src', should be &lt;video&gt; size",
-                        width:320,
-                        height:240,
-                        videoWidth:320,
-                        videoHeight:240
-                    },
-                    {
-                        src:"content/bogus",
-                        poster:"content/greenbox.png",
-                        description:"'poster' and invalid 'src', should be image size",
-                        width:25,
-                        height:25,
-                        videoWidth:0,
-                        videoHeight:0
-                    },
-                ]
-            };
+movieInfo.forEach(function(movie) {
+    async_test(function(t) {
+        if (movie.poster) {
+            var image = document.createElement("img");
+            image.src = movie.poster;
+            document.body.appendChild(image);
+            image.onload = t.step_func(runTest);
+        } else {
+            runTest();
+        }
 
-            function setupNextConfiguration()
-            {
-                consoleWrite("");
-                if (movieInfo.current >= movieInfo.movies.length)
-                {
-                    endTest();
-                    return;
-                }
-
-                var movie = movieInfo.movies[movieInfo.current];
-                if (movie.src || movie.poster) {
-                    var desc = "<b>Setting ";
-                    if (movie.src && relativeURL(video.src) != movie.src) {
-                        video.src = findMediaFile("video", movie.src);
-                        desc += "'src' to <em>\""+ movie.src + ".[extension]\"</em> ";
-                    }
-                    if (movie.poster && relativeURL(video.poster) != movie.poster) {
-                        video.poster = movie.poster;
-                        desc += "'poster' to <em>\""+ movie.poster + "\"</em>";
-                    }
-                    consoleWrite(desc + "</b>");
-                }
-
-                // Remove width/height attributes if present
-                if (video.width || video.height) {
-                    consoleWrite("<b>Removing 'width' and 'height' attributes.</b>");
-                    video.removeAttribute('width');
-                    video.removeAttribute('height');
-                }
-
-                if (!movie.src || movie.src.indexOf('bogus') >= 0)
-                    setTimeout(testMovie, 100);
+        function runTest() {
+            var video = document.createElement("video");
+            document.body.appendChild(video);
+            if (movie.setSize) {
+                video.setAttribute("width", "640");
+                video.setAttribute("height", "480");
             }
 
-            function testMovie()
-            {
-                if (movieInfo.current >= movieInfo.movies.length)
-                    return;
+            if (movie.src)
+                video.src = findMediaFile("video", movie.src);
 
-                var temp = document.body.offsetWidth;
-                var movie = movieInfo.movies[movieInfo.current];
+            if (movie.poster)
+                video.poster = movie.poster;
 
-                var desc = "<b>Testing movie with " + movie.description + ".</b>";
-                consoleWrite(desc);
+            video.onloadedmetadata = t.step_func_done(testMovieSize);
 
-                testExpected("video.clientWidth", movie.width);
-                testExpected("video.clientHeight", movie.height);
-                testExpected("video.videoWidth", movie.videoWidth);
-                testExpected("video.videoHeight", movie.videoHeight);
-
-                movieInfo.current++;
-                setupNextConfiguration();
+            if (!movie.src || movie.src.indexOf("bogus") >= 0) {
+                setTimeout(t.step_func_done(testMovieSize), 0);
             }
 
-            function test()
-            {
-                findMediaElement();
-                testMovie();
+            function testMovieSize() {
+                assert_equals(video.clientWidth, movie.width);
+                assert_equals(video.clientHeight, movie.height);
+                assert_equals(video.videoWidth, movie.videoWidth);
+                assert_equals(video.videoHeight, movie.videoHeight);
             }
-        </script>
-    </head>
-
-    <body onload="setTimeout(test, 100)">
-
-        <video controls width=640 height=480 onloadedmetadata="testMovie()"></video>
-        <p>Test &lt;video&gt; element size with and without 'src' and 'poster' attributes.</p>
-
-    </body>
-</html>
+        }
+    }, movie.description);
+});
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/video-timeupdate-during-playback-expected.txt b/third_party/WebKit/LayoutTests/media/video-timeupdate-during-playback-expected.txt
deleted file mode 100644
index 2b3d6797..0000000
--- a/third_party/WebKit/LayoutTests/media/video-timeupdate-during-playback-expected.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-Test 'timeupdate' events are posted while playing but not while paused.
-
-RUN(video.play())
-
-EVENT(play)
-EVENT(waiting)
-EVENT(loadstart)
-EVENT(durationchange)
-EVENT(loadedmetadata)
-EVENT(loadeddata)
-EVENT(canplay)
-EVENT(playing)
-
-RUN(video.pause())
-EVENT(pause)
-
-END OF TEST
-
diff --git a/third_party/WebKit/LayoutTests/media/video-timeupdate-during-playback.html b/third_party/WebKit/LayoutTests/media/video-timeupdate-during-playback.html
index 9d3c06914..b5a3e4cf 100644
--- a/third_party/WebKit/LayoutTests/media/video-timeupdate-during-playback.html
+++ b/third_party/WebKit/LayoutTests/media/video-timeupdate-during-playback.html
@@ -1,58 +1,25 @@
-<html>
-<body>
+<!DOCTYPE html>
+<title>Test "timeupdate" events are posted while playing but not while paused.</title>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="media-file.js"></script>
+<video></video>
+<script>
+async_test(function(t) {
+    var video = document.querySelector("video");
+    video.src = findMediaFile("video", "content/test");
 
-    <video controls></video>
+    video.onplaying = t.step_func(function() {
+        video.ontimeupdate = t.step_func(function() {
+            video.pause();
+        });
+    });
 
-    <p>
-    Test 'timeupdate' events are posted while playing but not while paused.
-    </p>
-    <script src=media-file.js></script>
-    <!-- TODO(foolip): Convert test to testharness.js. crbug.com/588956
-         (Please avoid writing new tests using video-test.js) -->
-    <script src=video-test.js></script>
-    <script>
-        setSrcByTagName("video", findMediaFile("video", "content/test"));
+    video.onpause = t.step_func(function() {
+        video.ontimeupdate = t.unreached_func();
+        setTimeout(t.step_func_done(), 250);
+    });
 
-        var timeupdateEventCount = 0;
-        var countWhilePlaying = 0;
-
-        function someTimeLater()
-        {
-            if (countWhilePlaying != timeupdateEventCount)
-                failTest("'timeupdate' events posted after pausing");
-            endTest();
-        }
-
-        function pause()
-        {
-            countWhilePlaying = timeupdateEventCount;
-            setTimeout(someTimeLater, 400) ;
-            consoleWrite("");
-        }
-
-        function playing()
-        {
-            setTimeout(function () { run("video.pause()"); }, 500) ;
-            consoleWrite("");
-        }
-
-        mediaElement.addEventListener("timeupdate", function () { ++timeupdateEventCount; });
-
-        waitForEvent('error');
-        waitForEvent("loadstart");
-        waitForEvent("waiting");
-        waitForEvent("ratechange");
-        waitForEvent("durationchange");
-        waitForEvent("loadedmetadata");
-        waitForEvent("loadeddata");
-        waitForEvent("canplay");
-        waitForEvent("pause", pause);
-        waitForEvent("play");
-        waitForEvent("playing", playing);
-
-        run("video.play()");
-        consoleWrite("");
-    </script>
-
-</body>
-</html>
+    video.play();
+});
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/payments/payment-request-interface.html b/third_party/WebKit/LayoutTests/payments/payment-request-interface.html
index 3a65ab1..f580608 100644
--- a/third_party/WebKit/LayoutTests/payments/payment-request-interface.html
+++ b/third_party/WebKit/LayoutTests/payments/payment-request-interface.html
@@ -246,6 +246,18 @@
     ['Empty supported payment method identifiers should throw TypeError.', null, function() {
         new PaymentRequest([{'supportedMethods': []}], buildDetails())
     }],
+    ['Duplicate supported payment method identifiers should throw TypeError.', null, function() {
+        new PaymentRequest([{'supportedMethods': ['foo', 'foo']}], buildDetails(), {})
+    }],
+    ['Duplicate supported payment method identifiers should throw TypeError.', null, function() {
+        new PaymentRequest([{'supportedMethods': ['foo']}, {'supportedMethods': ['foo']}], buildDetails(), {})
+    }],
+    ['Duplicate supported payment method identifiers in modifiers should throw TypeError.', null, function() {
+        new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'modifiers': [{'supportedMethods': ['foo', 'foo']}]})
+    }],
+    ['Duplicate supported payment method identifiers in modifiers should throw TypeError.', null, function() {
+        new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'modifiers': [{'supportedMethods': ['foo']}, {'supportedMethods': ['foo']}]})
+    }],
     ['Empty details should throw', null, function() {
         new PaymentRequest([{'supportedMethods': ['foo']}], {})
     }],
diff --git a/third_party/WebKit/LayoutTests/platform/android/editing/inserting/insert-div-018-expected.png b/third_party/WebKit/LayoutTests/platform/android/editing/inserting/insert-div-018-expected.png
deleted file mode 100644
index 1ae4159a..0000000
--- a/third_party/WebKit/LayoutTests/platform/android/editing/inserting/insert-div-018-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/editing/inserting/insert-div-018-expected.png b/third_party/WebKit/LayoutTests/platform/linux/editing/inserting/insert-div-018-expected.png
deleted file mode 100644
index 2fed467c..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/editing/inserting/insert-div-018-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/editing/inserting/insert-div-018-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/editing/inserting/insert-div-018-expected.txt
deleted file mode 100644
index e96239a3..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/editing/inserting/insert-div-018-expected.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow (anonymous) at (0,0) size 784x28
-        LayoutText {#text} at (0,0) size 656x27
-          text run at (0,0) width 656: "Test inserting paragraphs: should see an empty blue box below \"bar\""
-      LayoutBlockFlow {DIV} at (0,28) size 784x36
-      LayoutBlockFlow (anonymous) at (0,64) size 784x28
-        LayoutText {#text} at (0,0) size 31x27
-          text run at (0,0) width 31: "bar"
-      LayoutBlockFlow {DIV} at (0,92) size 784x112 [border: (2px solid #0000FF)]
-        LayoutBlockFlow (anonymous) at (14,14) size 756x28
-          LayoutBR {BR} at (0,0) size 0x27
-        LayoutBlockFlow {DIV} at (14,42) size 756x56 [border: (2px solid #FF0000)]
-          LayoutText {#text} at (14,14) size 33x27
-            text run at (14,14) width 33: "baz"
-caret: position 0 of child 0 {BR} of child 3 {DIV} of body
diff --git a/third_party/WebKit/LayoutTests/platform/mac/editing/inserting/insert-div-018-expected.png b/third_party/WebKit/LayoutTests/platform/mac/editing/inserting/insert-div-018-expected.png
deleted file mode 100644
index 7c76bda..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/editing/inserting/insert-div-018-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/editing/inserting/insert-div-018-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/editing/inserting/insert-div-018-expected.txt
deleted file mode 100644
index 39d69d7..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/editing/inserting/insert-div-018-expected.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow (anonymous) at (0,0) size 784x28
-        LayoutText {#text} at (0,0) size 660x28
-          text run at (0,0) width 660: "Test inserting paragraphs: should see an empty blue box below \"bar\""
-      LayoutBlockFlow {DIV} at (0,28) size 784x36
-      LayoutBlockFlow (anonymous) at (0,64) size 784x28
-        LayoutText {#text} at (0,0) size 31x28
-          text run at (0,0) width 31: "bar"
-      LayoutBlockFlow {DIV} at (0,92) size 784x112 [border: (2px solid #0000FF)]
-        LayoutBlockFlow (anonymous) at (14,14) size 756x28
-          LayoutBR {BR} at (0,0) size 0x28
-        LayoutBlockFlow {DIV} at (14,42) size 756x56 [border: (2px solid #FF0000)]
-          LayoutText {#text} at (14,14) size 34x28
-            text run at (14,14) width 34: "baz"
-caret: position 0 of child 0 {BR} of child 3 {DIV} of body
diff --git a/third_party/WebKit/LayoutTests/platform/win/editing/inserting/insert-div-018-expected.png b/third_party/WebKit/LayoutTests/platform/win/editing/inserting/insert-div-018-expected.png
deleted file mode 100644
index 0586480b..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/editing/inserting/insert-div-018-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/editing/inserting/insert-div-018-expected.txt b/third_party/WebKit/LayoutTests/platform/win/editing/inserting/insert-div-018-expected.txt
deleted file mode 100644
index 5d8abfc..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/editing/inserting/insert-div-018-expected.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
-EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow (anonymous) at (0,0) size 784x27
-        LayoutText {#text} at (0,0) size 660x26
-          text run at (0,0) width 660: "Test inserting paragraphs: should see an empty blue box below \"bar\""
-      LayoutBlockFlow {DIV} at (0,27) size 784x36
-      LayoutBlockFlow (anonymous) at (0,63) size 784x27
-        LayoutText {#text} at (0,0) size 31x26
-          text run at (0,0) width 31: "bar"
-      LayoutBlockFlow {DIV} at (0,90) size 784x110 [border: (2px solid #0000FF)]
-        LayoutBlockFlow (anonymous) at (14,14) size 756x27
-          LayoutBR {BR} at (0,0) size 0x26
-        LayoutBlockFlow {DIV} at (14,41) size 756x55 [border: (2px solid #FF0000)]
-          LayoutText {#text} at (14,14) size 34x26
-            text run at (14,14) width 34: "baz"
-caret: position 0 of child 0 {BR} of child 3 {DIV} of body
diff --git a/third_party/WebKit/LayoutTests/resources/testharnessreport.js b/third_party/WebKit/LayoutTests/resources/testharnessreport.js
index 64c08a9..0dba6f20 100644
--- a/third_party/WebKit/LayoutTests/resources/testharnessreport.js
+++ b/third_party/WebKit/LayoutTests/resources/testharnessreport.js
@@ -66,9 +66,19 @@
         return !!document.querySelector('script[src*="/resources/testharness"]');
     }
 
+
     function injectSyntheticInput() {
         var path = window.location.pathname;
         if (path.match(/imported\/wpt\/.*\.html$/)) {
+            // Set a global variable for the address of automated input script if they need to use it.
+            var automated_input_scripts_folder = path.replace(/imported\/wpt\/(.*)\.html$/, 'imported/wpt_automation');
+
+            importAutomationScript = function(relativePath) {
+              var common_script = document.createElement('script');
+              common_script.setAttribute('src', automated_input_scripts_folder + relativePath);
+              document.head.appendChild(common_script);
+            }
+
             path = path.replace(/imported\/wpt\/(.*)\.html$/, "imported/wpt_automation/$1-input.js");
             var input_script = document.createElement('script');
             input_script.setAttribute('src', path);
diff --git a/third_party/WebKit/LayoutTests/shadow-dom/crashes/offsetParent-layoutObject-lifecycle.html b/third_party/WebKit/LayoutTests/shadow-dom/crashes/offsetParent-layoutObject-lifecycle.html
new file mode 100644
index 0000000..8a1d08d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/shadow-dom/crashes/offsetParent-layoutObject-lifecycle.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<script src='../../resources/testharness.js'></script>
+<script src='../../resources/testharnessreport.js'></script>
+<script>
+// This case is created from reproduction case by cloudfuzzer.
+window.addEventListener('load', () => {
+  test(() => {
+    var link = document.createElement('link');
+    link.setAttribute('rel','import');
+    document.head.appendChild(link);
+
+    var style = document.createElement('style');
+    style.textContent = '@import url(x)';
+    document.head.appendChild(style);
+
+    var frame = document.createElement('frame');
+    document.body.appendChild(frame);
+
+    // This could cause crash.
+    frame.offsetHeight;
+    assert_true(true, 'This test must run without crash.');
+  }, "HTMLElement.offsetHeight should not cause crash.");
+}, false);
+</script>
+<body></body>
diff --git a/third_party/WebKit/LayoutTests/storage/indexeddb/resources/observer.js b/third_party/WebKit/LayoutTests/storage/indexeddb/resources/observer.js
index 635e3ae3..341ab497 100644
--- a/third_party/WebKit/LayoutTests/storage/indexeddb/resources/observer.js
+++ b/third_party/WebKit/LayoutTests/storage/indexeddb/resources/observer.js
@@ -5,22 +5,31 @@
 function callback(){};
 
 async_test(function(t) {
-    var description = 'observers constructor test';
-    var dbname = location.pathname + ' - ' + description;
-    var openRequest = indexedDB.open(dbname);
-    var obs1 = new IDBObserver(callback, {transaction: true, values: true});
-    openRequest.onupgradeneeded = t.step_func(function() {
-        var db = openRequest.result;
-        db.createObjectStore('store');
-    });
-    openRequest.onsuccess = t.step_func(function() {
-        var db = openRequest.result;
-        var tx = db.transaction('store', 'readwrite');
-        obs1.observe(db, tx);
-        t.done();
-    });
+  var description = 'observer addition and removal test';
+  var dbname = location.pathname + ' - ' + description;
+  var openRequest = indexedDB.open(dbname);
+  var obs1 = new IDBObserver(callback, {transaction: true, values: true});
+  var obs2 = new IDBObserver(callback, {transaction: true, values: true});
 
-}, 'observers constructor test');
+  openRequest.onupgradeneeded = t.step_func(function() {
+      var db = openRequest.result;
+      db.createObjectStore('store');
+  });
+  openRequest.onsuccess = t.step_func(function() {
+    var db = openRequest.result;
+    var tx = db.transaction('store', 'readwrite');
+    var store = tx.objectStore('store');
+        var put_request = store.put(1,1);
+        obs1.observe(db, tx);
+        obs1.unobserve(db);
+        obs1.observe(db, tx);
+        obs2.observe(db, tx);
+        tx.oncomplete = t.step_func(function(){
+          obs1.unobserve(db);
+          t.done();
+        });
+      });
+}, 'observer addition and removal test');
 
 done();
 
diff --git a/third_party/WebKit/LayoutTests/svg/css/css-keyword-properties.html b/third_party/WebKit/LayoutTests/svg/css/css-keyword-properties.html
new file mode 100644
index 0000000..6ef8f25
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/css/css-keyword-properties.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>CSS keywords for SVG properties</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../css-parser/resources/property-parsing-test.js"></script>
+<script>
+function assert_valid_keywords(property, keywords) {
+    for (var keyword of keywords)
+        assert_valid_value(property, keyword);
+}
+
+// alignment-baseline: auto | baseline | before-edge | text-before-edge | middle |
+//                     central | after-edge | text-after-edge | ideographic | alphabetic |
+//                     hanging | mathematical
+assert_valid_keywords('alignmentBaseline', [
+    'auto', 'baseline', 'before-edge', 'text-before-edge', 'middle',
+    'central', 'after-edge', 'text-after-edge', 'ideographic', 'alphabetic',
+    'hanging', 'mathematical'
+]);
+
+// dominant-baseline: auto | use-script | no-change | reset-size | ideographic |
+//                    alphabetic | hanging | mathematical | central | middle |
+//                    text-after-edge | text-before-edge
+assert_valid_keywords('dominantBaseline', [
+    'auto', 'use-script', 'no-change', 'reset-size', 'ideographic',
+    'alphabetic', 'hanging', 'mathematical', 'central', 'middle',
+    'text-after-edge', 'text-before-edge'
+]);
+</script>
diff --git a/third_party/WebKit/LayoutTests/svg/filters/color-interpolation-filters-style-update-expected.html b/third_party/WebKit/LayoutTests/svg/filters/color-interpolation-filters-style-update-expected.html
new file mode 100644
index 0000000..9b92a24
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/filters/color-interpolation-filters-style-update-expected.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<svg>
+  <filter id="f" style="color-interpolation-filters: sRGB">
+    <feColorMatrix type="hueRotate" values="120"/>
+  </filter>
+  <rect fill="red" width="100" height="100" filter="url(#f)"/>
+</svg>
diff --git a/third_party/WebKit/LayoutTests/svg/filters/color-interpolation-filters-style-update.html b/third_party/WebKit/LayoutTests/svg/filters/color-interpolation-filters-style-update.html
new file mode 100644
index 0000000..683e1a05
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/filters/color-interpolation-filters-style-update.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<script src="../../resources/run-after-layout-and-paint.js"></script>
+<svg>
+  <filter id="f">
+    <feColorMatrix type="hueRotate" values="120"/>
+  </filter>
+  <rect fill="red" width="100" height="100" filter="url(#f)"/>
+</svg>
+<script>
+runAfterLayoutAndPaint(function() {
+  document.getElementById('f').style.colorInterpolationFilters = 'sRGB';
+}, true);
+</script>
diff --git a/third_party/WebKit/LayoutTests/tables/invalid-background-url-crash.html b/third_party/WebKit/LayoutTests/tables/invalid-background-url-crash.html
new file mode 100644
index 0000000..569ea7d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/tables/invalid-background-url-crash.html
@@ -0,0 +1,12 @@
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+
+<body onload="window.open()">
+  <table background="http://tLayp%e3s&quot;^1"></table>
+</body>
+
+<script>
+if (window.testRunner)
+  testRunner.setCanOpenWindows();
+test(() => {}, 'This test passes if it does not crash.');
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-position.html b/third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-position.html
index f8c22e0c..40717ac 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-position.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audiolistener-automation-position.html
@@ -180,13 +180,9 @@
 
         var prefix = 'Distance model: "' + options.distanceModel.model + '"';
         prefix += ', rolloff: ' + options.distanceModel.rolloff;
-        success = Should(prefix + ": left channel", actualLeft, {
-            verbose: true
-          })
+        success = Should(prefix + ": left channel", actualLeft)
           .beCloseToArray(expectedLeft, 0) && success;
-        success = Should(prefix + ": right channel", actualRight, {
-            verbose: true
-          })
+        success = Should(prefix + ": right channel", actualRight)
           .beCloseToArray(expectedRight, 0) && success;
 
         var message = 'Moving AudioListener with distance model: "';
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-automation-clamping.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-automation-clamping.html
index 5b9d5622..fac9315 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-automation-clamping.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-automation-clamping.html
@@ -89,9 +89,9 @@
             x => x != 0);
 
           // Verify that the expected clamping range is a subset of the actual range.
-          success = Should("Actual Clamp start (" + actualClampStart + ")",
+          success = Should("Actual Clamp start",
             actualClampStart).beLessThanOrEqualTo(clampStartFrame) && success;
-          success == Should("Actual Clamp end (" + actualClampEnd + ")",
+          success == Should("Actual Clamp end",
             actualClampEnd).beGreaterThanOrEqualTo(clampEndFrame) && success;
 
           if (success)
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous.html
index f5bbf22..37efafef 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous.html
@@ -215,9 +215,8 @@
           // Verify the ramp part of the curve
           startIndex += length;
           length = expected.rampPart.length;
-          success = Should(prefix, result.slice(startIndex, startIndex + length), {
-              verbose: true
-            }).beCloseToArray(expected.rampPart, thresholdRamp) && success;
+          success = Should(prefix, result.slice(startIndex, startIndex + length))
+            .beCloseToArray(expected.rampPart, thresholdRamp) && success;
 
           // Verify that the end of the curve after the ramp (if any) is a constant.
           startIndex += length;
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-duration.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-duration.html
index adbcacd..50be73c 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-duration.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-duration.html
@@ -52,7 +52,9 @@
 
            var message = "setValueCurve([" + curve + "], 0, " + duration + ")";
 
-           success = Should("Max amplitude of " + message, max).beLessThanOrEqualTo(expectedMax);
+           success = Should("Max amplitude of " + message, max, {
+             brief: true
+           }).beLessThanOrEqualTo(expectedMax);
 
            if (success)
              testPassed(message + " correctly rendered.")
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime-interpolation.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime-interpolation.html
index 312aee2..f5cd558 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime-interpolation.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime-interpolation.html
@@ -209,10 +209,16 @@
         source.start();
 
         // Some consistency checks on the test parameters
-        Should("Check: Curve end time", config.curveStartTime + config.curveDuration)
+        Should("Check: Curve end time", config.curveStartTime + config.curveDuration, {
+            brief: true
+          })
           .beLessThanOrEqualTo(testDurationSec);
-        Should("Check: Full gain start time", config.fullGainTime).beLessThanOrEqualTo(testDurationSec);
-        Should("Check: Full gain start time", config.fullGainTime).beGreaterThanOrEqualTo(config.curveStartTime + config.curveDuration);
+        Should("Check: Full gain start time", config.fullGainTime, {
+          brief: true
+        }).beLessThanOrEqualTo(testDurationSec);
+        Should("Check: Full gain start time", config.fullGainTime, {
+          brief: true
+        }).beGreaterThanOrEqualTo(config.curveStartTime + config.curveDuration);
 
         // Rock and roll!
         return context.startRendering().then(checkResult(config));
@@ -239,7 +245,9 @@
             }
           }
 
-          success = success && Should("SNR", SNR).beGreaterThanOrEqualTo(config.snrThreshold);
+          success = success && Should("SNR", SNR, {
+            brief: true
+          }).beGreaterThanOrEqualTo(config.snrThreshold);
 
           if (maxDiff <= config.maxErrorThreshold) {
             testPassed("Max difference is less than or equal to " + config.maxErrorThreshold + ".");
diff --git a/third_party/WebKit/LayoutTests/webaudio/iirfilter.html b/third_party/WebKit/LayoutTests/webaudio/iirfilter.html
index 5f1e42c..2488bce0 100644
--- a/third_party/WebKit/LayoutTests/webaudio/iirfilter.html
+++ b/third_party/WebKit/LayoutTests/webaudio/iirfilter.html
@@ -166,7 +166,7 @@
 
           // Threshold isn't exactly zero due to round-off in the single-precision IIRFilterNode
           // computations versus the double-precision Javascript computations.
-          Should('IIR 1-pole output', actual, {verbose: true})
+          Should('IIR 1-pole output', actual)
             .beCloseToArray(expected, {relativeThreshold: 5.723e-8});
         }).then(done);
       });
@@ -224,13 +224,14 @@
             // even if the threshold passes.  Thus, only print out a very small number of elements
             // of the array where we have tested that they are consistent.
             Should("IIRFilter for Biquad " + filterType, actual, {
-                precision: 5,
-                verbose: true
+                precision: 5
               })
               .beCloseToArray(expected, errorThreshold);
 
             var snr = 10*Math.log10(computeSNR(actual, expected));
-            Should("SNR for IIRFIlter for Biquad " + filterType, snr).beGreaterThanOrEqualTo(snrThreshold);
+            Should("SNR for IIRFIlter for Biquad " + filterType, snr, {
+              brief: true
+            }).beGreaterThanOrEqualTo(snrThreshold);
           }).then(done);
         };
       }
@@ -361,7 +362,9 @@
             });
 
             success = Should("Max difference between IIR and Biquad on channel " + channel,
-              maxError).beLessThanOrEqualTo(errorThresholds[channel]);
+              maxError, {
+                brief: true
+              }).beLessThanOrEqualTo(errorThresholds[channel]);
           }
 
           if (success) {
@@ -547,7 +550,6 @@
 
           Should("4-th order IIRFilter (biquad ref)",
               actual, {
-                verbose: true,
                 precision: 5
               })
             .beCloseToArray(expected, {
@@ -557,7 +559,9 @@
             });
 
           var snr = 10*Math.log10(computeSNR(actual, expected));
-          Should("SNR of 4-th order IIRFilter (biquad ref)", snr)
+          Should("SNR of 4-th order IIRFilter (biquad ref)", snr, {
+              brief: true
+            })
             .beGreaterThanOrEqualTo(108.947);
         }).then(done);
       });
diff --git a/third_party/WebKit/LayoutTests/webaudio/osc-low-freq.html b/third_party/WebKit/LayoutTests/webaudio/osc-low-freq.html
index de25c3b..6adda537 100644
--- a/third_party/WebKit/LayoutTests/webaudio/osc-low-freq.html
+++ b/third_party/WebKit/LayoutTests/webaudio/osc-low-freq.html
@@ -52,7 +52,9 @@
 
         var snr = 10 * Math.log10(signal / noise);
 
-        Should("SNR of " + desiredFrequencyHz + " Hz sine wave", snr).beGreaterThanOrEqualTo(snrThreshold);
+        Should("SNR of " + desiredFrequencyHz + " Hz sine wave", snr, {
+          brief: true
+        }).beGreaterThanOrEqualTo(snrThreshold);
         testPassed("PeriodicWave coefficients that must be ignored were correctly ignored.");
       }
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/osc-negative-freq.html b/third_party/WebKit/LayoutTests/webaudio/osc-negative-freq.html
index 467063f..41fa7154 100644
--- a/third_party/WebKit/LayoutTests/webaudio/osc-negative-freq.html
+++ b/third_party/WebKit/LayoutTests/webaudio/osc-negative-freq.html
@@ -138,7 +138,6 @@
 
           Should("Sum of positive and negative frequency custom oscillators",
               actual, {
-                verbose: true,
                 precision: 6
               })
             .beCloseToArray(expected, 4.7684e-7);
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-automation-position.html b/third_party/WebKit/LayoutTests/webaudio/panner-automation-position.html
index 34e3b21..56fad32 100644
--- a/third_party/WebKit/LayoutTests/webaudio/panner-automation-position.html
+++ b/third_party/WebKit/LayoutTests/webaudio/panner-automation-position.html
@@ -251,13 +251,9 @@
             if (options.errorThreshold)
                errorThreshold = options.errorThreshold[channelCount - 1]
 
-            Should(prefix + "distanceModel: " + info + ", left channel", data0, {
-                verbose: true
-              })
+            Should(prefix + "distanceModel: " + info + ", left channel", data0)
               .beCloseToArray(expected0, errorThreshold);
-            Should(prefix + "distanceModel: " + info + ", right channel", data1, {
-                verbose: true
-              })
+            Should(prefix + "distanceModel: " + info + ", right channel", data1)
               .beCloseToArray(expected1, errorThreshold);
           });
       }
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-byte-data.html b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-byte-data.html
index 270c5f9..7e789f09 100644
--- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-byte-data.html
+++ b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-byte-data.html
@@ -71,8 +71,12 @@
           var indexMax = floatData.findIndex(function (x) { return x > 1; });
           var indexMin = floatData.findIndex(function (x) { return x < -1; });
       
-          Should("Index of first sample greater than +1", indexMax).beGreaterThanOrEqualTo(0);
-          Should("Index of first sample less than -1", indexMin).beGreaterThanOrEqualTo(0);
+          Should("Index of first sample greater than +1", indexMax, {
+            brief: true
+          }).beGreaterThanOrEqualTo(0);
+          Should("Index of first sample less than -1", indexMin, {
+            brief: true
+          }).beGreaterThanOrEqualTo(0);
 
           // Verify explicitly that clipping happened correctly at the above indices.
           Should("Clip  " + floatData[indexMax].toPrecision(6) + ": byteData[" + indexMax + "]",
@@ -81,9 +85,7 @@
             byteData[indexMin]).beEqualTo(0);
 
           // Verify that all other samples are computed correctly.
-          Should("Byte data", byteData, {
-            verbose: true
-          }).beEqualToArray(expected);
+          Should("Byte data", byteData).beEqualToArray(expected);
         }).then(context.resume.bind(context))
 
         src.start();
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-downmix.html b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-downmix.html
index edb1df4..5148c4c 100644
--- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-downmix.html
+++ b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-downmix.html
@@ -102,9 +102,7 @@
 
           // Verify the time domain data is correct.
           var prefix = "Analyser downmix " + options.message + " to mono"
-          success = Should(prefix + " time data", timeData, {
-              verbose: true
-            })
+          success = Should(prefix + " time data", timeData)
             .beEqualToArray(renderedBuffer.getChannelData(0).subarray(0, analyser.fftSize));
 
           var expectedTimeData = renderedBuffer.getChannelData(0).subarray(0, analyser.fftSize);
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-smoothing.html b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-smoothing.html
index 9564433..10bbed3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-smoothing.html
+++ b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data-smoothing.html
@@ -72,9 +72,8 @@
           var expectedByteData = convertFloatToByte(smoothedFloatResult.map(linearToDb),
             analyser.minDecibels, analyser.maxDecibels);
 
-          success = Should(analyser.fftSize + "-point byte FFT", byteFreqData, {
-            verbose: true
-          }).beCloseToArray(expectedByteData, 0) && success;
+          success = Should(analyser.fftSize + "-point byte FFT", byteFreqData)
+              .beCloseToArray(expectedByteData, 0) && success;
 
         }).then(context.resume.bind(context));
 
@@ -111,9 +110,8 @@
           var expectedByteData = convertFloatToByte(smoothedFloatResult.map(linearToDb),
             analyser.minDecibels, analyser.maxDecibels);
 
-          success = Should(analyser.fftSize + "-point byte FFT", byteFreqData, {
-            verbose: true
-          }).beCloseToArray(expectedByteData, 0) && success;
+          success = Should(analyser.fftSize + "-point byte FFT", byteFreqData)
+            .beCloseToArray(expectedByteData, 0) && success;
 
         }).then(context.resume.bind(context));
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data.html b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data.html
index acaf585b..030c8d2 100644
--- a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data.html
+++ b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-freq-data.html
@@ -184,9 +184,13 @@
           var minValue = Math.min(...expected);
           var maxValue = Math.max(...expected);
 
-          basicTestsPassed = Should("Min FFT value", minValue)
+          basicTestsPassed = Should("Min FFT value", minValue, {
+              brief: true
+            })
             .beLessThanOrEqualTo(analyser.minDecibels) && basicTestsPassed;
-          basicTestsPassed = Should("Max FFT value", maxValue)
+          basicTestsPassed = Should("Max FFT value", maxValue, {
+              brief: true
+            })
             .beGreaterThanOrEqualTo(analyser.maxDecibels) && basicTestsPassed;
 
           // Test the byte frequency data.
@@ -198,9 +202,8 @@
           var expectedByteData = convertFloatToByte(expected, analyser.minDecibels,
             analyser.maxDecibels);
 
-          basicTestsPassed = Should(analyser.fftSize + "-point byte FFT", byteFreqData, {
-            verbose: true
-          }).beCloseToArray(expectedByteData, 0) && basicTestsPassed;
+          basicTestsPassed = Should(analyser.fftSize + "-point byte FFT", byteFreqData)
+            .beCloseToArray(expectedByteData, 0) && basicTestsPassed;
 
         }).then(context.resume.bind(context));
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/audio-testing.js b/third_party/WebKit/LayoutTests/webaudio/resources/audio-testing.js
index ebc337b2..c248762 100644
--- a/third_party/WebKit/LayoutTests/webaudio/resources/audio-testing.js
+++ b/third_party/WebKit/LayoutTests/webaudio/resources/audio-testing.js
@@ -420,7 +420,7 @@
 
         // If true, verbose output for the failure case is printed, for methods where this makes
         // sense.
-        this.verbose = opts.verbose;
+        this.verbose = !opts.brief;
 
         // If set, this is the precision with which numbers will be printed.
         this.PRINT_PRECISION = opts.precision;
@@ -1046,7 +1046,8 @@
     return function (desc, target, opts) {
         var _opts = {
             numberOfErrorLog: 8,
-            numberOfArrayLog: 16
+            numberOfArrayLog: 16,
+            verbose: true
         };
 
         if (opts instanceof Object) {
@@ -1054,8 +1055,8 @@
                 _opts.numberOfErrorLog = opts.numberOfErrorLog;
             if (opts.hasOwnProperty('numberOfArrayLog'))
                 _opts.numberOfArrayLog = opts.numberOfArrayLog;
-            if (opts.hasOwnProperty('verbose'))
-                _opts.verbose = opts.verbose;
+            if (opts.hasOwnProperty('brief'))
+                _opts.brief = opts.brief;
             if (opts.hasOwnProperty('precision'))
                 _opts.precision = opts.precision;
         }
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 49078d7..69cd1b8 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -390,6 +390,7 @@
 [Worker]     attribute @@toStringTag
 [Worker]     method constructor
 [Worker]     method observe
+[Worker]     method unobserve
 [Worker] interface IDBObserverChangesRecord
 [Worker]     attribute @@toStringTag
 [Worker]     getter key
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 6ef0f843..b979613 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -3474,6 +3474,7 @@
     attribute @@toStringTag
     method constructor
     method observe
+    method unobserve
 interface IDBObserverChanges
     attribute @@toStringTag
     getter database
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
index d989d70..5f4b3e3c6 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -377,6 +377,7 @@
 [Worker]     attribute @@toStringTag
 [Worker]     method constructor
 [Worker]     method observe
+[Worker]     method unobserve
 [Worker] interface IDBObserverChangesRecord
 [Worker]     attribute @@toStringTag
 [Worker]     getter key
diff --git a/third_party/WebKit/PerformanceTests/Canvas/draw-dynamic-webgl-to-hw-accelerated-canvas-2d.html b/third_party/WebKit/PerformanceTests/Canvas/draw-dynamic-webgl-to-hw-accelerated-canvas-2d.html
index c35f28c..c6777c36 100644
--- a/third_party/WebKit/PerformanceTests/Canvas/draw-dynamic-webgl-to-hw-accelerated-canvas-2d.html
+++ b/third_party/WebKit/PerformanceTests/Canvas/draw-dynamic-webgl-to-hw-accelerated-canvas-2d.html
@@ -46,7 +46,7 @@
 function ensureComplete() {
     // Using destCanvas2D as a source image is just to flush out the content when
     // accelerated 2D canvas is in use. 
-    dummyCtx2D.drawImage(destCanvas2D, 0, 0, 1, 1, 0, 0, 1, 1);
+    dummyCtx2D.drawImage(canvas2D, 0, 0, 1, 1, 0, 0, 1, 1);
 }
 
 window.onload = function () {
diff --git a/third_party/WebKit/PerformanceTests/Canvas/draw-static-webgl-to-hw-accelerated-canvas-2d.html b/third_party/WebKit/PerformanceTests/Canvas/draw-static-webgl-to-hw-accelerated-canvas-2d.html
index baa2c3d..d3d7bcc 100644
--- a/third_party/WebKit/PerformanceTests/Canvas/draw-static-webgl-to-hw-accelerated-canvas-2d.html
+++ b/third_party/WebKit/PerformanceTests/Canvas/draw-static-webgl-to-hw-accelerated-canvas-2d.html
@@ -45,7 +45,7 @@
 function ensureComplete() {
     // Using destCanvas2D as a source image is just to flush out the content when
     // accelerated 2D canvas is in use. 
-    dummyCtx2D.drawImage(destCanvas2D, 0, 0, 1, 1, 0, 0, 1, 1);
+    dummyCtx2D.drawImage(canvas2D, 0, 0, 1, 1, 0, 0, 1, 1);
 }
 
 window.onload = function () {
diff --git a/third_party/WebKit/Source/bindings/core/v8/CallbackPromiseAdapter.h b/third_party/WebKit/Source/bindings/core/v8/CallbackPromiseAdapter.h
index ee01896..97c401d 100644
--- a/third_party/WebKit/Source/bindings/core/v8/CallbackPromiseAdapter.h
+++ b/third_party/WebKit/Source/bindings/core/v8/CallbackPromiseAdapter.h
@@ -187,6 +187,7 @@
             ScriptPromiseResolver* resolver = this->resolver();
             if (!resolver->getExecutionContext() || resolver->getExecutionContext()->activeDOMObjectsAreStopped())
                 return;
+            ScriptState::Scope scope(resolver->getScriptState());
             resolver->reject(T::take(resolver, pass(result)));
         }
     };
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Binding.h b/third_party/WebKit/Source/bindings/core/v8/V8Binding.h
index cb32c689..eabb4a2 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8Binding.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8Binding.h
@@ -908,7 +908,7 @@
 // Attaches |environment| to |function| and returns it.
 inline v8::Local<v8::Function> createClosure(v8::FunctionCallback function, v8::Local<v8::Value> environment, v8::Isolate* isolate)
 {
-    return v8::Function::New(isolate, function, environment);
+    return v8::Function::New(isolate->GetCurrentContext(), function, environment, 0, v8::ConstructorBehavior::kThrow).ToLocalChecked();
 }
 
 // FIXME: This will be soon embedded in the generated code.
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8LazyEventListener.cpp b/third_party/WebKit/Source/bindings/core/v8/V8LazyEventListener.cpp
index 633e5e0..71812424 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8LazyEventListener.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8LazyEventListener.cpp
@@ -183,8 +183,8 @@
     // source returned (sometimes a RegExp is applied as well) for some
     // other use. That fails miserably if the actual wrapper source is
     // returned.
-    v8::Local<v8::Function> toStringFunction = v8::Function::New(isolate(), V8LazyEventListenerToString);
-    if (toStringFunction.IsEmpty())
+    v8::Local<v8::Function> toStringFunction;
+    if (!v8::Function::New(scriptState->context(), V8LazyEventListenerToString, v8::Local<v8::Value>(), 0, v8::ConstructorBehavior::kThrow).ToLocal(&toStringFunction))
         return;
     String toStringString = "function " + m_functionName + "(" + m_eventParameterName + ") {\n  " + m_code + "\n}";
     V8HiddenValue::setHiddenValue(scriptState, wrappedFunction, V8HiddenValue::toStringString(isolate()), v8String(isolate(), toStringString));
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
index ba9345e..f85a045 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8ScriptRunner.cpp
@@ -123,7 +123,7 @@
     }
     v8::MicrotasksScope microtasksScope(isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
     V8PerIsolateData::from(isolate)->setIsHandlingRecursionLevelError(true);
-    v8::Local<v8::Value> result = v8::Function::New(isolate, throwStackOverflowException)->Call(v8::Undefined(isolate), 0, 0);
+    v8::Local<v8::Value> result = v8::Function::New(isolate->GetCurrentContext(), throwStackOverflowException, v8::Local<v8::Value>(), 0, v8::ConstructorBehavior::kThrow).ToLocalChecked()->Call(v8::Undefined(isolate), 0, 0);
     V8PerIsolateData::from(isolate)->setIsHandlingRecursionLevelError(false);
     return result;
 }
diff --git a/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp b/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp
index 0ad55527..c6cb296 100644
--- a/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp
@@ -272,11 +272,13 @@
     }
     // If Origin Trials have been registered before the V8 context was ready,
     // then inject them into the context now
-    ExecutionContext* executionContext = m_scriptState->getExecutionContext();
-    if (executionContext) {
-        OriginTrialContext* originTrialContext = OriginTrialContext::from(executionContext);
-        if (originTrialContext)
-            originTrialContext->initializePendingFeatures();
+    if (m_world->isMainWorld()) {
+        ExecutionContext* executionContext = m_scriptState->getExecutionContext();
+        if (executionContext) {
+            OriginTrialContext* originTrialContext = OriginTrialContext::from(executionContext);
+            if (originTrialContext)
+                originTrialContext->initializePendingFeatures();
+        }
     }
     return true;
 }
diff --git a/third_party/WebKit/Source/bindings/scripts/idl_definitions.py b/third_party/WebKit/Source/bindings/scripts/idl_definitions.py
index c66920b..1428577 100644
--- a/third_party/WebKit/Source/bindings/scripts/idl_definitions.py
+++ b/third_party/WebKit/Source/bindings/scripts/idl_definitions.py
@@ -137,6 +137,10 @@
             callback_function.accept(visitor)
         for dictionary in self.dictionaries.itervalues():
             dictionary.accept(visitor)
+        for enumeration in self.enumerations.itervalues():
+            enumeration.accept(visitor)
+        for implement in self.implements:
+            implement.accept(visitor)
         for typedef in self.typedefs.itervalues():
             typedef.accept(visitor)
 
@@ -254,6 +258,9 @@
         for child in node.GetChildren():
             self.values.append(child.GetName())
 
+    def accept(self, visitor):
+        visitor.visit_enumeration(self)
+
 
 ################################################################################
 # Typedefs
@@ -837,6 +844,9 @@
         self.left_interface = node.GetName()
         self.right_interface = node.GetProperty('REFERENCE')
 
+    def accept(self, visitor):
+        visitor.visit_implement(self)
+
 
 ################################################################################
 # Extended attributes
@@ -1092,6 +1102,12 @@
     def visit_dictionary_member(self, member):
         self.visit_typed_object(member)
 
+    def visit_enumeration(self, enumeration):
+        pass
+
+    def visit_implement(self, implement):
+        pass
+
     def visit_interface(self, interface):
         pass
 
diff --git a/third_party/WebKit/Source/core/animation/StringKeyframe.h b/third_party/WebKit/Source/core/animation/StringKeyframe.h
index fa161e6..51c343b0 100644
--- a/third_party/WebKit/Source/core/animation/StringKeyframe.h
+++ b/third_party/WebKit/Source/core/animation/StringKeyframe.h
@@ -50,12 +50,12 @@
 
     class CSSPropertySpecificKeyframe : public Keyframe::PropertySpecificKeyframe {
     public:
-        static PassRefPtr<CSSPropertySpecificKeyframe> create(double offset, PassRefPtr<TimingFunction> easing, CSSValue* value, EffectModel::CompositeOperation composite)
+        static PassRefPtr<CSSPropertySpecificKeyframe> create(double offset, PassRefPtr<TimingFunction> easing, const CSSValue* value, EffectModel::CompositeOperation composite)
         {
             return adoptRef(new CSSPropertySpecificKeyframe(offset, easing, value, composite));
         }
 
-        CSSValue* value() const { return m_value.get(); }
+        const CSSValue* value() const { return m_value.get(); }
 
         bool populateAnimatableValue(CSSPropertyID, Element&, const ComputedStyle& baseStyle, const ComputedStyle* parentStyle) const final;
         const PassRefPtr<AnimatableValue> getAnimatableValue() const final { return m_animatableValueCache.get(); }
@@ -65,9 +65,9 @@
         PassRefPtr<Keyframe::PropertySpecificKeyframe> neutralKeyframe(double offset, PassRefPtr<TimingFunction> easing) const final;
 
     private:
-        CSSPropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, CSSValue* value, EffectModel::CompositeOperation composite)
+        CSSPropertySpecificKeyframe(double offset, PassRefPtr<TimingFunction> easing, const CSSValue* value, EffectModel::CompositeOperation composite)
             : Keyframe::PropertySpecificKeyframe(offset, easing, composite)
-            , m_value(value)
+            , m_value(const_cast<CSSValue*>(value))
         { }
 
         virtual PassRefPtr<Keyframe::PropertySpecificKeyframe> cloneWithOffset(double offset) const;
@@ -75,6 +75,7 @@
 
         void populateAnimatableValueCaches(CSSPropertyID, Keyframe::PropertySpecificKeyframe&, Element*, CSSValue& fromCSSValue, CSSValue& toCSSValue) const;
 
+        // TODO(sashab): Make this a const CSSValue.
         Persistent<CSSValue> m_value;
         mutable RefPtr<AnimatableValue> m_animatableValueCache;
     };
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi
index aad436ff..a5e5d17 100644
--- a/third_party/WebKit/Source/core/core.gypi
+++ b/third_party/WebKit/Source/core/core.gypi
@@ -2010,10 +2010,14 @@
             'page/TouchDisambiguation.cpp',
             'page/TouchDisambiguation.h',
             'page/WindowFeatures.cpp',
+            'page/scrolling/ChildViewportScrollCallback.cpp',
+            'page/scrolling/ChildViewportScrollCallback.h',
             'page/scrolling/OverscrollController.cpp',
             'page/scrolling/OverscrollController.h',
             'page/scrolling/RootScrollerController.cpp',
             'page/scrolling/RootScrollerController.h',
+            'page/scrolling/RootViewportScrollCallback.cpp',
+            'page/scrolling/RootViewportScrollCallback.h',
             'page/scrolling/ScrollingCoordinator.cpp',
             'page/scrolling/ScrollingCoordinator.h',
             'page/scrolling/SnapCoordinator.cpp',
@@ -3136,6 +3140,8 @@
             'html/forms/MultipleFieldsTemporalInputTypeView.h',
             'html/forms/NumberInputType.cpp',
             'html/forms/NumberInputType.h',
+            'html/forms/OptionList.cpp',
+            'html/forms/OptionList.h',
             'html/forms/PasswordInputType.cpp',
             'html/forms/PasswordInputType.h',
             'html/forms/RadioButtonGroupScope.cpp',
@@ -4116,6 +4122,7 @@
             'html/canvas/CanvasFontCacheTest.cpp',
             'html/forms/EmailInputTypeTest.cpp',
             'html/forms/FileInputTypeTest.cpp',
+            'html/forms/OptionListTest.cpp',
             'html/forms/StepRangeTest.cpp',
             'html/parser/AtomicHTMLTokenTest.cpp',
             'html/parser/CompactHTMLTokenTest.cpp',
@@ -4125,6 +4132,7 @@
             'html/parser/HTMLPreloadScannerTest.cpp',
             'html/parser/HTMLResourcePreloaderTest.cpp',
             'html/parser/HTMLSrcsetParserTest.cpp',
+            'html/parser/HTMLTokenizerTest.cpp',
             'html/parser/HTMLTreeBuilderSimulatorTest.cpp',
             'html/shadow/MediaControlsTest.cpp',
             'html/track/vtt/BufferedLineReaderTest.cpp',
@@ -4184,6 +4192,7 @@
             'paint/PaintPropertyTreeBuilderTest.cpp',
             'paint/TableCellPainterTest.cpp',
             'paint/TextPainterTest.cpp',
+            'paint/VideoPainterTest.cpp',
             'streams/ReadableStreamOperationsTest.cpp',
             'streams/ReadableStreamReaderTest.cpp',
             'streams/ReadableStreamTest.cpp',
diff --git a/third_party/WebKit/Source/core/css/CSSImageValue.cpp b/third_party/WebKit/Source/core/css/CSSImageValue.cpp
index 076639a9..074de691 100644
--- a/third_party/WebKit/Source/core/css/CSSImageValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSImageValue.cpp
@@ -80,7 +80,7 @@
 
 void CSSImageValue::restoreCachedResourceIfNeeded(Document& document) const
 {
-    if (m_isCachePending || !m_cachedImage || !document.fetcher())
+    if (m_isCachePending || !m_cachedImage || !document.fetcher() || m_absoluteURL.isNull())
         return;
     if (document.fetcher()->cachedResource(KURL(ParsedURLString, m_absoluteURL)))
         return;
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
index 2d066f0..0fe51e79e 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
+++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -207,17 +207,24 @@
             if (opposite.isAuto())
                 return CSSPrimitiveValue::create(0, CSSPrimitiveValue::UnitType::Pixels);
 
-            if (opposite.hasPercent()) {
-                LayoutUnit containingBlockSize =
-                    (propertyID == CSSPropertyLeft || propertyID == CSSPropertyRight) ?
-                    toLayoutBox(layoutObject)->containingBlockLogicalWidthForContent() :
-                    toLayoutBox(layoutObject)->containingBlockLogicalHeightForGetComputedStyle();
-                return zoomAdjustedPixelValue(-floatValueForLength(opposite, containingBlockSize), style);
+            if (opposite.hasPercent() || opposite.isCalculated()) {
+                if (layoutObject->isBox()) {
+                    LayoutUnit containingBlockSize =
+                        (propertyID == CSSPropertyLeft || propertyID == CSSPropertyRight) ?
+                        toLayoutBox(layoutObject)->containingBlockLogicalWidthForContent() :
+                        toLayoutBox(layoutObject)->containingBlockLogicalHeightForGetComputedStyle();
+                    return zoomAdjustedPixelValue(-floatValueForLength(opposite, containingBlockSize), style);
+                }
+                // FIXME:  fall back to auto for position:relative, display:inline
+                return CSSPrimitiveValue::createIdentifier(CSSValueAuto);
             }
-            return zoomAdjustedPixelValue(-opposite.pixels(), style);
+
+            // Length doesn't provide operator -, so multiply by -1.
+            opposite *= -1.f;
+            return zoomAdjustedPixelValueForLength(opposite, style);
         }
 
-        if (layoutObject->isOutOfFlowPositioned()) {
+        if (layoutObject->isOutOfFlowPositioned() && layoutObject->isBox()) {
             // For fixed and absolute positioned elements, the top, left, bottom, and right
             // are defined relative to the corresponding sides of the containing block.
             LayoutBlock* container = layoutObject->containingBlock();
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp
index bab67578..7719e27b 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp
@@ -475,8 +475,8 @@
         // auto | baseline | before-edge | text-before-edge | middle |
         // central | after-edge | text-after-edge | ideographic | alphabetic |
         // hanging | mathematical
-        return valueID == CSSValueAuto || valueID == CSSValueBaseline || valueID == CSSValueMiddle
-            || (valueID >= CSSValueBeforeEdge && valueID <= CSSValueMathematical);
+        return valueID == CSSValueAuto || valueID == CSSValueAlphabetic || valueID == CSSValueBaseline
+            || valueID == CSSValueMiddle || (valueID >= CSSValueBeforeEdge && valueID <= CSSValueMathematical);
     case CSSPropertyAll:
         return false; // Only accepts css-wide keywords
     case CSSPropertyBackgroundRepeatX: // repeat | no-repeat
@@ -523,7 +523,7 @@
         // auto | use-script | no-change | reset-size | ideographic |
         // alphabetic | hanging | mathematical | central | middle |
         // text-after-edge | text-before-edge
-        return valueID == CSSValueAuto || valueID == CSSValueMiddle
+        return valueID == CSSValueAuto || valueID == CSSValueAlphabetic || valueID == CSSValueMiddle
             || (valueID >= CSSValueUseScript && valueID <= CSSValueResetSize)
             || (valueID >= CSSValueCentral && valueID <= CSSValueMathematical);
     case CSSPropertyEmptyCells: // show | hide
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 24fa070..179c4229 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -195,11 +195,12 @@
 #include "core/page/FrameTree.h"
 #include "core/page/Page.h"
 #include "core/page/PointerLockController.h"
+#include "core/page/scrolling/ChildViewportScrollCallback.h"
 #include "core/page/scrolling/RootScrollerController.h"
+#include "core/page/scrolling/RootViewportScrollCallback.h"
 #include "core/page/scrolling/ScrollStateCallback.h"
 #include "core/page/scrolling/ScrollingCoordinator.h"
 #include "core/page/scrolling/SnapCoordinator.h"
-#include "core/page/scrolling/ViewportScrollCallback.h"
 #include "core/svg/SVGDocumentExtensions.h"
 #include "core/svg/SVGScriptElement.h"
 #include "core/svg/SVGTitleElement.h"
@@ -460,17 +461,7 @@
         m_fetcher = ResourceFetcher::create(nullptr);
     }
 
-    ViewportScrollCallback* applyScroll = nullptr;
-    if (isInMainFrame()) {
-        applyScroll = RootScrollerController::createViewportApplyScroll(
-            &frameHost()->topControls(), &frameHost()->overscrollController());
-    } else {
-        applyScroll =
-            RootScrollerController::createViewportApplyScroll(nullptr, nullptr);
-    }
-
-    m_rootScrollerController =
-        RootScrollerController::create(*this, applyScroll);
+    m_rootScrollerController = RootScrollerController::create(*this);
 
     // We depend on the url getting immediately set in subframes, but we
     // also depend on the url NOT getting immediately set in opened windows.
@@ -600,6 +591,11 @@
     m_rootScrollerController->set(newScroller);
 }
 
+void Document::initializeRootScroller(ViewportScrollCallback* callback)
+{
+    m_rootScrollerController->setViewportScrollCallback(callback);
+}
+
 Element* Document::rootScroller() const
 {
     return m_rootScrollerController->get();
@@ -5726,8 +5722,9 @@
     if (!frame() || !frame()->page())
         return;
     m_associatedFormControls.add(element);
+    // We add a slight delay because this could be called rapidly.
     if (!m_didAssociateFormControlsTimer.isActive())
-        m_didAssociateFormControlsTimer.startOneShot(0, BLINK_FROM_HERE);
+        m_didAssociateFormControlsTimer.startOneShot(0.3, BLINK_FROM_HERE);
 }
 
 void Document::removeFormAssociation(Element* element)
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index 048bb13..e0bc025 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -167,6 +167,7 @@
 class TouchList;
 class TransformSource;
 class TreeWalker;
+class ViewportScrollCallback;
 class VisitedLinkState;
 class VisualViewport;
 class WebGLRenderingContext;
@@ -1083,6 +1084,7 @@
 
     bool containsV1ShadowTree() const { return m_shadowCascadeOrder == ShadowCascadeOrder::ShadowCascadeV1; }
 
+    void initializeRootScroller(ViewportScrollCallback*);
     Element* rootScroller() const;
     void setRootScroller(Element*, ExceptionState&);
     const Element* effectiveRootScroller() const;
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
index 6ae5e2c..a8337a8d 100644
--- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
@@ -121,7 +121,7 @@
     m_pendingScript = nullptr;
 }
 
-// Helper function. Must take a lowercase language as input.
+// Helper function
 static bool isLegacySupportedJavaScriptLanguage(const String& language)
 {
     // Mozilla 1.8 accepts javascript1.0 - javascript1.7, but WinIE 7 accepts only javascript1.1 - javascript1.3.
@@ -131,19 +131,24 @@
     // We want to accept all the values that either of these browsers accept, but not other values.
 
     // FIXME: This function is not HTML5 compliant. These belong in the MIME registry as "text/javascript<version>" entries.
-    DCHECK_EQ(language, language.lower());
-    return language == "javascript"
-        || language == "javascript1.0"
-        || language == "javascript1.1"
-        || language == "javascript1.2"
-        || language == "javascript1.3"
-        || language == "javascript1.4"
-        || language == "javascript1.5"
-        || language == "javascript1.6"
-        || language == "javascript1.7"
-        || language == "livescript"
-        || language == "ecmascript"
-        || language == "jscript";
+    typedef HashSet<String, CaseFoldingHash> LanguageSet;
+    DEFINE_STATIC_LOCAL(LanguageSet, languages, ());
+    if (languages.isEmpty()) {
+        languages.add("javascript");
+        languages.add("javascript1.0");
+        languages.add("javascript1.1");
+        languages.add("javascript1.2");
+        languages.add("javascript1.3");
+        languages.add("javascript1.4");
+        languages.add("javascript1.5");
+        languages.add("javascript1.6");
+        languages.add("javascript1.7");
+        languages.add("livescript");
+        languages.add("ecmascript");
+        languages.add("jscript");
+    }
+
+    return languages.contains(language);
 }
 
 void ScriptLoader::dispatchErrorEvent()
@@ -158,30 +163,29 @@
     setHaveFiredLoadEvent(true);
 }
 
-bool ScriptLoader::isValidScriptTypeAndLanguage(const String& type, const String& language, LegacyTypeSupport supportLegacyTypes)
+bool ScriptLoader::isScriptTypeSupported(LegacyTypeSupport supportLegacyTypes) const
 {
     // FIXME: isLegacySupportedJavaScriptLanguage() is not valid HTML5. It is used here to maintain backwards compatibility with existing layout tests. The specific violations are:
     // - Allowing type=javascript. type= should only support MIME types, such as text/javascript.
     // - Allowing a different set of languages for language= and type=. language= supports Javascript 1.1 and 1.4-1.6, but type= does not.
+
+    String type = client()->typeAttributeValue();
+    String language = client()->languageAttributeValue();
+    if (type.isEmpty() && language.isEmpty())
+        return true; // Assume text/javascript.
     if (type.isEmpty()) {
-        String lowerLanguage = language.lower();
-        return language.isEmpty() // assume text/javascript.
-            || MIMETypeRegistry::isSupportedJavaScriptMIMEType("text/" + lowerLanguage)
-            || isLegacySupportedJavaScriptLanguage(lowerLanguage);
+        type = "text/" + language.lower();
+        if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(type) || isLegacySupportedJavaScriptLanguage(language))
+            return true;
     } else if (RuntimeEnabledFeatures::moduleScriptsEnabled() && type == "module") {
         return true;
-    } else if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(type.stripWhiteSpace()) || (supportLegacyTypes == AllowLegacyTypeInTypeAttribute && isLegacySupportedJavaScriptLanguage(type.lower()))) {
+    } else if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(type.stripWhiteSpace()) || (supportLegacyTypes == AllowLegacyTypeInTypeAttribute && isLegacySupportedJavaScriptLanguage(type))) {
         return true;
     }
 
     return false;
 }
 
-bool ScriptLoader::isScriptTypeSupported(LegacyTypeSupport supportLegacyTypes) const
-{
-    return isValidScriptTypeAndLanguage(client()->typeAttributeValue(), client()->languageAttributeValue(), supportLegacyTypes);
-}
-
 // http://dev.w3.org/html5/spec/Overview.html#prepare-a-script
 bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, LegacyTypeSupport supportLegacyTypes)
 {
@@ -340,10 +344,9 @@
 
 void ScriptLoader::logScriptMimetype(ScriptResource* resource, LocalFrame* frame, String mimetype)
 {
-    String lowerMimetype = mimetype.lower();
-    bool text = lowerMimetype.startsWith("text/");
-    bool application = lowerMimetype.startsWith("application/");
-    bool expectedJs = MIMETypeRegistry::isSupportedJavaScriptMIMEType(lowerMimetype) || (text && isLegacySupportedJavaScriptLanguage(lowerMimetype.substring(5)));
+    bool text = mimetype.lower().startsWith("text/");
+    bool application = mimetype.lower().startsWith("application/");
+    bool expectedJs = MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimetype) || (text && isLegacySupportedJavaScriptLanguage(mimetype.substring(5)));
     bool sameOrigin = m_element->document().getSecurityOrigin()->canRequest(m_resource->url());
     if (expectedJs) {
         return;
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.h b/third_party/WebKit/Source/core/dom/ScriptLoader.h
index 1fc84c7d..0af9f42 100644
--- a/third_party/WebKit/Source/core/dom/ScriptLoader.h
+++ b/third_party/WebKit/Source/core/dom/ScriptLoader.h
@@ -50,8 +50,6 @@
     Element* element() const { return m_element; }
 
     enum LegacyTypeSupport { DisallowLegacyTypeInTypeAttribute, AllowLegacyTypeInTypeAttribute };
-    static bool isValidScriptTypeAndLanguage(const String& typeAttributeValue, const String& languageAttributeValue, LegacyTypeSupport supportLegacyTypes);
-
     bool prepareScript(const TextPosition& scriptStartPosition = TextPosition::minimumPosition(), LegacyTypeSupport = DisallowLegacyTypeInTypeAttribute);
 
     String scriptCharset() const { return m_characterEncoding; }
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp
index caf368c..46f0e4e9 100644
--- a/third_party/WebKit/Source/core/editing/Editor.cpp
+++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -752,8 +752,7 @@
     DCHECK(composition);
     dispatchEditableContentChangedEvents(composition->startingRootEditableElement(), composition->endingRootEditableElement());
     // TODO(chongz): Filter empty InputType after spec is finalized.
-    // TODO(chongz): Fill in |data| field.
-    dispatchInputEventEditableContentChanged(composition->startingRootEditableElement(), composition->endingRootEditableElement(), inputTypeFromCommand(cmd), emptyString(), isComposingFromCommand(cmd));
+    dispatchInputEventEditableContentChanged(composition->startingRootEditableElement(), composition->endingRootEditableElement(), inputTypeFromCommand(cmd), cmd->textDataForInputEvent(), isComposingFromCommand(cmd));
     VisibleSelection newSelection(cmd->endingSelection());
 
     // Don't clear the typing style with this selection change. We do those things elsewhere if necessary.
diff --git a/third_party/WebKit/Source/core/editing/EphemeralRange.cpp b/third_party/WebKit/Source/core/editing/EphemeralRange.cpp
index 5558185..aa36e1d 100644
--- a/third_party/WebKit/Source/core/editing/EphemeralRange.cpp
+++ b/third_party/WebKit/Source/core/editing/EphemeralRange.cpp
@@ -27,6 +27,7 @@
     DCHECK_EQ(m_startPosition.document(), m_endPosition.document());
     DCHECK(m_startPosition.inShadowIncludingDocument());
     DCHECK(m_endPosition.inShadowIncludingDocument());
+    DCHECK_LE(m_startPosition, m_endPosition);
 }
 
 template <typename Strategy>
diff --git a/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp b/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp
index 29a7b6b8..08dfe81 100644
--- a/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp
+++ b/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp
@@ -349,7 +349,7 @@
     EXPECT_EQ(24u, controller().getSelectionOffsets().end());
 }
 
-TEST_F(InputMethodControllerTest, CompositionFireBeforeInput)
+TEST_F(InputMethodControllerTest, CompositionInputEventIsComposing)
 {
     document().settings()->setScriptEnabled(true);
     Element* editable = insertHTMLElement("<div id='sample' contentEditable='true'></div>", "sample");
@@ -376,8 +376,42 @@
 
     document().setTitle(emptyString());
     controller().confirmComposition();
-    // Last 'beforeinput' should also be inside composition scope.
+    // Last pair of InputEvent should also be inside composition scope.
     EXPECT_STREQ("beforeinput.isComposing:true;input.isComposing:true;", document().title().utf8().data());
 }
 
+TEST_F(InputMethodControllerTest, CompositionInputEventData)
+{
+    document().settings()->setScriptEnabled(true);
+    Element* editable = insertHTMLElement("<div id='sample' contentEditable='true'></div>", "sample");
+    Element* script = document().createElement("script", ASSERT_NO_EXCEPTION);
+    script->setInnerHTML(
+        "document.getElementById('sample').addEventListener('beforeinput', function(event) {"
+        "    document.title = `beforeinput.data:${event.data};`;"
+        "});"
+        "document.getElementById('sample').addEventListener('input', function(event) {"
+        "    document.title += `input.data:${event.data};`;"
+        "});",
+        ASSERT_NO_EXCEPTION);
+    document().body()->appendChild(script, ASSERT_NO_EXCEPTION);
+    document().view()->updateAllLifecyclePhases();
+
+    // Simulate composition in the |contentEditable|.
+    Vector<CompositionUnderline> underlines;
+    underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0));
+    editable->focus();
+
+    document().setTitle(emptyString());
+    controller().setComposition("n", underlines, 0, 1);
+    EXPECT_STREQ("beforeinput.data:n;input.data:n;", document().title().utf8().data());
+
+    document().setTitle(emptyString());
+    controller().setComposition("ni", underlines, 0, 1);
+    EXPECT_STREQ("beforeinput.data:ni;input.data:ni;", document().title().utf8().data());
+
+    document().setTitle(emptyString());
+    controller().confirmComposition();
+    EXPECT_STREQ("beforeinput.data:ni;input.data:ni;", document().title().utf8().data());
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/commands/EditCommand.cpp b/third_party/WebKit/Source/core/editing/commands/EditCommand.cpp
index 3450391..8a188371 100644
--- a/third_party/WebKit/Source/core/editing/commands/EditCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/EditCommand.cpp
@@ -53,6 +53,11 @@
     return EditActionUnspecified;
 }
 
+String EditCommand::textDataForInputEvent() const
+{
+    return emptyString();
+}
+
 static inline EditCommandComposition* compositionIfPossible(EditCommand* command)
 {
     if (!command->isCompositeEditCommand())
diff --git a/third_party/WebKit/Source/core/editing/commands/EditCommand.h b/third_party/WebKit/Source/core/editing/commands/EditCommand.h
index e1a5df1..91ecb82 100644
--- a/third_party/WebKit/Source/core/editing/commands/EditCommand.h
+++ b/third_party/WebKit/Source/core/editing/commands/EditCommand.h
@@ -55,6 +55,9 @@
     // The |EditingState*| argument must not be nullptr.
     virtual void doApply(EditingState*) = 0;
 
+    // |TypingCommand| will return the text of the last |m_commands|.
+    virtual String textDataForInputEvent() const;
+
     DECLARE_VIRTUAL_TRACE();
 
 protected:
diff --git a/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.cpp b/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.cpp
index 174c39d..c54fdf7e 100644
--- a/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.cpp
@@ -44,6 +44,11 @@
 {
 }
 
+String InsertTextCommand::textDataForInputEvent() const
+{
+    return m_text;
+}
+
 Position InsertTextCommand::positionInsideTextNode(const Position& p, EditingState* editingState)
 {
     Position pos = p;
diff --git a/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.h b/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.h
index b922761..b255335 100644
--- a/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.h
+++ b/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.h
@@ -43,6 +43,8 @@
         return new InsertTextCommand(document, text, selectInsertedText, rebalanceType);
     }
 
+    String textDataForInputEvent() const final;
+
 private:
     InsertTextCommand(Document&, const String& text, bool selectInsertedText, RebalanceType);
 
diff --git a/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp b/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp
index 23111d3..2e6cbfa2 100644
--- a/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp
@@ -1313,7 +1313,7 @@
     if (editingState->isAborted())
         return;
 
-    if (m_sanitizeFragment) {
+    if (m_sanitizeFragment && insertedNodes.firstNodeInserted()) {
         applyCommandToComposite(SimplifyMarkupCommand::create(document(), insertedNodes.firstNodeInserted(), insertedNodes.pastLastLeaf()), editingState);
         if (editingState->isAborted())
             return;
diff --git a/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommandTest.cpp b/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommandTest.cpp
index 2613cb5..201f984 100644
--- a/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommandTest.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommandTest.cpp
@@ -25,6 +25,34 @@
 class ReplaceSelectionCommandTest : public EditingTestBase {
 };
 
+// This is a regression test for https://crbug.com/619131
+TEST_F(ReplaceSelectionCommandTest, pastingEmptySpan)
+{
+    document().setDesignMode("on");
+    setBodyContent("foo");
+
+    LocalFrame* frame = document().frame();
+    frame->selection().setSelection(
+        VisibleSelection(Position(document().body(), 0)));
+
+    DocumentFragment* fragment = document().createDocumentFragment();
+    fragment->appendChild(document().createElement("span", ASSERT_NO_EXCEPTION));
+
+    // |options| are taken from |Editor::replaceSelectionWithFragment()| with
+    // |selectReplacement| and |smartReplace|.
+    ReplaceSelectionCommand::CommandOptions options =
+        ReplaceSelectionCommand::PreventNesting |
+        ReplaceSelectionCommand::SanitizeFragment |
+        ReplaceSelectionCommand::SelectReplacement |
+        ReplaceSelectionCommand::SmartReplace;
+    ReplaceSelectionCommand* command =
+        ReplaceSelectionCommand::create(document(), fragment, options);
+
+    EXPECT_TRUE(command->apply())
+        << "the replace command should have succeeded";
+    EXPECT_EQ("foo", document().body()->innerHTML()) << "no DOM tree mutation";
+}
+
 // This is a regression test for https://crbug.com/121163
 TEST_F(ReplaceSelectionCommandTest, styleTagsInPastedHeadIncludedInContent)
 {
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
index 03a4cfb..8e56bf043 100644
--- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
@@ -122,6 +122,13 @@
     TypingCommand::create(document, ForwardDeleteKey, "", options, granularity)->apply();
 }
 
+String TypingCommand::textDataForInputEvent() const
+{
+    if (m_commands.isEmpty())
+        return m_textToInsert;
+    return m_commands.last()->textDataForInputEvent();
+}
+
 void TypingCommand::updateSelectionIfDifferentFromCurrentSelection(TypingCommand* typingCommand, LocalFrame* frame)
 {
     DCHECK(frame);
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
index 7eb723f..30d3554 100644
--- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
+++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
@@ -79,6 +79,8 @@
 
     ETypingCommand commandTypeOfOpenCommand() const { return m_commandType; }
     TextCompositionType compositionType() const { return m_compositionType; }
+    // |TypingCommand| may contain multiple |InsertTextCommand|, should return |textDataForInputEvent()| of the last one.
+    String textDataForInputEvent() const final;
 
 private:
     static TypingCommand* create(Document& document, ETypingCommand command, const String& text = "", Options options = 0, TextGranularity granularity = CharacterGranularity)
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
index 12cd193..45fc8ee 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
+++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
@@ -679,6 +679,7 @@
 
 void SpellChecker::updateMarkersForWordsAffectedByEditing(bool doNotRemoveIfSelectionAtWordBoundary)
 {
+    DCHECK(frame().selection().isAvailable());
     TRACE_EVENT0("blink", "SpellChecker::updateMarkersForWordsAffectedByEditing");
     if (!isSpellCheckingEnabledFor(frame().selection().selection()))
         return;
@@ -735,6 +736,17 @@
     if (startOfFirstWord.isNull() || endOfFirstWord.isNull() || startOfLastWord.isNull() || endOfLastWord.isNull())
         return;
 
+    const Position& removeMarkerStart = startOfFirstWord.deepEquivalent();
+    const Position& removeMarkerEnd = endOfLastWord.deepEquivalent();
+    if (removeMarkerStart > removeMarkerEnd) {
+        // editing/inserting/insert-br-008.html and more reach here.
+        // TODO(yosin): To avoid |DCHECK(removeMarkerStart <= removeMarkerEnd)|
+        // in |EphemeralRange| constructor, we have this if-statement. Once we
+        // fix |startOfWord()| and |endOfWord()|, we should remove this
+        // if-statement.
+        return;
+    }
+
     // Now we remove markers on everything between startOfFirstWord and endOfLastWord.
     // However, if an autocorrection change a single word to multiple words, we want to remove correction mark from all the
     // resulted words even we only edit one of them. For example, assuming autocorrection changes "avantgarde" to "avant
@@ -743,7 +755,7 @@
     // of marker that contains the word in question, and remove marker on that whole range.
     Document* document = frame().document();
     DCHECK(document);
-    const EphemeralRange wordRange(startOfFirstWord.deepEquivalent(), endOfLastWord.deepEquivalent());
+    const EphemeralRange wordRange(removeMarkerStart, removeMarkerEnd);
     document->markers().removeMarkers(wordRange, DocumentMarker::MisspellingMarkers(), DocumentMarkerController::RemovePartiallyOverlappingMarker);
 }
 
@@ -864,14 +876,14 @@
 
     VisiblePosition oldStart(oldSelection.visibleStart());
     VisibleSelection oldAdjacentWords = VisibleSelection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary));
-    if (oldAdjacentWords != newAdjacentWords) {
-        if (isContinuousSpellCheckingEnabled()) {
-            VisibleSelection selectedSentence = VisibleSelection(startOfSentence(oldStart), endOfSentence(oldStart));
-            markMisspellingsAndBadGrammar(oldAdjacentWords, true, selectedSentence);
-        } else {
-            markMisspellingsAndBadGrammar(oldAdjacentWords, false, oldAdjacentWords);
-        }
+    if (oldAdjacentWords == newAdjacentWords)
+        return;
+    if (isContinuousSpellCheckingEnabled()) {
+        VisibleSelection selectedSentence = VisibleSelection(startOfSentence(oldStart), endOfSentence(oldStart));
+        markMisspellingsAndBadGrammar(oldAdjacentWords, true, selectedSentence);
+        return;
     }
+    markMisspellingsAndBadGrammar(oldAdjacentWords, false, oldAdjacentWords);
 }
 
 static Node* findFirstMarkable(Node* node)
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp
index 19c2e95..7ba54bf 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp
+++ b/third_party/WebKit/Source/core/editing/spellcheck/TextCheckingHelper.cpp
@@ -199,9 +199,16 @@
 EphemeralRange TextCheckingParagraph::offsetAsRange() const
 {
     DCHECK(m_checkingRange.isNotNull());
-    if (m_offsetAsRange.isNull())
-        m_offsetAsRange = EphemeralRange(paragraphRange().startPosition(), checkingRange().startPosition());
-
+    if (m_offsetAsRange.isNotNull())
+        return m_offsetAsRange;
+    const Position& paragraphStart = paragraphRange().startPosition();
+    const Position& checkingStart = checkingRange().startPosition();
+    if (paragraphStart <= checkingStart) {
+        m_offsetAsRange = EphemeralRange(paragraphStart, checkingStart);
+        return m_offsetAsRange;
+    }
+    // editing/pasteboard/paste-table-001.html and more reach here.
+    m_offsetAsRange = EphemeralRange(checkingStart, paragraphStart);
     return m_offsetAsRange;
 }
 
diff --git a/third_party/WebKit/Source/core/events/AddEventListenerOptions.idl b/third_party/WebKit/Source/core/events/AddEventListenerOptions.idl
index a7d157c..cce9d59 100644
--- a/third_party/WebKit/Source/core/events/AddEventListenerOptions.idl
+++ b/third_party/WebKit/Source/core/events/AddEventListenerOptions.idl
@@ -5,5 +5,5 @@
 // https://dom.spec.whatwg.org/#dictdef-addeventlisteneroptions
 
 dictionary AddEventListenerOptions : EventListenerOptions {
-    [RuntimeEnabled=PassiveEventListeners] boolean passive;
+    boolean passive;
 };
diff --git a/third_party/WebKit/Source/core/events/EventTarget.cpp b/third_party/WebKit/Source/core/events/EventTarget.cpp
index 92bd274..c9316bd7 100644
--- a/third_party/WebKit/Source/core/events/EventTarget.cpp
+++ b/third_party/WebKit/Source/core/events/EventTarget.cpp
@@ -67,10 +67,15 @@
     return nullptr;
 }
 
-bool isScrollBlockingEvent(const AtomicString& eventType)
+bool isTouchScrollBlockingEvent(const AtomicString& eventType)
 {
     return eventType == EventTypeNames::touchstart
-        || eventType == EventTypeNames::touchmove
+        || eventType == EventTypeNames::touchmove;
+}
+
+bool isScrollBlockingEvent(const AtomicString& eventType)
+{
+    return isTouchScrollBlockingEvent(eventType)
         || eventType == EventTypeNames::mousewheel
         || eventType == EventTypeNames::wheel;
 }
@@ -105,7 +110,7 @@
 
     String messageText = String::format(
         "Handling of '%s' input event was delayed for %ld ms due to main thread being busy. "
-        "Consider marking event handler as 'passive' to make the page more responive.",
+        "Consider marking event handler as 'passive' to make the page more responsive.",
         event->type().getString().utf8().data(), lround(delayedSeconds * 1000));
 
     v8::Local<v8::Function> function = eventListenerEffectiveFunction(v8Listener->isolate(), handler);
@@ -199,7 +204,7 @@
         }
     }
 
-    if (RuntimeEnabledFeatures::passiveDocumentEventListenersEnabled()) {
+    if (RuntimeEnabledFeatures::passiveDocumentEventListenersEnabled() && isTouchScrollBlockingEvent(eventType)) {
         if (!options.hasPassive()) {
             if (Node* node = toNode()) {
                 if (node->isDocumentNode() || node->document().documentElement() == node || node->document().body() == node) {
diff --git a/third_party/WebKit/Source/core/events/MouseRelatedEvent.cpp b/third_party/WebKit/Source/core/events/MouseRelatedEvent.cpp
index 1fdb6af..8f0ff4f 100644
--- a/third_party/WebKit/Source/core/events/MouseRelatedEvent.cpp
+++ b/third_party/WebKit/Source/core/events/MouseRelatedEvent.cpp
@@ -132,6 +132,22 @@
     m_hasCachedRelativePosition = false;
 }
 
+static const LayoutObject* findTargetLayoutObject(Node*& targetNode)
+{
+    LayoutObject* layoutObject = targetNode->layoutObject();
+    if (!layoutObject || !layoutObject->isSVG())
+        return layoutObject;
+    // If this is an SVG node, compute the offset to the padding box of the
+    // outermost SVG root (== the closest ancestor that has a CSS layout box.)
+    while (!layoutObject->isSVGRoot())
+        layoutObject = layoutObject->parent();
+    // Update the target node to point to the SVG root.
+    targetNode = layoutObject->node();
+    DCHECK(!targetNode
+        || (targetNode->isSVGElement() && toSVGElement(*targetNode).isOutermostSVGSVGElement()));
+    return layoutObject;
+}
+
 void MouseRelatedEvent::computeRelativePosition()
 {
     Node* targetNode = target() ? target()->toNode() : nullptr;
@@ -146,13 +162,13 @@
     targetNode->document().updateStyleAndLayoutIgnorePendingStylesheets();
 
     // Adjust offsetLocation to be relative to the target's padding box.
-    if (LayoutObject* r = targetNode->layoutObject()) {
-        FloatPoint localPos = r->absoluteToLocal(FloatPoint(absoluteLocation()), UseTransforms);
+    if (const LayoutObject* layoutObject = findTargetLayoutObject(targetNode)) {
+        FloatPoint localPos = layoutObject->absoluteToLocal(FloatPoint(absoluteLocation()), UseTransforms);
 
         // Adding this here to address crbug.com/570666. Basically we'd like to
         // find the local coordinates relative to the padding box not the border box.
-        if (r->isBoxModelObject()) {
-            LayoutBoxModelObject* layoutBox = toLayoutBoxModelObject(r);
+        if (layoutObject->isBoxModelObject()) {
+            const LayoutBoxModelObject* layoutBox = toLayoutBoxModelObject(layoutObject);
             localPos.move(-layoutBox->borderLeft(), -layoutBox->borderTop());
         }
 
diff --git a/third_party/WebKit/Source/core/events/UIEvent.idl b/third_party/WebKit/Source/core/events/UIEvent.idl
index 235ec54d3e..bbf6c47 100644
--- a/third_party/WebKit/Source/core/events/UIEvent.idl
+++ b/third_party/WebKit/Source/core/events/UIEvent.idl
@@ -24,7 +24,7 @@
 ] interface UIEvent : Event {
     readonly attribute Window? view;
     readonly attribute long detail;
-    [RuntimeEnabled=InputDeviceCapabilities] readonly attribute InputDeviceCapabilities? sourceCapabilities;
+    readonly attribute InputDeviceCapabilities? sourceCapabilities;
 
     // https://w3c.github.io/uievents/#idl-interface-UIEvent-initializers
     // TODO(foolip): None of the initUIEvent() arguments should be optional.
diff --git a/third_party/WebKit/Source/core/events/UIEventInit.idl b/third_party/WebKit/Source/core/events/UIEventInit.idl
index e1f9cbe..a994a6b 100644
--- a/third_party/WebKit/Source/core/events/UIEventInit.idl
+++ b/third_party/WebKit/Source/core/events/UIEventInit.idl
@@ -7,5 +7,5 @@
 dictionary UIEventInit : EventInit {
     Window? view = null;
     long detail = 0;
-    [RuntimeEnabled=InputDeviceCapabilities] InputDeviceCapabilities? sourceCapabilities = null; 
-};
\ No newline at end of file
+    InputDeviceCapabilities? sourceCapabilities = null;
+};
diff --git a/third_party/WebKit/Source/core/fetch/MultipartImageResourceParserTest.cpp b/third_party/WebKit/Source/core/fetch/MultipartImageResourceParserTest.cpp
index 6512ee43..549e7a5 100644
--- a/third_party/WebKit/Source/core/fetch/MultipartImageResourceParserTest.cpp
+++ b/third_party/WebKit/Source/core/fetch/MultipartImageResourceParserTest.cpp
@@ -89,7 +89,6 @@
     };
     for (size_t i = 0; i < WTF_ARRAY_LENGTH(tests); ++i) {
         WebURLResponse response;
-        response.initialize();
         size_t end = 0;
         bool result = Platform::current()->parseMultipartHeadersFromBody(tests[i].data, strlen(tests[i].data), &response, &end);
         EXPECT_EQ(tests[i].result, result);
@@ -100,7 +99,6 @@
 TEST(MultipartResponseTest, ParseMultipartHeaders)
 {
     WebURLResponse webResponse;
-    webResponse.initialize();
     webResponse.addHTTPHeaderField(WebString::fromLatin1("foo"), WebString::fromLatin1("bar"));
     webResponse.addHTTPHeaderField(WebString::fromLatin1("range"), WebString::fromLatin1("piyo"));
     webResponse.addHTTPHeaderField(WebString::fromLatin1("content-length"), WebString::fromLatin1("999"));
@@ -121,7 +119,6 @@
 TEST(MultipartResponseTest, ParseMultipartHeadersContentCharset)
 {
     WebURLResponse webResponse;
-    webResponse.initialize();
 
     const char data[] = "content-type: text/html; charset=utf-8\n\n";
     size_t end = 0;
diff --git a/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp b/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp
index 88dc902..3bb812e 100644
--- a/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp
+++ b/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp
@@ -238,7 +238,6 @@
 
     WrappedResourceRequest requestIn(request);
     WebURLResponse responseOut;
-    responseOut.initialize();
     WebURLError errorOut;
     WebData dataOut;
     m_loader->loadSynchronously(requestIn, responseOut, errorOut, dataOut);
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp
index 9853026..2d84b43a 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -78,6 +78,8 @@
 #include "core/page/FocusController.h"
 #include "core/page/FrameTree.h"
 #include "core/page/Page.h"
+#include "core/page/scrolling/ChildViewportScrollCallback.h"
+#include "core/page/scrolling/RootViewportScrollCallback.h"
 #include "core/page/scrolling/ScrollingCoordinator.h"
 #include "core/paint/FramePainter.h"
 #include "core/paint/PaintLayer.h"
@@ -165,9 +167,7 @@
     , m_scrollAnchor(this)
     , m_needsScrollbarsUpdate(false)
     , m_suppressAdjustViewSize(false)
-    , m_inPluginUpdate(false)
-    , m_inForcedLayoutByChildEmbeddedReplacedContent(false)
-    , m_allowsLayoutInvalidationAfterLayoutClean(false)
+    , m_allowsLayoutInvalidationAfterLayoutClean(true)
 {
     ASSERT(m_frame);
     init();
@@ -772,7 +772,6 @@
     // correct size, which LayoutSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying
     // out for the first time, or when the LayoutSVGRoot size has changed dynamically (eg. via <script>).
     FrameView* frameView = ownerLayoutObject->frame()->view();
-    TemporaryChange<bool> t(frameView->m_inForcedLayoutByChildEmbeddedReplacedContent, true);
 
     // Mark the owner layoutObject as needing layout.
     ownerLayoutObject->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::Unknown);
@@ -939,8 +938,6 @@
     TRACE_EVENT0("blink,benchmark", "FrameView::layout");
     TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "Layout");
 
-    TemporaryChange<bool> allowsLayoutInvalidation(m_allowsLayoutInvalidationAfterLayoutClean, true);
-
     if (m_autoSizeInfo)
         m_autoSizeInfo->autoSizeIfNeeded();
 
@@ -1229,9 +1226,6 @@
             if (widget->isFrameView()) {
                 FrameView* frameView = toFrameView(widget);
                 bool didNeedLayout = frameView->needsLayout();
-                // LayoutPart::updateWidgetGeometry() may invalidate and update layout of the sub-FrameView. This is
-                // allowed, but layout should be clean after updateWidgetGeometry unless the FrameView is throttled.
-                TemporaryChange<bool> allowLayoutInvalidation(frameView->m_allowsLayoutInvalidationAfterLayoutClean, true);
                 part->updateWidgetGeometry();
                 if (!didNeedLayout && !frameView->shouldThrottleRendering())
                     frameView->checkDoesNotNeedLayout();
@@ -1825,36 +1819,14 @@
 
 void FrameView::checkLayoutInvalidationIsAllowed() const
 {
-    CHECK(!m_inPluginUpdate);
+    if (m_allowsLayoutInvalidationAfterLayoutClean)
+        return;
 
     if (!m_frame->document())
         return;
 
-    // TODO(crbug.com/442939): These are hacks to support embedded SVG. This is called from
-    // FrameView::forceLayoutParentViewIfNeeded() and the dirty layout will be cleaned up immediately.
-    // This is for the parent view of the view containing the embedded SVG.
-    if (m_inForcedLayoutByChildEmbeddedReplacedContent)
-        return;
-    // This is for the view containing the embedded SVG.
-    if (embeddedReplacedContent()) {
-        if (const LayoutObject* ownerLayoutObject = m_frame->ownerLayoutObject()) {
-            if (LocalFrame* frame = ownerLayoutObject->frame()) {
-                if (frame->view()->m_inForcedLayoutByChildEmbeddedReplacedContent)
-                    return;
-            }
-        }
-    }
-
-    CHECK(lifecycle().stateAllowsLayoutInvalidation());
-
-    if (m_allowsLayoutInvalidationAfterLayoutClean)
-        return;
-
     // If we are updating all lifecycle phases beyond LayoutClean, we don't expect dirty layout after LayoutClean.
-    if (FrameView* rootFrameView = m_frame->localFrameRoot()->view()) {
-        if (rootFrameView->m_currentUpdateLifecyclePhasesTargetState > DocumentLifecycle::LayoutClean)
-            CHECK(lifecycle().state() < DocumentLifecycle::LayoutClean);
-    }
+    CHECK(lifecycle().state() < DocumentLifecycle::LayoutClean);
 }
 
 void FrameView::scheduleRelayout()
@@ -2392,13 +2364,31 @@
 
 void FrameView::didAttachDocument()
 {
+    FrameHost* frameHost = m_frame->host();
+    DCHECK(frameHost);
+
+    DCHECK(m_frame->document());
+
+    ViewportScrollCallback* viewportScrollCallback = nullptr;
+
     if (m_frame->isMainFrame()) {
-        DCHECK(m_frame->host());
-        ScrollableArea& visualViewport = m_frame->host()->visualViewport();
+        ScrollableArea& visualViewport = frameHost->visualViewport();
         ScrollableArea* layoutViewport = layoutViewportScrollableArea();
         DCHECK(layoutViewport);
-        m_viewportScrollableArea = RootFrameViewport::create(visualViewport, *layoutViewport);
+
+        RootFrameViewport* rootFrameViewport =
+            RootFrameViewport::create(visualViewport, *layoutViewport);
+        m_viewportScrollableArea = rootFrameViewport;
+
+        viewportScrollCallback = RootViewportScrollCallback::create(
+            &frameHost->topControls(),
+            &frameHost->overscrollController(),
+            *rootFrameViewport);
+    } else {
+        viewportScrollCallback = ChildViewportScrollCallback::create();
     }
+
+    m_frame->document()->initializeRootScroller(viewportScrollCallback);
 }
 
 void FrameView::updateScrollCorner()
@@ -2535,6 +2525,11 @@
     }
 
     if (LayoutViewItem view = layoutViewItem()) {
+        forAllNonThrottledFrameViews([](FrameView& frameView) {
+            frameView.checkDoesNotNeedLayout();
+            frameView.m_allowsLayoutInvalidationAfterLayoutClean = false;
+        });
+
         {
             TRACE_EVENT1("devtools.timeline", "UpdateLayerTree", "data", InspectorUpdateLayerTreeEvent::data(m_frame.get()));
 
@@ -2543,7 +2538,7 @@
             view.compositor()->updateIfNeededRecursive();
             scrollContentsIfNeededRecursive();
 
-            ASSERT(lifecycle().state() >= DocumentLifecycle::CompositingClean);
+            DCHECK(lifecycle().state() >= DocumentLifecycle::CompositingClean);
 
             if (targetState >= DocumentLifecycle::PrePaintClean) {
                 if (!RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled())
@@ -2568,10 +2563,15 @@
             if (RuntimeEnabledFeatures::slimmingPaintV2Enabled())
                 pushPaintArtifactToCompositor();
 
-            ASSERT(!view.hasPendingSelection());
-            ASSERT((m_frame->document()->printing() && lifecycle().state() == DocumentLifecycle::PaintInvalidationClean)
+            DCHECK(!view.hasPendingSelection());
+            DCHECK((m_frame->document()->printing() && lifecycle().state() == DocumentLifecycle::PaintInvalidationClean)
                 || lifecycle().state() == DocumentLifecycle::PaintClean);
         }
+
+        forAllNonThrottledFrameViews([](FrameView& frameView) {
+            frameView.checkDoesNotNeedLayout();
+            frameView.m_allowsLayoutInvalidationAfterLayoutClean = true;
+        });
     }
 
     updateViewportIntersectionsForSubtree(targetState);
@@ -2696,6 +2696,8 @@
     m_frame->document()->updateStyleAndLayoutTree();
 
     CHECK(!shouldThrottleRendering());
+    CHECK(m_frame->document()->isActive());
+    CHECK(!m_nestedLayoutCount);
 
     if (needsLayout())
         layout();
@@ -2707,15 +2709,12 @@
     // TODO(leviw): This currently runs the entire lifecycle on plugin WebViews. We
     // should have a way to only run these other Documents to the same lifecycle stage
     // as this frame.
-    {
-        TemporaryChange<bool> t(m_inPluginUpdate, true);
-        const ChildrenWidgetSet* viewChildren = children();
-        for (const Member<Widget>& child : *viewChildren) {
-            if ((*child).isPluginContainer())
-                toPluginView(child.get())->updateAllLifecyclePhases();
-        }
-        checkDoesNotNeedLayout();
+    const ChildrenWidgetSet* viewChildren = children();
+    for (const Member<Widget>& child : *viewChildren) {
+        if ((*child).isPluginContainer())
+            toPluginView(child.get())->updateAllLifecyclePhases();
     }
+    checkDoesNotNeedLayout();
 
     // FIXME: Calling layout() shouldn't trigger script execution or have any
     // observable effects on the frame tree but we're not quite there yet.
diff --git a/third_party/WebKit/Source/core/frame/FrameView.h b/third_party/WebKit/Source/core/frame/FrameView.h
index d6b20250c..808842b6 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.h
+++ b/third_party/WebKit/Source/core/frame/FrameView.h
@@ -915,8 +915,6 @@
 
     bool m_needsScrollbarsUpdate;
     bool m_suppressAdjustViewSize;
-    bool m_inPluginUpdate;
-    bool m_inForcedLayoutByChildEmbeddedReplacedContent;
     bool m_allowsLayoutInvalidationAfterLayoutClean;
 
     // For testing.
diff --git a/third_party/WebKit/Source/core/frame/RootFrameViewport.cpp b/third_party/WebKit/Source/core/frame/RootFrameViewport.cpp
index 8b2e6c2a..2eed1f5a 100644
--- a/third_party/WebKit/Source/core/frame/RootFrameViewport.cpp
+++ b/third_party/WebKit/Source/core/frame/RootFrameViewport.cpp
@@ -18,6 +18,11 @@
 {
 }
 
+void RootFrameViewport::setLayoutViewport(ScrollableArea& newLayoutViewport)
+{
+    m_layoutViewport = &newLayoutViewport;
+}
+
 void RootFrameViewport::updateScrollAnimator()
 {
     scrollAnimator().setCurrentPosition(toFloatPoint(scrollOffsetFromScrollAnimators()));
diff --git a/third_party/WebKit/Source/core/frame/RootFrameViewport.h b/third_party/WebKit/Source/core/frame/RootFrameViewport.h
index 2b0a4d9..1342700f 100644
--- a/third_party/WebKit/Source/core/frame/RootFrameViewport.h
+++ b/third_party/WebKit/Source/core/frame/RootFrameViewport.h
@@ -31,6 +31,8 @@
 
     DECLARE_VIRTUAL_TRACE();
 
+    void setLayoutViewport(ScrollableArea&);
+
     // ScrollableArea Implementation
     void setScrollPosition(const DoublePoint&, ScrollType, ScrollBehavior = ScrollBehaviorInstant) override;
     LayoutRect scrollIntoView(
diff --git a/third_party/WebKit/Source/core/frame/RootFrameViewportTest.cpp b/third_party/WebKit/Source/core/frame/RootFrameViewportTest.cpp
index e0edd0c..87ff48b 100644
--- a/third_party/WebKit/Source/core/frame/RootFrameViewportTest.cpp
+++ b/third_party/WebKit/Source/core/frame/RootFrameViewportTest.cpp
@@ -441,4 +441,38 @@
     EXPECT_POINT_EQ(DoublePoint(10, 10), layoutViewport->scrollPositionDouble());
 }
 
+// Tests that setting an alternate layout viewport scrolls the alternate
+// instead of the original.
+TEST_F(RootFrameViewportTest, SetAlternateLayoutViewport)
+{
+    IntSize viewportSize(100, 100);
+    RootFrameViewStub* layoutViewport = RootFrameViewStub::create(viewportSize, IntSize(200, 300));
+    VisualViewportStub* visualViewport = VisualViewportStub::create(viewportSize, viewportSize);
+
+    RootFrameViewStub* alternateScroller = RootFrameViewStub::create(viewportSize, IntSize(600, 500));
+
+    RootFrameViewport* rootFrameViewport =
+        RootFrameViewport::create(*visualViewport, *layoutViewport);
+
+    visualViewport->setScale(2);
+
+    rootFrameViewport->setScrollPosition(DoublePoint(100, 100), UserScroll);
+    EXPECT_POINT_EQ(DoublePoint(50, 50), visualViewport->scrollPositionDouble());
+    EXPECT_POINT_EQ(DoublePoint(50, 50), layoutViewport->scrollPositionDouble());
+    EXPECT_POINT_EQ(DoublePoint(100, 100), rootFrameViewport->scrollPositionDouble());
+
+    rootFrameViewport->setLayoutViewport(*alternateScroller);
+    EXPECT_POINT_EQ(DoublePoint(50, 50), visualViewport->scrollPositionDouble());
+    EXPECT_POINT_EQ(DoublePoint(0, 0), alternateScroller->scrollPositionDouble());
+    EXPECT_POINT_EQ(DoublePoint(50, 50), rootFrameViewport->scrollPositionDouble());
+
+    rootFrameViewport->setScrollPosition(DoublePoint(200, 200), UserScroll);
+    EXPECT_POINT_EQ(DoublePoint(50, 50), visualViewport->scrollPositionDouble());
+    EXPECT_POINT_EQ(DoublePoint(150, 150), alternateScroller->scrollPositionDouble());
+    EXPECT_POINT_EQ(DoublePoint(200, 200), rootFrameViewport->scrollPositionDouble());
+    EXPECT_POINT_EQ(DoublePoint(50, 50), layoutViewport->scrollPositionDouble());
+
+    EXPECT_POINT_EQ(DoublePoint(550, 450), rootFrameViewport->maximumScrollPositionDouble());
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPSource.cpp b/third_party/WebKit/Source/core/frame/csp/CSPSource.cpp
index 34f11635..b4283a1 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPSource.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/CSPSource.cpp
@@ -91,6 +91,9 @@
     if (port == m_port)
         return true;
 
+    if (m_port == 80 && (port == 443 || (port == 0 && defaultPortForProtocol(url.protocol()) == 443)))
+        return true;
+
     if (!port)
         return isDefaultPortForProtocol(m_port, url.protocol());
 
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPSourceTest.cpp b/third_party/WebKit/Source/core/frame/csp/CSPSourceTest.cpp
index 016f20a..012ba8b 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPSourceTest.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/CSPSourceTest.cpp
@@ -71,7 +71,7 @@
     EXPECT_FALSE(source.matches(KURL(base, "http://example.com:9000/foo/"), ResourceRequest::RedirectStatus::NoRedirect));
 }
 
-TEST_F(CSPSourceTest, InsecureSourceMatchesSecure)
+TEST_F(CSPSourceTest, InsecureSchemeMatchesSecureScheme)
 {
     KURL base;
     CSPSource source(csp.get(), "http", "", 0, "/", CSPSource::NoWildcard, CSPSource::HasWildcard);
@@ -83,7 +83,7 @@
     EXPECT_FALSE(source.matches(KURL(base, "ftp://example.com:8000/")));
 }
 
-TEST_F(CSPSourceTest, InsecureHostMatchesSecure)
+TEST_F(CSPSourceTest, InsecureHostSchemeMatchesSecureScheme)
 {
     KURL base;
     CSPSource source(csp.get(), "http", "example.com", 0, "/", CSPSource::NoWildcard, CSPSource::HasWildcard);
@@ -94,4 +94,28 @@
     EXPECT_FALSE(source.matches(KURL(base, "https://not-example.com:8000/")));
 }
 
+TEST_F(CSPSourceTest, InsecureHostSchemePortMatchesSecurePort)
+{
+    KURL base;
+    CSPSource source(csp.get(), "http", "example.com", 80, "/", CSPSource::NoWildcard, CSPSource::NoWildcard);
+    EXPECT_TRUE(source.matches(KURL(base, "http://example.com/")));
+    EXPECT_TRUE(source.matches(KURL(base, "http://example.com:80/")));
+    EXPECT_TRUE(source.matches(KURL(base, "http://example.com:443/")));
+    EXPECT_TRUE(source.matches(KURL(base, "https://example.com/")));
+    EXPECT_TRUE(source.matches(KURL(base, "https://example.com:80/")));
+    EXPECT_TRUE(source.matches(KURL(base, "https://example.com:443/")));
+
+    EXPECT_FALSE(source.matches(KURL(base, "http://example.com:8443/")));
+    EXPECT_FALSE(source.matches(KURL(base, "https://example.com:8443/")));
+
+    EXPECT_FALSE(source.matches(KURL(base, "http://not-example.com/")));
+    EXPECT_FALSE(source.matches(KURL(base, "http://not-example.com:80/")));
+    EXPECT_FALSE(source.matches(KURL(base, "http://not-example.com:443/")));
+    EXPECT_FALSE(source.matches(KURL(base, "https://not-example.com/")));
+    EXPECT_FALSE(source.matches(KURL(base, "https://not-example.com:80/")));
+    EXPECT_FALSE(source.matches(KURL(base, "https://not-example.com:443/")));
+}
+
+
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLDialogElement.cpp b/third_party/WebKit/Source/core/html/HTMLDialogElement.cpp
index 00e598d..3131829 100644
--- a/third_party/WebKit/Source/core/html/HTMLDialogElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLDialogElement.cpp
@@ -55,7 +55,7 @@
         Element* element = toElement(node);
         if (element->isFormControlElement()) {
             HTMLFormControlElement* control = toHTMLFormControlElement(node);
-            if (control->isAutofocusable()) {
+            if (control->isAutofocusable() && control->isFocusable()) {
                 control->focus();
                 return;
             }
diff --git a/third_party/WebKit/Source/core/html/HTMLElement.cpp b/third_party/WebKit/Source/core/html/HTMLElement.cpp
index 9ad44bc..5160f599 100644
--- a/third_party/WebKit/Source/core/html/HTMLElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLElement.cpp
@@ -1054,33 +1054,33 @@
 
 int HTMLElement::offsetLeftForBinding()
 {
-    document().updateStyleAndLayoutIgnorePendingStylesheetsForNode(this);
+    Element* offsetParent = unclosedOffsetParent();
     if (LayoutBoxModelObject* layoutObject = layoutBoxModelObject())
-        return adjustLayoutUnitForAbsoluteZoom(LayoutUnit(layoutObject->pixelSnappedOffsetLeft(unclosedOffsetParent())), layoutObject->styleRef()).round();
+        return adjustLayoutUnitForAbsoluteZoom(LayoutUnit(layoutObject->pixelSnappedOffsetLeft(offsetParent)), layoutObject->styleRef()).round();
     return 0;
 }
 
 int HTMLElement::offsetTopForBinding()
 {
-    document().updateStyleAndLayoutIgnorePendingStylesheetsForNode(this);
+    Element* offsetParent = unclosedOffsetParent();
     if (LayoutBoxModelObject* layoutObject = layoutBoxModelObject())
-        return adjustLayoutUnitForAbsoluteZoom(LayoutUnit(layoutObject->pixelSnappedOffsetTop(unclosedOffsetParent())), layoutObject->styleRef()).round();
+        return adjustLayoutUnitForAbsoluteZoom(LayoutUnit(layoutObject->pixelSnappedOffsetTop(offsetParent)), layoutObject->styleRef()).round();
     return 0;
 }
 
 int HTMLElement::offsetWidthForBinding()
 {
-    document().updateStyleAndLayoutIgnorePendingStylesheetsForNode(this);
+    Element* offsetParent = unclosedOffsetParent();
     if (LayoutBoxModelObject* layoutObject = layoutBoxModelObject())
-        return adjustLayoutUnitForAbsoluteZoom(LayoutUnit(layoutObject->pixelSnappedOffsetWidth(unclosedOffsetParent())), layoutObject->styleRef()).round();
+        return adjustLayoutUnitForAbsoluteZoom(LayoutUnit(layoutObject->pixelSnappedOffsetWidth(offsetParent)), layoutObject->styleRef()).round();
     return 0;
 }
 
 int HTMLElement::offsetHeightForBinding()
 {
-    document().updateStyleAndLayoutIgnorePendingStylesheetsForNode(this);
+    Element* offsetParent = unclosedOffsetParent();
     if (LayoutBoxModelObject* layoutObject = layoutBoxModelObject())
-        return adjustLayoutUnitForAbsoluteZoom(LayoutUnit(layoutObject->pixelSnappedOffsetHeight(unclosedOffsetParent())), layoutObject->styleRef()).round();
+        return adjustLayoutUnitForAbsoluteZoom(LayoutUnit(layoutObject->pixelSnappedOffsetHeight(offsetParent)), layoutObject->styleRef()).round();
     return 0;
 }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h
index 1f9eed4..975a9ff 100644
--- a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h
@@ -92,6 +92,7 @@
     void setSandboxFlags(SandboxFlags);
 
     bool loadOrRedirectSubframe(const KURL&, const AtomicString& frameName, bool replaceCurrentItem);
+    bool isKeyboardFocusable() const override;
 
 private:
     // Intentionally private to prevent redundant checks when the type is
@@ -99,7 +100,6 @@
     bool isLocal() const override { return true; }
     bool isRemote() const override { return false; }
 
-    bool isKeyboardFocusable() const override;
     bool isFrameOwnerElement() const final { return true; }
 
     virtual ReferrerPolicy referrerPolicyAttribute() { return ReferrerPolicyDefault; }
diff --git a/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp b/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp
index 08e4899..f307a3f 100644
--- a/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp
@@ -32,7 +32,6 @@
 #include "core/dom/shadow/ShadowRoot.h"
 #include "core/fetch/ImageResource.h"
 #include "core/frame/Settings.h"
-#include "core/html/FormData.h"
 #include "core/html/HTMLDocument.h"
 #include "core/html/HTMLImageLoader.h"
 #include "core/html/HTMLMetaElement.h"
diff --git a/third_party/WebKit/Source/core/html/HTMLObjectElement.h b/third_party/WebKit/Source/core/html/HTMLObjectElement.h
index e1eedf6d..6721fc9 100644
--- a/third_party/WebKit/Source/core/html/HTMLObjectElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLObjectElement.h
@@ -31,6 +31,9 @@
 
 class HTMLFormElement;
 
+// Inheritance of FormAssociatedElement was used for NPAPI form association, but is still
+// kept here so that legacy APIs such as form attribute can keep working according to the spec.
+// See: https://html.spec.whatwg.org/multipage/embedded-content.html#the-object-element
 class CORE_EXPORT HTMLObjectElement final : public HTMLPlugInElement, public FormAssociatedElement {
     DEFINE_WRAPPERTYPEINFO();
     USING_GARBAGE_COLLECTED_MIXIN(HTMLObjectElement);
diff --git a/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp b/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
index db0e19a6..b62b61d 100644
--- a/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLPlugInElement.cpp
@@ -375,9 +375,9 @@
 
 bool HTMLPlugInElement::isKeyboardFocusable() const
 {
-    if (!document().isActive())
-        return false;
-    return pluginWidget() && pluginWidget()->isPluginView() && toPluginView(pluginWidget())->supportsKeyboardFocus();
+    if (HTMLFrameOwnerElement::isKeyboardFocusable())
+        return true;
+    return document().isActive() && pluginWidget() && pluginWidget()->isPluginView() && toPluginView(pluginWidget())->supportsKeyboardFocus();
 }
 
 bool HTMLPlugInElement::hasCustomFocusLogic() const
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
index 66ac700..fb051148 100644
--- a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
@@ -145,7 +145,7 @@
     if (optionIndex == selectedIndex())
         return;
 
-    selectOption(optionIndex, DeselectOtherOptions | MakeOptionDirty | (fireOnChangeNow ? DispatchInputAndChangeEvent : 0));
+    selectOption(item(optionIndex), DeselectOtherOptions | MakeOptionDirty | (fireOnChangeNow ? DispatchInputAndChangeEvent : 0));
 }
 
 bool HTMLSelectElement::hasPlaceholderLabelOption() const
@@ -283,6 +283,7 @@
     // We clear the previously selected option(s) when needed, to guarantee
     // calling setSelectedIndex() only once.
     int optionIndex = 0;
+    HTMLOptionElement* option = nullptr;
     if (value.isNull()) {
         optionIndex = -1;
     } else {
@@ -291,8 +292,10 @@
         for (auto& item : listItems()) {
             if (!isHTMLOptionElement(item))
                 continue;
-            if (toHTMLOptionElement(item)->value() == value)
+            if (toHTMLOptionElement(item)->value() == value) {
+                option = toHTMLOptionElement(item);
                 break;
+            }
             optionIndex++;
         }
         if (optionIndex >= static_cast<int>(listItems().size()))
@@ -306,7 +309,7 @@
     SelectOptionFlags flags = DeselectOtherOptions | MakeOptionDirty;
     if (sendEvents)
         flags |= DispatchInputAndChangeEvent;
-    selectOption(optionIndex, flags);
+    selectOption(option, flags);
 
     if (sendEvents && previousSelectedIndex != selectedIndex() && !usesMenuList())
         listBoxOnChange();
@@ -880,17 +883,13 @@
     if (multiple())
         return;
     HTMLOptionElement* firstEnabledOption = nullptr;
-    int firstEnabledOptionIndex = -1;
     HTMLOptionElement* lastSelectedOption = nullptr;
     bool didChange = false;
     int optionIndex = 0;
     // We can't use HTMLSelectElement::options here because this function is
     // called in Node::insertedInto and Node::removedFrom before invalidating
     // node collections.
-    for (auto& item : listItems()) {
-        if (!isHTMLOptionElement(item))
-            continue;
-        HTMLOptionElement* option = toHTMLOptionElement(item);
+    for (const auto& option : optionList()) {
         if (option->selected()) {
             if (lastSelectedOption) {
                 lastSelectedOption->setSelectedState(false);
@@ -900,7 +899,6 @@
         }
         if (!firstEnabledOption && !option->isDisabledFormControl()) {
             firstEnabledOption = option;
-            firstEnabledOptionIndex = optionIndex;
             if (reason == ResetReasonSelectedOptionRemoved) {
                 // There must be no selected OPTIONs.
                 break;
@@ -909,7 +907,7 @@
         ++optionIndex;
     }
     if (!lastSelectedOption && m_size <= 1 && firstEnabledOption && !firstEnabledOption->selected()) {
-        selectOption(firstEnabledOption, firstEnabledOptionIndex, reason == ResetReasonSelectedOptionRemoved ? 0 : DeselectOtherOptions);
+        selectOption(firstEnabledOption, reason == ResetReasonSelectedOptionRemoved ? 0 : DeselectOtherOptions);
         lastSelectedOption = firstEnabledOption;
         didChange = true;
     }
@@ -945,7 +943,7 @@
 
 void HTMLSelectElement::setSelectedIndex(int index)
 {
-    selectOption(index, DeselectOtherOptions | MakeOptionDirty);
+    selectOption(item(index), DeselectOtherOptions | MakeOptionDirty);
 }
 
 void HTMLSelectElement::setSuggestedOption(HTMLOptionElement* option)
@@ -1054,25 +1052,14 @@
     m_lastOnChangeSelection.clear();
 }
 
-void HTMLSelectElement::selectOption(int optionIndex, SelectOptionFlags flags)
-{
-    selectOption(optionIndex < 0 ? nullptr : item(optionIndex), flags);
-}
-
-void HTMLSelectElement::selectOption(HTMLOptionElement* option, SelectOptionFlags flags)
-{
-    selectOption(option, option ? option->index() : -1, flags);
-}
-
 // TODO(tkent): This function is not efficient.  It contains multiple O(N)
 // operations. crbug.com/577989.
-void HTMLSelectElement::selectOption(HTMLOptionElement* element, int optionIndex, SelectOptionFlags flags)
+void HTMLSelectElement::selectOption(HTMLOptionElement* element, SelectOptionFlags flags)
 {
     TRACE_EVENT0("blink", "HTMLSelectElement::selectOption");
-    ASSERT((!element && optionIndex < 0) || (element && optionIndex >= 0));
 
-    // selectedIndex() is O(N).
-    if (isAutofilled() && selectedIndex() != optionIndex)
+    // selectedOption() is O(N).
+    if (isAutofilled() && selectedOption() != element)
         setAutofilled(false);
 
     if (element) {
@@ -1095,6 +1082,14 @@
             setActiveSelectionEnd(element);
     }
 
+    // Need to update m_lastOnChangeOption before
+    // LayoutMenuList::updateFromElement.
+    bool shouldDispatchEvents = false;
+    if (usesMenuList()) {
+        shouldDispatchEvents = (flags & DispatchInputAndChangeEvent) && m_lastOnChangeOption != element;
+        m_lastOnChangeOption = element;
+    }
+
     // For the menu list case, this is what makes the selected element appear.
     if (LayoutObject* layoutObject = this->layoutObject())
         layoutObject->updateFromElement();
@@ -1106,16 +1101,16 @@
     setNeedsValidityCheck();
 
     if (usesMenuList()) {
-        if (flags & DispatchInputAndChangeEvent)
-            dispatchInputAndChangeEventForMenuList();
-        else
-            m_lastOnChangeOption = element;
+        if (shouldDispatchEvents) {
+            dispatchInputEvent();
+            dispatchFormControlChangeEvent();
+        }
         if (LayoutObject* layoutObject = this->layoutObject()) {
-            // Need to check usesMenuList() again because
-            // dispatchInputAndChangeEventForMenuList() might change the status.
+            // Need to check usesMenuList() again because event handlers might
+            // change the status.
             if (usesMenuList()) {
-                // didSetSelectedIndex() is O(N) because of optionToListIndex.
-                toLayoutMenuList(layoutObject)->didSetSelectedIndex(optionIndex);
+                // didSelectOption() is O(N) because of HTMLOptionElement::index().
+                toLayoutMenuList(layoutObject)->didSelectOption(element);
             }
         }
     }
@@ -1244,11 +1239,13 @@
         if (index < itemsSize && isHTMLOptionElement(items[index]) && toHTMLOptionElement(items[index])->value() == state[0]) {
             toHTMLOptionElement(items[index])->setSelectedState(true);
             toHTMLOptionElement(items[index])->setDirty(true);
+            m_lastOnChangeOption = toHTMLOptionElement(items[index]);
         } else {
             size_t foundIndex = searchOptionsForValue(state[0], 0, itemsSize);
             if (foundIndex != kNotFound) {
                 toHTMLOptionElement(items[foundIndex])->setSelectedState(true);
                 toHTMLOptionElement(items[foundIndex])->setDirty(true);
+                m_lastOnChangeOption = toHTMLOptionElement(items[foundIndex]);
             }
         }
     } else {
@@ -1279,7 +1276,7 @@
 void HTMLSelectElement::parseMultipleAttribute(const AtomicString& value)
 {
     bool oldMultiple = m_multiple;
-    int oldSelectedIndex = selectedIndex();
+    HTMLOptionElement* oldSelectedOption = selectedOption();
     m_multiple = !value.isNull();
     setNeedsValidityCheck();
     lazyReattachIfAttached();
@@ -1289,8 +1286,8 @@
         // Preserving the first selection is compatible with Firefox and
         // WebKit. However Edge seems to "ask for a reset" simply.  As of 2016
         // March, the HTML specification says nothing about this.
-        if (oldSelectedIndex >= 0)
-            selectOption(oldSelectedIndex, DeselectOtherOptions);
+        if (oldSelectedOption)
+            selectOption(oldSelectedOption, DeselectOtherOptions);
         else
             resetToDefaultSelection();
     }
@@ -1793,7 +1790,10 @@
     int index = m_typeAhead.handleEvent(event, TypeAhead::MatchPrefix | TypeAhead::CycleFirstChar);
     if (index < 0)
         return;
-    selectOption(listToOptionIndex(index), DeselectOtherOptions | MakeOptionDirty | DispatchInputAndChangeEvent);
+    HTMLOptionElement* option = nullptr;
+    if (static_cast<size_t>(index) < listItems().size() && isHTMLOptionElement(listItems()[index]))
+        option = toHTMLOptionElement(listItems()[index]);
+    selectOption(option, DeselectOtherOptions | MakeOptionDirty | DispatchInputAndChangeEvent);
     if (!usesMenuList())
         listBoxOnChange();
 }
@@ -1804,26 +1804,22 @@
     if (!focused())
         accessKeyAction(false);
 
-    const ListItems& items = listItems();
-    int listIndex = optionToListIndex(index);
-    if (listIndex < 0)
-        return;
-    HTMLElement& element = *items[listIndex];
-    if (!isHTMLOptionElement(element))
+    HTMLOptionElement* option = item(index);
+    if (!option)
         return;
     EventQueueScope scope;
     // If this index is already selected, unselect. otherwise update the
     // selected index.
     SelectOptionFlags flags = DispatchInputAndChangeEvent | (multiple() ? 0 : DeselectOtherOptions);
-    if (toHTMLOptionElement(element).selected()) {
+    if (option->selected()) {
         if (usesMenuList())
-            selectOption(-1, flags);
+            selectOption(nullptr, flags);
         else
-            toHTMLOptionElement(element).setSelectedState(false);
+            option->setSelectedState(false);
     } else {
-        selectOption(index, flags);
+        selectOption(option, flags);
     }
-    toHTMLOptionElement(element).setDirty(true);
+    option->setDirty(true);
     if (usesMenuList())
         return;
     listBoxOnChange();
@@ -1975,13 +1971,17 @@
         layoutObject()->updateFromElement();
 }
 
-int HTMLSelectElement::optionIndexToBeShown() const
+HTMLOptionElement* HTMLSelectElement::optionToBeShown() const
 {
-    if (m_indexToSelectOnCancel >= 0)
-        return listToOptionIndex(m_indexToSelectOnCancel);
+    if (m_indexToSelectOnCancel >= 0 && static_cast<size_t>(m_indexToSelectOnCancel) < listItems().size() && isHTMLOptionElement(listItems()[m_indexToSelectOnCancel]))
+        return toHTMLOptionElement(listItems()[m_indexToSelectOnCancel]);
     if (m_suggestedOption)
-        return m_suggestedOption->index();
-    return selectedIndex();
+        return m_suggestedOption;
+    // TODO(tkent): We should not call optionToBeShown() in multiple() case.
+    if (multiple())
+        return selectedOption();
+    DCHECK_EQ(selectedOption(), m_lastOnChangeOption);
+    return m_lastOnChangeOption;
 }
 
 void HTMLSelectElement::valueChanged(unsigned listIndex)
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.h b/third_party/WebKit/Source/core/html/HTMLSelectElement.h
index cdc4fe9..3bb86d9 100644
--- a/third_party/WebKit/Source/core/html/HTMLSelectElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.h
@@ -31,6 +31,7 @@
 #include "core/html/HTMLContentElement.h"
 #include "core/html/HTMLFormControlElementWithState.h"
 #include "core/html/HTMLOptionsCollection.h"
+#include "core/html/forms/OptionList.h"
 #include "core/html/forms/TypeAhead.h"
 #include "wtf/Vector.h"
 
@@ -83,14 +84,23 @@
     String suggestedValue() const;
     void setSuggestedValue(const String&);
 
+    // |options| and |selectedOptions| are not safe to be used in in
+    // HTMLOptionElement::removedFrom() and insertedInto() because their cache
+    // is inconsistent in these functions.
     HTMLOptionsCollection* options();
     HTMLCollection* selectedOptions();
 
+    // This is similar to |options| HTMLCollection.  But this is safe in
+    // HTMLOptionElement::removedFrom() and insertedInto().
+    // OptionList supports only forward iteration.
+    OptionList optionList() { return OptionList(*this); }
+
     void optionElementChildrenChanged(const HTMLOptionElement&);
 
     void invalidateSelectedItems();
 
     using ListItems = HeapVector<Member<HTMLElement>>;
+    // We prefer |optionList()| to |listItems()|.
     const ListItems& listItems() const;
 
     void accessKeyAction(bool sendMouseEvents) override;
@@ -150,7 +160,7 @@
     void provisionalSelectionChanged(unsigned);
     void popupDidHide();
     bool popupIsVisible() const { return m_popupIsVisible; }
-    int optionIndexToBeShown() const;
+    HTMLOptionElement* optionToBeShown() const;
     void showPopup();
     void hidePopup();
     PopupMenu* popup() const { return m_popup.get(); }
@@ -219,9 +229,7 @@
         MakeOptionDirty = 1 << 2,
     };
     typedef unsigned SelectOptionFlags;
-    void selectOption(int optionIndex, SelectOptionFlags);
     void selectOption(HTMLOptionElement*, SelectOptionFlags);
-    void selectOption(HTMLOptionElement*, int optionIndex, SelectOptionFlags);
     void deselectItemsWithoutValidation(HTMLElement* elementToExclude = 0);
     void parseMultipleAttribute(const AtomicString&);
     HTMLOptionElement* lastSelectedOption() const;
diff --git a/third_party/WebKit/Source/core/html/forms/OptionList.cpp b/third_party/WebKit/Source/core/html/forms/OptionList.cpp
new file mode 100644
index 0000000..06f4f6f
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/forms/OptionList.cpp
@@ -0,0 +1,40 @@
+// 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 "core/html/forms/OptionList.h"
+
+#include "core/dom/ElementTraversal.h"
+#include "core/html/HTMLOptionElement.h"
+#include "core/html/HTMLSelectElement.h"
+
+namespace blink {
+
+void OptionListIterator::advance(HTMLOptionElement* previous)
+{
+    // This function returns only
+    // - An OPTION child of m_select, or
+    // - An OPTION child of an OPTGROUP child of m_select.
+
+    Element* current;
+    if (previous) {
+        DCHECK_EQ(previous->ownerSelectElement(), m_select);
+        current = ElementTraversal::nextSkippingChildren(*previous, m_select);
+    } else {
+        current = ElementTraversal::firstChild(*m_select);
+    }
+    while (current) {
+        if (isHTMLOptionElement(current)) {
+            m_current = toHTMLOptionElement(current);
+            return;
+        }
+        if (isHTMLOptGroupElement(current) && current->parentNode() == m_select) {
+            if ((m_current = Traversal<HTMLOptionElement>::firstChild(*current)))
+                return;
+        }
+        current = ElementTraversal::nextSkippingChildren(*current, m_select);
+    }
+    m_current = nullptr;
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/html/forms/OptionList.h b/third_party/WebKit/Source/core/html/forms/OptionList.h
new file mode 100644
index 0000000..07a36cf7
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/forms/OptionList.h
@@ -0,0 +1,56 @@
+// 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 OptionList_h
+#define OptionList_h
+
+#include "core/CoreExport.h"
+#include "platform/heap/Handle.h"
+
+namespace blink {
+
+class HTMLSelectElement;
+class HTMLOptionElement;
+
+class CORE_EXPORT OptionListIterator final {
+    STACK_ALLOCATED();
+public:
+    explicit OptionListIterator(HTMLSelectElement* select) : m_select(select)
+    {
+        if (m_select)
+            advance(nullptr);
+    }
+    HTMLOptionElement* operator*() { return m_current; }
+    void operator++()
+    {
+        if (m_current)
+            advance(m_current);
+    }
+    bool operator==(const OptionListIterator& other) const { return m_current == other.m_current; }
+    bool operator!=(const OptionListIterator& other) const { return !(*this == other); }
+
+private:
+    void advance(HTMLOptionElement* current);
+
+    Member<HTMLSelectElement> m_select;
+    Member<HTMLOptionElement> m_current; // nullptr means we reached to the end.
+};
+
+// OptionList class is a lightweight version of HTMLOptionsCollection.
+class OptionList final {
+    STACK_ALLOCATED();
+public:
+    explicit OptionList(HTMLSelectElement& select) : m_select(select) {}
+    using Iterator = OptionListIterator;
+    Iterator begin() { return Iterator(m_select); }
+    Iterator end() { return Iterator(nullptr); }
+
+private:
+    Member<HTMLSelectElement> m_select;
+};
+
+} // namespace blink
+
+#endif
+
diff --git a/third_party/WebKit/Source/core/html/forms/OptionListTest.cpp b/third_party/WebKit/Source/core/html/forms/OptionListTest.cpp
new file mode 100644
index 0000000..15bdafdd2
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/forms/OptionListTest.cpp
@@ -0,0 +1,89 @@
+// 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 "core/html/forms/OptionList.h"
+
+#include "core/html/HTMLDocument.h"
+#include "core/html/HTMLOptionElement.h"
+#include "core/html/HTMLSelectElement.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+namespace {
+
+AtomicString id(const HTMLOptionElement* option)
+{
+    return option->fastGetAttribute(HTMLNames::idAttr);
+}
+
+} // namespace
+
+class OptionListTest : public ::testing::Test {
+protected:
+    void SetUp() override
+    {
+        HTMLDocument* document = HTMLDocument::create();
+        HTMLSelectElement* select = HTMLSelectElement::create(*document);
+        document->appendChild(select);
+        m_select = select;
+    }
+    HTMLSelectElement& select() const { return *m_select; }
+
+private:
+    Persistent<HTMLSelectElement> m_select;
+};
+
+TEST_F(OptionListTest, Empty)
+{
+    OptionList list = select().optionList();
+    EXPECT_EQ(list.end(), list.begin()) << "OptionList should iterate over empty SELECT successfully";
+}
+
+TEST_F(OptionListTest, OptionOnly)
+{
+    select().setInnerHTML("text<input><option id=o1></option><input><option id=o2></option><input>", ASSERT_NO_EXCEPTION);
+    HTMLElement* div = toHTMLElement(select().document().createElement("div", ASSERT_NO_EXCEPTION));
+    div->setInnerHTML("<option id=o3></option>", ASSERT_NO_EXCEPTION);
+    select().appendChild(div);
+    OptionList list = select().optionList();
+    OptionList::Iterator iter = list.begin();
+    EXPECT_EQ("o1", id(*iter));
+    ++iter;
+    EXPECT_EQ("o2", id(*iter));
+    ++iter;
+    // No "o3" because it's in DIV.
+    EXPECT_EQ(list.end(), iter);
+}
+
+TEST_F(OptionListTest, Optgroup)
+{
+    select().setInnerHTML("<optgroup><option id=g11></option><option id=g12></option></optgroup>"
+        "<optgroup><option id=g21></option></optgroup>"
+        "<optgroup></optgroup>"
+        "<option id=o1></option>"
+        "<optgroup><option id=g41></option></optgroup>", ASSERT_NO_EXCEPTION);
+    OptionList list = select().optionList();
+    OptionList::Iterator iter = list.begin();
+    EXPECT_EQ("g11", id(*iter));
+    ++iter;
+    EXPECT_EQ("g12", id(*iter));
+    ++iter;
+    EXPECT_EQ("g21", id(*iter));
+    ++iter;
+    EXPECT_EQ("o1", id(*iter));
+    ++iter;
+    EXPECT_EQ("g41", id(*iter));
+    ++iter;
+    EXPECT_EQ(list.end(), iter);
+
+    toHTMLElement(select().firstChild())->setInnerHTML(
+        "<optgroup><option id=gg11></option></optgroup>"
+        "<option id=g11></option>", ASSERT_NO_EXCEPTION);
+    list = select().optionList();
+    iter = list.begin();
+    EXPECT_EQ("g11", id(*iter)) << "Nested OPTGROUP should be ignored.";
+}
+
+} // naemespace blink
diff --git a/third_party/WebKit/Source/core/html/parser/AtomicHTMLToken.h b/third_party/WebKit/Source/core/html/parser/AtomicHTMLToken.h
index 3c28c83c..52948ef 100644
--- a/third_party/WebKit/Source/core/html/parser/AtomicHTMLToken.h
+++ b/third_party/WebKit/Source/core/html/parser/AtomicHTMLToken.h
@@ -235,10 +235,8 @@
         if (attribute.nameAsVector().isEmpty())
             continue;
 
-        ASSERT(attribute.nameRange().start);
-        ASSERT(attribute.nameRange().end);
-        ASSERT(attribute.valueRange().start);
-        ASSERT(attribute.valueRange().end);
+        attribute.nameRange().checkValid();
+        attribute.valueRange().checkValid();
 
         AtomicString value(attribute.value8BitIfNecessary());
         const QualifiedName& name = nameForAttribute(attribute);
diff --git a/third_party/WebKit/Source/core/html/parser/BackgroundHTMLInputStream.cpp b/third_party/WebKit/Source/core/html/parser/BackgroundHTMLInputStream.cpp
index 56f10af2..971a71d 100644
--- a/third_party/WebKit/Source/core/html/parser/BackgroundHTMLInputStream.cpp
+++ b/third_party/WebKit/Source/core/html/parser/BackgroundHTMLInputStream.cpp
@@ -90,8 +90,10 @@
         m_current.append(SegmentedString(m_segments[i]));
     }
 
-    if (!unparsedInput.isEmpty())
-        m_current.prepend(SegmentedString(unparsedInput));
+    if (!unparsedInput.isEmpty()) {
+        m_current.prepend(SegmentedString(unparsedInput),
+            SegmentedString::PrependType::NewInput);
+    }
 
     if (isClosed && !m_current.isClosed())
         m_current.close();
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLEntityParser.cpp b/third_party/WebKit/Source/core/html/parser/HTMLEntityParser.cpp
index 43fc4eb..cd8005ab 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLEntityParser.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLEntityParser.cpp
@@ -97,7 +97,8 @@
         source.push(consumedCharacters[1]);
         source.push(consumedCharacters[0]);
     } else
-        source.prepend(SegmentedString(String(consumedCharacters)));
+        source.prepend(SegmentedString(String(consumedCharacters)),
+            SegmentedString::PrependType::Unconsume);
 }
 
 static bool consumeNamedEntity(SegmentedString& source, DecodedHTMLEntity& decodedEntity, bool& notEnoughCharacters, UChar additionalAllowedCharacter, UChar& cc)
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp
index a6b5992..14ecba3 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp
@@ -34,7 +34,6 @@
 #include "core/css/MediaValuesCached.h"
 #include "core/css/parser/SizesAttributeParser.h"
 #include "core/dom/Document.h"
-#include "core/dom/ScriptLoader.h"
 #include "core/fetch/IntegrityMetadata.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/Settings.h"
@@ -222,6 +221,7 @@
             }
         }
 
+
         TextPosition position = TextPosition(source.currentLine(), source.currentColumn());
         FetchRequest::ResourceWidth resourceWidth;
         float sourceSize = m_sourceSize;
@@ -272,10 +272,6 @@
         // explanation.
         else if (match(attributeName, integrityAttr))
             SubresourceIntegrity::parseIntegrityAttribute(attributeValue, m_integrityMetadata);
-        else if (match(attributeName, typeAttr))
-            m_typeAttributeValue = attributeValue;
-        else if (match(attributeName, languageAttr))
-            m_languageAttributeValue = attributeValue;
     }
 
     template<typename NameType>
@@ -444,8 +440,6 @@
             return false;
         if (match(m_tagImpl, inputTag) && !m_inputIsImage)
             return false;
-        if (match(m_tagImpl, scriptTag) && !ScriptLoader::isValidScriptTypeAndLanguage(m_typeAttributeValue, m_languageAttributeValue, ScriptLoader::AllowLegacyTypeInTypeAttribute))
-            return false;
         return true;
     }
 
@@ -477,8 +471,6 @@
     String m_imgSrcUrl;
     String m_srcsetAttributeValue;
     String m_asAttributeValue;
-    String m_typeAttributeValue;
-    String m_languageAttributeValue;
     float m_sourceSize;
     bool m_sourceSizeSet;
     FetchRequest::DeferOption m_defer;
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp
index 8932e764..bc584d1e 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp
@@ -414,33 +414,4 @@
         test(testCase);
 }
 
-// The preload scanner should follow the same policy that the ScriptLoader does
-// with regard to the type and language attribute.
-TEST_F(HTMLPreloadScannerTest, testScriptTypeAndLanguage)
-{
-    TestCase testCases[] = {
-        // Allow empty src and language attributes.
-        {"http://example.test", "<script src='test.js'></script>", "test.js", "http://example.test/", Resource::Script, 0},
-        {"http://example.test", "<script type='' language='' src='test.js'></script>", "test.js", "http://example.test/", Resource::Script, 0},
-        // Allow standard language and type attributes.
-        {"http://example.test", "<script type='text/javascript' src='test.js'></script>", "test.js", "http://example.test/", Resource::Script, 0},
-        {"http://example.test", "<script type='text/javascript' language='javascript' src='test.js'></script>", "test.js", "http://example.test/", Resource::Script, 0},
-        // Allow legacy languages in the "language" attribute with an empty
-        // type.
-        {"http://example.test", "<script language='javascript1.1' src='test.js'></script>", "test.js", "http://example.test/", Resource::Script, 0},
-        // Allow legacy languages in the "type" attribute.
-        {"http://example.test", "<script type='javascript' src='test.js'></script>", "test.js", "http://example.test/", Resource::Script, 0},
-        {"http://example.test", "<script type='javascript1.7' src='test.js'></script>", "test.js", "http://example.test/", Resource::Script, 0},
-        // Do not allow invalid types in the "type" attribute.
-        {"http://example.test", "<script type='invalid' src='test.js'></script>", nullptr, "http://example.test/", Resource::Script, 0},
-        {"http://example.test", "<script type='asdf' src='test.js'></script>", nullptr, "http://example.test/", Resource::Script, 0},
-        // Do not allow invalid languages.
-        {"http://example.test", "<script language='french' src='test.js'></script>", nullptr, "http://example.test/", Resource::Script, 0},
-        {"http://example.test", "<script language='python' src='test.js'></script>", nullptr, "http://example.test/", Resource::Script, 0},
-    };
-
-    for (const auto& testCase : testCases)
-        test(testCase);
-}
-
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLToken.h b/third_party/WebKit/Source/core/html/parser/HTMLToken.h
index 679a187..3f0d7637 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLToken.h
+++ b/third_party/WebKit/Source/core/html/parser/HTMLToken.h
@@ -81,6 +81,32 @@
         class Range {
             DISALLOW_NEW();
         public:
+            static constexpr int kInvalidOffset = -1;
+
+            inline void clear()
+            {
+#if ENABLE(ASSERT)
+                start = kInvalidOffset;
+                end = kInvalidOffset;
+#endif
+            }
+
+            // Check Range instance that is actively being parsed.
+            inline void checkValidStart() const
+            {
+                DCHECK(start != kInvalidOffset);
+                DCHECK_GE(start, 0);
+            }
+
+            // Check Range instance which finished parse.
+            inline void checkValid() const
+            {
+                checkValidStart();
+                DCHECK(end != kInvalidOffset);
+                DCHECK_GE(end, 0);
+                DCHECK_LE(start, end);
+            }
+
             int start;
             int end;
         };
@@ -122,8 +148,8 @@
     void clear()
     {
         m_type = Uninitialized;
+        m_range.clear();
         m_range.start = 0;
-        m_range.end = 0;
         m_baseOffset = 0;
         // Don't call Vector::clear() as that would destroy the
         // alloced VectorBuffer. If the innerHTML'd content has
@@ -314,45 +340,43 @@
         ASSERT(m_type == StartTag || m_type == EndTag);
         m_attributes.grow(m_attributes.size() + 1);
         m_currentAttribute = &m_attributes.last();
-#if ENABLE(ASSERT)
-        m_currentAttribute->mutableNameRange().start = 0;
-        m_currentAttribute->mutableNameRange().end = 0;
-        m_currentAttribute->mutableValueRange().start = 0;
-        m_currentAttribute->mutableValueRange().end = 0;
-#endif
+        m_currentAttribute->mutableNameRange().clear();
+        m_currentAttribute->mutableValueRange().clear();
     }
 
     void beginAttributeName(int offset)
     {
         m_currentAttribute->mutableNameRange().start = offset - m_baseOffset;
+        m_currentAttribute->nameRange().checkValidStart();
     }
 
     void endAttributeName(int offset)
     {
         int index = offset - m_baseOffset;
         m_currentAttribute->mutableNameRange().end = index;
+        m_currentAttribute->nameRange().checkValid();
         m_currentAttribute->mutableValueRange().start = index;
         m_currentAttribute->mutableValueRange().end = index;
     }
 
     void beginAttributeValue(int offset)
     {
+        m_currentAttribute->mutableValueRange().clear();
         m_currentAttribute->mutableValueRange().start = offset - m_baseOffset;
-#if ENABLE(ASSERT)
-        m_currentAttribute->mutableValueRange().end = 0;
-#endif
+        m_currentAttribute->valueRange().checkValidStart();
     }
 
     void endAttributeValue(int offset)
     {
         m_currentAttribute->mutableValueRange().end = offset - m_baseOffset;
+        m_currentAttribute->valueRange().checkValid();
     }
 
     void appendToAttributeName(UChar character)
     {
         ASSERT(character);
         ASSERT(m_type == StartTag || m_type == EndTag);
-        ASSERT(m_currentAttribute->nameRange().start);
+        m_currentAttribute->nameRange().checkValidStart();
         m_currentAttribute->appendToName(character);
     }
 
@@ -360,7 +384,7 @@
     {
         ASSERT(character);
         ASSERT(m_type == StartTag || m_type == EndTag);
-        ASSERT(m_currentAttribute->valueRange().start);
+        m_currentAttribute->valueRange().checkValidStart();
         m_currentAttribute->appendToValue(character);
     }
 
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLTokenizerTest.cpp b/third_party/WebKit/Source/core/html/parser/HTMLTokenizerTest.cpp
new file mode 100644
index 0000000..1b98177a
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/parser/HTMLTokenizerTest.cpp
@@ -0,0 +1,32 @@
+// 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 "core/html/parser/HTMLTokenizer.h"
+
+#include "core/html/parser/HTMLParserOptions.h"
+#include "core/html/parser/HTMLToken.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include <memory>
+
+namespace blink {
+
+// This is a regression test for crbug.com/619141
+TEST(HTMLTokenizerTest, ZeroOffsetAttributeNameRange)
+{
+    HTMLParserOptions options;
+    std::unique_ptr<HTMLTokenizer> tokenizer = HTMLTokenizer::create(options);
+    HTMLToken token;
+
+    SegmentedString input("<script ");
+    EXPECT_FALSE(tokenizer->nextToken(input, token));
+
+    EXPECT_EQ(HTMLToken::StartTag, token.type());
+
+    SegmentedString input2("type='javascript'");
+    // Below should not fail ASSERT
+    EXPECT_FALSE(tokenizer->nextToken(input2, token));
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp
index 2e22bf0..6949fe78 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp
@@ -86,6 +86,16 @@
     return nullptr;
 }
 
+ScriptPromise ImageBitmapFactories::createImageBitmapFromBlob(ScriptState* scriptState, EventTarget& eventTarget, ImageBitmapSource* bitmapSource, const IntRect& cropRect, const ImageBitmapOptions& options)
+{
+    Blob* blob = static_cast<Blob*>(bitmapSource);
+    ImageBitmapLoader* loader = ImageBitmapFactories::ImageBitmapLoader::create(from(eventTarget), cropRect, options, scriptState);
+    ScriptPromise promise = loader->promise();
+    from(eventTarget).addLoader(loader);
+    loader->loadBlobAsync(eventTarget.getExecutionContext(), blob);
+    return promise;
+}
+
 ScriptPromise ImageBitmapFactories::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, const ImageBitmapSourceUnion& bitmapSource, const ImageBitmapOptions& options, ExceptionState& exceptionState)
 {
     UseCounter::Feature feature = UseCounter::CreateImageBitmap;
@@ -93,14 +103,8 @@
     ImageBitmapSource* bitmapSourceInternal = toImageBitmapSourceInternal(bitmapSource, exceptionState, false);
     if (!bitmapSourceInternal)
         return ScriptPromise();
-    if (bitmapSourceInternal->isBlob()) {
-        Blob* blob = static_cast<Blob*>(bitmapSourceInternal);
-        ImageBitmapLoader* loader = ImageBitmapFactories::ImageBitmapLoader::create(from(eventTarget), IntRect(), options, scriptState);
-        ScriptPromise promise = loader->promise();
-        from(eventTarget).addLoader(loader);
-        loader->loadBlobAsync(eventTarget.getExecutionContext(), blob);
-        return promise;
-    }
+    if (bitmapSourceInternal->isBlob())
+        return createImageBitmapFromBlob(scriptState, eventTarget, bitmapSourceInternal, IntRect(), options);
     IntSize srcSize = bitmapSourceInternal->bitmapSourceSize();
     return createImageBitmap(scriptState, eventTarget, bitmapSourceInternal, 0, 0, srcSize.width(), srcSize.height(), options, exceptionState);
 }
@@ -122,12 +126,7 @@
             exceptionState.throwDOMException(IndexSizeError, String::format("The source %s provided is 0.", sw ? "height" : "width"));
             return ScriptPromise();
         }
-        Blob* blob = static_cast<Blob*>(bitmapSource);
-        ImageBitmapLoader* loader = ImageBitmapFactories::ImageBitmapLoader::create(from(eventTarget), IntRect(sx, sy, sw, sh), options, scriptState);
-        ScriptPromise promise = loader->promise();
-        from(eventTarget).addLoader(loader);
-        loader->loadBlobAsync(eventTarget.getExecutionContext(), blob);
-        return promise;
+        return createImageBitmapFromBlob(scriptState, eventTarget, bitmapSource, IntRect(sx, sy, sw, sh), options);
     }
 
     return bitmapSource->createImageBitmap(scriptState, eventTarget, sx, sy, sw, sh, options, exceptionState);
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h
index 80df930..d17c2cc 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h
@@ -62,6 +62,7 @@
     static ScriptPromise createImageBitmap(ScriptState*, EventTarget&, const ImageBitmapSourceUnion&, const ImageBitmapOptions&, ExceptionState&);
     static ScriptPromise createImageBitmap(ScriptState*, EventTarget&, const ImageBitmapSourceUnion&, int sx, int sy, int sw, int sh, const ImageBitmapOptions&, ExceptionState&);
     static ScriptPromise createImageBitmap(ScriptState*, EventTarget&, ImageBitmapSource*, int sx, int sy, int sw, int sh, const ImageBitmapOptions&, ExceptionState&);
+    static ScriptPromise createImageBitmapFromBlob(ScriptState*, EventTarget&, ImageBitmapSource*, const IntRect&, const ImageBitmapOptions&);
 
     virtual ~ImageBitmapFactories() { }
 
diff --git a/third_party/WebKit/Source/core/input/InputDeviceCapabilities.idl b/third_party/WebKit/Source/core/input/InputDeviceCapabilities.idl
index 0b73ea7b..98ef633 100644
--- a/third_party/WebKit/Source/core/input/InputDeviceCapabilities.idl
+++ b/third_party/WebKit/Source/core/input/InputDeviceCapabilities.idl
@@ -11,7 +11,6 @@
 
 [
     Constructor(optional InputDeviceCapabilitiesInit deviceInitDict),
-    RuntimeEnabled=InputDeviceCapabilities,
 ] interface InputDeviceCapabilities {
     
     // Whether this device dispatches touch events for movement.  This is used to detect
diff --git a/third_party/WebKit/Source/core/input/InputDeviceCapabilitiesInit.idl b/third_party/WebKit/Source/core/input/InputDeviceCapabilitiesInit.idl
index e7ae86d..6dc6147 100644
--- a/third_party/WebKit/Source/core/input/InputDeviceCapabilitiesInit.idl
+++ b/third_party/WebKit/Source/core/input/InputDeviceCapabilitiesInit.idl
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-[
-    RuntimeEnabled=InputDeviceCapabilities,
-] dictionary InputDeviceCapabilitiesInit {
+dictionary InputDeviceCapabilitiesInit {
     boolean firesTouchEvents = false;
 };
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.cpp
index 75f9c12..dabdbe5 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.cpp
@@ -141,9 +141,9 @@
         return v8::MaybeLocal<v8::Function>();
     if (!data->Set(context, v8String(isolate, "useCapture"), v8Boolean(useCapture, isolate)).FromMaybe(false))
         return v8::MaybeLocal<v8::Function>();
-    v8::Local<v8::Function> removeFunction = v8::Function::New(isolate, removeEventListenerCallback, data);
+    v8::Local<v8::Function> removeFunction = v8::Function::New(context, removeEventListenerCallback, data, 0, v8::ConstructorBehavior::kThrow).ToLocalChecked();
     v8::Local<v8::Function> toStringFunction;
-    if (v8::Function::New(context, returnDataCallback, v8String(isolate, "function remove() { [Command Line API] }")).ToLocal(&toStringFunction))
+    if (v8::Function::New(context, returnDataCallback, v8String(isolate, "function remove() { [Command Line API] }"), 0, v8::ConstructorBehavior::kThrow).ToLocal(&toStringFunction))
         removeFunction->Set(v8String(context->GetIsolate(), "toString"), toStringFunction);
     return removeFunction;
 }
diff --git a/third_party/WebKit/Source/core/inspector/InspectorHighlight.cpp b/third_party/WebKit/Source/core/inspector/InspectorHighlight.cpp
index 2cf7381..b69bf787 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorHighlight.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorHighlight.cpp
@@ -12,6 +12,7 @@
 #include "core/layout/LayoutObject.h"
 #include "core/layout/shapes/ShapeOutsideInfo.h"
 #include "core/style/ComputedStyleConstants.h"
+#include "platform/HostWindow.h"
 #include "platform/graphics/Path.h"
 
 namespace blink {
@@ -27,9 +28,11 @@
 
     std::unique_ptr<protocol::ListValue> release() { return std::move(m_path); }
 
-    void appendPath(const Path& path)
+    void appendPath(const Path& path, float scale)
     {
-        path.apply(this, &PathBuilder::appendPathElement);
+        Path transformPath(path);
+        transformPath.transform(AffineTransform().scale(scale));
+        transformPath.apply(this, &PathBuilder::appendPathElement);
     }
 
 protected:
@@ -90,10 +93,10 @@
         , m_layoutObject(layoutObject)
         , m_shapeOutsideInfo(shapeOutsideInfo) { }
 
-    static std::unique_ptr<protocol::ListValue> buildPath(FrameView& view, LayoutObject& layoutObject, const ShapeOutsideInfo& shapeOutsideInfo, const Path& path)
+    static std::unique_ptr<protocol::ListValue> buildPath(FrameView& view, LayoutObject& layoutObject, const ShapeOutsideInfo& shapeOutsideInfo, const Path& path, float scale)
     {
         ShapePathBuilder builder(view, layoutObject, shapeOutsideInfo);
-        builder.appendPath(path);
+        builder.appendPath(path, scale);
         return builder.release();
     }
 
@@ -213,11 +216,12 @@
 
 } // namespace
 
-InspectorHighlight::InspectorHighlight()
+InspectorHighlight::InspectorHighlight(float scale)
     : m_highlightPaths(protocol::ListValue::create())
     , m_showRulers(false)
     , m_showExtensionLines(false)
     , m_displayAsMaterial(false)
+    , m_scale(scale)
 {
 }
 
@@ -234,7 +238,11 @@
     , m_showRulers(highlightConfig.showRulers)
     , m_showExtensionLines(highlightConfig.showExtensionLines)
     , m_displayAsMaterial(highlightConfig.displayAsMaterial)
+    , m_scale(1.f)
 {
+    FrameView* frameView = node->document().view();
+    if (frameView)
+        m_scale = 1.f / frameView->getHostWindow()->windowToViewportScalar(1.f);
     appendPathsForShapeOutside(node, highlightConfig);
     appendNodeHighlight(node, highlightConfig);
     if (appendElementInfo && node->isElementNode())
@@ -249,7 +257,7 @@
 {
     Path path = quadToPath(quad);
     PathBuilder builder;
-    builder.appendPath(path);
+    builder.appendPath(path, m_scale);
     appendPath(builder.release(), fillColor, outlineColor, name);
 }
 
@@ -288,9 +296,9 @@
         return;
     }
 
-    appendPath(ShapePathBuilder::buildPath(*node->document().view(), *node->layoutObject(), *shapeOutsideInfo, paths.shape), config.shape, Color::transparent);
+    appendPath(ShapePathBuilder::buildPath(*node->document().view(), *node->layoutObject(), *shapeOutsideInfo, paths.shape, m_scale), config.shape, Color::transparent);
     if (paths.marginShape.length())
-        appendPath(ShapePathBuilder::buildPath(*node->document().view(), *node->layoutObject(), *shapeOutsideInfo, paths.marginShape), config.shapeMargin, Color::transparent);
+        appendPath(ShapePathBuilder::buildPath(*node->document().view(), *node->layoutObject(), *shapeOutsideInfo, paths.marginShape, m_scale), config.shapeMargin, Color::transparent);
 }
 
 void InspectorHighlight::appendNodeHighlight(Node* node, const InspectorHighlightConfig& highlightConfig)
@@ -362,8 +370,8 @@
     if (const ShapeOutsideInfo* shapeOutsideInfo = shapeOutsideInfoForNode(node, &paths, &boundsQuad)) {
         (*model)->setShapeOutside(protocol::DOM::ShapeOutsideInfo::create()
             .setBounds(buildArrayForQuad(boundsQuad))
-            .setShape(protocol::Array<protocol::Value>::parse(ShapePathBuilder::buildPath(*view, *layoutObject, *shapeOutsideInfo, paths.shape).get(), &errors))
-            .setMarginShape(protocol::Array<protocol::Value>::parse(ShapePathBuilder::buildPath(*view, *layoutObject, *shapeOutsideInfo, paths.marginShape).get(), &errors))
+            .setShape(protocol::Array<protocol::Value>::parse(ShapePathBuilder::buildPath(*view, *layoutObject, *shapeOutsideInfo, paths.shape, 1.f).get(), &errors))
+            .setMarginShape(protocol::Array<protocol::Value>::parse(ShapePathBuilder::buildPath(*view, *layoutObject, *shapeOutsideInfo, paths.marginShape, 1.f).get(), &errors))
             .build());
     }
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorHighlight.h b/third_party/WebKit/Source/core/inspector/InspectorHighlight.h
index d8e1ef86..632d766 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorHighlight.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorHighlight.h
@@ -46,7 +46,7 @@
     STACK_ALLOCATED();
 public:
     InspectorHighlight(Node*, const InspectorHighlightConfig&, bool appendElementInfo);
-    InspectorHighlight();
+    explicit InspectorHighlight(float scale);
     ~InspectorHighlight();
 
     static bool getBoxModel(Node*, std::unique_ptr<protocol::DOM::BoxModel>*);
@@ -67,6 +67,7 @@
     bool m_showRulers;
     bool m_showExtensionLines;
     bool m_displayAsMaterial;
+    float m_scale;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp b/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp
index f76be3e..80e3085 100644
--- a/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp
+++ b/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp
@@ -173,12 +173,12 @@
 {
     v8::Local<v8::String> funcName = v8String(context->GetIsolate(), name);
     v8::Local<v8::Function> func;
-    if (!v8::Function::New(context, callback, v8::External::New(context->GetIsolate(), this)).ToLocal(&func))
+    if (!v8::Function::New(context, callback, v8::External::New(context->GetIsolate(), this), 0, v8::ConstructorBehavior::kThrow).ToLocal(&func))
         return;
     func->SetName(funcName);
     v8::Local<v8::String> returnValue = v8String(context->GetIsolate(), description);
     v8::Local<v8::Function> toStringFunction;
-    if (v8::Function::New(context, returnDataCallback, returnValue).ToLocal(&toStringFunction))
+    if (v8::Function::New(context, returnDataCallback, returnValue, 0, v8::ConstructorBehavior::kThrow).ToLocal(&toStringFunction))
         func->Set(v8String(context->GetIsolate(), "toString"), toStringFunction);
     if (!object->Set(context, funcName, func).FromMaybe(false))
         return;
@@ -241,7 +241,7 @@
 v8::Local<v8::Function> ThreadDebugger::eventLogFunction()
 {
     if (m_eventLogFunction.IsEmpty())
-        m_eventLogFunction.Reset(m_isolate, v8::Function::New(m_isolate, logCallback, v8::External::New(m_isolate, this)));
+        m_eventLogFunction.Reset(m_isolate, v8::Function::New(m_isolate->GetCurrentContext(), logCallback, v8::External::New(m_isolate, this), 0, v8::ConstructorBehavior::kThrow).ToLocalChecked());
     return m_eventLogFunction.Get(m_isolate);
 }
 
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.json b/third_party/WebKit/Source/core/inspector/browser_protocol.json
index 20bc399..eb201e2 100644
--- a/third_party/WebKit/Source/core/inspector/browser_protocol.json
+++ b/third_party/WebKit/Source/core/inspector/browser_protocol.json
@@ -4188,6 +4188,10 @@
         "hidden": true,
         "types": [
             {
+                "id": "BrowserContextID",
+                "type": "string"
+            },
+            {
                 "id": "TargetID",
                 "type": "string"
             },
@@ -4204,6 +4208,50 @@
         ],
         "commands": [
             {
+                "name": "createBrowserContext",
+                "description": "Creates a new empty BrowserContext. Similar to an incognito profile but you can have more than one.",
+                "returns": [
+                    { "name": "browserContextId", "$ref": "BrowserContextID", "description": "The id of the context created." }
+                ],
+                "handlers": ["browser"]
+            },
+            {
+                "name": "disposeBrowserContext",
+                "description": "Deletes a BrowserContext, will fail of any open page uses it.",
+                "parameters": [
+                    { "name": "browserContextId", "$ref": "BrowserContextID" }
+                ],
+                "returns": [
+                    { "name": "success", "type": "boolean" }
+                ],
+                "handlers": ["browser"]
+            },
+            {
+                "name": "createTarget",
+                "description": "Creates a new page.",
+                "parameters": [
+                    { "name": "initialUrl", "type": "string", "description": "The initial URL the page will be navigated to." },
+                    { "name": "width", "type": "integer", "description": "Window width (headless chrome only).", "optional": true },
+                    { "name": "height", "type": "integer", "description": "Window height (headless chrome only).", "optional": true },
+                    { "name": "browserContextId", "$ref": "BrowserContextID", "description": "The browser context to create the page in (headless chrome only).", "optional": true }
+                ],
+                "returns": [
+                    { "name": "targetId", "$ref": "TargetID", "description": "The id of the page opened." }
+                ],
+                "handlers": ["browser"]
+            },
+            {
+                "name": "closeTarget",
+                "description": "Closes the target. If the target is a page that gets closed too.",
+                "parameters": [
+                    { "name": "targetId", "$ref": "TargetID" }
+                ],
+                "returns": [
+                    { "name": "success", "type": "boolean" }
+                ],
+                "handlers": ["browser"]
+            },
+            {
                 "name": "getTargets",
                 "returns": [
                     { "name": "targetInfo", "type": "array", "items": { "$ref": "TargetInfo" } }
@@ -4248,5 +4296,83 @@
                 "handlers": ["browser"]
             }
         ]
+    },
+    {
+        "domain": "SystemInfo",
+        "description": "The SystemInfo domain defines methods and events for querying low-level system information.",
+        "hidden": true,
+        "types": [
+            {
+                "id": "GPUDevice",
+                "type": "object",
+                "properties": [
+                    { "name": "vendorId", "type": "number", "description": "PCI ID of the GPU vendor, if available; 0 otherwise." },
+                    { "name": "deviceId", "type": "number", "description": "PCI ID of the GPU device, if available; 0 otherwise." },
+                    { "name": "vendorString", "type": "string", "description": "String description of the GPU vendor, if the PCI ID is not available." },
+                    { "name": "deviceString", "type": "string", "description": "String description of the GPU device, if the PCI ID is not available." }
+                ],
+                "description": "Describes a single graphics processor (GPU)."
+            },
+            {
+                "id": "GPUInfo",
+                "type": "object",
+                "properties": [
+                    { "name": "devices", "type": "array", "items": { "$ref": "GPUDevice" }, "description": "The graphics devices on the system. Element 0 is the primary GPU." },
+                    { "name": "auxAttributes", "type": "object", "optional": "true", "description": "An optional dictionary of additional GPU related attributes." },
+                    { "name": "featureStatus", "type": "object", "optional": "true", "description": "An optional dictionary of graphics features and their status." },
+                    { "name": "driverBugWorkarounds", "type": "array", "items": { "type": "string" }, "description": "An optional array of GPU driver bug workarounds." }
+                ],
+                "description": "Provides information about the GPU(s) on the system."
+            }
+        ],
+        "commands": [
+            {
+                "name": "getInfo",
+                "async": true,
+                "description": "Returns information about the system.",
+                "returns": [
+                    { "name": "gpu", "$ref": "GPUInfo", "description": "Information about the GPUs on the system." },
+                    { "name": "modelName", "type": "string", "description": "A platform-dependent description of the model of the machine. On Mac OS, this is, for example, 'MacBookPro'. Will be the empty string if not supported." },
+                    { "name": "modelVersion", "type": "string", "description": "A platform-dependent description of the version of the machine. On Mac OS, this is, for example, '10.1'. Will be the empty string if not supported." }
+                ],
+                "handlers": ["browser"]
+            }
+        ]
+    },
+    {
+        "domain": "Tethering",
+        "description": "The Tethering domain defines methods and events for browser port binding.",
+        "hidden": true,
+        "commands": [
+            {
+                "name": "bind",
+                "async": true,
+                "description": "Request browser port binding.",
+                "parameters": [
+                    { "name": "port", "type": "integer", "description": "Port number to bind." }
+                ],
+                "handlers": ["browser"]
+            },
+            {
+                "name": "unbind",
+                "async": true,
+                "description": "Request browser port unbinding.",
+                "parameters": [
+                    { "name": "port", "type": "integer", "description": "Port number to unbind." }
+                ],
+                "handlers": ["browser"]
+            }
+        ],
+        "events": [
+            {
+                "name": "accepted",
+                "description": "Informs that port was successfully bound and got a specified connection id.",
+                "parameters": [
+                    {"name": "port", "type": "integer", "description": "Port number that was successfully bound." },
+                    {"name": "connectionId", "type": "string", "description": "Connection id to be used." }
+                ],
+                "handlers": ["browser"]
+            }
+        ]
     }]
 }
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
index 0db1696e..3f70ca65 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
@@ -635,7 +635,7 @@
     LayoutBox* scrollAncestor = layer()->ancestorOverflowLayer()->isRootLayer() ? nullptr : toLayoutBox(layer()->ancestorOverflowLayer()->layoutObject());
 
     LayoutRect containerContentRect = containingBlock->layoutOverflowRect();
-    LayoutUnit maxContainerWidth = containingBlock->containingBlockLogicalWidthForContent();
+    LayoutUnit maxContainerWidth = containingBlock->isLayoutView() ? containingBlock->logicalWidth() : containingBlock->containingBlockLogicalWidthForContent();
     // Sticky positioned element ignore any override logical width on the containing block (as they don't call
     // containingBlockLogicalWidthForContent). It's unclear whether this is totally fine.
     // Compute the container-relative area within which the sticky element is allowed to move.
diff --git a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp
index 840cd19..7bdedffe 100644
--- a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp
@@ -863,8 +863,6 @@
 
     PaintLayerScrollableArea::PreventRelayoutScope preventRelayoutScope(layoutScope);
 
-    dirtyForLayoutFromPercentageHeightDescendants(layoutScope);
-
     m_orderIterator.first();
     LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
     while (computeNextFlexLine(orderedChildren, sumFlexBaseSize, totalFlexGrow, totalFlexShrink, totalWeightedFlexShrink, sumHypotheticalMainSize, relayoutChildren)) {
@@ -1606,8 +1604,8 @@
             resetAutoMarginsAndLogicalTopInCrossAxis(*child);
         }
         // We may have already forced relayout for orthogonal flowing children in computeInnerFlexBaseSizeForChild.
-        bool forceChildRelayout = relayoutChildren && !childFlexBaseSizeRequiresLayout(*child);
-        if (child->isLayoutBlock() && toLayoutBlock(*child).hasPercentHeightDescendants() && m_relaidOutChildren.contains(child)) {
+        bool forceChildRelayout = relayoutChildren && !m_relaidOutChildren.contains(child);
+        if (child->isLayoutBlock() && toLayoutBlock(*child).hasPercentHeightDescendants()) {
             // Have to force another relayout even though the child is sized correctly, because
             // its descendants are not sized correctly yet. Our previous layout of the child was
             // done without an override height set. So, redo it here.
diff --git a/third_party/WebKit/Source/core/layout/LayoutMenuList.cpp b/third_party/WebKit/Source/core/layout/LayoutMenuList.cpp
index a5e44c0a..b0e9753 100644
--- a/third_party/WebKit/Source/core/layout/LayoutMenuList.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutMenuList.cpp
@@ -178,19 +178,14 @@
 
 void LayoutMenuList::updateFromElement()
 {
-    setTextFromOption(selectElement()->optionIndexToBeShown());
-}
-
-void LayoutMenuList::setTextFromOption(int optionIndex)
-{
     HTMLSelectElement* select = selectElement();
-    const HeapVector<Member<HTMLElement>>& listItems = select->listItems();
-    const int size = listItems.size();
-
+    HTMLOptionElement* option = select->optionToBeShown();
     String text = emptyString();
     m_optionStyle.clear();
 
-    if (selectElement()->multiple()) {
+    if (select->multiple()) {
+        const HeapVector<Member<HTMLElement>>& listItems = select->listItems();
+        const int size = listItems.size();
         unsigned selectedCount = 0;
         int firstSelectedIndex = -1;
         for (int i = 0; i < size; ++i) {
@@ -218,19 +213,15 @@
             ASSERT(!m_optionStyle);
         }
     } else {
-        const int i = select->optionToListIndex(optionIndex);
-        if (i >= 0 && i < size) {
-            Element* element = listItems[i];
-            if (isHTMLOptionElement(*element)) {
-                text = toHTMLOptionElement(element)->textIndentedToRespectGroupLabel();
-                m_optionStyle = element->mutableComputedStyle();
-            }
+        if (option) {
+            text = option->textIndentedToRespectGroupLabel();
+            m_optionStyle = option->mutableComputedStyle();
         }
     }
 
     setText(text.stripWhiteSpace());
 
-    didUpdateActiveOption(optionIndex);
+    didUpdateActiveOption(option);
 }
 
 void LayoutMenuList::setText(const String& s)
@@ -289,23 +280,22 @@
     LayoutBox::computeLogicalHeight(logicalHeight, logicalTop, computedValues);
 }
 
-void LayoutMenuList::didSetSelectedIndex(int optionIndex)
+void LayoutMenuList::didSelectOption(HTMLOptionElement* option)
 {
-    didUpdateActiveOption(optionIndex);
+    didUpdateActiveOption(option);
 }
 
-void LayoutMenuList::didUpdateActiveOption(int optionIndex)
+void LayoutMenuList::didUpdateActiveOption(HTMLOptionElement* option)
 {
     if (!document().existingAXObjectCache())
         return;
 
+    int optionIndex = option ? option->index() : -1;
     if (m_lastActiveIndex == optionIndex)
         return;
     m_lastActiveIndex = optionIndex;
 
-    HTMLSelectElement* select = selectElement();
-    int listIndex = select->optionToListIndex(optionIndex);
-    if (listIndex < 0 || listIndex >= static_cast<int>(select->listItems().size()))
+    if (optionIndex < 0)
         return;
 
     // We skip sending accessiblity notifications for the very first option, otherwise
diff --git a/third_party/WebKit/Source/core/layout/LayoutMenuList.h b/third_party/WebKit/Source/core/layout/LayoutMenuList.h
index fa96089f..743f94c1 100644
--- a/third_party/WebKit/Source/core/layout/LayoutMenuList.h
+++ b/third_party/WebKit/Source/core/layout/LayoutMenuList.h
@@ -39,7 +39,7 @@
     ~LayoutMenuList() override;
 
     HTMLSelectElement* selectElement() const;
-    void didSetSelectedIndex(int optionIndex);
+    void didSelectOption(HTMLOptionElement*);
     String text() const;
 
     const char* name() const override { return "LayoutMenuList"; }
@@ -79,13 +79,12 @@
     void createInnerBlock();
     void adjustInnerStyle();
     void setText(const String&);
-    void setTextFromOption(int optionIndex);
     void updateInnerBlockHeight();
     void updateOptionsWidth() const;
     float computeTextWidth(const TextRun&, const ComputedStyle&) const;
     void setIndexToSelectOnCancel(int listIndex);
 
-    void didUpdateActiveOption(int optionIndex);
+    void didUpdateActiveOption(HTMLOptionElement*);
 
     LayoutText* m_buttonText;
     LayoutBlock* m_innerBlock;
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
index 5255bb3..4dc1e45 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
@@ -2374,7 +2374,7 @@
     // Paint the whole layer if "mainFrameClipsContent" is false, meaning that WebPreferences::record_whole_document is true.
     bool shouldPaintWholePage = !m_owningLayer.layoutObject()->document().settings()->mainFrameClipsContent();
     if (shouldPaintWholePage
-        || (graphicsLayer != m_graphicsLayer.get() && graphicsLayer != m_squashingLayer.get() && graphicsLayer != m_squashingLayer.get() && graphicsLayer != m_scrollingContentsLayer.get()))
+        || (graphicsLayer != m_graphicsLayer.get() && graphicsLayer != m_squashingLayer.get() && graphicsLayer != m_scrollingContentsLayer.get()))
         return wholeLayerRect;
 
     IntRect newInterestRect = recomputeInterestRect(graphicsLayer);
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceFilterPrimitive.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceFilterPrimitive.cpp
index c2aa8c5..3c1b8d9e 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceFilterPrimitive.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceFilterPrimitive.cpp
@@ -50,6 +50,8 @@
         if (newStyle.lightingColor() != oldStyle->svgStyle().lightingColor())
             toLayoutSVGResourceFilter(filter)->primitiveAttributeChanged(this, SVGNames::lighting_colorAttr);
     }
+    if (newStyle.colorInterpolationFilters() != oldStyle->svgStyle().colorInterpolationFilters())
+        toLayoutSVGResourceFilter(filter)->primitiveAttributeChanged(this, SVGNames::color_interpolation_filtersAttr);
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
index 7672e99..d73172a9 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -321,7 +321,7 @@
     TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceSendRequest", TRACE_EVENT_SCOPE_THREAD, "data", InspectorSendRequestEvent::data(identifier, frame(), request));
     InspectorInstrumentation::willSendRequest(frame(), identifier, masterDocumentLoader(), request, redirectResponse, initiatorInfo);
     if (frame()->frameScheduler())
-        frame()->frameScheduler()->incrementPendingResourceLoadCount();
+        frame()->frameScheduler()->didStartLoading(identifier);
 }
 
 void FrameFetchContext::dispatchDidReceiveResponse(unsigned long identifier, const ResourceResponse& response, WebURLRequest::FrameType frameType, WebURLRequest::RequestContext requestContext, Resource* resource)
@@ -372,7 +372,7 @@
     TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceFinish", TRACE_EVENT_SCOPE_THREAD, "data", InspectorResourceFinishEvent::data(identifier, finishTime, false));
     InspectorInstrumentation::didFinishLoading(frame(), identifier, finishTime, encodedDataLength);
     if (frame()->frameScheduler())
-        frame()->frameScheduler()->decrementPendingResourceLoadCount();
+        frame()->frameScheduler()->didStopLoading(identifier);
 }
 
 void FrameFetchContext::dispatchDidFail(unsigned long identifier, const ResourceError& error, bool isInternalRequest)
@@ -385,7 +385,7 @@
     if (!isInternalRequest)
         frame()->console().didFailLoading(identifier, error);
     if (frame()->frameScheduler())
-        frame()->frameScheduler()->decrementPendingResourceLoadCount();
+        frame()->frameScheduler()->didStopLoading(identifier);
 }
 
 void FrameFetchContext::dispatchDidLoadResourceFromMemoryCache(unsigned long identifier, Resource* resource, WebURLRequest::FrameType frameType, WebURLRequest::RequestContext requestContext)
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index 026c90b..71242fc 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -860,7 +860,7 @@
 
 static NavigationType determineNavigationType(FrameLoadType frameLoadType, bool isFormSubmission, bool haveEvent)
 {
-    bool isReload = frameLoadType == FrameLoadTypeReload || frameLoadType == FrameLoadTypeReloadBypassingCache;
+    bool isReload = frameLoadType == FrameLoadTypeReload || frameLoadType == FrameLoadTypeReloadMainResource || frameLoadType == FrameLoadTypeReloadBypassingCache;
     bool isBackForward = isBackForwardLoadType(frameLoadType);
     if (isFormSubmission)
         return (isReload || isBackForward) ? NavigationTypeFormResubmitted : NavigationTypeFormSubmitted;
diff --git a/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp b/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
index 1ee913c9..3056a2a4 100644
--- a/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
+++ b/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
@@ -396,7 +396,6 @@
         timing.initialize();
 
         WebURLResponse response;
-        response.initialize();
         response.setURL(url);
         response.setHTTPStatusCode(301);
         response.setLoadTiming(timing);
@@ -414,7 +413,6 @@
         timing.initialize();
 
         WebURLResponse response;
-        response.initialize();
         response.setURL(url);
         response.setHTTPStatusCode(301);
         response.setLoadTiming(timing);
diff --git a/third_party/WebKit/Source/core/page/scrolling/ChildViewportScrollCallback.cpp b/third_party/WebKit/Source/core/page/scrolling/ChildViewportScrollCallback.cpp
new file mode 100644
index 0000000..3ac8d9f1
--- /dev/null
+++ b/third_party/WebKit/Source/core/page/scrolling/ChildViewportScrollCallback.cpp
@@ -0,0 +1,44 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/page/scrolling/ChildViewportScrollCallback.h"
+
+#include "core/page/scrolling/ScrollState.h"
+#include "platform/geometry/FloatSize.h"
+#include "platform/scroll/ScrollTypes.h"
+#include "platform/scroll/ScrollableArea.h"
+
+namespace blink {
+
+ChildViewportScrollCallback::ChildViewportScrollCallback()
+{
+}
+
+ChildViewportScrollCallback::~ChildViewportScrollCallback()
+{
+}
+
+DEFINE_TRACE(ChildViewportScrollCallback)
+{
+    visitor->trace(m_scroller);
+    ViewportScrollCallback::trace(visitor);
+}
+
+
+void ChildViewportScrollCallback::handleEvent(ScrollState* state)
+{
+    DCHECK(state);
+
+    if (!m_scroller)
+        return;
+
+    performNativeScroll(*state, *m_scroller);
+}
+
+void ChildViewportScrollCallback::setScroller(ScrollableArea* scroller)
+{
+    m_scroller = scroller;
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/page/scrolling/ChildViewportScrollCallback.h b/third_party/WebKit/Source/core/page/scrolling/ChildViewportScrollCallback.h
new file mode 100644
index 0000000..bab9d870
--- /dev/null
+++ b/third_party/WebKit/Source/core/page/scrolling/ChildViewportScrollCallback.h
@@ -0,0 +1,42 @@
+// 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 ChildViewportScrollCallback_h
+#define ChildViewportScrollCallback_h
+
+#include "core/page/scrolling/ViewportScrollCallback.h"
+#include "platform/heap/Handle.h"
+
+namespace blink {
+
+class ScrollableArea;
+class ScrollState;
+
+// The ViewportScrollCallback used by non-root Frames, i.e. iframes. This is
+// essentially a no-op implementation that simply scrolls the frame since
+// iframes don't have any additional scrolling actions, unlike the root frame
+// which moves the top controls and provides overscroll glow.
+class ChildViewportScrollCallback : public ViewportScrollCallback {
+public:
+    static ChildViewportScrollCallback* create()
+    {
+        return new ChildViewportScrollCallback();
+    }
+
+    virtual ~ChildViewportScrollCallback();
+
+    void handleEvent(ScrollState*) override;
+    void setScroller(ScrollableArea*) override;
+
+    DECLARE_VIRTUAL_TRACE();
+
+private:
+    ChildViewportScrollCallback();
+
+    WeakMember<ScrollableArea> m_scroller;
+};
+
+} // namespace blink
+
+#endif // ChildViewportScrollCallback_h
diff --git a/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp b/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp
index 3822b25..9bac01d 100644
--- a/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp
@@ -27,8 +27,12 @@
 
     LayoutBox* box = toLayoutBox(element.layoutObject());
 
+    // For a FrameView, we use the layoutViewport rather than the
+    // getScrollableArea() since that could be the RootFrameViewport. The
+    // rootScroller's ScrollableArea will be swapped in as the layout viewport
+    // in RootFrameViewport so we need to ensure we get the layout viewport.
     if (box->isDocumentElement())
-        return element.document().view()->getScrollableArea();
+        return element.document().view()->layoutViewportScrollableArea();
 
     return static_cast<PaintInvalidationCapableScrollableArea*>(
         box->getScrollableArea());
@@ -73,15 +77,8 @@
 
 } // namespace
 
-ViewportScrollCallback* RootScrollerController::createViewportApplyScroll(
-    TopControls* topControls, OverscrollController* overscrollController)
-{
-    return new ViewportScrollCallback(topControls, overscrollController);
-}
-
-RootScrollerController::RootScrollerController(Document& document, ViewportScrollCallback* applyScrollCallback)
+RootScrollerController::RootScrollerController(Document& document)
     : m_document(&document)
-    , m_viewportApplyScroll(applyScrollCallback)
 {
 }
 
@@ -114,6 +111,12 @@
     updateEffectiveRootScroller();
 }
 
+void RootScrollerController::setViewportScrollCallback(ViewportScrollCallback* callback)
+{
+    m_viewportApplyScroll = callback;
+    moveViewportApplyScroll(m_effectiveRootScroller);
+}
+
 void RootScrollerController::updateEffectiveRootScroller()
 {
     bool rootScrollerValid =
@@ -126,34 +129,35 @@
     if (m_effectiveRootScroller == newEffectiveRootScroller)
         return;
 
-    moveViewportApplyScroll(newEffectiveRootScroller);
-    m_effectiveRootScroller = newEffectiveRootScroller;
+    if (moveViewportApplyScroll(newEffectiveRootScroller))
+        m_effectiveRootScroller = newEffectiveRootScroller;
 }
 
-void RootScrollerController::moveViewportApplyScroll(Element* target)
+bool RootScrollerController::moveViewportApplyScroll(Element* target)
 {
-    if (!m_viewportApplyScroll)
-        return;
+    if (!m_viewportApplyScroll || !target)
+        return false;
+
+    ScrollableArea* targetScroller = scrollableAreaFor(*target);
+    if (!targetScroller)
+        return false;
 
     if (m_effectiveRootScroller)
         m_effectiveRootScroller->removeApplyScroll();
 
-    ScrollableArea* targetScroller =
-        target ? scrollableAreaFor(*target) : nullptr;
-
-    if (targetScroller) {
-        // Use disable-native-scroll since the ViewportScrollCallback needs to
-        // apply scroll actions both before (TopControls) and after (overscroll)
-        // scrolling the element so it will apply scroll to the element itself.
-        target->setApplyScroll(
-            m_viewportApplyScroll,
-            "disable-native-scroll");
-    }
+    // Use disable-native-scroll since the ViewportScrollCallback needs to
+    // apply scroll actions both before (TopControls) and after (overscroll)
+    // scrolling the element so it will apply scroll to the element itself.
+    target->setApplyScroll(m_viewportApplyScroll, "disable-native-scroll");
 
     // Ideally, scroll customization would pass the current element to scroll to
     // the apply scroll callback but this doesn't happen today so we set it
-    // through a back door here.
+    // through a back door here. This is also needed by the
+    // RootViewportScrollCallback to swap the target into the layout viewport
+    // in RootFrameViewport.
     m_viewportApplyScroll->setScroller(targetScroller);
+
+    return true;
 }
 
 Element* RootScrollerController::defaultEffectiveRootScroller()
diff --git a/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.h b/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.h
index b42428a..dd497226 100644
--- a/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.h
+++ b/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.h
@@ -12,8 +12,6 @@
 
 class Document;
 class Element;
-class OverscrollController;
-class TopControls;
 class ViewportScrollCallback;
 
 // Manages the root scroller associated with a given document. The root scroller
@@ -38,24 +36,15 @@
 class CORE_EXPORT RootScrollerController
     : public GarbageCollected<RootScrollerController> {
 public:
-    // Creates a RootScrollerController for the given document. An optional
-    // ViewportScrollCallback can be provided. If it is, RootScrollerController
-    // will ensure that the effectiveRootScroller element always has this set as
-    // the apply scroll callback.
-    static RootScrollerController* create(
-        Document& document,
-        ViewportScrollCallback* applyScrollCallback)
+    // Creates a RootScrollerController for the given document. You should use
+    // setViewportScrollCallback to provide this class with a scroll callback
+    // that RootScrollerController will keep applied to the current RootScroller
+    // so that special actions can occur on scrolling.
+    static RootScrollerController* create(Document& document)
     {
-        return new RootScrollerController(document, applyScrollCallback);
+        return new RootScrollerController(document);
     }
 
-    // Creates an apply scroll callback that handles viewport actions like
-    // TopControls movement and Overscroll. The TopControls and
-    // OverscrollController are given to the ViewportScrollCallback but are not
-    // owned or kept alive by it.
-    static ViewportScrollCallback* createViewportApplyScroll(
-        TopControls*, OverscrollController*);
-
     DECLARE_TRACE();
 
     // Sets the element that will be used as the root scroller. This can be
@@ -89,20 +78,30 @@
         return m_viewportApplyScroll;
     }
 
+    void setViewportScrollCallback(ViewportScrollCallback*);
+
 private:
-    RootScrollerController(Document&, ViewportScrollCallback*);
+    RootScrollerController(Document&);
 
     Element* defaultEffectiveRootScroller();
 
     // Ensures the effective root scroller is currently valid and replaces it
     // with the default if not.
     void updateEffectiveRootScroller();
-    void moveViewportApplyScroll(Element* target);
+
+    // Returns true if the move was successful.
+    bool moveViewportApplyScroll(Element* target);
 
     WeakMember<Document> m_document;
     Member<ViewportScrollCallback> m_viewportApplyScroll;
 
     WeakMember<Element> m_rootScroller;
+
+    // The element currently being used as the root scroller. If
+    // m_viewportApplyScroll has been set, this element is guaranteed to have it
+    // set as its applyScroll callback. This can be nullptr during
+    // initialization and will not be set until m_viewportApplyScroll is
+    // provided.
     WeakMember<Element> m_effectiveRootScroller;
 };
 
diff --git a/third_party/WebKit/Source/core/page/scrolling/RootViewportScrollCallback.cpp b/third_party/WebKit/Source/core/page/scrolling/RootViewportScrollCallback.cpp
new file mode 100644
index 0000000..d1a5206f
--- /dev/null
+++ b/third_party/WebKit/Source/core/page/scrolling/RootViewportScrollCallback.cpp
@@ -0,0 +1,108 @@
+// 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 "core/page/scrolling/RootViewportScrollCallback.h"
+
+#include "core/frame/FrameHost.h"
+#include "core/frame/FrameView.h"
+#include "core/frame/RootFrameViewport.h"
+#include "core/frame/Settings.h"
+#include "core/frame/TopControls.h"
+#include "core/page/scrolling/OverscrollController.h"
+#include "core/page/scrolling/ScrollState.h"
+#include "platform/geometry/FloatSize.h"
+#include "platform/scroll/ScrollableArea.h"
+
+namespace blink {
+
+RootViewportScrollCallback::RootViewportScrollCallback(
+    TopControls* topControls,
+    OverscrollController* overscrollController,
+    RootFrameViewport& rootFrameViewport)
+    : m_topControls(topControls)
+    , m_overscrollController(overscrollController)
+    , m_rootFrameViewport(&rootFrameViewport)
+{
+}
+
+RootViewportScrollCallback::~RootViewportScrollCallback()
+{
+}
+
+DEFINE_TRACE(RootViewportScrollCallback)
+{
+    visitor->trace(m_topControls);
+    visitor->trace(m_overscrollController);
+    visitor->trace(m_rootFrameViewport);
+    ViewportScrollCallback::trace(visitor);
+}
+
+bool RootViewportScrollCallback::shouldScrollTopControls(const FloatSize& delta,
+    ScrollGranularity granularity) const
+{
+    if (granularity != ScrollByPixel && granularity != ScrollByPrecisePixel)
+        return false;
+
+    if (!m_rootFrameViewport)
+        return false;
+
+    DoublePoint maxScroll = m_rootFrameViewport->maximumScrollPositionDouble();
+    DoublePoint scrollPosition = m_rootFrameViewport->scrollPositionDouble();
+
+    // Always give the delta to the top controls if the scroll is in
+    // the direction to show the top controls. If it's in the
+    // direction to hide the top controls, only give the delta to the
+    // top controls when the frame can scroll.
+    return delta.height() < 0 || scrollPosition.y() < maxScroll.y();
+}
+
+bool RootViewportScrollCallback::scrollTopControls(ScrollState& state)
+{
+    // Scroll top controls.
+    if (m_topControls) {
+        if (state.isBeginning())
+            m_topControls->scrollBegin();
+
+        FloatSize delta(state.deltaX(), state.deltaY());
+        ScrollGranularity granularity =
+            ScrollGranularity(static_cast<int>(state.deltaGranularity()));
+        if (shouldScrollTopControls(delta, granularity)) {
+            FloatSize remainingDelta = m_topControls->scrollBy(delta);
+            FloatSize consumed = delta - remainingDelta;
+            state.consumeDeltaNative(consumed.width(), consumed.height());
+            return !consumed.isZero();
+        }
+    }
+
+    return false;
+}
+
+void RootViewportScrollCallback::handleEvent(ScrollState* state)
+{
+    DCHECK(state);
+    if (!m_rootFrameViewport)
+        return;
+
+    bool topControlsDidScroll = scrollTopControls(*state);
+
+    ScrollResult result = performNativeScroll(*state, *m_rootFrameViewport);
+
+    // We consider top controls movement to be scrolling.
+    result.didScrollY |= topControlsDidScroll;
+
+    // Handle Overscroll.
+    if (m_overscrollController) {
+        FloatPoint position(state->positionX(), state->positionY());
+        FloatSize velocity(state->velocityX(), state->velocityY());
+        m_overscrollController->handleOverscroll(result, position, velocity);
+    }
+}
+
+void RootViewportScrollCallback::setScroller(ScrollableArea* scroller)
+{
+    DCHECK(scroller);
+    m_rootFrameViewport->setLayoutViewport(*scroller);
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/page/scrolling/RootViewportScrollCallback.h b/third_party/WebKit/Source/core/page/scrolling/RootViewportScrollCallback.h
new file mode 100644
index 0000000..a1a7ebb
--- /dev/null
+++ b/third_party/WebKit/Source/core/page/scrolling/RootViewportScrollCallback.h
@@ -0,0 +1,59 @@
+// 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 RootViewportScrollCallback_h
+#define RootViewportScrollCallback_h
+
+#include "core/page/scrolling/ViewportScrollCallback.h"
+#include "platform/heap/Handle.h"
+#include "platform/scroll/ScrollTypes.h"
+
+namespace blink {
+
+class FloatSize;
+class ScrollableArea;
+class ScrollState;
+class TopControls;
+class OverscrollController;
+class RootFrameViewport;
+
+// The ViewportScrollCallback used by the one root frame on the page. This
+// callback provides scrolling of the frame as well as associated actions like
+// top controls movement and overscroll glow.
+class RootViewportScrollCallback : public ViewportScrollCallback {
+public:
+    // The TopControls and OverscrollController are given to the
+    // RootViewportScrollCallback but are not owned or kept alive by it.
+    static RootViewportScrollCallback* create(
+        TopControls* topControls,
+        OverscrollController* overscrollController,
+        RootFrameViewport& rootFrameViewport)
+    {
+        return new RootViewportScrollCallback(
+            topControls, overscrollController, rootFrameViewport);
+    }
+
+    virtual ~RootViewportScrollCallback();
+
+    void handleEvent(ScrollState*) override;
+    void setScroller(ScrollableArea*) override;
+
+    DECLARE_VIRTUAL_TRACE();
+
+private:
+    // RootViewportScrollCallback does not assume ownership of TopControls or of
+    // OverscrollController.
+    RootViewportScrollCallback(TopControls*, OverscrollController*, RootFrameViewport&);
+
+    bool shouldScrollTopControls(const FloatSize&, ScrollGranularity) const;
+    bool scrollTopControls(ScrollState&);
+
+    WeakMember<TopControls> m_topControls;
+    WeakMember<OverscrollController> m_overscrollController;
+    WeakMember<RootFrameViewport> m_rootFrameViewport;
+};
+
+} // namespace blink
+
+#endif // RootViewportScrollCallback_h
diff --git a/third_party/WebKit/Source/core/page/scrolling/ViewportScrollCallback.cpp b/third_party/WebKit/Source/core/page/scrolling/ViewportScrollCallback.cpp
index f8cc13a..0c0e1d83 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ViewportScrollCallback.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/ViewportScrollCallback.cpp
@@ -4,101 +4,28 @@
 
 #include "core/page/scrolling/ViewportScrollCallback.h"
 
-#include "core/frame/FrameHost.h"
-#include "core/frame/FrameView.h"
-#include "core/frame/Settings.h"
-#include "core/frame/TopControls.h"
-#include "core/page/scrolling/OverscrollController.h"
 #include "core/page/scrolling/ScrollState.h"
-#include "platform/geometry/FloatSize.h"
 #include "platform/scroll/ScrollableArea.h"
 
 namespace blink {
 
-ViewportScrollCallback::ViewportScrollCallback(
-    TopControls* topControls, OverscrollController* overscrollController)
-    : m_topControls(topControls)
-    , m_overscrollController(overscrollController)
+ScrollResult ViewportScrollCallback::performNativeScroll(
+    ScrollState& state, ScrollableArea& scroller)
 {
-}
-
-ViewportScrollCallback::~ViewportScrollCallback()
-{
-}
-
-DEFINE_TRACE(ViewportScrollCallback)
-{
-    visitor->trace(m_topControls);
-    visitor->trace(m_overscrollController);
-    visitor->trace(m_scroller);
-    ScrollStateCallback::trace(visitor);
-}
-
-bool ViewportScrollCallback::shouldScrollTopControls(const FloatSize& delta,
-    ScrollGranularity granularity) const
-{
-    if (granularity != ScrollByPixel && granularity != ScrollByPrecisePixel)
-        return false;
-
-    if (!m_scroller)
-        return false;
-
-    DoublePoint maxScroll = m_scroller->maximumScrollPositionDouble();
-    DoublePoint scrollPosition = m_scroller->scrollPositionDouble();
-
-    // Always give the delta to the top controls if the scroll is in
-    // the direction to show the top controls. If it's in the
-    // direction to hide the top controls, only give the delta to the
-    // top controls when the frame can scroll.
-    return delta.height() < 0 || scrollPosition.y() < maxScroll.y();
-}
-
-void ViewportScrollCallback::handleEvent(ScrollState* state)
-{
-    FloatSize delta(state->deltaX(), state->deltaY());
+    FloatSize delta(state.deltaX(), state.deltaY());
     ScrollGranularity granularity =
-        ScrollGranularity(static_cast<int>(state->deltaGranularity()));
-    FloatSize remainingDelta = delta;
+        ScrollGranularity(static_cast<int>(state.deltaGranularity()));
 
-    // Scroll top controls.
-    if (m_topControls) {
-        if (state->isBeginning())
-            m_topControls->scrollBegin();
-
-        if (shouldScrollTopControls(delta, granularity))
-            remainingDelta = m_topControls->scrollBy(delta);
-    }
-
-    bool topControlsConsumedScroll = remainingDelta.height() != delta.height();
-
-    // Scroll the element's scrollable area.
-    if (!m_scroller)
-        return;
-
-    ScrollResult result = m_scroller->userScroll(granularity, remainingDelta);
-
-    // We consider top controls movement to be scrolling.
-    result.didScrollY |= topControlsConsumedScroll;
-
-    // Handle Overscroll.
-    if (m_overscrollController) {
-        FloatPoint position(state->positionX(), state->positionY());
-        FloatSize velocity(state->velocityX(), state->velocityY());
-        m_overscrollController->handleOverscroll(result, position, velocity);
-    }
+    ScrollResult result = scroller.userScroll(granularity, delta);
 
     // The viewport consumes everything.
     // TODO(bokan): This isn't actually consuming everything but doing so breaks
-    // the main thread pull-to-refresh action. I need to figure out where that
-    // gets activated. crbug.com/607210.
-    state->consumeDeltaNative(
-        state->deltaX() - result.unusedScrollDeltaX,
-        state->deltaY() - result.unusedScrollDeltaY);
-}
+    // the main thread pull-to-refresh action. crbug.com/607210.
+    state.consumeDeltaNative(
+        delta.width() - result.unusedScrollDeltaX,
+        delta.height() - result.unusedScrollDeltaY);
 
-void ViewportScrollCallback::setScroller(ScrollableArea* scroller)
-{
-    m_scroller = scroller;
+    return result;
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/page/scrolling/ViewportScrollCallback.h b/third_party/WebKit/Source/core/page/scrolling/ViewportScrollCallback.h
index 6fa6d1a..a27c0d4 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ViewportScrollCallback.h
+++ b/third_party/WebKit/Source/core/page/scrolling/ViewportScrollCallback.h
@@ -11,33 +11,34 @@
 
 namespace blink {
 
-class FloatSize;
-class FrameHost;
-class Element;
 class ScrollableArea;
 class ScrollState;
-class TopControls;
-class OverscrollController;
 
+// ViewportScrollCallback is an interface that's used by the
+// RootScrollerController to apply scrolls to the designated rootScroller
+// element. It is a ScrollStateCallback, meaning that it's applied during the
+// applyScroll step of ScrollCustomization and child classes must implement
+// handleEvent in order to actually do the scrolling as well as any possible
+// associated actions.
+//
+// ScrollCustomization generally relies on using the nativeApplyScroll to
+// scroll the element; however, the rootScroller may need to execute actions
+// both before and after the native scroll which is currently unsupported.
+// Because of this, the ViewportScrollCallback can scroll the Element directly.
+// This is accomplished by descendant classes implementing the setScroller
+// method which RootScrollerController will call to fill the callback with the
+// appropriate ScrollableArea to use.
 class ViewportScrollCallback : public ScrollStateCallback {
 public:
-    // ViewportScrollCallback does not assume ownership of TopControls or of
-    // OverscrollController.
-    ViewportScrollCallback(TopControls*, OverscrollController*);
-    ~ViewportScrollCallback();
+    virtual ~ViewportScrollCallback() {}
 
-    void handleEvent(ScrollState*) override;
+    virtual void setScroller(ScrollableArea*) = 0;
 
-    void setScroller(ScrollableArea*);
-
-    DECLARE_VIRTUAL_TRACE();
-
-private:
-    bool shouldScrollTopControls(const FloatSize&, ScrollGranularity) const;
-
-    WeakMember<TopControls> m_topControls;
-    WeakMember<OverscrollController> m_overscrollController;
-    WeakMember<ScrollableArea> m_scroller;
+    DEFINE_INLINE_VIRTUAL_TRACE() {
+        ScrollStateCallback::trace(visitor);
+    }
+protected:
+    ScrollResult performNativeScroll(ScrollState&, ScrollableArea&);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
index 16803f4..a2fc110 100644
--- a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
+++ b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
@@ -354,13 +354,14 @@
     LayoutUnit computedXPosition = roundedMinimumValueForLength(fillLayer.xPosition(), availableWidth);
     if (backgroundRepeatX == RoundFill && positioningAreaSize.width() > LayoutUnit() && fillTileSize.width() > LayoutUnit()) {
         int nrTiles = std::max(1, roundToInt(positioningAreaSize.width() / fillTileSize.width()));
-
-        fillTileSize.setWidth(positioningAreaSize.width() / nrTiles);
+        LayoutUnit roundedWidth = positioningAreaSize.width() / nrTiles;
 
         // Maintain aspect ratio if background-size: auto is set
         if (fillLayer.size().size.height().isAuto() && backgroundRepeatY != RoundFill) {
-            fillTileSize.setHeight(fillTileSize.height() * positioningAreaSize.width() / (nrTiles * fillTileSize.width()));
+            fillTileSize.setHeight(fillTileSize.height() * roundedWidth / fillTileSize.width());
         }
+        fillTileSize.setWidth(roundedWidth);
+
         setTileSize(applySubPixelHeuristicToImageSize(fillTileSize, m_destRect));
         setPhaseX(tileSize().width()
             ? LayoutUnit(roundf(tileSize().width() - fmodf((computedXPosition + left), tileSize().width())))
@@ -371,13 +372,13 @@
     LayoutUnit computedYPosition = roundedMinimumValueForLength(fillLayer.yPosition(), availableHeight);
     if (backgroundRepeatY == RoundFill && positioningAreaSize.height() > LayoutUnit() && fillTileSize.height() > LayoutUnit()) {
         int nrTiles = std::max(1, roundToInt(positioningAreaSize.height() / fillTileSize.height()));
-
-        fillTileSize.setHeight(positioningAreaSize.height() / nrTiles);
-
+        LayoutUnit roundedHeight = positioningAreaSize.height() / nrTiles;
         // Maintain aspect ratio if background-size: auto is set
         if (fillLayer.size().size.width().isAuto() && backgroundRepeatX != RoundFill) {
-            fillTileSize.setWidth(fillTileSize.width() * positioningAreaSize.height() / (nrTiles * fillTileSize.height()));
+            fillTileSize.setWidth(fillTileSize.width() * roundedHeight / fillTileSize.height());
         }
+        fillTileSize.setHeight(roundedHeight);
+
         setTileSize(applySubPixelHeuristicToImageSize(fillTileSize, m_destRect));
         setPhaseY(tileSize().height()
             ? LayoutUnit(roundf(tileSize().height() - fmodf((computedYPosition + top), tileSize().height())))
diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
index cab7bfb..f1a452f 100644
--- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
@@ -39,7 +39,7 @@
     return &gTextBlobCache->add(&inlineTextBox, nullptr).storedValue->value;
 }
 
-static bool paintsMarkerHighlights(const LayoutObject& layoutObject)
+bool InlineTextBoxPainter::paintsMarkerHighlights(const LayoutObject& layoutObject)
 {
     return layoutObject.node() && layoutObject.document().markers().hasMarkers(layoutObject.node());
 }
diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.h b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.h
index 15a43e2..b468693d 100644
--- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.h
+++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.h
@@ -22,6 +22,7 @@
 class Font;
 class GraphicsContext;
 class InlineTextBox;
+class LayoutObject;
 class LayoutPoint;
 class LayoutTextCombine;
 
@@ -39,6 +40,7 @@
     void paintTextMatchMarkerBackground(const PaintInfo&, const LayoutPoint& boxOrigin, DocumentMarker*, const ComputedStyle&, const Font&);
 
     static void removeFromTextBlobCache(const InlineTextBox&);
+    static bool paintsMarkerHighlights(const LayoutObject&);
 
 private:
     enum class PaintOptions { Normal, CombinedText };
diff --git a/third_party/WebKit/Source/core/paint/LayoutObjectDrawingRecorderTest.cpp b/third_party/WebKit/Source/core/paint/LayoutObjectDrawingRecorderTest.cpp
index 5bd3b81..c0eb0e53 100644
--- a/third_party/WebKit/Source/core/paint/LayoutObjectDrawingRecorderTest.cpp
+++ b/third_party/WebKit/Source/core/paint/LayoutObjectDrawingRecorderTest.cpp
@@ -112,9 +112,11 @@
     // the opposite direction to enclosing, and in the y direction, the edges
     // are exactly on a half-pixel boundary. The numbers chosen map nicely to
     // both float and LayoutUnit, to make equality checking reliable.
+    //
+    // The final cull rect should be the enclosing int rect of this rect.
     FloatRect rect(20.75, -5.5, 5.375, 10);
-    EXPECT_EQ(rect, drawAndGetCullRect(rootPaintController(), layoutView(), rect));
-    EXPECT_EQ(rect, drawAndGetCullRect(rootPaintController(), layoutView(), LayoutRect(rect)));
+    EXPECT_EQ(enclosingIntRect(rect), drawAndGetCullRect(rootPaintController(), layoutView(), rect));
+    EXPECT_EQ(enclosingIntRect(rect), drawAndGetCullRect(rootPaintController(), layoutView(), LayoutRect(rect)));
 }
 
 #if 0 // TODO(wangxianzhu): Rewrite this test for slimmingPaintInvalidation.
diff --git a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp
index 93f1068..71497f1 100644
--- a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.cpp
@@ -38,6 +38,23 @@
     return !paintInfo.isPrinting() && m_svgInlineTextBox.getSelectionState() != SelectionNone;
 }
 
+FloatRect SVGInlineTextBoxPainter::boundsForDrawingRecorder(
+    const LayoutPoint& paintOffset, bool includeSelectionRect) const
+{
+    // We compute the paint rect with what looks like the logical values, to match the
+    // computation in SVGInlineTextBox::calculateBoundaries, and the fact that vertical (etc)
+    // layouts are handled by SVGTextLayoutEngine.
+    LayoutRect bounds(
+        m_svgInlineTextBox.topLeft(),
+        LayoutSize(m_svgInlineTextBox.logicalWidth(), m_svgInlineTextBox.logicalHeight()));
+    if (includeSelectionRect) {
+        bounds.unite(m_svgInlineTextBox.localSelectionRect(
+            m_svgInlineTextBox.start(), m_svgInlineTextBox.start() + m_svgInlineTextBox.len()));
+    }
+    bounds.moveBy(paintOffset);
+    return FloatRect(bounds);
+}
+
 void SVGInlineTextBoxPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset)
 {
     ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
@@ -49,7 +66,8 @@
     // We're explicitly not supporting composition & custom underlines and custom highlighters -- unlike InlineTextBox.
     // If we ever need that for SVG, it's very easy to refactor and reuse the code.
 
-    if (paintInfo.phase == PaintPhaseSelection && !shouldPaintSelection(paintInfo))
+    bool haveSelection = shouldPaintSelection(paintInfo);
+    if (!haveSelection && paintInfo.phase == PaintPhaseSelection)
         return;
 
     LayoutSVGInlineText& textLayoutObject = toLayoutSVGInlineText(*LineLayoutAPIShim::layoutObjectFrom(m_svgInlineTextBox.getLineLayoutItem()));
@@ -61,8 +79,10 @@
         LayoutObject& parentLayoutObject = *LineLayoutAPIShim::layoutObjectFrom(m_svgInlineTextBox.parent()->getLineLayoutItem());
         const ComputedStyle& style = parentLayoutObject.styleRef();
 
-        // TODO(chrishtr): passing the cull rect is incorrect.
-        DrawingRecorder recorder(paintInfo.context, m_svgInlineTextBox, displayItemType, FloatRect(paintInfo.cullRect().m_rect));
+        bool includeSelectionRect = paintInfo.phase != PaintPhaseSelection
+            && (haveSelection || InlineTextBoxPainter::paintsMarkerHighlights(textLayoutObject));
+        DrawingRecorder recorder(paintInfo.context, m_svgInlineTextBox, displayItemType,
+            boundsForDrawingRecorder(paintOffset, includeSelectionRect));
         InlineTextBoxPainter(m_svgInlineTextBox).paintDocumentMarkers(
             paintInfo, paintOffset, style,
             textLayoutObject.scaledFont(), DocumentMarkerPaintPhase::Background);
diff --git a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.h b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.h
index 5704099f..73e4615 100644
--- a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.h
+++ b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainter.h
@@ -45,6 +45,7 @@
 
 private:
     bool shouldPaintSelection(const PaintInfo&) const;
+    FloatRect boundsForDrawingRecorder(const LayoutPoint&, bool includeSelectionRect) const;
     void paintTextFragments(const PaintInfo&, LayoutObject&);
     void paintDecoration(const PaintInfo&, TextDecoration, const SVGTextFragment&);
     bool setupTextPaint(const PaintInfo&, const ComputedStyle&, LayoutSVGResourceMode, SkPaint&);
diff --git a/third_party/WebKit/Source/core/paint/VideoPainter.cpp b/third_party/WebKit/Source/core/paint/VideoPainter.cpp
index dbeece3f..49ea54a 100644
--- a/third_party/WebKit/Source/core/paint/VideoPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/VideoPainter.cpp
@@ -13,6 +13,7 @@
 #include "core/paint/PaintInfo.h"
 #include "platform/geometry/LayoutPoint.h"
 #include "platform/graphics/paint/ClipRecorder.h"
+#include "platform/graphics/paint/ForeignLayerDisplayItem.h"
 
 namespace blink {
 
@@ -39,11 +40,25 @@
     if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, m_layoutVideo, paintInfo.phase))
         return;
 
-    LayoutObjectDrawingRecorder drawingRecorder(context, m_layoutVideo, paintInfo.phase, contentRect);
 
     // Video frames are only painted in software for printing or capturing node images via web APIs.
     bool forceSoftwareVideoPaint = paintInfo.getGlobalPaintFlags() & GlobalPaintFlattenCompositingLayers;
 
+    bool paintWithForeignLayer =
+        !displayingPoster && !forceSoftwareVideoPaint
+        && RuntimeEnabledFeatures::slimmingPaintV2Enabled();
+    if (paintWithForeignLayer) {
+        if (WebLayer* layer = m_layoutVideo.mediaElement()->platformLayer()) {
+            IntRect pixelSnappedRect = pixelSnappedIntRect(contentRect);
+            recordForeignLayer(
+                context, m_layoutVideo, DisplayItem::ForeignLayerVideo, layer,
+                pixelSnappedRect.location(), pixelSnappedRect.size());
+            return;
+        }
+    }
+
+    LayoutObjectDrawingRecorder drawingRecorder(context, m_layoutVideo, paintInfo.phase, contentRect);
+
     if (displayingPoster || !forceSoftwareVideoPaint) {
         // This will display the poster image, if one is present, and otherwise paint nothing.
         ImagePainter(m_layoutVideo).paintIntoRect(context, rect);
diff --git a/third_party/WebKit/Source/core/paint/VideoPainterTest.cpp b/third_party/WebKit/Source/core/paint/VideoPainterTest.cpp
new file mode 100644
index 0000000..29551ff
--- /dev/null
+++ b/third_party/WebKit/Source/core/paint/VideoPainterTest.cpp
@@ -0,0 +1,166 @@
+// 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 "core/paint/VideoPainter.h"
+
+#include "core/frame/FrameView.h"
+#include "core/frame/Settings.h"
+#include "core/html/HTMLMediaElement.h"
+#include "core/loader/EmptyClients.h"
+#include "core/testing/DummyPageHolder.h"
+#include "platform/graphics/compositing/PaintArtifactCompositor.h"
+#include "platform/testing/UnitTestHelpers.h"
+#include "platform/testing/WebLayerTreeViewImplForTesting.h"
+#include "public/platform/Platform.h"
+#include "public/platform/WebCompositorSupport.h"
+#include "public/platform/WebLayer.h"
+#include "public/platform/WebMediaPlayer.h"
+#include "public/platform/WebSize.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Integration tests of video painting code (in SPv2 mode).
+
+namespace blink {
+namespace {
+
+class StubChromeClient : public EmptyChromeClient {
+public:
+    StubChromeClient(WebLayerTreeViewImplForTesting::LayerListPolicy layerListPolicy)
+        : m_layerTreeView(layerListPolicy)
+    {
+        m_layerTreeView.setRootLayer(*m_paintArtifactCompositor.getWebLayer());
+    }
+
+    bool hasLayer(const WebLayer& layer) { return m_layerTreeView.hasLayer(layer); }
+
+    // ChromeClient
+    void didPaint(const PaintArtifact& artifact)
+    {
+        m_paintArtifactCompositor.update(artifact);
+    }
+
+private:
+    WebLayerTreeViewImplForTesting m_layerTreeView;
+    PaintArtifactCompositor m_paintArtifactCompositor;
+};
+
+class StubWebMediaPlayer : public WebMediaPlayer {
+public:
+    StubWebMediaPlayer(WebMediaPlayerClient* client)
+        : m_client(client) {}
+
+    const WebLayer* getWebLayer() { return m_webLayer.get(); }
+
+    // WebMediaPlayer
+    void load(LoadType, const WebMediaPlayerSource&, CORSMode)
+    {
+        m_networkState = NetworkStateLoaded;
+        m_client->networkStateChanged();
+        m_readyState = ReadyStateHaveEnoughData;
+        m_client->readyStateChanged();
+        m_webLayer = wrapUnique(Platform::current()->compositorSupport()->createLayer());
+        m_client->setWebLayer(m_webLayer.get());
+    }
+    void play() override {}
+    void pause() override {}
+    bool supportsSave() const override { return false; }
+    void seek(double seconds) override {}
+    void setRate(double) override {}
+    void setVolume(double) override {}
+    WebTimeRanges buffered() const override { return WebTimeRanges(); }
+    WebTimeRanges seekable() const override { return WebTimeRanges(); }
+    void setSinkId(const WebString& sinkId, const WebSecurityOrigin&, WebSetSinkIdCallbacks*) override {}
+    bool hasVideo() const override { return false; }
+    bool hasAudio() const override { return false; }
+    WebSize naturalSize() const override { return WebSize(0, 0); }
+    bool paused() const override { return false; }
+    bool seeking() const override { return false; }
+    double duration() const override { return 0.0; }
+    double currentTime() const override { return 0.0; }
+    NetworkState getNetworkState() const override { return m_networkState; }
+    ReadyState getReadyState() const override { return m_readyState; }
+    WebString getErrorMessage() override { return WebString(); }
+    bool didLoadingProgress() override { return false; }
+    bool hasSingleSecurityOrigin() const override { return true; }
+    bool didPassCORSAccessCheck() const override { return true; }
+    double mediaTimeForTimeValue(double timeValue) const override { return timeValue; }
+    unsigned decodedFrameCount() const override { return 0; }
+    unsigned droppedFrameCount() const override { return 0; }
+    size_t audioDecodedByteCount() const override { return 0; }
+    size_t videoDecodedByteCount() const override { return 0; }
+    void paint(WebCanvas*, const WebRect&, unsigned char alpha, SkXfermode::Mode) override {}
+
+private:
+    WebMediaPlayerClient* m_client;
+    std::unique_ptr<WebLayer> m_webLayer;
+    NetworkState m_networkState = NetworkStateEmpty;
+    ReadyState m_readyState = ReadyStateHaveNothing;
+};
+
+class StubFrameLoaderClient : public EmptyFrameLoaderClient {
+public:
+    // FrameLoaderClient
+    std::unique_ptr<WebMediaPlayer> createWebMediaPlayer(HTMLMediaElement&, const WebMediaPlayerSource&, WebMediaPlayerClient* client) override
+    {
+        return wrapUnique(new StubWebMediaPlayer(client));
+    }
+};
+
+class VideoPainterTestForSPv2 : public ::testing::TestWithParam<WebLayerTreeViewImplForTesting::LayerListPolicy> {
+protected:
+    void SetUp() override
+    {
+        RuntimeEnabledFeatures::setSlimmingPaintV2Enabled(true);
+        m_chromeClient = new StubChromeClient(GetParam());
+        m_frameLoaderClient = new StubFrameLoaderClient;
+        Page::PageClients clients;
+        fillWithEmptyClients(clients);
+        clients.chromeClient = m_chromeClient.get();
+        m_pageHolder = DummyPageHolder::create(IntSize(800, 600), &clients, m_frameLoaderClient.get(),
+            [](Settings& settings) { settings.setAcceleratedCompositingEnabled(true); });
+        document().view()->setParentVisible(true);
+        document().view()->setSelfVisible(true);
+        document().setURL(KURL(KURL(), "https://example.com/"));
+    }
+
+    void TearDown() override
+    {
+        m_featuresBackup.restore();
+    }
+
+    Document& document() { return m_pageHolder->document(); }
+    bool hasLayerAttached(const WebLayer& layer) { return m_chromeClient->hasLayer(layer); }
+
+private:
+    RuntimeEnabledFeatures::Backup m_featuresBackup;
+    Persistent<StubChromeClient> m_chromeClient;
+    Persistent<StubFrameLoaderClient> m_frameLoaderClient;
+    std::unique_ptr<DummyPageHolder> m_pageHolder;
+};
+
+INSTANTIATE_TEST_CASE_P(, VideoPainterTestForSPv2, ::testing::Values(
+    WebLayerTreeViewImplForTesting::DontUseLayerLists,
+    WebLayerTreeViewImplForTesting::UseLayerLists));
+
+TEST_P(VideoPainterTestForSPv2, VideoLayerAppearsInLayerTree)
+{
+    // Insert a <video> and allow it to begin loading.
+    document().body()->setInnerHTML("<video width=300 height=200 src=test.ogv>", ASSERT_NO_EXCEPTION);
+    testing::runPendingTasks();
+
+    // Force the page to paint.
+    document().view()->updateAllLifecyclePhases();
+
+    // Fetch the layer associated with the <video>, and check that it was
+    // correctly configured in the layer tree.
+    HTMLMediaElement* element = toHTMLMediaElement(document().body()->firstChild());
+    StubWebMediaPlayer* player = static_cast<StubWebMediaPlayer*>(element->webMediaPlayer());
+    const WebLayer* layer = player->getWebLayer();
+    ASSERT_TRUE(layer);
+    EXPECT_TRUE(hasLayerAttached(*layer));
+    EXPECT_EQ(WebSize(300, 200), layer->bounds());
+}
+
+} // namespace
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGFEBlendElement.cpp b/third_party/WebKit/Source/core/svg/SVGFEBlendElement.cpp
index 070ac3f..ff30498 100644
--- a/third_party/WebKit/Source/core/svg/SVGFEBlendElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGFEBlendElement.cpp
@@ -113,8 +113,7 @@
     if (attrName == SVGNames::modeAttr)
         return blend->setBlendMode(toWebBlendMode(m_mode->currentValue()->enumValue()));
 
-    ASSERT_NOT_REACHED();
-    return false;
+    return SVGFilterPrimitiveStandardAttributes::setFilterEffectAttribute(effect, attrName);
 }
 
 void SVGFEBlendElement::svgAttributeChanged(const QualifiedName& attrName)
diff --git a/third_party/WebKit/Source/core/svg/SVGFEColorMatrixElement.cpp b/third_party/WebKit/Source/core/svg/SVGFEColorMatrixElement.cpp
index 2dd476e..1155c44 100644
--- a/third_party/WebKit/Source/core/svg/SVGFEColorMatrixElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGFEColorMatrixElement.cpp
@@ -67,8 +67,7 @@
     if (attrName == SVGNames::valuesAttr)
         return colorMatrix->setValues(m_values->currentValue()->toFloatVector());
 
-    ASSERT_NOT_REACHED();
-    return false;
+    return SVGFilterPrimitiveStandardAttributes::setFilterEffectAttribute(effect, attrName);
 }
 
 void SVGFEColorMatrixElement::svgAttributeChanged(const QualifiedName& attrName)
diff --git a/third_party/WebKit/Source/core/svg/SVGFECompositeElement.cpp b/third_party/WebKit/Source/core/svg/SVGFECompositeElement.cpp
index 37aa025..869cb4a 100644
--- a/third_party/WebKit/Source/core/svg/SVGFECompositeElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGFECompositeElement.cpp
@@ -93,8 +93,7 @@
     if (attrName == SVGNames::k4Attr)
         return composite->setK4(m_k4->currentValue()->value());
 
-    ASSERT_NOT_REACHED();
-    return false;
+    return SVGFilterPrimitiveStandardAttributes::setFilterEffectAttribute(effect, attrName);
 }
 
 
diff --git a/third_party/WebKit/Source/core/svg/SVGFEConvolveMatrixElement.cpp b/third_party/WebKit/Source/core/svg/SVGFEConvolveMatrixElement.cpp
index 1cf1488..0b168f17 100644
--- a/third_party/WebKit/Source/core/svg/SVGFEConvolveMatrixElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGFEConvolveMatrixElement.cpp
@@ -151,9 +151,7 @@
         return convolveMatrix->setTargetOffset(targetPoint());
     if (attrName == SVGNames::preserveAlphaAttr)
         return convolveMatrix->setPreserveAlpha(m_preserveAlpha->currentValue()->value());
-
-    ASSERT_NOT_REACHED();
-    return false;
+    return SVGFilterPrimitiveStandardAttributes::setFilterEffectAttribute(effect, attrName);
 }
 
 void SVGFEConvolveMatrixElement::svgAttributeChanged(const QualifiedName& attrName)
diff --git a/third_party/WebKit/Source/core/svg/SVGFEDiffuseLightingElement.cpp b/third_party/WebKit/Source/core/svg/SVGFEDiffuseLightingElement.cpp
index f148e7c0..e83d6514 100644
--- a/third_party/WebKit/Source/core/svg/SVGFEDiffuseLightingElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGFEDiffuseLightingElement.cpp
@@ -86,8 +86,7 @@
     if (attrName == SVGNames::limitingConeAngleAttr)
         return lightSource->setLimitingConeAngle(lightElement->limitingConeAngle()->currentValue()->value());
 
-    ASSERT_NOT_REACHED();
-    return false;
+    return SVGFilterPrimitiveStandardAttributes::setFilterEffectAttribute(effect, attrName);
 }
 
 void SVGFEDiffuseLightingElement::svgAttributeChanged(const QualifiedName& attrName)
diff --git a/third_party/WebKit/Source/core/svg/SVGFEDisplacementMapElement.cpp b/third_party/WebKit/Source/core/svg/SVGFEDisplacementMapElement.cpp
index b36f09e..dabb9d0 100644
--- a/third_party/WebKit/Source/core/svg/SVGFEDisplacementMapElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGFEDisplacementMapElement.cpp
@@ -74,8 +74,7 @@
     if (attrName == SVGNames::scaleAttr)
         return displacementMap->setScale(m_scale->currentValue()->value());
 
-    ASSERT_NOT_REACHED();
-    return false;
+    return SVGFilterPrimitiveStandardAttributes::setFilterEffectAttribute(effect, attrName);
 }
 
 void SVGFEDisplacementMapElement::svgAttributeChanged(const QualifiedName& attrName)
diff --git a/third_party/WebKit/Source/core/svg/SVGFEDropShadowElement.cpp b/third_party/WebKit/Source/core/svg/SVGFEDropShadowElement.cpp
index 6bf775c..f1dd4aa 100644
--- a/third_party/WebKit/Source/core/svg/SVGFEDropShadowElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGFEDropShadowElement.cpp
@@ -73,9 +73,7 @@
         dropShadow->setShadowOpacity(svgStyle.floodOpacity());
         return true;
     }
-
-    NOTREACHED();
-    return false;
+    return SVGFilterPrimitiveStandardAttributes::setFilterEffectAttribute(effect, attrName);
 }
 
 void SVGFEDropShadowElement::svgAttributeChanged(const QualifiedName& attrName)
diff --git a/third_party/WebKit/Source/core/svg/SVGFEFloodElement.cpp b/third_party/WebKit/Source/core/svg/SVGFEFloodElement.cpp
index f0ce9e7a..f13540b 100644
--- a/third_party/WebKit/Source/core/svg/SVGFEFloodElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGFEFloodElement.cpp
@@ -46,8 +46,7 @@
     if (attrName == SVGNames::flood_opacityAttr)
         return flood->setFloodOpacity(style.svgStyle().floodOpacity());
 
-    ASSERT_NOT_REACHED();
-    return false;
+    return SVGFilterPrimitiveStandardAttributes::setFilterEffectAttribute(effect, attrName);
 }
 
 FilterEffect* SVGFEFloodElement::build(SVGFilterBuilder*, Filter* filter)
diff --git a/third_party/WebKit/Source/core/svg/SVGFEMorphologyElement.cpp b/third_party/WebKit/Source/core/svg/SVGFEMorphologyElement.cpp
index c3fd89f0..7ad0d9c7 100644
--- a/third_party/WebKit/Source/core/svg/SVGFEMorphologyElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGFEMorphologyElement.cpp
@@ -68,9 +68,7 @@
         bool isRadiusYChanged = morphology->setRadiusY(radiusY()->currentValue()->value());
         return isRadiusXChanged || isRadiusYChanged;
     }
-
-    ASSERT_NOT_REACHED();
-    return false;
+    return SVGFilterPrimitiveStandardAttributes::setFilterEffectAttribute(effect, attrName);
 }
 
 void SVGFEMorphologyElement::svgAttributeChanged(const QualifiedName& attrName)
diff --git a/third_party/WebKit/Source/core/svg/SVGFESpecularLightingElement.cpp b/third_party/WebKit/Source/core/svg/SVGFESpecularLightingElement.cpp
index 2f90a33d..838b9c1 100644
--- a/third_party/WebKit/Source/core/svg/SVGFESpecularLightingElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGFESpecularLightingElement.cpp
@@ -92,8 +92,7 @@
     if (attrName == SVGNames::limitingConeAngleAttr)
         return lightSource->setLimitingConeAngle(lightElement->limitingConeAngle()->currentValue()->value());
 
-    ASSERT_NOT_REACHED();
-    return false;
+    return SVGFilterPrimitiveStandardAttributes::setFilterEffectAttribute(effect, attrName);
 }
 
 void SVGFESpecularLightingElement::svgAttributeChanged(const QualifiedName& attrName)
diff --git a/third_party/WebKit/Source/core/svg/SVGFETurbulenceElement.cpp b/third_party/WebKit/Source/core/svg/SVGFETurbulenceElement.cpp
index 7e7db1ce..23e44da 100644
--- a/third_party/WebKit/Source/core/svg/SVGFETurbulenceElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGFETurbulenceElement.cpp
@@ -89,8 +89,7 @@
     if (attrName == SVGNames::numOctavesAttr)
         return turbulence->setNumOctaves(m_numOctaves->currentValue()->value());
 
-    ASSERT_NOT_REACHED();
-    return false;
+    return SVGFilterPrimitiveStandardAttributes::setFilterEffectAttribute(effect, attrName);
 }
 
 void SVGFETurbulenceElement::svgAttributeChanged(const QualifiedName& attrName)
diff --git a/third_party/WebKit/Source/core/svg/SVGFilterPrimitiveStandardAttributes.cpp b/third_party/WebKit/Source/core/svg/SVGFilterPrimitiveStandardAttributes.cpp
index d519fa5..aa3c99c 100644
--- a/third_party/WebKit/Source/core/svg/SVGFilterPrimitiveStandardAttributes.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGFilterPrimitiveStandardAttributes.cpp
@@ -25,6 +25,7 @@
 #include "core/layout/svg/LayoutSVGResourceContainer.h"
 #include "core/layout/svg/LayoutSVGResourceFilterPrimitive.h"
 #include "core/svg/SVGLength.h"
+#include "core/svg/graphics/filters/SVGFilterBuilder.h"
 #include "platform/graphics/filters/FilterEffect.h"
 
 namespace blink {
@@ -62,11 +63,16 @@
     SVGElement::trace(visitor);
 }
 
-bool SVGFilterPrimitiveStandardAttributes::setFilterEffectAttribute(FilterEffect*, const QualifiedName&)
+bool SVGFilterPrimitiveStandardAttributes::setFilterEffectAttribute(FilterEffect* effect, const QualifiedName& attrName)
 {
-    // When all filters support this method, it will be changed to a pure virtual method.
-    ASSERT_NOT_REACHED();
-    return false;
+    DCHECK(attrName == SVGNames::color_interpolation_filtersAttr);
+    DCHECK(layoutObject());
+    EColorInterpolation colorInterpolation = layoutObject()->styleRef().svgStyle().colorInterpolationFilters();
+    ColorSpace resolvedColorSpace = SVGFilterBuilder::resolveColorSpace(colorInterpolation);
+    if (resolvedColorSpace == effect->operatingColorSpace())
+        return false;
+    effect->setOperatingColorSpace(resolvedColorSpace);
+    return true;
 }
 
 void SVGFilterPrimitiveStandardAttributes::svgAttributeChanged(const QualifiedName& attrName)
diff --git a/third_party/WebKit/Source/core/svg/graphics/filters/SVGFilterBuilder.cpp b/third_party/WebKit/Source/core/svg/graphics/filters/SVGFilterBuilder.cpp
index ba326a9..b88584a 100644
--- a/third_party/WebKit/Source/core/svg/graphics/filters/SVGFilterBuilder.cpp
+++ b/third_party/WebKit/Source/core/svg/graphics/filters/SVGFilterBuilder.cpp
@@ -158,6 +158,11 @@
     return parentColorInterpolation;
 }
 
+ColorSpace SVGFilterBuilder::resolveColorSpace(EColorInterpolation colorInterpolation)
+{
+    return colorInterpolation == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB;
+}
+
 void SVGFilterBuilder::buildGraph(Filter* filter, SVGFilterElement& filterElement, const FloatRect& referenceBox)
 {
     EColorInterpolation filterColorInterpolation = colorInterpolationForElement(filterElement, CI_AUTO);
@@ -177,7 +182,7 @@
         effectElement->setStandardAttributes(effect);
         effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(effectElement, filterElement.primitiveUnits()->currentValue()->enumValue(), referenceBox));
         EColorInterpolation colorInterpolation = colorInterpolationForElement(*effectElement, filterColorInterpolation);
-        effect->setOperatingColorSpace(colorInterpolation == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB);
+        effect->setOperatingColorSpace(resolveColorSpace(colorInterpolation));
         if (effectElement->taintsOrigin(effect->inputsTaintOrigin()))
             effect->setOriginTainted();
 
diff --git a/third_party/WebKit/Source/core/svg/graphics/filters/SVGFilterBuilder.h b/third_party/WebKit/Source/core/svg/graphics/filters/SVGFilterBuilder.h
index 37603db..3e6ce02 100644
--- a/third_party/WebKit/Source/core/svg/graphics/filters/SVGFilterBuilder.h
+++ b/third_party/WebKit/Source/core/svg/graphics/filters/SVGFilterBuilder.h
@@ -21,6 +21,7 @@
 #ifndef SVGFilterBuilder_h
 #define SVGFilterBuilder_h
 
+#include "core/style/SVGComputedStyleDefs.h"
 #include "platform/graphics/filters/FilterEffect.h"
 #include "platform/heap/Handle.h"
 #include "wtf/HashMap.h"
@@ -88,6 +89,8 @@
     FilterEffect* getEffectById(const AtomicString& id) const;
     FilterEffect* lastEffect() const { return m_lastEffect.get(); }
 
+    static ColorSpace resolveColorSpace(EColorInterpolation);
+
 private:
     void add(const AtomicString& id, FilterEffect*);
     void addBuiltinEffects();
diff --git a/third_party/WebKit/Source/devtools/PRESUBMIT.py b/third_party/WebKit/Source/devtools/PRESUBMIT.py
index f740637..48c11e1 100644
--- a/third_party/WebKit/Source/devtools/PRESUBMIT.py
+++ b/third_party/WebKit/Source/devtools/PRESUBMIT.py
@@ -69,10 +69,10 @@
     # should be added to the list of triggers.
     devtools_front_end = input_api.os_path.join("devtools", "front_end")
     if (any(devtools_front_end in path for path in local_paths) or
-        any("protocol.json" in path for path in local_paths) or
-        any("compile_frontend.py" in path for path in local_paths) or
-        any("InjectedScriptSource.js" in path for path in local_paths) or
-        any("DebuggerScript.js" in path for path in local_paths)):
+            any("_protocol.json" in path for path in local_paths) or
+            any("compile_frontend.py" in path for path in local_paths) or
+            any("InjectedScriptSource.js" in path for path in local_paths) or
+            any("DebuggerScript.js" in path for path in local_paths)):
         lint_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
             "scripts", "compile_frontend.py")
         out, _ = input_api.subprocess.Popen(
diff --git a/third_party/WebKit/Source/devtools/devtools.gypi b/third_party/WebKit/Source/devtools/devtools.gypi
index dba0285b..97666e3 100644
--- a/third_party/WebKit/Source/devtools/devtools.gypi
+++ b/third_party/WebKit/Source/devtools/devtools.gypi
@@ -561,6 +561,7 @@
             'front_end/network/NetworkDataGridNode.js',
             'front_end/network/NetworkItemView.js',
             'front_end/network/NetworkLogView.js',
+            'front_end/network/NetworkLogViewColumns.js',
             'front_end/network/NetworkOverview.js',
             'front_end/network/NetworkPanel.js',
             'front_end/network/NetworkTimeCalculator.js',
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/AuditController.js b/third_party/WebKit/Source/devtools/front_end/audits/AuditController.js
index 9d16eac..be7afd4 100644
--- a/third_party/WebKit/Source/devtools/front_end/audits/AuditController.js
+++ b/third_party/WebKit/Source/devtools/front_end/audits/AuditController.js
@@ -71,7 +71,8 @@
             resultCallback(mainResourceURL, results);
         }
 
-        var requests = target.networkLog.requests().slice();
+        var networkLog = WebInspector.NetworkLog.fromTarget(target);
+        var requests = networkLog ? networkLog.requests().slice() : [];
         var compositeProgress = new WebInspector.CompositeProgress(this._progress);
         var subprogresses = [];
         for (var i = 0; i < categories.length; ++i)
diff --git a/third_party/WebKit/Source/devtools/front_end/common/ResourceType.js b/third_party/WebKit/Source/devtools/front_end/common/ResourceType.js
index b715e96..57f4fd2 100644
--- a/third_party/WebKit/Source/devtools/front_end/common/ResourceType.js
+++ b/third_party/WebKit/Source/devtools/front_end/common/ResourceType.js
@@ -195,114 +195,114 @@
 
 /**
  * @param {string} url
- * @return {string}
+ * @return {string|undefined}
  */
 WebInspector.ResourceType.mimeFromURL = function(url)
 {
     var name = WebInspector.ParsedURL.extractName(url);
-    if (WebInspector.ResourceType.mimeTypeByName[name]) {
-        return WebInspector.ResourceType.mimeTypeByName[name];
+    if (WebInspector.ResourceType._mimeTypeByName.has(name)) {
+        return WebInspector.ResourceType._mimeTypeByName.get(name);
     }
     var ext = WebInspector.ParsedURL.extractExtension(url).toLowerCase();
-    return WebInspector.ResourceType.mimeTypeByExtension[ext];
+    return WebInspector.ResourceType._mimeTypeByExtension.get(ext);
 }
 
-WebInspector.ResourceType.mimeTypeByName = {
+WebInspector.ResourceType._mimeTypeByName = new Map([
     // CoffeeScript
-    "Cakefile": "text/x-coffeescript"
-}
+    ["Cakefile", "text/x-coffeescript"]
+]);
 
-WebInspector.ResourceType.mimeTypeByExtension = {
+WebInspector.ResourceType._mimeTypeByExtension = new Map([
     // Web extensions
-    "js": "text/javascript",
-    "css": "text/css",
-    "html": "text/html",
-    "htm": "text/html",
-    "xml": "application/xml",
-    "xsl": "application/xml",
+    ["js", "text/javascript"],
+    ["css", "text/css"],
+    ["html", "text/html"],
+    ["htm", "text/html"],
+    ["xml", "application/xml"],
+    ["xsl", "application/xml"],
 
-    // HTML Embedded Scripts: ASP, JSP
-    "asp": "application/x-aspx",
-    "aspx": "application/x-aspx",
-    "jsp": "application/x-jsp",
+    // HTML Embedded Scripts, ASP], JSP
+    ["asp", "application/x-aspx"],
+    ["aspx", "application/x-aspx"],
+    ["jsp", "application/x-jsp"],
 
     // C/C++
-    "c": "text/x-c++src",
-    "cc": "text/x-c++src",
-    "cpp": "text/x-c++src",
-    "h": "text/x-c++src",
-    "m": "text/x-c++src",
-    "mm": "text/x-c++src",
+    ["c", "text/x-c++src"],
+    ["cc", "text/x-c++src"],
+    ["cpp", "text/x-c++src"],
+    ["h", "text/x-c++src"],
+    ["m", "text/x-c++src"],
+    ["mm", "text/x-c++src"],
 
     // CoffeeScript
-    "coffee": "text/x-coffeescript",
+    ["coffee", "text/x-coffeescript"],
 
     // Dart
-    "dart": "text/javascript",
+    ["dart", "text/javascript"],
 
     // TypeScript
-    "ts": "text/typescript",
-    "tsx": "text/typescript",
+    ["ts", "text/typescript"],
+    ["tsx", "text/typescript"],
 
     // JSON
-    "json": "application/json",
-    "gyp": "application/json",
-    "gypi": "application/json",
+    ["json", "application/json"],
+    ["gyp", "application/json"],
+    ["gypi", "application/json"],
 
     // C#
-    "cs": "text/x-csharp",
+    ["cs", "text/x-csharp"],
 
     // Java
-    "java": "text/x-java",
+    ["java", "text/x-java"],
 
     // Less
-    "less": "text/x-less",
+    ["less", "text/x-less"],
 
     // PHP
-    "php": "text/x-php",
-    "phtml": "application/x-httpd-php",
+    ["php", "text/x-php"],
+    ["phtml", "application/x-httpd-php"],
 
     // Python
-    "py": "text/x-python",
+    ["py", "text/x-python"],
 
     // Shell
-    "sh": "text/x-sh",
+    ["sh", "text/x-sh"],
 
     // SCSS
-    "scss": "text/x-scss",
+    ["scss", "text/x-scss"],
 
     // Video Text Tracks.
-    "vtt": "text/vtt",
+    ["vtt", "text/vtt"],
 
     // LiveScript
-    "ls": "text/x-livescript",
+    ["ls", "text/x-livescript"],
 
     // ClojureScript
-    "cljs": "text/x-clojure",
-    "cljc": "text/x-clojure",
-    "cljx": "text/x-clojure",
+    ["cljs", "text/x-clojure"],
+    ["cljc", "text/x-clojure"],
+    ["cljx", "text/x-clojure"],
 
     // Stylus
-    "styl": "text/x-styl",
+    ["styl", "text/x-styl"],
 
     // JSX
-    "jsx": "text/jsx",
+    ["jsx", "text/jsx"],
 
     // Image
-    "jpeg": "image/jpeg",
-    "jpg": "image/jpeg",
-    "svg": "image/svg",
-    "gif": "image/gif",
-    "webp": "image/webp",
-    "png": "image/png",
-    "ico": "image/ico",
-    "tiff": "image/tiff",
-    "tif": "image/tif",
-    "bmp": "image/bmp",
+    ["jpeg", "image/jpeg"],
+    ["jpg", "image/jpeg"],
+    ["svg", "image/svg"],
+    ["gif", "image/gif"],
+    ["webp", "image/webp"],
+    ["png", "image/png"],
+    ["ico", "image/ico"],
+    ["tiff", "image/tiff"],
+    ["tif", "image/tif"],
+    ["bmp", "image/bmp"],
 
     // Font
-    "ttf": "font/opentype",
-    "otf": "font/opentype",
-    "ttc": "font/opentype",
-    "woff": "application/font-woff"
-}
+    ["ttf", "font/opentype"],
+    ["otf", "font/opentype"],
+    ["ttc", "font/opentype"],
+    ["woff", "application/font-woff"]
+]);
diff --git a/third_party/WebKit/Source/devtools/front_end/components/ObjectPopoverHelper.js b/third_party/WebKit/Source/devtools/front_end/components/ObjectPopoverHelper.js
index f2baae21..4b9b2fe 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/ObjectPopoverHelper.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/ObjectPopoverHelper.js
@@ -112,23 +112,6 @@
         }
 
         /**
-         * @param {?WebInspector.DebuggerModel.GeneratorObjectDetails} response
-         * @this {WebInspector.ObjectPopoverHelper}
-         */
-        function didGetGeneratorObjectDetails(response)
-        {
-            if (!response || popover.disposed)
-                return;
-
-            var rawLocation = response.location;
-            var sourceURL = response.sourceURL;
-            if (rawLocation && sourceURL) {
-                var link = this._lazyLinkifier().linkifyRawLocation(rawLocation, sourceURL, "function-location-link");
-                this._titleElement.appendChild(link);
-            }
-        }
-
-        /**
          * @param {!WebInspector.RemoteObject} result
          * @param {boolean} wasThrown
          * @param {!Element=} anchorOverride
@@ -176,20 +159,16 @@
                     popoverContentElement = createElement("div");
                     this._titleElement = popoverContentElement.createChild("div", "monospace");
                     this._titleElement.createChild("span", "source-frame-popover-title").textContent = description;
-                    var section = new WebInspector.ObjectPropertiesSection(result, "");
+                    var section = new WebInspector.ObjectPropertiesSection(result, "", this._lazyLinkifier());
                     section.element.classList.add("source-frame-popover-tree");
                     section.titleLessMode();
                     popoverContentElement.appendChild(section.element);
-
-                    if (result.subtype === "generator")
-                        result.generatorObjectDetails(didGetGeneratorObjectDetails.bind(this));
                 }
                 var popoverWidth = 300;
                 var popoverHeight = 250;
                 popover.showForAnchor(popoverContentElement, anchorElement, popoverWidth, popoverHeight);
             }
         }
-
         this._queryObject(element, didQueryObject.bind(this), this._popoverObjectGroup);
     },
 
diff --git a/third_party/WebKit/Source/devtools/front_end/components/ObjectPropertiesSection.js b/third_party/WebKit/Source/devtools/front_end/components/ObjectPropertiesSection.js
index 5f9d406..8a90167 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/ObjectPropertiesSection.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/ObjectPropertiesSection.js
@@ -29,18 +29,19 @@
  * @extends {TreeOutlineInShadow}
  * @param {!WebInspector.RemoteObject} object
  * @param {?string|!Element=} title
+ * @param {!WebInspector.Linkifier=} linkifier
  * @param {?string=} emptyPlaceholder
  * @param {boolean=} ignoreHasOwnProperty
  * @param {!Array.<!WebInspector.RemoteObjectProperty>=} extraProperties
  */
-WebInspector.ObjectPropertiesSection = function(object, title, emptyPlaceholder, ignoreHasOwnProperty, extraProperties)
+WebInspector.ObjectPropertiesSection = function(object, title, linkifier, emptyPlaceholder, ignoreHasOwnProperty, extraProperties)
 {
     this._object = object;
     this._editable = true;
     TreeOutlineInShadow.call(this);
     this.hideOverflow();
     this.setFocusable(false);
-    this._objectTreeElement = new WebInspector.ObjectPropertiesSection.RootElement(object, emptyPlaceholder, ignoreHasOwnProperty, extraProperties);
+    this._objectTreeElement = new WebInspector.ObjectPropertiesSection.RootElement(object, linkifier, emptyPlaceholder, ignoreHasOwnProperty, extraProperties);
     this.appendChild(this._objectTreeElement);
     if (typeof title === "string" || !title)
         this.element.createChild("span").textContent = title || "";
@@ -58,10 +59,11 @@
 
 /**
  * @param {!WebInspector.RemoteObject} object
+ * @param {!WebInspector.Linkifier=} linkifier
  * @param {boolean=} skipProto
  * @return {!Element}
  */
-WebInspector.ObjectPropertiesSection.defaultObjectPresentation = function(object, skipProto)
+WebInspector.ObjectPropertiesSection.defaultObjectPresentation = function(object, linkifier, skipProto)
 {
     var componentRoot = createElementWithClass("span", "source-code");
     var shadowRoot = WebInspector.createShadowRootWithCoreStyles(componentRoot, "components/objectValue.css");
@@ -69,7 +71,7 @@
     if (!object.hasChildren)
         return componentRoot;
 
-    var objectPropertiesSection = new WebInspector.ObjectPropertiesSection(object, componentRoot);
+    var objectPropertiesSection = new WebInspector.ObjectPropertiesSection(object, componentRoot, linkifier);
     objectPropertiesSection.editable = false;
     if (skipProto)
         objectPropertiesSection.skipProto();
@@ -150,11 +152,12 @@
  * @constructor
  * @extends {TreeElement}
  * @param {!WebInspector.RemoteObject} object
+ * @param {!WebInspector.Linkifier=} linkifier
  * @param {?string=} emptyPlaceholder
  * @param {boolean=} ignoreHasOwnProperty
  * @param {!Array.<!WebInspector.RemoteObjectProperty>=} extraProperties
  */
-WebInspector.ObjectPropertiesSection.RootElement = function(object, emptyPlaceholder, ignoreHasOwnProperty, extraProperties)
+WebInspector.ObjectPropertiesSection.RootElement = function(object, linkifier, emptyPlaceholder, ignoreHasOwnProperty, extraProperties)
 {
     this._object = object;
     this._extraProperties = extraProperties || [];
@@ -166,6 +169,7 @@
     this.selectable = false;
     this.toggleOnClick = true;
     this.listItemElement.classList.add("object-properties-section-root-element");
+    this._linkifier = linkifier;
 }
 
 WebInspector.ObjectPropertiesSection.RootElement.prototype = {
@@ -194,7 +198,7 @@
 
     onpopulate: function()
     {
-        WebInspector.ObjectPropertyTreeElement._populate(this, this._object, !!this.treeOutline._skipProto, this._emptyPlaceholder, this._ignoreHasOwnProperty, this._extraProperties);
+        WebInspector.ObjectPropertyTreeElement._populate(this, this._object, !!this.treeOutline._skipProto, this._linkifier, this._emptyPlaceholder, this._ignoreHasOwnProperty, this._extraProperties);
     },
 
     __proto__: TreeElement.prototype
@@ -204,8 +208,9 @@
  * @constructor
  * @extends {TreeElement}
  * @param {!WebInspector.RemoteObjectProperty} property
+ * @param {!WebInspector.Linkifier=} linkifier
  */
-WebInspector.ObjectPropertyTreeElement = function(property)
+WebInspector.ObjectPropertyTreeElement = function(property, linkifier)
 {
     this.property = property;
 
@@ -215,6 +220,7 @@
     this.selectable = false;
     /** @type {!Array.<!Object>} */
     this._highlightChanges = [];
+    this._linkifier = linkifier;
 }
 
 WebInspector.ObjectPropertyTreeElement.prototype = {
@@ -268,7 +274,7 @@
         console.assert(propertyValue);
         var skipProto = this.treeOutline ? this.treeOutline._skipProto : true;
         var targetValue = this.property.name !== "__proto__" ? propertyValue : this.property.parentObject;
-        WebInspector.ObjectPropertyTreeElement._populate(this, propertyValue, skipProto, undefined, undefined, undefined, targetValue);
+        WebInspector.ObjectPropertyTreeElement._populate(this, propertyValue, skipProto, this._linkifier, undefined, undefined, undefined, targetValue);
     },
 
     /**
@@ -309,7 +315,7 @@
         separatorElement.textContent = ": ";
 
         if (this.property.value) {
-            this.valueElement = WebInspector.ObjectPropertiesSection.createValueElementWithCustomSupport(this.property.value, this.property.wasThrown, this.listItemElement);
+            this.valueElement = WebInspector.ObjectPropertiesSection.createValueElementWithCustomSupport(this.property.value, this.property.wasThrown, this.listItemElement, this._linkifier);
             this.valueElement.addEventListener("contextmenu", this._contextMenuFired.bind(this, this.property), false);
         } else if (this.property.getter) {
             this.valueElement = WebInspector.ObjectPropertyTreeElement.createRemoteObjectAccessorPropertySpan(this.property.parentObject, [this.property.name], this._onInvokeGetterClick.bind(this));
@@ -498,16 +504,17 @@
  * @param {!TreeElement} treeElement
  * @param {!WebInspector.RemoteObject} value
  * @param {boolean} skipProto
+ * @param {!WebInspector.Linkifier=} linkifier
  * @param {?string=} emptyPlaceholder
  * @param {boolean=} flattenProtoChain
  * @param {!Array.<!WebInspector.RemoteObjectProperty>=} extraProperties
  * @param {!WebInspector.RemoteObject=} targetValue
  */
-WebInspector.ObjectPropertyTreeElement._populate = function(treeElement, value, skipProto, emptyPlaceholder, flattenProtoChain, extraProperties, targetValue)
+WebInspector.ObjectPropertyTreeElement._populate = function(treeElement, value, skipProto, linkifier, emptyPlaceholder, flattenProtoChain, extraProperties, targetValue)
 {
     if (value.arrayLength() > WebInspector.ObjectPropertiesSection._arrayLoadThreshold) {
         treeElement.removeChildren();
-        WebInspector.ArrayGroupingTreeElement._populateArray(treeElement, value, 0, value.arrayLength() - 1);
+        WebInspector.ArrayGroupingTreeElement._populateArray(treeElement, value, 0, value.arrayLength() - 1, linkifier);
         return;
     }
 
@@ -526,7 +533,7 @@
             properties.push(extraProperties[i]);
 
         WebInspector.ObjectPropertyTreeElement.populateWithProperties(treeElement, properties, internalProperties,
-            skipProto, targetValue || value, emptyPlaceholder);
+            skipProto, targetValue || value, linkifier, emptyPlaceholder);
     }
 
     if (flattenProtoChain)
@@ -541,9 +548,10 @@
  * @param {?Array.<!WebInspector.RemoteObjectProperty>} internalProperties
  * @param {boolean} skipProto
  * @param {?WebInspector.RemoteObject} value
+ * @param {!WebInspector.Linkifier=} linkifier
  * @param {?string=} emptyPlaceholder
  */
-WebInspector.ObjectPropertyTreeElement.populateWithProperties = function(treeNode, properties, internalProperties, skipProto, value, emptyPlaceholder) {
+WebInspector.ObjectPropertyTreeElement.populateWithProperties = function(treeNode, properties, internalProperties, skipProto, value, linkifier, emptyPlaceholder) {
     properties.sort(WebInspector.ObjectPropertiesSection.CompareProperties);
 
     for (var i = 0; i < properties.length; ++i) {
@@ -553,29 +561,29 @@
         if (property.isAccessorProperty()) {
             if (property.name !== "__proto__" && property.getter) {
                 property.parentObject = value;
-                treeNode.appendChild(new WebInspector.ObjectPropertyTreeElement(property));
+                treeNode.appendChild(new WebInspector.ObjectPropertyTreeElement(property, linkifier));
             }
             if (property.isOwn) {
                 if (property.getter) {
                     var getterProperty = new WebInspector.RemoteObjectProperty("get " + property.name, property.getter);
                     getterProperty.parentObject = value;
-                    treeNode.appendChild(new WebInspector.ObjectPropertyTreeElement(getterProperty));
+                    treeNode.appendChild(new WebInspector.ObjectPropertyTreeElement(getterProperty, linkifier));
                 }
                 if (property.setter) {
                     var setterProperty = new WebInspector.RemoteObjectProperty("set " + property.name, property.setter);
                     setterProperty.parentObject = value;
-                    treeNode.appendChild(new WebInspector.ObjectPropertyTreeElement(setterProperty));
+                    treeNode.appendChild(new WebInspector.ObjectPropertyTreeElement(setterProperty, linkifier));
                 }
             }
         } else {
             property.parentObject = value;
-            treeNode.appendChild(new WebInspector.ObjectPropertyTreeElement(property));
+            treeNode.appendChild(new WebInspector.ObjectPropertyTreeElement(property, linkifier));
         }
     }
     if (internalProperties) {
         for (var i = 0; i < internalProperties.length; i++) {
             internalProperties[i].parentObject = value;
-            var treeElement = new WebInspector.ObjectPropertyTreeElement(internalProperties[i]);
+            var treeElement = new WebInspector.ObjectPropertyTreeElement(internalProperties[i], linkifier);
             if (internalProperties[i].name === "[[Entries]]") {
                 treeElement.setExpandable(true);
                 treeElement.expand();
@@ -598,7 +606,7 @@
             }
         }
         if (!hasTargetFunction)
-            treeNode.appendChild(new WebInspector.FunctionScopeMainTreeElement(value));
+            treeNode.appendChild(new WebInspector.FunctionScopeMainTreeElement(value, linkifier));
     }
     WebInspector.ObjectPropertyTreeElement._appendEmptyPlaceholderIfNeeded(treeNode, emptyPlaceholder);
 }
@@ -647,13 +655,15 @@
  * @constructor
  * @extends {TreeElement}
  * @param {!WebInspector.RemoteObject} remoteObject
+ * @param {!WebInspector.Linkifier=} linkifier
  */
-WebInspector.FunctionScopeMainTreeElement = function(remoteObject)
+WebInspector.FunctionScopeMainTreeElement = function(remoteObject, linkifier)
 {
     TreeElement.call(this, "<function scope>", true);
     this.toggleOnClick = true;
     this.selectable = false;
     this._remoteObject = remoteObject;
+    this._linkifier = linkifier;
 }
 
 WebInspector.FunctionScopeMainTreeElement.prototype = {
@@ -711,7 +721,7 @@
                     var property = new WebInspector.RemoteObjectProperty(title, remoteObject);
                     property.writable = false;
                     property.parentObject = null;
-                    this.appendChild(new WebInspector.ObjectPropertyTreeElement(property));
+                    this.appendChild(new WebInspector.ObjectPropertyTreeElement(property, this._linkifier));
                 } else {
                     var scopeRef = new WebInspector.ScopeRef(i, undefined);
                     var remoteObject = runtimeModel.createScopeRemoteObject(scope.object, scopeRef);
@@ -759,8 +769,9 @@
  * @param {number} fromIndex
  * @param {number} toIndex
  * @param {number} propertyCount
+ * @param {!WebInspector.Linkifier=} linkifier
  */
-WebInspector.ArrayGroupingTreeElement = function(object, fromIndex, toIndex, propertyCount)
+WebInspector.ArrayGroupingTreeElement = function(object, fromIndex, toIndex, propertyCount, linkifier)
 {
     TreeElement.call(this, String.sprintf("[%d \u2026 %d]", fromIndex, toIndex), true);
     this.toggleOnClick = true;
@@ -770,6 +781,7 @@
     this._object = object;
     this._readOnly = true;
     this._propertyCount = propertyCount;
+    this._linkifier = linkifier;
 }
 
 WebInspector.ArrayGroupingTreeElement._bucketThreshold = 100;
@@ -781,10 +793,11 @@
  * @param {!WebInspector.RemoteObject} object
  * @param {number} fromIndex
  * @param {number} toIndex
+ * @param {!WebInspector.Linkifier=} linkifier
  */
-WebInspector.ArrayGroupingTreeElement._populateArray = function(treeNode, object, fromIndex, toIndex)
+WebInspector.ArrayGroupingTreeElement._populateArray = function(treeNode, object, fromIndex, toIndex, linkifier)
 {
-    WebInspector.ArrayGroupingTreeElement._populateRanges(treeNode, object, fromIndex, toIndex, true);
+    WebInspector.ArrayGroupingTreeElement._populateRanges(treeNode, object, fromIndex, toIndex, true, linkifier);
 }
 
 /**
@@ -793,9 +806,10 @@
  * @param {number} fromIndex
  * @param {number} toIndex
  * @param {boolean} topLevel
+ * @param {!WebInspector.Linkifier=} linkifier
  * @this {WebInspector.ArrayGroupingTreeElement}
  */
-WebInspector.ArrayGroupingTreeElement._populateRanges = function(treeNode, object, fromIndex, toIndex, topLevel)
+WebInspector.ArrayGroupingTreeElement._populateRanges = function(treeNode, object, fromIndex, toIndex, topLevel, linkifier)
 {
     object.callFunctionJSON(packRanges, [
         { value: fromIndex },
@@ -889,20 +903,20 @@
             return;
         var ranges = /** @type {!Array.<!Array.<number>>} */ (result.ranges);
         if (ranges.length === 1) {
-            WebInspector.ArrayGroupingTreeElement._populateAsFragment(treeNode, object, ranges[0][0], ranges[0][1]);
+            WebInspector.ArrayGroupingTreeElement._populateAsFragment(treeNode, object, ranges[0][0], ranges[0][1], linkifier);
         } else {
             for (var i = 0; i < ranges.length; ++i) {
                 var fromIndex = ranges[i][0];
                 var toIndex = ranges[i][1];
                 var count = ranges[i][2];
                 if (fromIndex === toIndex)
-                    WebInspector.ArrayGroupingTreeElement._populateAsFragment(treeNode, object, fromIndex, toIndex);
+                    WebInspector.ArrayGroupingTreeElement._populateAsFragment(treeNode, object, fromIndex, toIndex, linkifier);
                 else
-                    treeNode.appendChild(new WebInspector.ArrayGroupingTreeElement(object, fromIndex, toIndex, count));
+                    treeNode.appendChild(new WebInspector.ArrayGroupingTreeElement(object, fromIndex, toIndex, count, linkifier));
             }
         }
         if (topLevel)
-            WebInspector.ArrayGroupingTreeElement._populateNonIndexProperties(treeNode, object, result.skipGetOwnPropertyNames);
+            WebInspector.ArrayGroupingTreeElement._populateNonIndexProperties(treeNode, object, result.skipGetOwnPropertyNames, linkifier);
     }
 }
 
@@ -911,9 +925,10 @@
  * @param {!WebInspector.RemoteObject} object
  * @param {number} fromIndex
  * @param {number} toIndex
+ * @param {!WebInspector.Linkifier=} linkifier
  * @this {WebInspector.ArrayGroupingTreeElement}
  */
-WebInspector.ArrayGroupingTreeElement._populateAsFragment = function(treeNode, object, fromIndex, toIndex)
+WebInspector.ArrayGroupingTreeElement._populateAsFragment = function(treeNode, object, fromIndex, toIndex, linkifier)
 {
     object.callFunction(buildArrayFragment, [{value: fromIndex}, {value: toIndex}, {value: WebInspector.ArrayGroupingTreeElement._sparseIterationThreshold}], processArrayFragment.bind(this));
 
@@ -965,7 +980,7 @@
         properties.sort(WebInspector.ObjectPropertiesSection.CompareProperties);
         for (var i = 0; i < properties.length; ++i) {
             properties[i].parentObject = this._object;
-            var childTreeElement = new WebInspector.ObjectPropertyTreeElement(properties[i]);
+            var childTreeElement = new WebInspector.ObjectPropertyTreeElement(properties[i], linkifier);
             childTreeElement._readOnly = true;
             treeNode.appendChild(childTreeElement);
         }
@@ -976,9 +991,10 @@
  * @param {!TreeElement} treeNode
  * @param {!WebInspector.RemoteObject} object
  * @param {boolean} skipGetOwnPropertyNames
+ * @param {!WebInspector.Linkifier=} linkifier
  * @this {WebInspector.ArrayGroupingTreeElement}
  */
-WebInspector.ArrayGroupingTreeElement._populateNonIndexProperties = function(treeNode, object, skipGetOwnPropertyNames)
+WebInspector.ArrayGroupingTreeElement._populateNonIndexProperties = function(treeNode, object, skipGetOwnPropertyNames, linkifier)
 {
     object.callFunction(buildObjectFragment, [{value: skipGetOwnPropertyNames}], processObjectFragment.bind(this));
 
@@ -1029,7 +1045,7 @@
         properties.sort(WebInspector.ObjectPropertiesSection.CompareProperties);
         for (var i = 0; i < properties.length; ++i) {
             properties[i].parentObject = this._object;
-            var childTreeElement = new WebInspector.ObjectPropertyTreeElement(properties[i]);
+            var childTreeElement = new WebInspector.ObjectPropertyTreeElement(properties[i], linkifier);
             childTreeElement._readOnly = true;
             treeNode.appendChild(childTreeElement);
         }
@@ -1040,10 +1056,10 @@
     onpopulate: function()
     {
         if (this._propertyCount >= WebInspector.ArrayGroupingTreeElement._bucketThreshold) {
-            WebInspector.ArrayGroupingTreeElement._populateRanges(this, this._object, this._fromIndex, this._toIndex, false);
+            WebInspector.ArrayGroupingTreeElement._populateRanges(this, this._object, this._fromIndex, this._toIndex, false, this._linkifier);
             return;
         }
-        WebInspector.ArrayGroupingTreeElement._populateAsFragment(this, this._object, this._fromIndex, this._toIndex);
+        WebInspector.ArrayGroupingTreeElement._populateAsFragment(this, this._object, this._fromIndex, this._toIndex, this._linkifier);
     },
 
     onattach: function()
@@ -1102,25 +1118,27 @@
  * @param {!WebInspector.RemoteObject} value
  * @param {boolean} wasThrown
  * @param {!Element=} parentElement
+ * @param {!WebInspector.Linkifier=} linkifier
  * @return {!Element}
  */
-WebInspector.ObjectPropertiesSection.createValueElementWithCustomSupport = function(value, wasThrown, parentElement)
+WebInspector.ObjectPropertiesSection.createValueElementWithCustomSupport = function(value, wasThrown, parentElement, linkifier)
 {
     if (value.customPreview()) {
         var result = (new WebInspector.CustomPreviewComponent(value)).element;
         result.classList.add("object-properties-section-custom-section");
         return result
     }
-    return WebInspector.ObjectPropertiesSection.createValueElement(value, wasThrown, parentElement);
+    return WebInspector.ObjectPropertiesSection.createValueElement(value, wasThrown, parentElement, linkifier);
 }
 
 /**
  * @param {!WebInspector.RemoteObject} value
  * @param {boolean} wasThrown
  * @param {!Element=} parentElement
+ * @param {!WebInspector.Linkifier=} linkifier
  * @return {!Element}
  */
-WebInspector.ObjectPropertiesSection.createValueElement = function(value, wasThrown, parentElement)
+WebInspector.ObjectPropertiesSection.createValueElement = function(value, wasThrown, parentElement, linkifier)
 {
     var valueElement = createElementWithClass("span", "value");
     var type = value.type;
@@ -1174,6 +1192,9 @@
         valueElement.title = description || "";
     }
 
+    if (type === "object" && subtype === "internal#location" && linkifier)
+        return linkifier.linkifyScriptLocation(value.target(), value.value.scriptId, "", value.value.lineNumber, value.value.columnNumber);
+
     function mouseMove()
     {
         WebInspector.DOMModel.highlightObjectAsDOMNode(value);
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js b/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
index cc77784..adf4bad 100644
--- a/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
+++ b/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
@@ -423,7 +423,7 @@
         var note = titleElement.createChild("span", "object-state-note");
         note.classList.add("info-note");
         note.title = WebInspector.UIString("Object value at left was snapshotted when logged, value below was evaluated just now.");
-        var section = new WebInspector.ObjectPropertiesSection(obj, titleElement);
+        var section = new WebInspector.ObjectPropertiesSection(obj, titleElement, this._linkifier);
         section.enableContextMenu();
         elem.appendChild(section.element);
         section.element.classList.add("console-view-object-properties-section");
diff --git a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAPI.js b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAPI.js
index 3f8150e..64f379b 100644
--- a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAPI.js
+++ b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAPI.js
@@ -978,6 +978,7 @@
     chrome.devtools.inspectedWindow.__proto__ = coreAPI.inspectedWindow;
     chrome.devtools.network = coreAPI.network;
     chrome.devtools.panels = coreAPI.panels;
+    chrome.devtools.panels.themeName = themeName;
 
     // default to expose experimental APIs for now.
     if (extensionInfo.exposeExperimentalAPIs !== false) {
@@ -998,27 +999,30 @@
 /**
  * @param {!ExtensionDescriptor} extensionInfo
  * @param {string} inspectedTabId
+ * @param {string} themeName
  * @return {string}
  */
-function buildPlatformExtensionAPI(extensionInfo, inspectedTabId)
+function buildPlatformExtensionAPI(extensionInfo, inspectedTabId, themeName)
 {
     return "var extensionInfo = " + JSON.stringify(extensionInfo) + ";" +
        "var tabId = " + inspectedTabId + ";" +
+       "var themeName = '" + themeName + "';" +
        platformExtensionAPI.toString();
 }
 
 /**
  * @param {!ExtensionDescriptor} extensionInfo
  * @param {string} inspectedTabId
+ * @param {string} themeName
  * @return {string}
  */
-function buildExtensionAPIInjectedScript(extensionInfo, inspectedTabId)
+function buildExtensionAPIInjectedScript(extensionInfo, inspectedTabId, themeName)
 {
     return "(function(injectedScriptId){ " +
         "var extensionServer;" +
         defineCommonExtensionSymbols.toString() + ";" +
         injectedExtensionAPI.toString() + ";" +
-        buildPlatformExtensionAPI(extensionInfo, inspectedTabId) + ";" +
+        buildPlatformExtensionAPI(extensionInfo, inspectedTabId, themeName) + ";" +
         "platformExtensionAPI(injectedExtensionAPI(injectedScriptId));" +
         "return {};" +
         "})";
diff --git a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionServer.js b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionServer.js
index 3130bbc6..26fc6ca 100644
--- a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionServer.js
+++ b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionServer.js
@@ -764,7 +764,7 @@
             var extensionOrigin = originMatch[1];
             if (!this._registeredExtensions[extensionOrigin]) {
                 // See ExtensionAPI.js for details.
-                InspectorFrontendHost.setInjectedScriptForOrigin(extensionOrigin, buildExtensionAPIInjectedScript(extensionInfo, this._inspectedTabId));
+                InspectorFrontendHost.setInjectedScriptForOrigin(extensionOrigin, buildExtensionAPIInjectedScript(extensionInfo, this._inspectedTabId, WebInspector.themeSupport.themeName()));
                 this._registeredExtensions[extensionOrigin] = { name: name };
             }
             var iframe = createElement("iframe");
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Main.js b/third_party/WebKit/Source/devtools/front_end/main/Main.js
index f9f215d..8c8748bf 100644
--- a/third_party/WebKit/Source/devtools/front_end/main/Main.js
+++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -308,7 +308,12 @@
             WebInspector.RemoteDebuggingTerminatedScreen.show(event.data.reason);
         }
 
-        var targetType = Runtime.queryParam("isSharedWorker") ? WebInspector.Target.Type.ServiceWorker : WebInspector.Target.Type.Page;
+        var targetType = WebInspector.Target.Type.Page;
+        if (Runtime.queryParam("isSharedWorker"))
+            targetType = WebInspector.Target.Type.ServiceWorker;
+        else if (Runtime.queryParam("v8only"))
+            targetType = WebInspector.Target.Type.JSInspector;
+
         this._mainTarget = WebInspector.targetManager.createTarget(WebInspector.UIString("Main"), targetType, connection, null);
         console.timeStamp("Main._mainTargetCreated");
         this._registerShortcuts();
@@ -317,7 +322,7 @@
         InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.ReloadInspectedPage, this._reloadInspectedPage, this);
         InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.EvaluateForTestInFrontend, this._evaluateForTestInFrontend, this);
 
-        if (this._mainTarget.isServiceWorker() || this._mainTarget.isPage())
+        if (this._mainTarget.isServiceWorker() || this._mainTarget.isPage() || this._mainTarget.isJSInspector())
             this._mainTarget.runtimeAgent().run();
 
         this._mainTarget.inspectorAgent().enable();
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js
index 36fcba3..5bc99b0 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js
@@ -51,13 +51,7 @@
     this._progressBarContainer = progressBarContainer;
     this._networkLogLargeRowsSetting = networkLogLargeRowsSetting;
 
-    var defaultColumnsVisibility = WebInspector.NetworkLogView._defaultColumnsVisibility;
-    this._columnsVisibilitySetting = WebInspector.settings.createSetting("networkLogColumnsVisibility", defaultColumnsVisibility);
-    var savedColumnsVisibility = this._columnsVisibilitySetting.get();
-    var columnsVisibility = {};
-    for (var columnId in defaultColumnsVisibility)
-        columnsVisibility[columnId] = savedColumnsVisibility.hasOwnProperty(columnId) ? savedColumnsVisibility[columnId] : defaultColumnsVisibility[columnId];
-    this._columnsVisibilitySetting.set(columnsVisibility);
+    this._columns = new WebInspector.NetworkLogViewColumns(this, networkLogLargeRowsSetting);
 
     /** @type {!Map.<string, !WebInspector.NetworkDataGridNode>} */
     this._nodesByRequestId = new Map();
@@ -68,8 +62,6 @@
     /** @type {number} */
     this._mainRequestDOMContentLoadedTime = -1;
     this._matchedRequestCount = 0;
-    /** @type {!Array<{time: number, element: !Element}>} */
-    this._eventDividers = [];
     this._highlightedSubstringChanges = [];
 
     /** @type {!Array.<!WebInspector.NetworkLogView.Filter>} */
@@ -81,11 +73,8 @@
     this._currentMatchedRequestIndex = -1;
 
     /** @type {!WebInspector.Linkifier} */
-    this._popupLinkifier = new WebInspector.Linkifier();
-    /** @type {!WebInspector.Linkifier} */
     this.linkifier = new WebInspector.Linkifier();
 
-    this._gridMode = true;
     this._recording = false;
     this._preserveLog = false;
 
@@ -109,11 +98,7 @@
 WebInspector.NetworkLogView._isMatchingSearchQuerySymbol = Symbol("isMatchingSearchQuery");
 
 WebInspector.NetworkLogView.HTTPSchemas = {"http": true, "https": true, "ws": true, "wss": true};
-WebInspector.NetworkLogView._responseHeaderColumns = ["Cache-Control", "Connection", "Content-Encoding", "Content-Length", "ETag", "Keep-Alive", "Last-Modified", "Server", "Vary"];
-WebInspector.NetworkLogView._defaultColumnsVisibility = {
-    method: false, status: true, protocol: false, scheme: false, domain: false, remoteAddress: false, type: true, initiator: true, cookies: false, setCookies: false, size: true, time: true, priority: false, connectionId: false,
-    "Cache-Control": false, "Connection": false, "Content-Encoding": false, "Content-Length": false, "ETag": false, "Keep-Alive": false, "Last-Modified": false, "Server": false, "Vary": false
-};
+
 WebInspector.NetworkLogView._defaultRefreshDelay = 200;
 
 WebInspector.NetworkLogView._waterfallMinOvertime = 1;
@@ -151,37 +136,6 @@
 /** @type {!Array.<string>} */
 WebInspector.NetworkLogView._searchKeys = Object.values(WebInspector.NetworkLogView.FilterType);
 
-/** @type {!Object.<string, string>} */
-WebInspector.NetworkLogView._columnTitles = {
-    "name": WebInspector.UIString("Name"),
-    "method": WebInspector.UIString("Method"),
-    "status": WebInspector.UIString("Status"),
-    "protocol": WebInspector.UIString("Protocol"),
-    "scheme": WebInspector.UIString("Scheme"),
-    "domain": WebInspector.UIString("Domain"),
-    "remoteAddress": WebInspector.UIString("Remote Address"),
-    "type": WebInspector.UIString("Type"),
-    "initiator": WebInspector.UIString("Initiator"),
-    "cookies": WebInspector.UIString("Cookies"),
-    "setCookies": WebInspector.UIString("Set-Cookies"),
-    "size": WebInspector.UIString("Size"),
-    "time": WebInspector.UIString("Time"),
-    "connectionId": WebInspector.UIString("Connection Id"),
-    "priority": WebInspector.UIString("Priority"),
-    "timeline": WebInspector.UIString("Timeline"),
-
-    // Response header columns
-    "Cache-Control": WebInspector.UIString("Cache-Control"),
-    "Connection": WebInspector.UIString("Connection"),
-    "Content-Encoding": WebInspector.UIString("Content-Encoding"),
-    "Content-Length": WebInspector.UIString("Content-Length"),
-    "ETag": WebInspector.UIString("ETag"),
-    "Keep-Alive": WebInspector.UIString("Keep-Alive"),
-    "Last-Modified": WebInspector.UIString("Last-Modified"),
-    "Server": WebInspector.UIString("Server"),
-    "Vary": WebInspector.UIString("Vary")
-};
-
 WebInspector.NetworkLogView.prototype = {
     /**
      * @param {boolean} recording
@@ -211,7 +165,9 @@
             target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._loadEventFired, this);
             target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.DOMContentLoaded, this._domContentLoadedEventFired, this);
         }
-        target.networkLog.requests().forEach(this._appendRequest.bind(this));
+        var networkLog = WebInspector.NetworkLog.fromTarget(target);
+        if (networkLog)
+            networkLog.requests().forEach(this._appendRequest.bind(this));
     },
 
     /**
@@ -240,7 +196,7 @@
             this._timeFilter = WebInspector.NetworkLogView._requestTimeFilter.bind(null, start, end);
             this._timeCalculator.setWindow(new WebInspector.NetworkTimeBoundary(start, end));
         }
-        this._updateDividersIfNeeded();
+        this._columns.updateDividersIfNeeded();
         this._filterRequests();
     },
 
@@ -286,7 +242,7 @@
      */
     _filterChanged: function(event)
     {
-        this._removeAllNodeHighlights();
+        this.removeAllNodeHighlights();
         this._parseFilterQuery(this._textFilterUI.value());
         this._filterRequests();
     },
@@ -295,16 +251,16 @@
     {
         this.element.id = "network-container";
 
-        this._createSortingFunctions();
-        this._createCalculators();
+        /** @type {!WebInspector.NetworkTransferTimeCalculator} */
+        this._timeCalculator = new WebInspector.NetworkTransferTimeCalculator();
+        /** @type {!WebInspector.NetworkTransferDurationCalculator} */
+        this._durationCalculator = new WebInspector.NetworkTransferDurationCalculator();
+        this._calculator = this._timeCalculator;
+
         this._createTable();
-        this._createTimelineGrid();
         this._summaryBarElement = this.element.createChild("div", "network-summary-bar");
 
         this._updateRowsSize();
-
-        this._popoverHelper = new WebInspector.PopoverHelper(this.element, this._getPopoverAnchor.bind(this), this._showPopover.bind(this), this._onHidePopover.bind(this));
-        this.switchViewMode(true);
     },
 
     _showRecordingHint: function()
@@ -345,144 +301,10 @@
         return [this._dataGrid.scrollContainer];
     },
 
-    _createTimelineGrid: function()
-    {
-        this._timelineGrid = new WebInspector.TimelineGrid();
-        this._timelineGrid.element.classList.add("network-timeline-grid");
-        this._dataGrid.element.appendChild(this._timelineGrid.element);
-    },
-
     _createTable: function()
     {
-        var columns = [];
-        columns.push({
-            id: "name",
-            titleDOMFragment: this._makeHeaderFragment(WebInspector.UIString("Name"), WebInspector.UIString("Path")),
-            title: WebInspector.NetworkLogView._columnTitles["name"],
-            weight: 20
-        });
-
-        columns.push({
-            id: "method",
-            title: WebInspector.NetworkLogView._columnTitles["method"],
-            weight: 6
-        });
-
-        columns.push({
-            id: "status",
-            titleDOMFragment: this._makeHeaderFragment(WebInspector.UIString("Status"), WebInspector.UIString("Text")),
-            title: WebInspector.NetworkLogView._columnTitles["status"],
-            weight: 6
-        });
-
-        columns.push({
-            id: "protocol",
-            title: WebInspector.NetworkLogView._columnTitles["protocol"],
-            weight: 6
-        });
-
-        columns.push({
-            id: "scheme",
-            title: WebInspector.NetworkLogView._columnTitles["scheme"],
-            weight: 6
-        });
-
-        columns.push({
-            id: "domain",
-            title: WebInspector.NetworkLogView._columnTitles["domain"],
-            weight: 6
-        });
-
-        columns.push({
-            id: "remoteAddress",
-            title: WebInspector.NetworkLogView._columnTitles["remoteAddress"],
-            weight: 10,
-            align: WebInspector.DataGrid.Align.Right
-        });
-
-        columns.push({
-            id: "type",
-            title: WebInspector.NetworkLogView._columnTitles["type"],
-            weight: 6
-        });
-
-        columns.push({
-            id: "initiator",
-            title: WebInspector.NetworkLogView._columnTitles["initiator"],
-            weight: 10
-        });
-
-        columns.push({
-            id: "cookies",
-            title: WebInspector.NetworkLogView._columnTitles["cookies"],
-            weight: 6,
-            align: WebInspector.DataGrid.Align.Right
-        });
-
-        columns.push({
-            id: "setCookies",
-            title: WebInspector.NetworkLogView._columnTitles["setCookies"],
-            weight: 6,
-            align: WebInspector.DataGrid.Align.Right
-        });
-
-        columns.push({
-            id: "size",
-            titleDOMFragment: this._makeHeaderFragment(WebInspector.UIString("Size"), WebInspector.UIString("Content")),
-            title: WebInspector.NetworkLogView._columnTitles["size"],
-            weight: 6,
-            align: WebInspector.DataGrid.Align.Right
-        });
-
-        columns.push({
-            id: "time",
-            titleDOMFragment: this._makeHeaderFragment(WebInspector.UIString("Time"), WebInspector.UIString("Latency")),
-            title: WebInspector.NetworkLogView._columnTitles["time"],
-            weight: 6,
-            align: WebInspector.DataGrid.Align.Right
-        });
-
-        columns.push({
-            id: "priority",
-            title: WebInspector.NetworkLogView._columnTitles["priority"],
-            weight: 6
-        });
-
-        columns.push({
-            id: "connectionId",
-            title: WebInspector.NetworkLogView._columnTitles["connectionId"],
-            weight: 6
-        });
-
-        var responseHeaderColumns = WebInspector.NetworkLogView._responseHeaderColumns;
-        for (var i = 0; i < responseHeaderColumns.length; ++i) {
-            var headerName = responseHeaderColumns[i];
-            var descriptor = {
-                id: headerName,
-                title: WebInspector.NetworkLogView._columnTitles[headerName],
-                weight: 6
-            };
-            if (headerName === "Content-Length")
-                descriptor.align = WebInspector.DataGrid.Align.Right;
-            columns.push(descriptor);
-        }
-
-        columns.push({
-            id: "timeline",
-            title: WebInspector.NetworkLogView._columnTitles["timeline"],
-            sortable: false,
-            weight: 40,
-            sort: WebInspector.DataGrid.Order.Ascending
-        });
-
-        for (var column of columns) {
-            column.sortable = column.id !== "timeline";
-            column.nonSelectable = column.id !== "name";
-        }
-
-        this._dataGrid = new WebInspector.SortableDataGrid(columns);
+        this._dataGrid = this._columns.createGrid(this._timeCalculator, this._durationCalculator);
         this._dataGrid.setStickToBottom(true);
-        this._updateColumns();
         this._dataGrid.setName("networkLog");
         this._dataGrid.setResizeMethod(WebInspector.DataGrid.ResizeMethod.Last);
         this._dataGrid.element.classList.add("network-log-grid");
@@ -490,14 +312,6 @@
         this._dataGrid.element.addEventListener("mousedown", this._dataGridMouseDown.bind(this), true);
         this._dataGrid.element.addEventListener("mousemove", this._dataGridMouseMove.bind(this), true);
         this._dataGrid.element.addEventListener("mouseleave", this._highlightInitiatorChain.bind(this, null), true);
-        this._dataGrid.asWidget().show(this.element);
-
-        // Event listeners need to be added _after_ we attach to the document, so that owner document is properly update.
-        this._dataGrid.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this._sortItems, this);
-        this._dataGrid.addEventListener(WebInspector.DataGrid.Events.ColumnsResized, this._updateDividersIfNeeded, this);
-
-        this._patchTimelineHeader();
-        this._dataGrid.sortNodes(this._sortingFunctions.startTime, false);
     },
 
     /**
@@ -554,158 +368,6 @@
         }
     },
 
-    /**
-     * @param {string} title
-     * @param {string} subtitle
-     * @return {!DocumentFragment}
-     */
-    _makeHeaderFragment: function(title, subtitle)
-    {
-        var fragment = createDocumentFragment();
-        fragment.createTextChild(title);
-        var subtitleDiv = fragment.createChild("div", "network-header-subtitle");
-        subtitleDiv.createTextChild(subtitle);
-        return fragment;
-    },
-
-    _patchTimelineHeader: function()
-    {
-        var timelineSorting = createElement("select");
-
-        var option = createElement("option");
-        option.value = "startTime";
-        option.label = WebInspector.UIString("Timeline");
-        option.disabled = true;
-        timelineSorting.appendChild(option);
-
-        option = createElement("option");
-        option.value = "startTime";
-        option.label = WebInspector.UIString("Timeline \u2013 Start Time");
-        option.sortOrder = WebInspector.DataGrid.Order.Ascending;
-        timelineSorting.appendChild(option);
-
-        option = createElement("option");
-        option.value = "responseTime";
-        option.label = WebInspector.UIString("Timeline \u2013 Response Time");
-        option.sortOrder = WebInspector.DataGrid.Order.Ascending;
-        timelineSorting.appendChild(option);
-
-        option = createElement("option");
-        option.value = "endTime";
-        option.label = WebInspector.UIString("Timeline \u2013 End Time");
-        option.sortOrder = WebInspector.DataGrid.Order.Ascending;
-        timelineSorting.appendChild(option);
-
-        option = createElement("option");
-        option.value = "duration";
-        option.label = WebInspector.UIString("Timeline \u2013 Total Duration");
-        option.sortOrder = WebInspector.DataGrid.Order.Descending;
-        timelineSorting.appendChild(option);
-
-        option = createElement("option");
-        option.value = "latency";
-        option.label = WebInspector.UIString("Timeline \u2013 Latency");
-        option.sortOrder = WebInspector.DataGrid.Order.Descending;
-        timelineSorting.appendChild(option);
-
-        var header = this._dataGrid.headerTableHeader("timeline");
-        header.replaceChild(timelineSorting, header.firstChild);
-        header.createChild("div", "sort-order-icon-container").createChild("div", "sort-order-icon");
-
-        timelineSorting.selectedIndex = 1;
-        timelineSorting.addEventListener("click", function(event) { event.consume(); }, false);
-        timelineSorting.addEventListener("change", this._sortByTimeline.bind(this), false);
-        this._timelineSortSelector = timelineSorting;
-    },
-
-    _createSortingFunctions: function()
-    {
-        this._sortingFunctions = {};
-        this._sortingFunctions.name = WebInspector.NetworkDataGridNode.NameComparator;
-        this._sortingFunctions.method = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "requestMethod");
-        this._sortingFunctions.status = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "statusCode");
-        this._sortingFunctions.protocol = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "protocol");
-        this._sortingFunctions.scheme = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "scheme");
-        this._sortingFunctions.domain = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "domain");
-        this._sortingFunctions.remoteAddress = WebInspector.NetworkDataGridNode.RemoteAddressComparator;
-        this._sortingFunctions.type = WebInspector.NetworkDataGridNode.TypeComparator;
-        this._sortingFunctions.initiator = WebInspector.NetworkDataGridNode.InitiatorComparator;
-        this._sortingFunctions.cookies = WebInspector.NetworkDataGridNode.RequestCookiesCountComparator;
-        this._sortingFunctions.setCookies = WebInspector.NetworkDataGridNode.ResponseCookiesCountComparator;
-        this._sortingFunctions.size = WebInspector.NetworkDataGridNode.SizeComparator;
-        this._sortingFunctions.time = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "duration");
-        this._sortingFunctions.connectionId = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "connectionId");
-        this._sortingFunctions.priority = WebInspector.NetworkDataGridNode.InitialPriorityComparator;
-        this._sortingFunctions.timeline = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "startTime");
-        this._sortingFunctions.startTime = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "startTime");
-        this._sortingFunctions.endTime = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "endTime");
-        this._sortingFunctions.responseTime = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "responseReceivedTime");
-        this._sortingFunctions.duration = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "duration");
-        this._sortingFunctions.latency = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "latency");
-
-        this._sortingFunctions["Cache-Control"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Cache-Control");
-        this._sortingFunctions["Connection"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Connection");
-        this._sortingFunctions["Content-Encoding"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Content-Encoding");
-        this._sortingFunctions["Content-Length"] = WebInspector.NetworkDataGridNode.ResponseHeaderNumberComparator.bind(null, "Content-Length");
-        this._sortingFunctions["ETag"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "ETag");
-        this._sortingFunctions["Keep-Alive"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Keep-Alive");
-        this._sortingFunctions["Last-Modified"] = WebInspector.NetworkDataGridNode.ResponseHeaderDateComparator.bind(null, "Last-Modified");
-        this._sortingFunctions["Server"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Server");
-        this._sortingFunctions["Vary"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Vary");
-    },
-
-    _createCalculators: function()
-    {
-        /** @type {!WebInspector.NetworkTransferTimeCalculator} */
-        this._timeCalculator = new WebInspector.NetworkTransferTimeCalculator();
-        /** @type {!WebInspector.NetworkTransferDurationCalculator} */
-        this._durationCalculator = new WebInspector.NetworkTransferDurationCalculator();
-
-        /** @type {!Object.<string, !WebInspector.NetworkTimeCalculator>} */
-        this._calculators = {};
-        this._calculators.timeline = this._timeCalculator;
-        this._calculators.startTime = this._timeCalculator;
-        this._calculators.endTime = this._timeCalculator;
-        this._calculators.responseTime = this._timeCalculator;
-        this._calculators.duration = this._durationCalculator;
-        this._calculators.latency = this._durationCalculator;
-
-        this._calculator = this._timeCalculator;
-    },
-
-    _sortItems: function()
-    {
-        this._removeAllNodeHighlights();
-        var columnIdentifier = this._dataGrid.sortColumnIdentifier();
-        if (columnIdentifier === "timeline") {
-            this._sortByTimeline();
-            return;
-        }
-        var sortingFunction = this._sortingFunctions[columnIdentifier];
-        if (!sortingFunction)
-            return;
-
-        this._dataGrid.sortNodes(sortingFunction, !this._dataGrid.isSortOrderAscending());
-        this._highlightNthMatchedRequestForSearch(this._updateMatchCountAndFindMatchIndex(this._currentMatchedRequestNode), false);
-        this._timelineSortSelector.selectedIndex = 0;
-    },
-
-    _sortByTimeline: function()
-    {
-        this._removeAllNodeHighlights();
-        var selectedIndex = this._timelineSortSelector.selectedIndex;
-        if (!selectedIndex)
-            selectedIndex = 1; // Sort by start time by default.
-        var selectedOption = this._timelineSortSelector[selectedIndex];
-        var value = selectedOption.value;
-
-        this._setCalculator(this._calculators[value]);
-        var sortingFunction = this._sortingFunctions[value];
-        this._dataGrid.sortNodes(sortingFunction);
-        this._highlightNthMatchedRequestForSearch(this._updateMatchCountAndFindMatchIndex(this._currentMatchedRequestNode), false);
-        this._dataGrid.markColumnAsSortedBy("timeline", selectedOption.sortOrder);
-    },
-
     _updateSummaryBar: function()
     {
         var requestsNumber = this._nodesByRequestId.size;
@@ -778,7 +440,7 @@
         summaryBar.title = text;
     },
 
-    _scheduleRefresh: function()
+    scheduleRefresh: function()
     {
         if (this._needsRefresh)
             return;
@@ -789,38 +451,12 @@
             this._refreshTimeout = setTimeout(this.refresh.bind(this), WebInspector.NetworkLogView._defaultRefreshDelay);
     },
 
-    _updateDividersIfNeeded: function()
-    {
-        if (!this.isShowing()) {
-            this._scheduleRefresh();
-            return;
-        }
-
-        var timelineOffset = this._dataGrid.columnOffset("timeline");
-        // Position timline grid location.
-        if (timelineOffset)
-            this._timelineGrid.element.style.left = timelineOffset + "px";
-
-        var calculator = this.calculator();
-        calculator.setDisplayWindow(this._timelineGrid.dividersElement.clientWidth);
-        this._timelineGrid.updateDividers(calculator, 75);
-
-        if (calculator.startAtZero) {
-            // If our current sorting method starts at zero, that means it shows all
-            // requests starting at the same point, and so onLoad event and DOMContent
-            // event lines really wouldn't make much sense here, so don't render them.
-            return;
-        }
-
-        this._updateEventDividers();
-    },
-
     /**
      * @param {!Array<number>} times
      */
     addFilmStripFrames: function(times)
     {
-        this._addEventDividers(times, "network-frame-divider");
+        this._columns.addEventDividers(times, "network-frame-divider");
     },
 
     /**
@@ -838,33 +474,6 @@
             divider.element.classList.toggle("network-frame-divider-selected", false);
     },
 
-    /**
-     * @param {!Array<number>} times
-     * @param {string} className
-     */
-    _addEventDividers: function(times, className)
-    {
-        for (var i = 0; i < times.length; ++i) {
-            var element = createElementWithClass("div", "network-event-divider " + className);
-            this._timelineGrid.addEventDivider(element);
-            this._eventDividers.push({time: times[i], element: element});
-        }
-        // Update event dividers immediately
-        this._updateEventDividers();
-        // Schedule refresh in case dividers change the calculator span.
-        this._scheduleRefresh();
-    },
-
-    _updateEventDividers: function()
-    {
-        var calculator = this.calculator();
-        for (var divider of this._eventDividers) {
-            var timePercent = calculator.computePercentageFromEventTime(divider.time);
-            divider.element.classList.toggle("invisible", timePercent < 0);
-            divider.element.style.left = timePercent + "%";
-        }
-    },
-
     _refreshIfNeeded: function()
     {
         if (this._needsRefresh)
@@ -898,7 +507,7 @@
     /**
      * @param {!WebInspector.NetworkTimeCalculator} x
      */
-    _setCalculator: function(x)
+    setCalculator: function(x)
     {
         if (!x || this._calculator === x)
             return;
@@ -907,9 +516,9 @@
         this._calculator.reset();
 
         if (this._calculator.startAtZero)
-            this._timelineGrid.hideEventDividers();
+            this._columns.hideEventDividers();
         else
-            this._timelineGrid.showEventDividers();
+            this._columns.showEventDividers();
 
         this._invalidateAllItems();
     },
@@ -925,7 +534,7 @@
         var data = /** @type {number} */ (event.data);
         if (data) {
             this._mainRequestLoadTime = data;
-            this._addEventDividers([data], "network-red-divider");
+            this._columns.addEventDividers([data], "network-red-divider");
         }
     },
 
@@ -939,7 +548,7 @@
         var data = /** @type {number} */ (event.data);
         if (data) {
             this._mainRequestDOMContentLoadedTime = data;
-            this._addEventDividers([data], "network-blue-divider");
+            this._columns.addEventDividers([data], "network-blue-divider");
         }
     },
 
@@ -950,7 +559,7 @@
 
     willHide: function()
     {
-        this._popoverHelper.hidePopover();
+        this._columns.willHide();
     },
 
     refresh: function()
@@ -961,7 +570,7 @@
             delete this._refreshTimeout;
         }
 
-        this._removeAllNodeHighlights();
+        this.removeAllNodeHighlights();
 
         var oldBoundary = this.calculator().boundary();
         this._timeCalculator.updateBoundariesForEventTime(this._mainRequestLoadTime);
@@ -1010,7 +619,7 @@
 
         if (!this.calculator().boundary().equals(oldBoundary)) {
             // The boundaries changed, so all item graphs are stale.
-            this._updateDividersIfNeeded();
+            this._columns.updateDividersIfNeeded();
             var nodes = this._nodesByRequestId.valuesArray();
             for (var i = 0; i < nodes.length; ++i)
                 nodes[i].refreshGraph();
@@ -1026,8 +635,8 @@
         this.dispatchEventToListeners(WebInspector.NetworkLogView.EventTypes.RequestSelected, null);
 
         this._clearSearchMatchedList();
-        if (this._popoverHelper)
-            this._popoverHelper.hidePopover();
+
+        this._columns.reset();
 
         this._timeFilter = null;
         this._calculator.reset();
@@ -1045,11 +654,9 @@
         this._mainRequestLoadTime = -1;
         this._mainRequestDOMContentLoadedTime = -1;
         this._eventDividers = [];
-        this._timelineGrid.removeEventDividers();
 
         if (this._dataGrid) {
             this._dataGrid.rootNode().removeChildren();
-            this._updateDividersIfNeeded();
             this._updateSummaryBar();
         }
     },
@@ -1150,7 +757,7 @@
 
         this._staleRequestIds[request.requestId] = true;
         this.dispatchEventToListeners(WebInspector.NetworkLogView.EventTypes.UpdateRequest, request);
-        this._scheduleRefresh();
+        this.scheduleRefresh();
     },
 
     /**
@@ -1166,7 +773,8 @@
 
         // Pick provisional load requests.
         var requestsToPick = [];
-        var requests = frame.target().networkLog.requests();
+        var networkLog = WebInspector.NetworkLog.fromTarget(frame.target());
+        var requests = networkLog ? networkLog.requests() : [];
         for (var i = 0; i < requests.length; ++i) {
             var request = requests[i];
             if (request.loaderId === loaderId)
@@ -1193,20 +801,7 @@
      */
     switchViewMode: function(gridMode)
     {
-        if (this._gridMode === gridMode)
-            return;
-        this._gridMode = gridMode;
-
-        if (gridMode) {
-            if (this._dataGrid.selectedNode)
-                this._dataGrid.selectedNode.selected = false;
-        } else {
-            this._removeAllNodeHighlights();
-            this._popoverHelper.hidePopover();
-        }
-
-        this.element.classList.toggle("brief-mode", !gridMode);
-        this._updateColumns();
+        this._columns.switchViewMode(gridMode);
     },
 
     /**
@@ -1222,120 +817,18 @@
         var largeRows = !!this._networkLogLargeRowsSetting.get();
         this._rowHeight = largeRows ? 41 : 21;
         this._dataGrid.element.classList.toggle("small", !largeRows);
-        this._timelineGrid.element.classList.toggle("small", !largeRows);
         this._dataGrid.scheduleUpdate();
     },
 
     /**
-     * @param {!Element} element
-     * @param {!Event} event
-     * @return {!Element|!AnchorBox|undefined}
-     */
-    _getPopoverAnchor: function(element, event)
-    {
-        if (!this._gridMode)
-            return;
-        var anchor = element.enclosingNodeOrSelfWithClass("network-graph-bar") || element.enclosingNodeOrSelfWithClass("network-graph-label");
-        if (anchor && anchor.parentElement.request && anchor.parentElement.request.timing)
-            return anchor;
-        anchor = element.enclosingNodeOrSelfWithClass("network-script-initiated");
-        if (anchor && anchor.request) {
-            var initiator = /** @type {!WebInspector.NetworkRequest} */ (anchor.request).initiator();
-            if (initiator && initiator.stack)
-                return anchor;
-        }
-    },
-
-    /**
-     * @param {!Element} anchor
-     * @param {!WebInspector.Popover} popover
-     */
-    _showPopover: function(anchor, popover)
-    {
-        var content;
-        if (anchor.classList.contains("network-script-initiated")) {
-            var request = /** @type {!WebInspector.NetworkRequest} */ (anchor.request);
-            var initiator = /** @type {!NetworkAgent.Initiator} */ (request.initiator());
-            content = WebInspector.DOMPresentationUtils.buildStackTracePreviewContents(request.target(), this._popupLinkifier, initiator.stack);
-            popover.setCanShrink(true);
-        } else {
-            content = WebInspector.RequestTimingView.createTimingTable(anchor.parentElement.request, this._timeCalculator.minimumBoundary());
-            popover.setCanShrink(false);
-        }
-        popover.showForAnchor(content, anchor);
-    },
-
-    _onHidePopover: function()
-    {
-        this._popupLinkifier.reset();
-    },
-
-    _updateColumns: function()
-    {
-        if (!this._dataGrid)
-            return;
-        var gridMode = this._gridMode;
-        var visibleColumns = {"name": true};
-        if (gridMode)
-            visibleColumns["timeline"] = true;
-        if (gridMode) {
-            var columnsVisibility = this._columnsVisibilitySetting.get();
-            for (var columnIdentifier in columnsVisibility)
-                visibleColumns[columnIdentifier] = columnsVisibility[columnIdentifier];
-        }
-
-        this._dataGrid.setColumnsVisiblity(visibleColumns);
-    },
-
-    /**
-     * @param {string} columnIdentifier
-     */
-    _toggleColumnVisibility: function(columnIdentifier)
-    {
-        var columnsVisibility = this._columnsVisibilitySetting.get();
-        columnsVisibility[columnIdentifier] = !columnsVisibility[columnIdentifier];
-        this._columnsVisibilitySetting.set(columnsVisibility);
-
-        this._updateColumns();
-    },
-
-    /**
-     * @return {!Array.<string>}
-     */
-    _getConfigurableColumnIDs: function()
-    {
-        if (this._configurableColumnIDs)
-            return this._configurableColumnIDs;
-
-        var columnTitles = WebInspector.NetworkLogView._columnTitles;
-        function compare(id1, id2)
-        {
-            return columnTitles[id1].compareTo(columnTitles[id2]);
-        }
-
-        var columnIDs = Object.keys(this._columnsVisibilitySetting.get());
-        this._configurableColumnIDs = columnIDs.sort(compare);
-        return this._configurableColumnIDs;
-    },
-
-    /**
      * @param {!Event} event
      */
     _contextMenu: function(event)
     {
-        var contextMenu = new WebInspector.ContextMenu(event);
-
-        if (this._gridMode && event.target.isSelfOrDescendant(this._dataGrid.headerTableBody)) {
-            var columnsVisibility = this._columnsVisibilitySetting.get();
-            var columnIDs = this._getConfigurableColumnIDs();
-            var columnTitles = WebInspector.NetworkLogView._columnTitles;
-            for (var i = 0; i < columnIDs.length; ++i) {
-                var columnIdentifier = columnIDs[i];
-                contextMenu.appendCheckboxItem(columnTitles[columnIdentifier], this._toggleColumnVisibility.bind(this, columnIdentifier), !!columnsVisibility[columnIdentifier]);
-            }
-            contextMenu.show();
+        // TODO(allada) Fix datagrid's contextmenu so NetworkLogViewColumns can attach it's own contextmenu event
+        if (this._columns.contextMenu(event))
             return;
-        }
+        var contextMenu = new WebInspector.ContextMenu(event);
 
         var gridNode = this._dataGrid.dataGridNodeFromNode(event.target);
         var request = gridNode && gridNode.request();
@@ -1514,12 +1007,17 @@
 
     _removeAllHighlights: function()
     {
-        this._removeAllNodeHighlights();
+        this.removeAllNodeHighlights();
         for (var i = 0; i < this._highlightedSubstringChanges.length; ++i)
             WebInspector.revertDomChanges(this._highlightedSubstringChanges[i]);
         this._highlightedSubstringChanges = [];
     },
 
+    dataGridSorted: function()
+    {
+        this._highlightNthMatchedRequestForSearch(this._updateMatchCountAndFindMatchIndex(this._currentMatchedRequestNode), false);
+    },
+
     /**
      * @param {number} n
      * @param {boolean} reveal
@@ -1826,7 +1324,7 @@
      */
     revealAndHighlightRequest: function(request)
     {
-        this._removeAllNodeHighlights();
+        this.removeAllNodeHighlights();
 
         var node = this._nodesByRequestId.get(request.requestId);
         if (node) {
@@ -1835,7 +1333,7 @@
         }
     },
 
-    _removeAllNodeHighlights: function()
+    removeAllNodeHighlights: function()
     {
         if (this._highlightedNode) {
             this._highlightedNode.element().classList.remove("highlighted-row");
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js
new file mode 100644
index 0000000..0355e2d
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js
@@ -0,0 +1,618 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @constructor
+ * @param {!WebInspector.NetworkLogView} networkLogView
+ * @param {!WebInspector.Setting} networkLogLargeRowsSetting
+ */
+WebInspector.NetworkLogViewColumns = function(networkLogView, networkLogLargeRowsSetting)
+{
+    this._networkLogView = networkLogView;
+
+    var defaultColumnsVisibility = WebInspector.NetworkLogViewColumns._defaultColumnsVisibility;
+    /** @type {!WebInspector.Setting} */
+    this._columnsVisibilitySetting = WebInspector.settings.createSetting("networkLogColumnsVisibility", defaultColumnsVisibility);
+    var savedColumnsVisibility = this._columnsVisibilitySetting.get();
+    /** @type {!Object.<boolean>} */
+    var columnsVisibility = {};
+    for (var columnId in defaultColumnsVisibility)
+        columnsVisibility[columnId] = savedColumnsVisibility.hasOwnProperty(columnId) ? savedColumnsVisibility[columnId] : defaultColumnsVisibility[columnId];
+    this._columnsVisibilitySetting.set(columnsVisibility);
+
+    networkLogLargeRowsSetting.addChangeListener(this._updateRowsSize, this);
+
+    /** @type {!Array<{time: number, element: !Element}>} */
+    this._eventDividers = [];
+
+    this._gridMode = true;
+
+    /** @type {?WebInspector.DataGrid} */
+    this._dataGrid = null;
+    /** @type {!Array.<!WebInspector.ColumnConfig>} */
+    this._columns = [];
+    /** @type {!Object.<string, function(!WebInspector.NetworkDataGridNode, !WebInspector.NetworkDataGridNode) : number>} */
+    this._sortingFunctions = {};
+    /** @type {!Object.<string, !WebInspector.NetworkTimeCalculator>} */
+    this._calculators = {};
+    /** @type {?Element} */
+    this._timelineSortSelector = null;
+
+    /** @type {?WebInspector.TimelineGrid} */
+    this._timelineGrid = null;
+
+    /** @type {!WebInspector.Linkifier} */
+    this._popupLinkifier = new WebInspector.Linkifier();
+}
+
+WebInspector.NetworkLogViewColumns._responseHeaderColumns = ["Cache-Control", "Connection", "Content-Encoding", "Content-Length", "ETag", "Keep-Alive", "Last-Modified", "Server", "Vary"];
+WebInspector.NetworkLogViewColumns._defaultColumnsVisibility = {
+    method: false, status: true, protocol: false, scheme: false, domain: false, remoteAddress: false, type: true, initiator: true, cookies: false, setCookies: false, size: true, time: true, priority: false, connectionId: false,
+    "Cache-Control": false, "Connection": false, "Content-Encoding": false, "Content-Length": false, "ETag": false, "Keep-Alive": false, "Last-Modified": false, "Server": false, "Vary": false
+};
+
+/**
+ * @typedef {{
+ *      id: string,
+ *      title: string,
+ *      titleDOMFragment: !DocumentFragment,
+ *      sortable: boolean,
+ *      weight: number,
+ *      sort: (?WebInspector.DataGrid.Order|undefined),
+ *      align: (?WebInspector.DataGrid.Align|undefined),
+ * }}
+ */
+WebInspector.ColumnConfig;
+
+/** @type {!Object.<string, string>} */
+WebInspector.NetworkLogViewColumns._columnTitles = {
+    "name": WebInspector.UIString("Name"),
+    "method": WebInspector.UIString("Method"),
+    "status": WebInspector.UIString("Status"),
+    "protocol": WebInspector.UIString("Protocol"),
+    "scheme": WebInspector.UIString("Scheme"),
+    "domain": WebInspector.UIString("Domain"),
+    "remoteAddress": WebInspector.UIString("Remote Address"),
+    "type": WebInspector.UIString("Type"),
+    "initiator": WebInspector.UIString("Initiator"),
+    "cookies": WebInspector.UIString("Cookies"),
+    "setCookies": WebInspector.UIString("Set-Cookies"),
+    "size": WebInspector.UIString("Size"),
+    "time": WebInspector.UIString("Time"),
+    "connectionId": WebInspector.UIString("Connection Id"),
+    "priority": WebInspector.UIString("Priority"),
+    "timeline": WebInspector.UIString("Timeline"),
+
+    // Response header columns
+    "Cache-Control": WebInspector.UIString("Cache-Control"),
+    "Connection": WebInspector.UIString("Connection"),
+    "Content-Encoding": WebInspector.UIString("Content-Encoding"),
+    "Content-Length": WebInspector.UIString("Content-Length"),
+    "ETag": WebInspector.UIString("ETag"),
+    "Keep-Alive": WebInspector.UIString("Keep-Alive"),
+    "Last-Modified": WebInspector.UIString("Last-Modified"),
+    "Server": WebInspector.UIString("Server"),
+    "Vary": WebInspector.UIString("Vary")
+};
+
+WebInspector.NetworkLogViewColumns.prototype = {
+    willHide: function()
+    {
+        this._popoverHelper.hidePopover();
+    },
+
+    reset: function()
+    {
+        if (this._popoverHelper)
+            this._popoverHelper.hidePopover();
+        this._timelineGrid.removeEventDividers();
+        this.updateDividersIfNeeded();
+    },
+
+    /**
+     * @param {!WebInspector.NetworkTransferTimeCalculator} timeCalculator
+     * @param {!WebInspector.NetworkTransferDurationCalculator} durationCalculator
+     * @return {!WebInspector.SortableDataGrid} dataGrid
+     */
+    createGrid: function(timeCalculator, durationCalculator)
+    {
+        this._createSortingFunctions();
+        this._popoverHelper = new WebInspector.PopoverHelper(this._networkLogView.element, this._getPopoverAnchor.bind(this), this._showPopover.bind(this), this._onHidePopover.bind(this));
+
+        this._calculators.timeline = timeCalculator;
+        this._calculators.startTime = timeCalculator;
+        this._calculators.endTime = timeCalculator;
+        this._calculators.responseTime = timeCalculator;
+        this._calculators.duration = durationCalculator;
+        this._calculators.latency = durationCalculator;
+
+        var columns = [];
+        columns.push({
+            id: "name",
+            titleDOMFragment: this._makeHeaderFragment(WebInspector.UIString("Name"), WebInspector.UIString("Path")),
+            title: WebInspector.NetworkLogViewColumns._columnTitles["name"],
+            weight: 20
+        });
+
+        columns.push({
+            id: "method",
+            title: WebInspector.NetworkLogViewColumns._columnTitles["method"],
+            weight: 6
+        });
+
+        columns.push({
+            id: "status",
+            titleDOMFragment: this._makeHeaderFragment(WebInspector.UIString("Status"), WebInspector.UIString("Text")),
+            title: WebInspector.NetworkLogViewColumns._columnTitles["status"],
+            weight: 6
+        });
+
+        columns.push({
+            id: "protocol",
+            title: WebInspector.NetworkLogViewColumns._columnTitles["protocol"],
+            weight: 6
+        });
+
+        columns.push({
+            id: "scheme",
+            title: WebInspector.NetworkLogViewColumns._columnTitles["scheme"],
+            weight: 6
+        });
+
+        columns.push({
+            id: "domain",
+            title: WebInspector.NetworkLogViewColumns._columnTitles["domain"],
+            weight: 6
+        });
+
+        columns.push({
+            id: "remoteAddress",
+            title: WebInspector.NetworkLogViewColumns._columnTitles["remoteAddress"],
+            weight: 10,
+            align: WebInspector.DataGrid.Align.Right
+        });
+
+        columns.push({
+            id: "type",
+            title: WebInspector.NetworkLogViewColumns._columnTitles["type"],
+            weight: 6
+        });
+
+        columns.push({
+            id: "initiator",
+            title: WebInspector.NetworkLogViewColumns._columnTitles["initiator"],
+            weight: 10
+        });
+
+        columns.push({
+            id: "cookies",
+            title: WebInspector.NetworkLogViewColumns._columnTitles["cookies"],
+            weight: 6,
+            align: WebInspector.DataGrid.Align.Right
+        });
+
+        columns.push({
+            id: "setCookies",
+            title: WebInspector.NetworkLogViewColumns._columnTitles["setCookies"],
+            weight: 6,
+            align: WebInspector.DataGrid.Align.Right
+        });
+
+        columns.push({
+            id: "size",
+            titleDOMFragment: this._makeHeaderFragment(WebInspector.UIString("Size"), WebInspector.UIString("Content")),
+            title: WebInspector.NetworkLogViewColumns._columnTitles["size"],
+            weight: 6,
+            align: WebInspector.DataGrid.Align.Right
+        });
+
+        columns.push({
+            id: "time",
+            titleDOMFragment: this._makeHeaderFragment(WebInspector.UIString("Time"), WebInspector.UIString("Latency")),
+            title: WebInspector.NetworkLogViewColumns._columnTitles["time"],
+            weight: 6,
+            align: WebInspector.DataGrid.Align.Right
+        });
+
+        columns.push({
+            id: "priority",
+            title: WebInspector.NetworkLogViewColumns._columnTitles["priority"],
+            weight: 6
+        });
+
+        columns.push({
+            id: "connectionId",
+            title: WebInspector.NetworkLogViewColumns._columnTitles["connectionId"],
+            weight: 6
+        });
+
+        var responseHeaderColumns = WebInspector.NetworkLogViewColumns._responseHeaderColumns;
+        for (var i = 0; i < responseHeaderColumns.length; ++i) {
+            var headerName = responseHeaderColumns[i];
+            var descriptor = {
+                id: headerName,
+                title: WebInspector.NetworkLogViewColumns._columnTitles[headerName],
+                weight: 6
+            };
+            if (headerName === "Content-Length")
+                descriptor.align = WebInspector.DataGrid.Align.Right;
+            columns.push(descriptor);
+        }
+
+        columns.push({
+            id: "timeline",
+            title: WebInspector.NetworkLogViewColumns._columnTitles["timeline"],
+            sortable: false,
+            weight: 40,
+            sort: WebInspector.DataGrid.Order.Ascending
+        });
+
+        for (var column of columns) {
+            column.sortable = column.id !== "timeline";
+            column.nonSelectable = column.id !== "name";
+        }
+        this._columns = columns;
+
+        this._networkLogView.switchViewMode(true);
+
+        this._dataGrid = new WebInspector.SortableDataGrid(this._columns);
+
+        this._dataGrid.asWidget().show(this._networkLogView.element);
+
+        this._timelineGrid = new WebInspector.TimelineGrid();
+        this._timelineGrid.element.classList.add("network-timeline-grid");
+        this._dataGrid.element.appendChild(this._timelineGrid.element);
+
+        this._updateColumns();
+        this._dataGrid.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this._sortItems, this);
+        this._dataGrid.sortNodes(this._sortingFunctions.startTime, false);
+        this._patchTimelineHeader();
+
+        this._dataGrid.addEventListener(WebInspector.DataGrid.Events.ColumnsResized, this.updateDividersIfNeeded, this);
+
+        return this._dataGrid;
+    },
+
+    _createSortingFunctions: function()
+    {
+        this._sortingFunctions.name = WebInspector.NetworkDataGridNode.NameComparator;
+        this._sortingFunctions.method = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "requestMethod");
+        this._sortingFunctions.status = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "statusCode");
+        this._sortingFunctions.protocol = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "protocol");
+        this._sortingFunctions.scheme = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "scheme");
+        this._sortingFunctions.domain = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "domain");
+        this._sortingFunctions.remoteAddress = WebInspector.NetworkDataGridNode.RemoteAddressComparator;
+        this._sortingFunctions.type = WebInspector.NetworkDataGridNode.TypeComparator;
+        this._sortingFunctions.initiator = WebInspector.NetworkDataGridNode.InitiatorComparator;
+        this._sortingFunctions.cookies = WebInspector.NetworkDataGridNode.RequestCookiesCountComparator;
+        this._sortingFunctions.setCookies = WebInspector.NetworkDataGridNode.ResponseCookiesCountComparator;
+        this._sortingFunctions.size = WebInspector.NetworkDataGridNode.SizeComparator;
+        this._sortingFunctions.time = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "duration");
+        this._sortingFunctions.connectionId = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "connectionId");
+        this._sortingFunctions.priority = WebInspector.NetworkDataGridNode.InitialPriorityComparator;
+        this._sortingFunctions.timeline = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "startTime");
+        this._sortingFunctions.startTime = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "startTime");
+        this._sortingFunctions.endTime = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "endTime");
+        this._sortingFunctions.responseTime = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "responseReceivedTime");
+        this._sortingFunctions.duration = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "duration");
+        this._sortingFunctions.latency = WebInspector.NetworkDataGridNode.RequestPropertyComparator.bind(null, "latency");
+
+        this._sortingFunctions["Cache-Control"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Cache-Control");
+        this._sortingFunctions["Connection"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Connection");
+        this._sortingFunctions["Content-Encoding"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Content-Encoding");
+        this._sortingFunctions["Content-Length"] = WebInspector.NetworkDataGridNode.ResponseHeaderNumberComparator.bind(null, "Content-Length");
+        this._sortingFunctions["ETag"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "ETag");
+        this._sortingFunctions["Keep-Alive"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Keep-Alive");
+        this._sortingFunctions["Last-Modified"] = WebInspector.NetworkDataGridNode.ResponseHeaderDateComparator.bind(null, "Last-Modified");
+        this._sortingFunctions["Server"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Server");
+        this._sortingFunctions["Vary"] = WebInspector.NetworkDataGridNode.ResponseHeaderStringComparator.bind(null, "Vary");
+    },
+
+    _sortItems: function()
+    {
+        this._networkLogView.removeAllNodeHighlights();
+        var columnIdentifier = this._dataGrid.sortColumnIdentifier();
+        if (!columnIdentifier)
+            return;
+        if (columnIdentifier === "timeline") {
+            this._sortByTimeline();
+            return;
+        }
+        var sortingFunction = this._sortingFunctions[columnIdentifier];
+        if (!sortingFunction)
+            return;
+
+        this._dataGrid.sortNodes(sortingFunction, !this._dataGrid.isSortOrderAscending());
+        this._timelineSortSelector.selectedIndex = 0;
+        this._networkLogView.dataGridSorted();
+    },
+
+    _sortByTimeline: function()
+    {
+        this._networkLogView.removeAllNodeHighlights();
+        var selectedIndex = this._timelineSortSelector.selectedIndex;
+        if (!selectedIndex)
+            selectedIndex = 1; // Sort by start time by default.
+        var selectedOption = this._timelineSortSelector[selectedIndex];
+        var value = selectedOption.value;
+
+        this._networkLogView.setCalculator(this._calculators[value]);
+        var sortingFunction = this._sortingFunctions[value];
+        this._dataGrid.sortNodes(sortingFunction);
+
+        this._networkLogView.dataGridSorted();
+
+        this._dataGrid.markColumnAsSortedBy("timeline", selectedOption.sortOrder);
+    },
+
+    _patchTimelineHeader: function()
+    {
+        var timelineSorting = createElement("select");
+
+        var option = createElement("option");
+        option.value = "startTime";
+        option.label = WebInspector.UIString("Timeline");
+        option.disabled = true;
+        timelineSorting.appendChild(option);
+
+        option = createElement("option");
+        option.value = "startTime";
+        option.label = WebInspector.UIString("Timeline \u2013 Start Time");
+        option.sortOrder = WebInspector.DataGrid.Order.Ascending;
+        timelineSorting.appendChild(option);
+
+        option = createElement("option");
+        option.value = "responseTime";
+        option.label = WebInspector.UIString("Timeline \u2013 Response Time");
+        option.sortOrder = WebInspector.DataGrid.Order.Ascending;
+        timelineSorting.appendChild(option);
+
+        option = createElement("option");
+        option.value = "endTime";
+        option.label = WebInspector.UIString("Timeline \u2013 End Time");
+        option.sortOrder = WebInspector.DataGrid.Order.Ascending;
+        timelineSorting.appendChild(option);
+
+        option = createElement("option");
+        option.value = "duration";
+        option.label = WebInspector.UIString("Timeline \u2013 Total Duration");
+        option.sortOrder = WebInspector.DataGrid.Order.Descending;
+        timelineSorting.appendChild(option);
+
+        option = createElement("option");
+        option.value = "latency";
+        option.label = WebInspector.UIString("Timeline \u2013 Latency");
+        option.sortOrder = WebInspector.DataGrid.Order.Descending;
+        timelineSorting.appendChild(option);
+
+        var header = this._dataGrid.headerTableHeader("timeline");
+        header.replaceChild(timelineSorting, header.firstChild);
+        header.createChild("div", "sort-order-icon-container").createChild("div", "sort-order-icon");
+
+        timelineSorting.selectedIndex = 1;
+        timelineSorting.addEventListener("click", function(event) { event.consume(); }, false);
+        timelineSorting.addEventListener("change", this._sortByTimeline.bind(this), false);
+        this._timelineSortSelector = timelineSorting;
+    },
+
+    _updateColumns: function()
+    {
+        if (!this._dataGrid)
+            return;
+        var gridMode = this._gridMode;
+        var visibleColumns = {"name": true};
+        if (gridMode)
+            visibleColumns["timeline"] = true;
+        if (gridMode) {
+            var columnsVisibility = this._columnsVisibilitySetting.get();
+            for (var columnIdentifier in columnsVisibility)
+                visibleColumns[columnIdentifier] = columnsVisibility[columnIdentifier];
+        }
+
+        this._dataGrid.setColumnsVisiblity(visibleColumns);
+    },
+
+    /**
+     * @param {boolean} gridMode
+     */
+    switchViewMode: function(gridMode)
+    {
+        if (this._gridMode === gridMode)
+            return;
+        this._gridMode = gridMode;
+
+        if (gridMode) {
+            if (this._dataGrid.selectedNode)
+                this._dataGrid.selectedNode.selected = false;
+        } else {
+            this._networkLogView.removeAllNodeHighlights();
+            this._popoverHelper.hidePopover();
+        }
+
+        this._networkLogView.element.classList.toggle("brief-mode", !gridMode);
+        this._updateColumns();
+    },
+
+    /**
+     * @param {string} columnIdentifier
+     */
+    _toggleColumnVisibility: function(columnIdentifier)
+    {
+        var columnsVisibility = this._columnsVisibilitySetting.get();
+        columnsVisibility[columnIdentifier] = !columnsVisibility[columnIdentifier];
+        this._columnsVisibilitySetting.set(columnsVisibility);
+
+        this._updateColumns();
+    },
+
+    /**
+     * @return {!Array.<string>}
+     */
+    _getConfigurableColumnIDs: function()
+    {
+        if (this._configurableColumnIDs)
+            return this._configurableColumnIDs;
+
+        var columnTitles = WebInspector.NetworkLogViewColumns._columnTitles;
+        function compare(id1, id2)
+        {
+            return columnTitles[id1].compareTo(columnTitles[id2]);
+        }
+
+        var columnIDs = Object.keys(this._columnsVisibilitySetting.get());
+        this._configurableColumnIDs = columnIDs.sort(compare);
+        return this._configurableColumnIDs;
+    },
+
+    /**
+     * @param {string} title
+     * @param {string} subtitle
+     * @return {!DocumentFragment}
+     */
+    _makeHeaderFragment: function(title, subtitle)
+    {
+        var fragment = createDocumentFragment();
+        fragment.createTextChild(title);
+        var subtitleDiv = fragment.createChild("div", "network-header-subtitle");
+        subtitleDiv.createTextChild(subtitle);
+        return fragment;
+    },
+
+    /**
+     * @param {!Event} event
+     * @return {boolean}
+     */
+    contextMenu: function(event)
+    {
+        if (!this._gridMode || !event.target.isSelfOrDescendant(this._dataGrid.headerTableBody))
+            return false;
+
+        var contextMenu = new WebInspector.ContextMenu(event);
+
+        var columnsVisibility = this._columnsVisibilitySetting.get();
+        var columnIDs = this._getConfigurableColumnIDs();
+        var columnTitles = WebInspector.NetworkLogViewColumns._columnTitles;
+        for (var i = 0; i < columnIDs.length; ++i) {
+            var columnIdentifier = columnIDs[i];
+            contextMenu.appendCheckboxItem(columnTitles[columnIdentifier], this._toggleColumnVisibility.bind(this, columnIdentifier), !!columnsVisibility[columnIdentifier]);
+        }
+        contextMenu.show();
+        return true;
+    },
+
+    updateDividersIfNeeded: function()
+    {
+        if (!this._networkLogView.isShowing()) {
+            this._networkLogView.scheduleRefresh();
+            return;
+        }
+
+        var timelineOffset = this._dataGrid.columnOffset("timeline");
+        // Position timline grid location.
+        if (timelineOffset)
+            this._timelineGrid.element.style.left = timelineOffset + "px";
+
+        var calculator = this._networkLogView.calculator();
+        calculator.setDisplayWindow(this._timelineGrid.dividersElement.clientWidth);
+        this._timelineGrid.updateDividers(calculator, 75);
+
+        if (calculator.startAtZero) {
+            // If our current sorting method starts at zero, that means it shows all
+            // requests starting at the same point, and so onLoad event and DOMContent
+            // event lines really wouldn't make much sense here, so don't render them.
+            return;
+        }
+
+        this._updateEventDividers();
+    },
+
+    /**
+     * @param {!Element} element
+     * @param {!Event} event
+     * @return {!Element|!AnchorBox|undefined}
+     */
+    _getPopoverAnchor: function(element, event)
+    {
+        if (!this._gridMode)
+            return;
+        var anchor = element.enclosingNodeOrSelfWithClass("network-graph-bar") || element.enclosingNodeOrSelfWithClass("network-graph-label");
+        if (anchor && anchor.parentElement.request && anchor.parentElement.request.timing)
+            return anchor;
+        anchor = element.enclosingNodeOrSelfWithClass("network-script-initiated");
+        if (anchor && anchor.request) {
+            var initiator = /** @type {!WebInspector.NetworkRequest} */ (anchor.request).initiator();
+            if (initiator && initiator.stack)
+                return anchor;
+        }
+    },
+
+    /**
+     * @param {!Element} anchor
+     * @param {!WebInspector.Popover} popover
+     */
+    _showPopover: function(anchor, popover)
+    {
+        var content;
+        if (anchor.classList.contains("network-script-initiated")) {
+            var request = /** @type {!WebInspector.NetworkRequest} */ (anchor.request);
+            var initiator = /** @type {!NetworkAgent.Initiator} */ (request.initiator());
+            content = WebInspector.DOMPresentationUtils.buildStackTracePreviewContents(request.target(), this._popupLinkifier, initiator.stack);
+            popover.setCanShrink(true);
+        } else {
+            content = WebInspector.RequestTimingView.createTimingTable(anchor.parentElement.request, this._networkLogView.timeCalculator().minimumBoundary());
+            popover.setCanShrink(false);
+        }
+        popover.showForAnchor(content, anchor);
+    },
+
+    _onHidePopover: function()
+    {
+        this._popupLinkifier.reset();
+    },
+
+    /**
+     * @param {!Array<number>} times
+     * @param {string} className
+     */
+    addEventDividers: function(times, className)
+    {
+        for (var i = 0; i < times.length; ++i) {
+            var element = createElementWithClass("div", "network-event-divider " + className);
+            this._timelineGrid.addEventDivider(element);
+            this._eventDividers.push({time: times[i], element: element});
+        }
+        // Update event dividers immediately
+        this._updateEventDividers();
+        // Schedule refresh in case dividers change the calculator span.
+        this._networkLogView.scheduleRefresh();
+    },
+
+    _updateEventDividers: function()
+    {
+        var calculator = this._networkLogView.calculator();
+        for (var divider of this._eventDividers) {
+            var timePercent = calculator.computePercentageFromEventTime(divider.time);
+            divider.element.classList.toggle("invisible", timePercent < 0);
+            divider.element.style.left = timePercent + "%";
+        }
+    },
+
+    hideEventDividers: function()
+    {
+        this._timelineGrid.hideEventDividers();
+    },
+
+    showEventDividers: function()
+    {
+        this._timelineGrid.showEventDividers();
+    },
+
+    /**
+     * @param {!WebInspector.Event} event
+     */
+    _updateRowsSize: function(event)
+    {
+        this._timelineGrid.element.classList.toggle("small", !event.data);
+    }
+}
\ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/network/module.json b/third_party/WebKit/Source/devtools/front_end/network/module.json
index 8e1945e5..63f5ac7 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/network/module.json
@@ -107,6 +107,7 @@
         "NetworkItemView.js",
         "NetworkTimeCalculator.js",
         "NetworkLogView.js",
+        "NetworkLogViewColumns.js",
         "NetworkOverview.js",
         "RequestCookiesView.js",
         "RequestHeadersView.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js b/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js
index f8ac937..1f3dae0 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js
@@ -384,7 +384,7 @@
         case "key":
         case "primaryKey":
             cell.removeChildren();
-            var objectElement = WebInspector.ObjectPropertiesSection.defaultObjectPresentation(value, true);
+            var objectElement = WebInspector.ObjectPropertiesSection.defaultObjectPresentation(value, undefined, true);
             cell.appendChild(objectElement);
             break;
         default:
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkersView.js b/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkersView.js
index 2ff6091..74c4c81 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkersView.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkersView.js
@@ -37,9 +37,12 @@
         this._toolbar.appendToolbarItem(WebInspector.NetworkConditionsSelector.createOfflineToolbarCheckbox());
         var forceUpdate = new WebInspector.ToolbarCheckbox(WebInspector.UIString("Update on reload"), WebInspector.UIString("Force update Service Worker on page reload"), this._manager.forceUpdateOnReloadSetting());
         this._toolbar.appendToolbarItem(forceUpdate);
-        var fallbackToNetwork = new WebInspector.ToolbarCheckbox(WebInspector.UIString("Bypass for network"), WebInspector.UIString("Bypass Service Worker and load resources from the network"), target.networkManager.bypassServiceWorkerSetting());
-        this._toolbar.appendToolbarItem(fallbackToNetwork);
-        this._toolbar.appendSpacer();
+        var networkManager = this._target && WebInspector.NetworkManager.fromTarget(this._target);
+        if (networkManager) {
+            var fallbackToNetwork = new WebInspector.ToolbarCheckbox(WebInspector.UIString("Bypass for network"), WebInspector.UIString("Bypass Service Worker and load resources from the network"), networkManager.bypassServiceWorkerSetting());
+            this._toolbar.appendToolbarItem(fallbackToNetwork);
+            this._toolbar.appendSpacer();
+        }
         this._showAllCheckbox = new WebInspector.ToolbarCheckbox(WebInspector.UIString("Show all"), WebInspector.UIString("Show all Service Workers regardless of the origin"));
         this._showAllCheckbox.inputElement.addEventListener("change", this._updateSectionVisibility.bind(this), false);
         this._toolbar.appendToolbarItem(this._showAllCheckbox);
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSModel.js
index dea9998..5ee2239f 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/CSSModel.js
@@ -260,7 +260,7 @@
         var originalAndDetach = originalAndDetachIfSuccess.bind(this, header);
 
         if (!sourceMap.editable())
-            return originalAndDetach();
+            return original();
 
         return /** @type {!Promise<boolean>} */(sourceMap.editCompiled([range], [text])
             .then(onEditingDone.bind(this))
@@ -418,7 +418,7 @@
                 return false;
             this._domModel.markUndoableState();
             var edit = new WebInspector.CSSModel.Edit(styleSheetId, range, text, selectorPayload);
-            this._fireStyleSheetChangedAndDetach(styleSheetId, edit);
+            this._fireStyleSheetChanged(styleSheetId, edit);
             return true;
         }
 
@@ -448,7 +448,7 @@
                 return false;
             this._domModel.markUndoableState();
             var edit = new WebInspector.CSSModel.Edit(styleSheetId, range, text, payload);
-            this._fireStyleSheetChangedAndDetach(styleSheetId, edit);
+            this._fireStyleSheetChanged(styleSheetId, edit);
             return true;
         }
 
@@ -682,7 +682,7 @@
                 return false;
             this._domModel.markUndoableState();
             var edit = new WebInspector.CSSModel.Edit(styleSheetId, range, newMediaText, mediaPayload);
-            this._fireStyleSheetChangedAndDetach(styleSheetId, edit);
+            this._fireStyleSheetChanged(styleSheetId, edit);
             return true;
         }
 
@@ -716,7 +716,7 @@
                 return null;
             this._domModel.markUndoableState();
             var edit = new WebInspector.CSSModel.Edit(styleSheetId, ruleLocation, ruleText, rulePayload);
-            this._fireStyleSheetChangedAndDetach(styleSheetId, edit);
+            this._fireStyleSheetChanged(styleSheetId, edit);
             return new WebInspector.CSSStyleRule(this, rulePayload);
         }
     },
@@ -786,18 +786,6 @@
 
     /**
      * @param {!CSSAgent.StyleSheetId} styleSheetId
-     * @param {!WebInspector.CSSModel.Edit=} edit
-     */
-    _fireStyleSheetChangedAndDetach: function(styleSheetId, edit)
-    {
-        this.dispatchEventToListeners(WebInspector.CSSModel.Events.StyleSheetChanged, { styleSheetId: styleSheetId, edit: edit });
-        var header = this.styleSheetHeaderForId(styleSheetId);
-        if (header)
-            this._detachSourceMap(header);
-    },
-
-    /**
-     * @param {!CSSAgent.StyleSheetId} styleSheetId
      * @return {!Promise<string>}
      */
     _ensureOriginalStyleSheetText: function(styleSheetId)
@@ -1096,7 +1084,7 @@
      */
     styleSheetChanged: function(styleSheetId)
     {
-        this._cssModel._fireStyleSheetChangedAndDetach(styleSheetId);
+        this._cssModel._fireStyleSheetChanged(styleSheetId);
     },
 
     /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/ConsoleModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/ConsoleModel.js
index 782a8d1..523ecabc 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/ConsoleModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/ConsoleModel.js
@@ -269,7 +269,8 @@
     this._messageId = messageId || 0;
     this._relatedMessageId = relatedMessageId || 0;
 
-    this.request = requestId ? target.networkLog.requestForId(requestId) : null;
+    var networkLog = target && WebInspector.NetworkLog.fromTarget(target);
+    this.request = (requestId && networkLog) ? networkLog.requestForId(requestId) : null;
 
     if (this.request) {
         var initiator = this.request.initiator();
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js
index d8fa712..aa928e59 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js
@@ -39,7 +39,6 @@
 
     target.registerDebuggerDispatcher(new WebInspector.DebuggerDispatcher(this));
     this._agent = target.debuggerAgent();
-    WebInspector.targetManager.addEventListener(WebInspector.TargetManager.Events.TargetDisposed, this._targetDisposed, this);
 
     /** @type {?WebInspector.DebuggerPausedDetails} */
     this._debuggerPausedDetails = null;
@@ -62,9 +61,6 @@
 /** @typedef {{location: ?WebInspector.DebuggerModel.Location, sourceURL: ?string, functionName: string, scopeChain: (Array.<!DebuggerAgent.Scope>|null)}} */
 WebInspector.DebuggerModel.FunctionDetails;
 
-/** @typedef {{location: ?WebInspector.DebuggerModel.Location, sourceURL: ?string, functionName: string, status: string}} */
-WebInspector.DebuggerModel.GeneratorObjectDetails;
-
 /**
  * Keep these in sync with WebCore::V8Debugger
  *
@@ -717,34 +713,6 @@
     },
 
     /**
-     * @param {!WebInspector.RemoteObject} remoteObject
-     * @param {function(?WebInspector.DebuggerModel.GeneratorObjectDetails)} callback
-     */
-    generatorObjectDetails: function(remoteObject, callback)
-    {
-        this._agent.getGeneratorObjectDetails(remoteObject.objectId, didGetDetails.bind(this));
-
-        /**
-         * @param {?Protocol.Error} error
-         * @param {!DebuggerAgent.GeneratorObjectDetails} response
-         * @this {WebInspector.DebuggerModel}
-         */
-        function didGetDetails(error, response)
-        {
-            if (error) {
-                console.error(error);
-                callback(null);
-                return;
-            }
-            var location = response.location;
-            var script = location && this.scriptForId(location.scriptId);
-            var rawLocation = script ? this.createRawLocation(script, location.lineNumber, location.columnNumber || 0) : null;
-            var sourceURL = script ? script.contentURL() : null;
-            callback({location: rawLocation, sourceURL: sourceURL, functionName: response.functionName, status: response.status});
-        }
-    },
-
-    /**
      * @param {!DebuggerAgent.BreakpointId} breakpointId
      * @param {function(!WebInspector.Event)} listener
      * @param {!Object=} thisObject
@@ -786,14 +754,8 @@
         }
     },
 
-    /**
-     * @param {!WebInspector.Event} event
-     */
-    _targetDisposed: function(event)
+    dispose: function()
     {
-        var target = /** @type {!WebInspector.Target} */ (event.data);
-        if (target !== this.target())
-            return;
         WebInspector.moduleSetting("pauseOnExceptionEnabled").removeChangeListener(this._pauseOnExceptionStateChanged, this);
         WebInspector.moduleSetting("pauseOnCaughtException").removeChangeListener(this._pauseOnExceptionStateChanged, this);
         WebInspector.moduleSetting("enableAsyncStackTraces").removeChangeListener(this.asyncStackTracesStateChanged, this);
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/HAREntry.js b/third_party/WebKit/Source/devtools/front_end/sdk/HAREntry.js
index 5219b89..5978ef00 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/HAREntry.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/HAREntry.js
@@ -66,7 +66,7 @@
 
         if (this._request.connectionId !== "0")
             entry.connection = this._request.connectionId;
-        var page = this._request.target().networkLog.pageLoadForRequest(this._request);
+        var page = this._request.networkLog().pageLoadForRequest(this._request);
         if (page)
             entry.pageref = "page_" + page.id;
         return entry;
@@ -328,7 +328,7 @@
         var pages = [];
         for (var i = 0; i < this._requests.length; ++i) {
             var request = this._requests[i];
-            var page = request.target().networkLog.pageLoadForRequest(request);
+            var page = request.networkLog().pageLoadForRequest(request);
             if (!page || seenIdentifiers[page.id])
                 continue;
             seenIdentifiers[page.id] = true;
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkLog.js b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkLog.js
index 7c0afd8..35c0860 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkLog.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkLog.js
@@ -30,29 +30,40 @@
 
 /**
  * @constructor
- * @extends {WebInspector.SDKObject}
+ * @extends {WebInspector.SDKModel}
  * @param {!WebInspector.Target} target
+ * @param {!WebInspector.NetworkManager} networkManager
  */
-WebInspector.NetworkLog = function(target)
+WebInspector.NetworkLog = function(target, networkManager)
 {
-    WebInspector.SDKObject.call(this, target);
+    WebInspector.SDKModel.call(this, WebInspector.NetworkLog, target);
 
     this._requests = [];
     this._requestForId = {};
-    target.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestStarted, this._onRequestStarted, this);
+    networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestStarted, this._onRequestStarted, this);
     target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._onMainFrameNavigated, this);
     target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._onLoad, this);
     target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.DOMContentLoaded, this._onDOMContentLoaded, this);
 }
 
 /**
+ * @param {!WebInspector.Target} target
+ * @return {?WebInspector.NetworkLog}
+ */
+WebInspector.NetworkLog.fromTarget = function(target)
+{
+    return /** @type {?WebInspector.NetworkLog} */ (target.model(WebInspector.NetworkLog));
+}
+
+/**
  * @param {string} url
  * @return {?WebInspector.NetworkRequest}
  */
 WebInspector.NetworkLog.requestForURL = function(url)
 {
     for (var target of WebInspector.targetManager.targets()) {
-        var result = target.networkLog.requestForURL(url);
+        var networkLog = WebInspector.NetworkLog.fromTarget(target);
+        var result = networkLog && networkLog.requestForURL(url);
         if (result)
             return result;
     }
@@ -66,7 +77,9 @@
 {
     var result = [];
     for (var target of WebInspector.targetManager.targets()) {
-        result = result.concat(target.networkLog.requests());
+        var networkLog = WebInspector.NetworkLog.fromTarget(target);
+        if (networkLog)
+            result = result.concat(networkLog.requests());
     }
     return result;
 }
@@ -162,7 +175,7 @@
         return this._requestForId[requestId];
     },
 
-    __proto__: WebInspector.SDKObject.prototype
+    __proto__: WebInspector.SDKModel.prototype
 }
 
 /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkManager.js b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkManager.js
index a8da7ce..811ee9b 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkManager.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkManager.js
@@ -81,6 +81,15 @@
     "text/vtt":                    {"texttrack": true},
 }
 
+/**
+ * @param {!WebInspector.Target} target
+ * @return {?WebInspector.NetworkManager}
+ */
+WebInspector.NetworkManager.fromTarget = function(target)
+{
+    return /** @type {?WebInspector.NetworkManager} */ (target.model(WebInspector.NetworkManager));
+}
+
 /** @typedef {{download: number, upload: number, latency: number, title: string}} */
 WebInspector.NetworkManager.Conditions;
 /** @type {!WebInspector.NetworkManager.Conditions} */
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkRequest.js b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkRequest.js
index 2ed32a5..ffcbb8e3 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkRequest.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkRequest.js
@@ -44,6 +44,8 @@
 {
     WebInspector.SDKObject.call(this, target);
 
+    this._networkLog = /** @type {!WebInspector.NetworkLog} */ (WebInspector.NetworkLog.fromTarget(target));
+    this._networkManager = /** @type {!WebInspector.NetworkManager} */ (WebInspector.NetworkManager.fromTarget(target));
     this._requestId = requestId;
     this.url = url;
     this._documentURL = documentURL;
@@ -1124,7 +1126,7 @@
     initiatorRequest: function()
     {
         if (this._initiatorRequest === undefined)
-            this._initiatorRequest = this.target().networkLog.requestForURL(this.initiatorInfo().url);
+            this._initiatorRequest = this._networkLog.requestForURL(this.initiatorInfo().url);
         return this._initiatorRequest;
     },
 
@@ -1207,5 +1209,21 @@
         this.target().networkAgent().replayXHR(this.requestId);
     },
 
+    /**
+     * @return {!WebInspector.NetworkLog}
+     */
+    networkLog: function()
+    {
+        return this._networkLog;
+    },
+
+    /**
+     * @return {!WebInspector.NetworkManager}
+     */
+    networkManager: function()
+    {
+        return this._networkManager;
+    },
+
     __proto__: WebInspector.SDKObject.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/RemoteObject.js b/third_party/WebKit/Source/devtools/front_end/sdk/RemoteObject.js
index 5dd6a30..f59a6b0d 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/RemoteObject.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/RemoteObject.js
@@ -306,14 +306,6 @@
         {
             this.functionDetails(success);
         }
-    },
-
-    /**
-     * @param {function(?WebInspector.DebuggerModel.GeneratorObjectDetails)} callback
-     */
-    generatorObjectDetails: function(callback)
-    {
-        callback(null);
     }
 }
 
@@ -877,15 +869,6 @@
         this._debuggerModel.functionDetails(this, callback);
     },
 
-    /**
-     * @override
-     * @param {function(?WebInspector.DebuggerModel.GeneratorObjectDetails)} callback
-     */
-    generatorObjectDetails: function(callback)
-    {
-        this._debuggerModel.generatorObjectDetails(this, callback);
-    },
-
     __proto__: WebInspector.RemoteObject.prototype
 };
 
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/ResourceTreeModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/ResourceTreeModel.js
index 0539a60..8f5b5c55 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/ResourceTreeModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/ResourceTreeModel.js
@@ -32,13 +32,17 @@
  * @constructor
  * @extends {WebInspector.SDKModel}
  * @param {!WebInspector.Target} target
+ * @param {?WebInspector.NetworkManager} networkManager
  */
-WebInspector.ResourceTreeModel = function(target)
+WebInspector.ResourceTreeModel = function(target, networkManager)
 {
     WebInspector.SDKModel.call(this, WebInspector.ResourceTreeModel, target);
-
-    target.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestFinished, this._onRequestFinished, this);
-    target.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestUpdateDropped, this._onRequestUpdateDropped, this);
+    if (networkManager) {
+        networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestFinished,
+            this._onRequestFinished, this);
+        networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestUpdateDropped,
+            this._onRequestUpdateDropped, this);
+    }
 
     this._agent = target.pageAgent();
     this._agent.enable();
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/Target.js b/third_party/WebKit/Source/devtools/front_end/sdk/Target.js
index f79d7fb3..ebaf360 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/Target.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/Target.js
@@ -34,7 +34,8 @@
 WebInspector.Target.Type = {
     Page: 1,
     DedicatedWorker: 2,
-    ServiceWorker: 4
+    ServiceWorker: 4,
+    JSInspector: 8
 }
 
 WebInspector.Target._nextId = 1;
@@ -106,7 +107,7 @@
      */
     isWorker: function()
     {
-        return this.isDedicatedWorker() || this.isServiceWorker();
+        return this.isDedicatedWorker() || this.isServiceWorker() || this.isJSInspector();
     },
 
     /**
@@ -128,12 +129,28 @@
     /**
      * @return {boolean}
      */
+    isJSInspector: function()
+    {
+        return this._type === WebInspector.Target.Type.JSInspector;
+    },
+
+    /**
+     * @return {boolean}
+     */
     hasJSContext: function()
     {
         return !this.isServiceWorker();
     },
 
     /**
+     * @return {boolean}
+     */
+    supportsWorkers: function()
+    {
+        return this.isPage() || this.isServiceWorker();
+    },
+
+    /**
      * @return {?WebInspector.Target}
      */
     parentTarget: function()
@@ -150,9 +167,6 @@
     _dispose: function()
     {
         this._targetManager.dispatchEventToListeners(WebInspector.TargetManager.Events.TargetDisposed, this);
-        this.networkManager.dispose();
-        this.cpuProfilerModel.dispose();
-        WebInspector.ServiceWorkerCacheModel.fromTarget(this).dispose();
         if (this.workerManager)
             this.workerManager.dispose();
     },
@@ -218,6 +232,7 @@
 {
     WebInspector.SDKObject.call(this, target);
     target._modelByConstructor.set(modelClass, this);
+    WebInspector.targetManager.addEventListener(WebInspector.TargetManager.Events.TargetDisposed, this._targetDisposed, this);
 }
 
 WebInspector.SDKModel.prototype = {
@@ -237,5 +252,19 @@
         return Promise.resolve();
     },
 
+    dispose: function() { },
+
+    /**
+     * @param {!WebInspector.Event} event
+     */
+    _targetDisposed: function(event)
+    {
+        var target = /** @type {!WebInspector.Target} */ (event.data);
+        if (target !== this._target)
+            return;
+        this.dispose();
+        WebInspector.targetManager.removeEventListener(WebInspector.TargetManager.Events.TargetDisposed, this._targetDisposed, this);
+    },
+
     __proto__: WebInspector.SDKObject.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js b/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js
index 51994bd4..7e09dff 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js
@@ -196,12 +196,16 @@
 
         /** @type {!WebInspector.ConsoleModel} */
         target.consoleModel = new WebInspector.ConsoleModel(target);
-        /** @type {!WebInspector.NetworkManager} */
-        target.networkManager = new WebInspector.NetworkManager(target);
+
+        var networkManager = null;
+        if (!target.isJSInspector())
+            networkManager = new WebInspector.NetworkManager(target);
+
         /** @type {!WebInspector.ResourceTreeModel} */
-        target.resourceTreeModel = new WebInspector.ResourceTreeModel(target);
-        /** @type {!WebInspector.NetworkLog} */
-        target.networkLog = new WebInspector.NetworkLog(target);
+        target.resourceTreeModel = new WebInspector.ResourceTreeModel(target, networkManager);
+
+        if (networkManager)
+            new WebInspector.NetworkLog(target, networkManager);
 
         /** @type {!WebInspector.RuntimeModel} */
         target.runtimeModel = new WebInspector.RuntimeModel(target);
@@ -214,7 +218,7 @@
         }
 
         /** @type {?WebInspector.WorkerManager} */
-        target.workerManager = !target.isDedicatedWorker() ? new WebInspector.WorkerManager(target) : null;
+        target.workerManager = target.supportsWorkers() ? new WebInspector.WorkerManager(target) : null;
         /** @type {!WebInspector.CPUProfilerModel} */
         target.cpuProfilerModel = new WebInspector.CPUProfilerModel(target);
         /** @type {!WebInspector.HeapProfilerModel} */
diff --git a/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js b/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js
index 63927d4d4..a2bf52c 100644
--- a/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js
@@ -172,7 +172,7 @@
             var securityDetails = request.securityDetails();
             if (securityDetails) {
                 originState.securityDetails = securityDetails;
-                originState.certificateDetailsPromise = request.target().networkManager.certificateDetailsPromise(securityDetails.certificateId);
+                originState.certificateDetailsPromise = request.networkManager().certificateDetailsPromise(securityDetails.certificateId);
             }
 
             this._origins.set(origin, originState);
@@ -249,8 +249,11 @@
         this._target = target;
 
         target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._onMainFrameNavigated, this);
-        target.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResponseReceived, this._onResponseReceived, this);
-        target.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestFinished, this._onRequestFinished, this);
+        var networkManager = WebInspector.NetworkManager.fromTarget(target);
+        if (networkManager) {
+            networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResponseReceived, this._onResponseReceived, this);
+            networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestFinished, this._onRequestFinished, this);
+        }
 
         var securityModel = WebInspector.SecurityModel.fromTarget(target);
         securityModel.addEventListener(WebInspector.SecurityModel.EventTypes.SecurityStateChanged, this._onSecurityStateChanged, this);
@@ -553,7 +556,10 @@
     this._panel = panel;
 
     this._summarySection = this.contentElement.createChild("div", "security-summary");
-    this._securityExplanations = this.contentElement.createChild("div", "security-explanation-list");
+
+    // Info explanations should appear after all others.
+    this._securityExplanationsMain = this.contentElement.createChild("div", "security-explanation-list");
+    this._securityExplanationsExtra = this.contentElement.createChild("div", "security-explanation-list security-explanations-extra");
 
     // Fill the security summary section.
     this._summarySection.createChild("div", "security-summary-section-title").textContent = WebInspector.UIString("Security Overview");
@@ -572,12 +578,13 @@
 
 WebInspector.SecurityMainView.prototype = {
     /**
+     * @param {!Element} parent
      * @param {!SecurityAgent.SecurityStateExplanation} explanation
      * @return {!Element}
      */
-    _addExplanation: function(explanation)
+    _addExplanation: function(parent, explanation)
     {
-        var explanationSection = this._securityExplanations.createChild("div", "security-explanation");
+        var explanationSection = parent.createChild("div", "security-explanation");
         explanationSection.classList.add("security-explanation-" + explanation.securityState);
 
         explanationSection.createChild("div", "security-property").classList.add("security-property-" + explanation.securityState);
@@ -627,9 +634,15 @@
 
     refreshExplanations: function()
     {
-        this._securityExplanations.removeChildren();
-        for (var explanation of this._explanations)
-            this._addExplanation(explanation);
+        this._securityExplanationsMain.removeChildren();
+        this._securityExplanationsExtra.removeChildren();
+        for (var explanation of this._explanations) {
+            if (explanation.securityState === SecurityAgent.SecurityState.Info) {
+                this._addExplanation(this._securityExplanationsExtra, explanation);
+            } else {
+                this._addExplanation(this._securityExplanationsMain, explanation);
+            }
+        }
 
         this._addMixedContentExplanations();
     },
@@ -641,13 +654,13 @@
 
         if (this._mixedContentStatus && (this._mixedContentStatus.ranInsecureContent || this._mixedContentStatus.displayedInsecureContent)) {
             if (this._mixedContentStatus.ranInsecureContent)
-                this._addMixedContentExplanation(this._mixedContentStatus.ranInsecureContentStyle, WebInspector.UIString("Active Mixed Content"), WebInspector.UIString("You have recently allowed insecure content (such as scripts or iframes) to run on this site."), WebInspector.NetworkLogView.MixedContentFilterValues.BlockOverridden, showBlockOverriddenMixedContentInNetworkPanel);
+                this._addMixedContentExplanation(this._securityExplanationsMain, this._mixedContentStatus.ranInsecureContentStyle, WebInspector.UIString("Active Mixed Content"), WebInspector.UIString("You have recently allowed insecure content (such as scripts or iframes) to run on this site."), WebInspector.NetworkLogView.MixedContentFilterValues.BlockOverridden, showBlockOverriddenMixedContentInNetworkPanel);
             if (this._mixedContentStatus.displayedInsecureContent)
-                this._addMixedContentExplanation(this._mixedContentStatus.displayedInsecureContentStyle, WebInspector.UIString("Mixed Content"), WebInspector.UIString("The site includes HTTP resources."), WebInspector.NetworkLogView.MixedContentFilterValues.Displayed, showDisplayedMixedContentInNetworkPanel);
+                this._addMixedContentExplanation(this._securityExplanationsMain, this._mixedContentStatus.displayedInsecureContentStyle, WebInspector.UIString("Mixed Content"), WebInspector.UIString("The site includes HTTP resources."), WebInspector.NetworkLogView.MixedContentFilterValues.Displayed, showDisplayedMixedContentInNetworkPanel);
         }
 
         if (this._mixedContentStatus && (!this._mixedContentStatus.displayedInsecureContent && !this._mixedContentStatus.ranInsecureContent)) {
-            this._addExplanation(/** @type {!SecurityAgent.SecurityStateExplanation} */ ({
+            this._addExplanation(this._securityExplanationsMain, /** @type {!SecurityAgent.SecurityStateExplanation} */ ({
                 "securityState": SecurityAgent.SecurityState.Secure,
                 "summary": WebInspector.UIString("Secure Resources"),
                 "description": WebInspector.UIString("All resources on this page are served securely.")
@@ -655,7 +668,7 @@
         }
 
         if (this._panel.filterRequestCount(WebInspector.NetworkLogView.MixedContentFilterValues.Blocked) > 0)
-            this._addMixedContentExplanation(SecurityAgent.SecurityState.Info, WebInspector.UIString("Blocked mixed content"), WebInspector.UIString("Your page requested insecure resources that were blocked."), WebInspector.NetworkLogView.MixedContentFilterValues.Blocked, showBlockedMixedContentInNetworkPanel);
+            this._addMixedContentExplanation(this._securityExplanationsExtra, SecurityAgent.SecurityState.Info, WebInspector.UIString("Blocked mixed content"), WebInspector.UIString("Your page requested insecure resources that were blocked."), WebInspector.NetworkLogView.MixedContentFilterValues.Blocked, showBlockedMixedContentInNetworkPanel);
 
         /**
          * @param {!Event} e
@@ -701,13 +714,14 @@
     },
 
     /**
+     * @param {!Element} parent
      * @param {!SecurityAgent.SecurityState} securityState
      * @param {string} summary
      * @param {string} description
      * @param {!WebInspector.NetworkLogView.MixedContentFilterValues} filterKey
      * @param {!Function} networkFilterFn
      */
-    _addMixedContentExplanation: function(securityState, summary, description, filterKey, networkFilterFn)
+    _addMixedContentExplanation: function(parent, securityState, summary, description, filterKey, networkFilterFn)
     {
         var mixedContentExplanation = /** @type {!SecurityAgent.SecurityStateExplanation} */ ({
             "securityState": securityState,
@@ -716,7 +730,7 @@
         });
 
         var filterRequestCount = this._panel.filterRequestCount(filterKey);
-        var requestsAnchor = this._addExplanation(mixedContentExplanation).createChild("div", "security-mixed-content link");
+        var requestsAnchor = this._addExplanation(parent, mixedContentExplanation).createChild("div", "security-mixed-content link");
         if (filterRequestCount > 0) {
             requestsAnchor.textContent = WebInspector.UIString("View %d request%s in Network Panel", filterRequestCount, (filterRequestCount > 1 ? "s" : ""));
         } else {
diff --git a/third_party/WebKit/Source/devtools/front_end/security/mainView.css b/third_party/WebKit/Source/devtools/front_end/security/mainView.css
index 1f6449a..df51db5d 100644
--- a/third_party/WebKit/Source/devtools/front_end/security/mainView.css
+++ b/third_party/WebKit/Source/devtools/front_end/security/mainView.css
@@ -144,13 +144,17 @@
 .security-explanation-text {
     flex: auto;
     white-space: normal;
+    max-width: 400px;
 }
 
-.security-explanation-info {
-    border-bottom: none;
+.security-explanations-extra .security-explanation {
     background-color: transparent;
 }
 
+.security-explanations-extra .security-explanation:only-child {
+    border-bottom: none;
+}
+
 .security-certificate-button {
     margin-top: 8px;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/ScopeChainSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/ScopeChainSidebarPane.js
index 6b0dc58..f0a14e92 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/ScopeChainSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/ScopeChainSidebarPane.js
@@ -32,6 +32,7 @@
 {
     WebInspector.SidebarPane.call(this, WebInspector.UIString("Scope"));
     this._expandController = new WebInspector.ObjectPropertiesSectionExpandController();
+    this._linkifier = new WebInspector.Linkifier();
 }
 
 WebInspector.ScopeChainSidebarPane._pathSymbol = Symbol("path");
@@ -42,6 +43,7 @@
      */
     update: function(callFrame)
     {
+        this._linkifier.reset();
         WebInspector.SourceMapNamesResolver.resolveThisObject(callFrame)
             .then(this._innerUpdate.bind(this, callFrame));
     },
@@ -120,7 +122,7 @@
             titleElement.createChild("div", "scope-chain-sidebar-pane-section-subtitle").textContent = subtitle;
             titleElement.createChild("div", "scope-chain-sidebar-pane-section-title").textContent = title;
 
-            var section = new WebInspector.ObjectPropertiesSection(WebInspector.SourceMapNamesResolver.resolveScopeInObject(scope), titleElement, emptyPlaceholder, true, extraProperties);
+            var section = new WebInspector.ObjectPropertiesSection(WebInspector.SourceMapNamesResolver.resolveScopeInObject(scope), titleElement, this._linkifier, emptyPlaceholder, true, extraProperties);
             this._expandController.watchSection(title + (subtitle ? ":" + subtitle : ""), section);
 
             if (scope.type() === DebuggerAgent.ScopeType.Global)
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourceMapNamesResolver.js b/third_party/WebKit/Source/devtools/front_end/sources/SourceMapNamesResolver.js
index bef7691..955d19d3 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/SourceMapNamesResolver.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/SourceMapNamesResolver.js
@@ -582,15 +582,6 @@
         this._object.functionDetails(callback);
     },
 
-    /**
-     * @override
-     * @param {function(?WebInspector.DebuggerModel.GeneratorObjectDetails)} callback
-     */
-    generatorObjectDetails: function(callback)
-    {
-        this._object.generatorObjectDetails(callback);
-    },
-
     __proto__: WebInspector.RemoteObject.prototype
 }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
index f4bef52..3cb238a 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
@@ -952,8 +952,6 @@
         contextMenu.appendItem(WebInspector.UIString.capitalize("Store as ^global ^variable"), this._saveToTempVariable.bind(this, remoteObject));
         if (remoteObject.type === "function")
             contextMenu.appendItem(WebInspector.UIString.capitalize("Show ^function ^definition"), this._showFunctionDefinition.bind(this, remoteObject));
-        if (remoteObject.subtype === "generator")
-            contextMenu.appendItem(WebInspector.UIString.capitalize("Show ^generator ^location"), this._showGeneratorLocation.bind(this, remoteObject));
     },
 
     /**
@@ -1042,21 +1040,13 @@
      */
     _showFunctionDefinition: function(remoteObject)
     {
-        remoteObject.debuggerModel().functionDetails(remoteObject, this._didGetFunctionOrGeneratorObjectDetails.bind(this));
-    },
-
-    /**
-     * @param {!WebInspector.RemoteObject} remoteObject
-     */
-    _showGeneratorLocation: function(remoteObject)
-    {
-        remoteObject.debuggerModel().generatorObjectDetails(remoteObject, this._didGetFunctionOrGeneratorObjectDetails.bind(this));
+        remoteObject.debuggerModel().functionDetails(remoteObject, this._didGetFunctionDetails.bind(this));
     },
 
     /**
      * @param {?{location: ?WebInspector.DebuggerModel.Location}} response
      */
-    _didGetFunctionOrGeneratorObjectDetails: function(response)
+    _didGetFunctionDetails: function(response)
     {
         if (!response || !response.location)
             return;
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/WatchExpressionsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/WatchExpressionsSidebarPane.js
index f5b6762..f2e23b75 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/WatchExpressionsSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/WatchExpressionsSidebarPane.js
@@ -54,6 +54,8 @@
     this._expandController = new WebInspector.ObjectPropertiesSectionExpandController();
 
     WebInspector.context.addFlavorChangeListener(WebInspector.ExecutionContext, this.refreshExpressions, this);
+
+    this._linkifier = new WebInspector.Linkifier();
 }
 
 WebInspector.WatchExpressionsSidebarPane.prototype = {
@@ -129,6 +131,7 @@
 
     _rebuildWatchExpressions: function()
     {
+        this._linkifier.reset();
         this._bodyElement.removeChildren();
         this._watchExpressions = [];
         this._emptyElement = this._bodyElement.createChild("div", "info");
@@ -150,7 +153,7 @@
     _createWatchExpression: function(expression)
     {
         this._emptyElement.classList.add("hidden");
-        var watchExpression = new WebInspector.WatchExpression(expression, this._expandController);
+        var watchExpression = new WebInspector.WatchExpression(expression, this._expandController, this._linkifier);
         watchExpression.addEventListener(WebInspector.WatchExpression.Events.ExpressionUpdated, this._watchExpressionUpdated.bind(this));
         this._bodyElement.appendChild(watchExpression.element());
         this._watchExpressions.push(watchExpression);
@@ -218,13 +221,15 @@
  * @extends {WebInspector.Object}
  * @param {?string} expression
  * @param {!WebInspector.ObjectPropertiesSectionExpandController} expandController
+ * @param {!WebInspector.Linkifier} linkifier
  */
-WebInspector.WatchExpression = function(expression, expandController)
+WebInspector.WatchExpression = function(expression, expandController, linkifier)
 {
     this._expression = expression;
     this._expandController = expandController;
     this._element = createElementWithClass("div", "watch-expression monospace");
     this._editing = false;
+    this._linkifier = linkifier;
 
     this._createWatchExpression(null, false);
     this.update();
@@ -352,7 +357,7 @@
             titleElement.classList.add("dimmed");
             this._valueElement.textContent = WebInspector.UIString("<not available>");
         } else {
-            this._valueElement = WebInspector.ObjectPropertiesSection.createValueElementWithCustomSupport(result, wasThrown, titleElement);
+            this._valueElement = WebInspector.ObjectPropertiesSection.createValueElementWithCustomSupport(result, wasThrown, titleElement, this._linkifier);
         }
         var separatorElement = createElementWithClass("span", "watch-expressions-separator");
         separatorElement.textContent = ": ";
@@ -362,7 +367,7 @@
         this._objectPropertiesSection = null;
         if (!wasThrown && result && result.hasChildren && !result.customPreview()) {
             headerElement.classList.add("watch-expression-object-header");
-            this._objectPropertiesSection = new WebInspector.ObjectPropertiesSection(result, headerElement);
+            this._objectPropertiesSection = new WebInspector.ObjectPropertiesSection(result, headerElement, this._linkifier);
             this._objectPresentationElement = this._objectPropertiesSection.element;
             this._expandController.watchSection(/** @type {string} */ (this._expression), this._objectPropertiesSection);
             var objectTreeElement = this._objectPropertiesSection.objectTreeElement();
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js b/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
index 9858353..48a123b 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
@@ -1720,6 +1720,14 @@
     },
 
     /**
+     * @return {string}
+     */
+    themeName: function()
+    {
+        return this._themeName;
+    },
+
+    /**
      * @param {!Element} element
      */
     injectHighlightStyleSheets: function(element)
diff --git a/third_party/WebKit/Source/devtools/protocol.json b/third_party/WebKit/Source/devtools/protocol.json
index 4f6b96a1..d790d5db 100644
--- a/third_party/WebKit/Source/devtools/protocol.json
+++ b/third_party/WebKit/Source/devtools/protocol.json
@@ -1,7 +1,7 @@
 The protocol.json has split into separate files. https://crbug.com/580337
 
 One for the browser, one for a V8 javascript environment:
-    src/content/browser/devtools/browser_protocol.json
+    src/third_party/WebKit/Source/core/inspector/browser_protocol.json
     src/third_party/WebKit/Source/platform/v8_inspector/js_protocol.json
 
 Browsable here:
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBObserver.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBObserver.cpp
index 219b818..db4a1ea 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBObserver.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBObserver.cpp
@@ -7,8 +7,12 @@
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/modules/v8/ToV8ForModules.h"
 #include "bindings/modules/v8/V8BindingForModules.h"
+#include "core/dom/ExceptionCode.h"
+#include "modules/indexeddb/IDBDatabase.h"
 #include "modules/indexeddb/IDBObserverCallback.h"
 #include "modules/indexeddb/IDBObserverInit.h"
+#include "modules/indexeddb/IDBTransaction.h"
+#include "modules/indexeddb/WebIDBObserverImpl.h"
 
 namespace blink {
 
@@ -25,9 +29,53 @@
 {
 }
 
+IDBObserver::~IDBObserver() {}
+
 void IDBObserver::observe(IDBDatabase* database, IDBTransaction* transaction, ExceptionState& exceptionState)
 {
-    // TODO(palakj): Finish implementation.
+    if (transaction->isFinished() || transaction->isFinishing()) {
+        exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
+        return;
+    }
+    if (!transaction->isActive()) {
+        exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
+        return;
+    }
+    if (!database->backend()) {
+        exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
+        return;
+    }
+
+    std::unique_ptr<WebIDBObserverImpl> observer = WebIDBObserverImpl::create(this);
+    WebIDBObserverImpl* observerPtr = observer.get();
+    int32_t observerId = database->backend()->addObserver(std::move(observer), transaction->id());
+    m_observerIds.insert(observerId);
+    observerPtr->setId(observerId);
+}
+
+void IDBObserver::unobserve(IDBDatabase* database, ExceptionState& exceptionState)
+{
+    if (!database->backend()) {
+        exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
+        return;
+    }
+    auto it = m_observerIds.begin();
+    std::vector<int32_t> observerIdsToRemove;
+    while (it != m_observerIds.end()) {
+        if (database->backend()->containsObserverId(*it)) {
+            observerIdsToRemove.push_back(*it);
+            it = m_observerIds.erase(it);
+        } else {
+            it++;
+        }
+    }
+    if (!observerIdsToRemove.empty())
+        database->backend()->removeObservers(observerIdsToRemove);
+}
+
+void IDBObserver::removeObserver(int32_t id)
+{
+    m_observerIds.erase(id);
 }
 
 DEFINE_TRACE(IDBObserver)
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBObserver.h b/third_party/WebKit/Source/modules/indexeddb/IDBObserver.h
index 538995bc..c8500567 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBObserver.h
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBObserver.h
@@ -6,23 +6,29 @@
 #define IDBObserver_h
 
 #include "bindings/core/v8/ScriptWrappable.h"
-#include "modules/indexeddb/IDBDatabase.h"
-#include "modules/indexeddb/IDBTransaction.h"
+#include "modules/ModulesExport.h"
 #include "platform/heap/Handle.h"
+#include <set>
 
 namespace blink {
 
+class ExceptionState;
+class IDBDatabase;
 class IDBObserverCallback;
 class IDBObserverInit;
+class IDBTransaction;
 
-class IDBObserver final : public GarbageCollected<IDBObserver>, public ScriptWrappable {
+class MODULES_EXPORT IDBObserver final : public GarbageCollectedFinalized<IDBObserver>, public ScriptWrappable {
     DEFINE_WRAPPERTYPEINFO();
 
 public:
     static IDBObserver* create(IDBObserverCallback&, const IDBObserverInit&);
 
+    ~IDBObserver();
     // API methods
     void observe(IDBDatabase*, IDBTransaction*, ExceptionState&);
+    void unobserve(IDBDatabase*, ExceptionState&);
+    void removeObserver(int32_t id);
 
     DECLARE_TRACE();
 
@@ -33,6 +39,7 @@
     bool m_transaction;
     bool m_values;
     bool m_noRecords;
+    std::set<int32_t> m_observerIds;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBObserver.idl b/third_party/WebKit/Source/modules/indexeddb/IDBObserver.idl
index ab4d856..3723dbc 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBObserver.idl
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBObserver.idl
@@ -11,4 +11,5 @@
    RuntimeEnabled=IDBObserver
 ] interface IDBObserver {
     [RaisesException] void observe(IDBDatabase db, IDBTransaction tx);
+    [RaisesException] void unobserve(IDBDatabase db);
 };
diff --git a/third_party/WebKit/Source/modules/indexeddb/MockWebIDBDatabase.h b/third_party/WebKit/Source/modules/indexeddb/MockWebIDBDatabase.h
index 30445548..5d460252 100644
--- a/third_party/WebKit/Source/modules/indexeddb/MockWebIDBDatabase.h
+++ b/third_party/WebKit/Source/modules/indexeddb/MockWebIDBDatabase.h
@@ -9,6 +9,7 @@
 #include "modules/indexeddb/IDBKeyRange.h"
 #include "public/platform/modules/indexeddb/WebIDBDatabase.h"
 #include "public/platform/modules/indexeddb/WebIDBKeyRange.h"
+#include "public/platform/modules/indexeddb/WebIDBObserver.h"
 #include <gmock/gmock.h>
 #include <memory>
 
@@ -29,6 +30,11 @@
     MOCK_METHOD1(commit, void(long long transactionId));
     MOCK_METHOD7(createIndex, void(long long transactionId, long long objectStoreId, long long indexId, const WebString& name, const WebIDBKeyPath&, bool unique, bool multiEntry));
     MOCK_METHOD3(deleteIndex, void(long long transactionId, long long objectStoreId, long long indexId));
+
+    // Gmock does not support movable type, so cannot use MOCK_METHOD for addObserver. Issue: https://github.com/google/googletest/issues/395.
+    int32_t addObserver(std::unique_ptr<WebIDBObserver>, long long transactionId) { return -1; }
+    MOCK_CONST_METHOD1(containsObserverId, bool(int32_t id));
+    MOCK_METHOD1(removeObservers, void(const std::vector<int32_t>& observerIdsToRemove));
     MOCK_METHOD6(get, void(long long transactionId, long long objectStoreId, long long indexId, const WebIDBKeyRange&, bool keyOnly, WebIDBCallbacks*));
     MOCK_METHOD7(getAll, void(long long transactionId, long long objectStoreId, long long indexId, const WebIDBKeyRange&, long long maxCount, bool keyOnly, WebIDBCallbacks*));
     MOCK_METHOD9(put, void(long long transactionId, long long objectStoreId, const WebData& value, const WebVector<WebBlobInfo>&, const WebIDBKey&, WebIDBPutMode, WebIDBCallbacks*, const WebVector<long long>& indexIds, const WebVector<WebIndexKeys>&));
diff --git a/third_party/WebKit/Source/modules/indexeddb/WebIDBObserverImpl.cpp b/third_party/WebKit/Source/modules/indexeddb/WebIDBObserverImpl.cpp
new file mode 100644
index 0000000..3610e284
--- /dev/null
+++ b/third_party/WebKit/Source/modules/indexeddb/WebIDBObserverImpl.cpp
@@ -0,0 +1,37 @@
+// 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 "modules/indexeddb/WebIDBObserverImpl.h"
+
+#include "modules/indexeddb/IDBObserver.h"
+#include "wtf/PtrUtil.h"
+
+namespace blink {
+
+// static
+std::unique_ptr<WebIDBObserverImpl> WebIDBObserverImpl::create(IDBObserver* observer)
+{
+    return wrapUnique(new WebIDBObserverImpl(observer));
+}
+
+WebIDBObserverImpl::WebIDBObserverImpl(IDBObserver* observer)
+    : m_id(kInvalidObserverId)
+    , m_observer(observer)
+{
+}
+
+// Remove observe call id from IDBObserver.
+WebIDBObserverImpl::~WebIDBObserverImpl()
+{
+    if (m_id != kInvalidObserverId)
+        m_observer->removeObserver(m_id);
+}
+
+void WebIDBObserverImpl::setId(int32_t id)
+{
+    DCHECK_EQ(kInvalidObserverId, m_id);
+    m_id = id;
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/modules/indexeddb/WebIDBObserverImpl.h b/third_party/WebKit/Source/modules/indexeddb/WebIDBObserverImpl.h
new file mode 100644
index 0000000..97c53bb
--- /dev/null
+++ b/third_party/WebKit/Source/modules/indexeddb/WebIDBObserverImpl.h
@@ -0,0 +1,36 @@
+// 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 WebIDBObserverImpl_h
+#define WebIDBObserverImpl_h
+
+#include "platform/heap/Persistent.h"
+#include "public/platform/modules/indexeddb/WebIDBObserver.h"
+
+namespace blink {
+
+class IDBObserver;
+
+class WebIDBObserverImpl final : public WebIDBObserver {
+    USING_FAST_MALLOC(WebIDBObserverImpl);
+
+public:
+    static std::unique_ptr<WebIDBObserverImpl> create(IDBObserver*);
+
+    ~WebIDBObserverImpl() override;
+
+    void setId(int32_t);
+
+private:
+    enum { kInvalidObserverId = -1 };
+
+    explicit WebIDBObserverImpl(IDBObserver*);
+
+    int32_t m_id;
+    Persistent<IDBObserver> m_observer;
+};
+
+} // namespace blink
+
+#endif // WebIDBObserverImpl_h
diff --git a/third_party/WebKit/Source/modules/modules.gypi b/third_party/WebKit/Source/modules/modules.gypi
index b5e2a07..94c2d46 100644
--- a/third_party/WebKit/Source/modules/modules.gypi
+++ b/third_party/WebKit/Source/modules/modules.gypi
@@ -1223,6 +1223,8 @@
       'indexeddb/WebIDBCallbacksImpl.h',
       'indexeddb/WebIDBDatabaseCallbacksImpl.cpp',
       'indexeddb/WebIDBDatabaseCallbacksImpl.h',
+      'indexeddb/WebIDBObserverImpl.cpp',
+      'indexeddb/WebIDBObserverImpl.h',
       'installedapp/InstalledAppController.cpp',
       'installedapp/InstalledAppController.h',
       'installedapp/NavigatorInstalledApp.cpp',
@@ -1636,8 +1638,6 @@
       'vr/VRStageParameters.h',
       'wake_lock/ScreenWakeLock.cpp',
       'wake_lock/ScreenWakeLock.h',
-      'webaudio/AbstractAudioContext.cpp',
-      'webaudio/AbstractAudioContext.h',
       'webaudio/AnalyserNode.cpp',
       'webaudio/AnalyserNode.h',
       'webaudio/AsyncAudioDecoder.cpp',
@@ -1674,6 +1674,8 @@
       'webaudio/AudioSourceNode.h',
       'webaudio/AudioSummingJunction.cpp',
       'webaudio/AudioSummingJunction.h',
+      'webaudio/BaseAudioContext.cpp',
+      'webaudio/BaseAudioContext.h',
       'webaudio/BiquadDSPKernel.cpp',
       'webaudio/BiquadDSPKernel.h',
       'webaudio/BiquadFilterNode.cpp',
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
index e3da8a5..294efb8b 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
@@ -25,6 +25,7 @@
 #include "mojo/public/cpp/bindings/wtf_array.h"
 #include "platform/mojo/MojoHelper.h"
 #include "public/platform/ServiceRegistry.h"
+#include "wtf/HashSet.h"
 #include <utility>
 
 namespace mojo {
@@ -224,11 +225,19 @@
         return;
     }
 
+    HashSet<String> uniqueMethods;
     for (const auto& modifier : modifiers) {
         if (modifier.supportedMethods().isEmpty()) {
             exceptionState.throwTypeError("Must specify at least one payment method identifier");
             return;
         }
+        for (const auto& method : modifier.supportedMethods()) {
+            if (uniqueMethods.contains(method)) {
+                exceptionState.throwTypeError("Duplicate payment method identifiers are not allowed");
+                return;
+            }
+            uniqueMethods.add(method);
+        }
 
         if (modifier.hasTotal()) {
             validateShippingOptionOrPaymentItem(modifier.total(), exceptionState);
@@ -289,11 +298,19 @@
         return;
     }
 
+    HashSet<String> uniqueMethods;
     for (const auto& pmd : paymentMethodData) {
         if (pmd.supportedMethods().isEmpty()) {
             exceptionState.throwTypeError("Must specify at least one payment method identifier");
             return;
         }
+        for (const auto& method : pmd.supportedMethods()) {
+            if (uniqueMethods.contains(method)) {
+                exceptionState.throwTypeError("Duplicate payment method identifiers are not allowed");
+                return;
+            }
+            uniqueMethods.add(method);
+        }
 
         String stringifiedData = "";
         if (pmd.hasData() && !pmd.data().isEmpty()) {
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerError.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerError.cpp
index 4a376381..ea8ea6cf 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerError.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerError.cpp
@@ -30,6 +30,8 @@
 
 #include "modules/serviceworkers/ServiceWorkerError.h"
 
+#include "bindings/core/v8/ScriptPromiseResolver.h"
+#include "bindings/core/v8/ToV8.h"
 #include "core/dom/DOMException.h"
 #include "core/dom/ExceptionCode.h"
 
@@ -37,49 +39,81 @@
 
 namespace blink {
 
-static DOMException* createException(ExceptionCode code, const String& defaultMessage, const String& message)
+namespace {
+
+struct ExceptionParams {
+    ExceptionParams(ExceptionCode code, const String& defaultMessage = String(), const String& message = String())
+        : code(code), message(message.isEmpty() ? defaultMessage : message) {}
+
+    ExceptionCode code;
+    String message;
+};
+
+ExceptionParams getExceptionParams(const WebServiceWorkerError& webError)
 {
-    return DOMException::create(code, message.isEmpty() ? defaultMessage : message);
+    switch (webError.errorType) {
+    case WebServiceWorkerError::ErrorTypeAbort:
+        return ExceptionParams(AbortError, "The Service Worker operation was aborted.", webError.message);
+    case WebServiceWorkerError::ErrorTypeActivate:
+        // Not currently returned as a promise rejection.
+        // TODO: Introduce new ActivateError type to ExceptionCodes?
+        return ExceptionParams(AbortError, "The Service Worker activation failed.", webError.message);
+    case WebServiceWorkerError::ErrorTypeDisabled:
+        return ExceptionParams(NotSupportedError, "Service Worker support is disabled.", webError.message);
+    case WebServiceWorkerError::ErrorTypeInstall:
+        // TODO: Introduce new InstallError type to ExceptionCodes?
+        return ExceptionParams(AbortError, "The Service Worker installation failed.", webError.message);
+    case WebServiceWorkerError::ErrorTypeScriptEvaluateFailed:
+        return ExceptionParams(AbortError, "The Service Worker script failed to evaluate.", webError.message);
+    case WebServiceWorkerError::ErrorTypeNavigation:
+        // ErrorTypeNavigation should have bailed out before calling this.
+        ASSERT_NOT_REACHED();
+        return ExceptionParams(UnknownError);
+    case WebServiceWorkerError::ErrorTypeNetwork:
+        return ExceptionParams(NetworkError, "The Service Worker failed by network.", webError.message);
+    case WebServiceWorkerError::ErrorTypeNotFound:
+        return ExceptionParams(NotFoundError, "The specified Service Worker resource was not found.", webError.message);
+    case WebServiceWorkerError::ErrorTypeSecurity:
+        return ExceptionParams(SecurityError, "The Service Worker security policy prevented an action.", webError.message);
+    case WebServiceWorkerError::ErrorTypeState:
+        return ExceptionParams(InvalidStateError, "The Service Worker state was not valid.", webError.message);
+    case WebServiceWorkerError::ErrorTypeTimeout:
+        return ExceptionParams(AbortError, "The Service Worker operation timed out.", webError.message);
+    case WebServiceWorkerError::ErrorTypeUnknown:
+        return ExceptionParams(UnknownError, "An unknown error occurred within Service Worker.", webError.message);
+    case WebServiceWorkerError::ErrorTypeType:
+        // ErrorTypeType should have been handled before reaching this point.
+        ASSERT_NOT_REACHED();
+        return ExceptionParams(UnknownError);
+    }
+    ASSERT_NOT_REACHED();
+    return ExceptionParams(UnknownError);
 }
 
+} // namespace
+
 // static
 DOMException* ServiceWorkerError::take(ScriptPromiseResolver*, const WebServiceWorkerError& webError)
 {
-    switch (webError.errorType) {
-    case WebServiceWorkerError::ErrorTypeAbort:
-        return createException(AbortError, "The Service Worker operation was aborted.", webError.message);
-    case WebServiceWorkerError::ErrorTypeActivate:
-        // Not currently returned as a promise rejection.
-        // FIXME: Introduce new ActivateError type to ExceptionCodes?
-        return createException(AbortError, "The Service Worker activation failed.", webError.message);
-    case WebServiceWorkerError::ErrorTypeDisabled:
-        return createException(NotSupportedError, "Service Worker support is disabled.", webError.message);
-    case WebServiceWorkerError::ErrorTypeInstall:
-        // FIXME: Introduce new InstallError type to ExceptionCodes?
-        return createException(AbortError, "The Service Worker installation failed.", webError.message);
-    case WebServiceWorkerError::ErrorTypeNavigation:
-        // ErrorTypeNavigation should have bailed out before calling this.
-        ASSERT_NOT_REACHED();
-        return DOMException::create(UnknownError);
+    ExceptionParams params = getExceptionParams(webError);
+    ASSERT(params.code != UnknownError);
+    return DOMException::create(params.code, params.message);
+}
+
+// static
+v8::Local<v8::Value> ServiceWorkerErrorForUpdate::take(ScriptPromiseResolver* resolver, const WebServiceWorkerError& webError)
+{
+    ScriptState* scriptState = resolver->getScriptState();
+    switch(webError.errorType) {
     case WebServiceWorkerError::ErrorTypeNetwork:
-        return createException(NetworkError, "The Service Worker failed by network.", webError.message);
     case WebServiceWorkerError::ErrorTypeNotFound:
-        return createException(NotFoundError, "The specified Service Worker resource was not found.", webError.message);
-    case WebServiceWorkerError::ErrorTypeSecurity:
-        return createException(SecurityError, "The Service Worker security policy prevented an action.", webError.message);
-    case WebServiceWorkerError::ErrorTypeState:
-        return createException(InvalidStateError, "The Service Worker state was not valid.", webError.message);
-    case WebServiceWorkerError::ErrorTypeTimeout:
-        return createException(AbortError, "The Service Worker operation timed out.", webError.message);
-    case WebServiceWorkerError::ErrorTypeUnknown:
-        return createException(UnknownError, "An unknown error occurred within Service Worker.", webError.message);
-    case WebServiceWorkerError::ErrorTypeType:
-        // ErrorTypeType should have been handled before reaching this point.
-        ASSERT_NOT_REACHED();
-        return DOMException::create(UnknownError);
+    case WebServiceWorkerError::ErrorTypeScriptEvaluateFailed:
+        // According to the spec, these errors during update should result in
+        // a TypeError.
+        return V8ThrowException::createTypeError(scriptState->isolate(), getExceptionParams(webError).message);
+    default:
+        return toV8(ServiceWorkerError::take(resolver, webError), scriptState->context()->Global(), scriptState->isolate());
     }
-    ASSERT_NOT_REACHED();
-    return DOMException::create(UnknownError);
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerError.h b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerError.h
index 9145d11..5a15fa4 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerError.h
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerError.h
@@ -34,6 +34,8 @@
 #include "platform/heap/Handle.h"
 #include "public/platform/modules/serviceworker/WebServiceWorkerError.h"
 
+#include <v8.h>
+
 namespace blink {
 
 class DOMException;
@@ -47,6 +49,13 @@
     static DOMException* take(ScriptPromiseResolver*, const WebServiceWorkerError& webError);
 };
 
+class ServiceWorkerErrorForUpdate : public ServiceWorkerError {
+    STATIC_ONLY(ServiceWorkerErrorForUpdate);
+public:
+    // For CallbackPromiseAdapter
+    static v8::Local<v8::Value> take(ScriptPromiseResolver* resolver, const WebServiceWorkerError& webError);
+};
+
 } // namespace blink
 
 #endif // ServiceWorkerError_h
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerRegistration.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerRegistration.cpp
index 1582384..85fbce82 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerRegistration.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerRegistration.cpp
@@ -79,7 +79,7 @@
 
     ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
     ScriptPromise promise = resolver->promise();
-    m_handle->registration()->update(client->provider(), new CallbackPromiseAdapter<void, ServiceWorkerError>(resolver));
+    m_handle->registration()->update(client->provider(), new CallbackPromiseAdapter<void, ServiceWorkerErrorForUpdate>(resolver));
     return promise;
 }
 
diff --git a/third_party/WebKit/Source/modules/wake_lock/ScreenWakeLock.cpp b/third_party/WebKit/Source/modules/wake_lock/ScreenWakeLock.cpp
index 2c42f90..3062214e 100644
--- a/third_party/WebKit/Source/modules/wake_lock/ScreenWakeLock.cpp
+++ b/third_party/WebKit/Source/modules/wake_lock/ScreenWakeLock.cpp
@@ -4,6 +4,7 @@
 
 #include "modules/wake_lock/ScreenWakeLock.h"
 
+#include "core/dom/Document.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/Screen.h"
 #include "core/page/PageVisibilityState.h"
@@ -39,17 +40,14 @@
 // static
 ScreenWakeLock* ScreenWakeLock::from(LocalFrame* frame)
 {
-    return static_cast<ScreenWakeLock*>(Supplement<LocalFrame>::from(frame, supplementName()));
-}
-
-// static
-void ScreenWakeLock::provideTo(LocalFrame& frame, ServiceRegistry* registry)
-{
-    DCHECK(RuntimeEnabledFeatures::wakeLockEnabled());
-    Supplement<LocalFrame>::provideTo(
-        frame,
-        ScreenWakeLock::supplementName(),
-        registry ? new ScreenWakeLock(frame, registry) : nullptr);
+    if (!RuntimeEnabledFeatures::wakeLockEnabled())
+        return nullptr;
+    ScreenWakeLock* supplement = static_cast<ScreenWakeLock*>(Supplement<LocalFrame>::from(frame, supplementName()));
+    if (!supplement) {
+        supplement = new ScreenWakeLock(*frame);
+        Supplement<LocalFrame>::provideTo(*frame, supplementName(), supplement);
+    }
+    return supplement;
 }
 
 void ScreenWakeLock::pageVisibilityChanged()
@@ -57,14 +55,7 @@
     notifyService();
 }
 
-void ScreenWakeLock::didCommitLoad(LocalFrame* committedFrame)
-{
-    // Reset wake lock flag for this frame if it is the one being navigated.
-    if (committedFrame == frame())
-        setKeepAwake(false);
-}
-
-void ScreenWakeLock::willDetachFrameHost()
+void ScreenWakeLock::contextDestroyed()
 {
     setKeepAwake(false);
 }
@@ -73,17 +64,17 @@
 {
     Supplement<LocalFrame>::trace(visitor);
     PageLifecycleObserver::trace(visitor);
-    LocalFrameLifecycleObserver::trace(visitor);
+    ContextLifecycleObserver::trace(visitor);
 }
 
-ScreenWakeLock::ScreenWakeLock(LocalFrame& frame, ServiceRegistry* registry)
-    : PageLifecycleObserver(frame.page())
-    , LocalFrameLifecycleObserver(&frame)
+ScreenWakeLock::ScreenWakeLock(LocalFrame& frame)
+    : ContextLifecycleObserver(frame.document())
+    , PageLifecycleObserver(frame.page())
     , m_keepAwake(false)
 {
     DCHECK(!m_service.is_bound());
-    DCHECK(registry);
-    registry->connectToRemoteService(mojo::GetProxy(&m_service));
+    DCHECK(frame.serviceRegistry());
+    frame.serviceRegistry()->connectToRemoteService(mojo::GetProxy(&m_service));
 }
 
 bool ScreenWakeLock::keepAwake() const
@@ -108,7 +99,7 @@
     if (!m_service)
         return;
 
-    if (m_keepAwake && frame()->page() && frame()->page()->isPageVisible())
+    if (m_keepAwake && page() && page()->isPageVisible())
         m_service->RequestWakeLock();
     else
         m_service->CancelWakeLock();
diff --git a/third_party/WebKit/Source/modules/wake_lock/ScreenWakeLock.h b/third_party/WebKit/Source/modules/wake_lock/ScreenWakeLock.h
index eeddc68..1e9e9ca 100644
--- a/third_party/WebKit/Source/modules/wake_lock/ScreenWakeLock.h
+++ b/third_party/WebKit/Source/modules/wake_lock/ScreenWakeLock.h
@@ -5,7 +5,7 @@
 #ifndef ScreenWakeLock_h
 #define ScreenWakeLock_h
 
-#include "core/frame/LocalFrameLifecycleObserver.h"
+#include "core/dom/ContextLifecycleObserver.h"
 #include "core/page/PageLifecycleObserver.h"
 #include "modules/ModulesExport.h"
 #include "public/platform/modules/wake_lock/wake_lock_service.mojom-blink.h"
@@ -17,7 +17,7 @@
 class Screen;
 class ServiceRegistry;
 
-class MODULES_EXPORT ScreenWakeLock final : public GarbageCollectedFinalized<ScreenWakeLock>, public Supplement<LocalFrame>, public PageLifecycleObserver, public LocalFrameLifecycleObserver {
+class MODULES_EXPORT ScreenWakeLock final : public GarbageCollectedFinalized<ScreenWakeLock>, public Supplement<LocalFrame>, public ContextLifecycleObserver, public PageLifecycleObserver {
     USING_GARBAGE_COLLECTED_MIXIN(ScreenWakeLock);
     WTF_MAKE_NONCOPYABLE(ScreenWakeLock);
 public:
@@ -26,21 +26,17 @@
 
     static const char* supplementName();
     static ScreenWakeLock* from(LocalFrame*);
-    static void provideTo(LocalFrame&, ServiceRegistry*);
 
     ~ScreenWakeLock() = default;
 
     DECLARE_VIRTUAL_TRACE();
 
 private:
-    ScreenWakeLock(LocalFrame&, ServiceRegistry*);
+    explicit ScreenWakeLock(LocalFrame&);
 
     // Inherited from PageLifecycleObserver.
     void pageVisibilityChanged() override;
-    void didCommitLoad(LocalFrame*) override;
-
-    // Inherited from LocalFrameLifecycleObserver.
-    void willDetachFrameHost() override;
+    void contextDestroyed() override;
 
     bool keepAwake() const;
     void setKeepAwake(bool);
diff --git a/third_party/WebKit/Source/modules/webaudio/AnalyserNode.cpp b/third_party/WebKit/Source/modules/webaudio/AnalyserNode.cpp
index 4340364..6f33807 100644
--- a/third_party/WebKit/Source/modules/webaudio/AnalyserNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AnalyserNode.cpp
@@ -113,13 +113,13 @@
 
 // ----------------------------------------------------------------
 
-AnalyserNode::AnalyserNode(AbstractAudioContext& context)
+AnalyserNode::AnalyserNode(BaseAudioContext& context)
     : AudioBasicInspectorNode(context)
 {
     setHandler(AnalyserHandler::create(*this, context.sampleRate()));
 }
 
-AnalyserNode* AnalyserNode::create(AbstractAudioContext& context, ExceptionState& exceptionState)
+AnalyserNode* AnalyserNode::create(BaseAudioContext& context, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
diff --git a/third_party/WebKit/Source/modules/webaudio/AnalyserNode.h b/third_party/WebKit/Source/modules/webaudio/AnalyserNode.h
index dd373b1..5999f7aa 100644
--- a/third_party/WebKit/Source/modules/webaudio/AnalyserNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/AnalyserNode.h
@@ -31,7 +31,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 class ExceptionState;
 
 class AnalyserHandler final : public AudioBasicInspectorHandler {
@@ -76,7 +76,7 @@
 class AnalyserNode final : public AudioBasicInspectorNode {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static AnalyserNode* create(AbstractAudioContext&, ExceptionState&);
+    static AnalyserNode* create(BaseAudioContext&, ExceptionState&);
 
     unsigned fftSize() const;
     void setFftSize(unsigned size, ExceptionState&);
@@ -93,7 +93,7 @@
     void getByteTimeDomainData(DOMUint8Array*);
 
 private:
-    AnalyserNode(AbstractAudioContext&);
+    AnalyserNode(BaseAudioContext&);
     AnalyserHandler& analyserHandler() const;
 };
 
diff --git a/third_party/WebKit/Source/modules/webaudio/AsyncAudioDecoder.cpp b/third_party/WebKit/Source/modules/webaudio/AsyncAudioDecoder.cpp
index 360ad1ad..12aa3b88 100644
--- a/third_party/WebKit/Source/modules/webaudio/AsyncAudioDecoder.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AsyncAudioDecoder.cpp
@@ -23,10 +23,10 @@
  */
 
 #include "core/dom/DOMArrayBuffer.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AsyncAudioDecoder.h"
 #include "modules/webaudio/AudioBuffer.h"
 #include "modules/webaudio/AudioBufferCallback.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "platform/CrossThreadFunctional.h"
 #include "platform/audio/AudioBus.h"
 #include "platform/audio/AudioFileReader.h"
@@ -45,7 +45,7 @@
 {
 }
 
-void AsyncAudioDecoder::decodeAsync(DOMArrayBuffer* audioData, float sampleRate, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, ScriptPromiseResolver* resolver, AbstractAudioContext* context)
+void AsyncAudioDecoder::decodeAsync(DOMArrayBuffer* audioData, float sampleRate, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, ScriptPromiseResolver* resolver, BaseAudioContext* context)
 {
     ASSERT(isMainThread());
     ASSERT(audioData);
@@ -55,7 +55,7 @@
     m_thread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, crossThreadBind(&AsyncAudioDecoder::decode, wrapCrossThreadPersistent(audioData), sampleRate, wrapCrossThreadPersistent(successCallback), wrapCrossThreadPersistent(errorCallback), wrapCrossThreadPersistent(resolver), wrapCrossThreadPersistent(context)));
 }
 
-void AsyncAudioDecoder::decode(DOMArrayBuffer* audioData, float sampleRate, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, ScriptPromiseResolver* resolver, AbstractAudioContext* context)
+void AsyncAudioDecoder::decode(DOMArrayBuffer* audioData, float sampleRate, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, ScriptPromiseResolver* resolver, BaseAudioContext* context)
 {
     RefPtr<AudioBus> bus = createBusFromInMemoryAudioFile(audioData->data(), audioData->byteLength(), false, sampleRate);
 
@@ -64,7 +64,7 @@
     Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_HERE, crossThreadBind(&AsyncAudioDecoder::notifyComplete, wrapCrossThreadPersistent(audioData), wrapCrossThreadPersistent(successCallback), wrapCrossThreadPersistent(errorCallback), bus.release(), wrapCrossThreadPersistent(resolver), wrapCrossThreadPersistent(context)));
 }
 
-void AsyncAudioDecoder::notifyComplete(DOMArrayBuffer*, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, AudioBus* audioBus, ScriptPromiseResolver* resolver, AbstractAudioContext* context)
+void AsyncAudioDecoder::notifyComplete(DOMArrayBuffer*, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, AudioBus* audioBus, ScriptPromiseResolver* resolver, BaseAudioContext* context)
 {
     ASSERT(isMainThread());
 
diff --git a/third_party/WebKit/Source/modules/webaudio/AsyncAudioDecoder.h b/third_party/WebKit/Source/modules/webaudio/AsyncAudioDecoder.h
index b05694c..2d2c301 100644
--- a/third_party/WebKit/Source/modules/webaudio/AsyncAudioDecoder.h
+++ b/third_party/WebKit/Source/modules/webaudio/AsyncAudioDecoder.h
@@ -32,7 +32,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 class AudioBuffer;
 class AudioBufferCallback;
 class AudioBus;
@@ -52,12 +52,12 @@
     // Must be called on the main thread.  |decodeAsync| and callees must not modify any of the
     // parameters except |audioData|.  They are used to associate this decoding instance with the
     // caller to process the decoding appropriately when finished.
-    void decodeAsync(DOMArrayBuffer* audioData, float sampleRate, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, ScriptPromiseResolver* , AbstractAudioContext*);
+    void decodeAsync(DOMArrayBuffer* audioData, float sampleRate, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, ScriptPromiseResolver* , BaseAudioContext*);
 
 private:
     AudioBuffer* createAudioBufferFromAudioBus(AudioBus*);
-    static void decode(DOMArrayBuffer* audioData, float sampleRate, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, ScriptPromiseResolver*, AbstractAudioContext*);
-    static void notifyComplete(DOMArrayBuffer* audioData, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, AudioBus*, ScriptPromiseResolver*, AbstractAudioContext*);
+    static void decode(DOMArrayBuffer* audioData, float sampleRate, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, ScriptPromiseResolver*, BaseAudioContext*);
+    static void notifyComplete(DOMArrayBuffer* audioData, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, AudioBus*, ScriptPromiseResolver*, BaseAudioContext*);
 
     std::unique_ptr<WebThread> m_thread;
 };
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioBasicInspectorNode.cpp b/third_party/WebKit/Source/modules/webaudio/AudioBasicInspectorNode.cpp
index c71427c..f9343a1 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioBasicInspectorNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioBasicInspectorNode.cpp
@@ -23,9 +23,9 @@
  */
 
 #include "modules/webaudio/AudioBasicInspectorNode.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioNodeInput.h"
 #include "modules/webaudio/AudioNodeOutput.h"
+#include "modules/webaudio/BaseAudioContext.h"
 
 namespace blink {
 
@@ -50,7 +50,7 @@
 {
     ASSERT(isMainThread());
 
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     AudioNode::connect(destination, outputIndex, inputIndex, exceptionState);
     static_cast<AudioBasicInspectorHandler&>(handler()).updatePullStatus();
@@ -62,7 +62,7 @@
 {
     ASSERT(isMainThread());
 
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     AudioNode::disconnect(outputIndex, exceptionState);
     static_cast<AudioBasicInspectorHandler&>(handler()).updatePullStatus();
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioBasicInspectorNode.h b/third_party/WebKit/Source/modules/webaudio/AudioBasicInspectorNode.h
index 4a27e79..cbad7c18 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioBasicInspectorNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/AudioBasicInspectorNode.h
@@ -29,12 +29,12 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 class ExceptionState;
 
 // AudioBasicInspectorNode is an AudioNode with one input and one output where the output might not necessarily connect to another node's input.
 // If the output is not connected to any other node, then the AudioBasicInspectorNode's processIfNecessary() function will be called automatically by
-// AbstractAudioContext before the end of each render quantum so that it can inspect the audio stream.
+// BaseAudioContext before the end of each render quantum so that it can inspect the audio stream.
 class AudioBasicInspectorHandler : public AudioHandler {
 public:
     AudioBasicInspectorHandler(NodeType, AudioNode&, float sampleRate, unsigned outputChannelCount);
@@ -46,12 +46,12 @@
     void updatePullStatus();
 
 private:
-    bool m_needAutomaticPull; // When setting to true, AudioBasicInspectorHandler will be pulled automaticlly by AbstractAudioContext before the end of each render quantum.
+    bool m_needAutomaticPull; // When setting to true, AudioBasicInspectorHandler will be pulled automaticlly by BaseAudioContext before the end of each render quantum.
 };
 
 class AudioBasicInspectorNode : public AudioNode {
 protected:
-    explicit AudioBasicInspectorNode(AbstractAudioContext& context) : AudioNode(context) { }
+    explicit AudioBasicInspectorNode(BaseAudioContext& context) : AudioNode(context) { }
 
 private:
     // TODO(tkent): Should AudioBasicInspectorNode override other variants of
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioBasicProcessorHandlerTest.cpp b/third_party/WebKit/Source/modules/webaudio/AudioBasicProcessorHandlerTest.cpp
index 535d1a1..3d6b926 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioBasicProcessorHandlerTest.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioBasicProcessorHandlerTest.cpp
@@ -27,7 +27,7 @@
 
 class MockProcessorNode final : public AudioNode {
 public:
-    MockProcessorNode(AbstractAudioContext& context)
+    MockProcessorNode(BaseAudioContext& context)
         : AudioNode(context)
     {
         setHandler(AudioBasicProcessorHandler::create(AudioHandler::NodeTypeWaveShaper, *this, 48000, wrapUnique(new MockAudioProcessor())));
@@ -43,7 +43,7 @@
     AudioBasicProcessorHandler& handler = static_cast<AudioBasicProcessorHandler&>(node->handler());
     EXPECT_TRUE(handler.processor());
     EXPECT_TRUE(handler.processor()->isInitialized());
-    AbstractAudioContext::AutoLocker locker(context);
+    BaseAudioContext::AutoLocker locker(context);
     handler.dispose();
     // The AudioProcessor should live after dispose() and should not be
     // finalized because an audio thread is using it.
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioBuffer.cpp b/third_party/WebKit/Source/modules/webaudio/AudioBuffer.cpp
index c171de6b..7fdeda0 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioBuffer.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioBuffer.cpp
@@ -31,7 +31,7 @@
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/ExceptionCode.h"
-#include "modules/webaudio/AbstractAudioContext.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "platform/audio/AudioBus.h"
 #include "platform/audio/AudioFileReader.h"
 #include "platform/audio/AudioUtilities.h"
@@ -41,7 +41,7 @@
 
 AudioBuffer* AudioBuffer::create(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
 {
-    if (!AudioUtilities::isValidAudioBufferSampleRate(sampleRate) || numberOfChannels > AbstractAudioContext::maxNumberOfChannels() || !numberOfChannels || !numberOfFrames)
+    if (!AudioUtilities::isValidAudioBufferSampleRate(sampleRate) || numberOfChannels > BaseAudioContext::maxNumberOfChannels() || !numberOfChannels || !numberOfFrames)
         return nullptr;
 
     AudioBuffer* buffer = new AudioBuffer(numberOfChannels, numberOfFrames, sampleRate);
@@ -53,7 +53,7 @@
 
 AudioBuffer* AudioBuffer::create(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionState& exceptionState)
 {
-    if (!numberOfChannels || numberOfChannels > AbstractAudioContext::maxNumberOfChannels()) {
+    if (!numberOfChannels || numberOfChannels > BaseAudioContext::maxNumberOfChannels()) {
         exceptionState.throwDOMException(
             NotSupportedError,
             ExceptionMessages::indexOutsideRange(
@@ -61,7 +61,7 @@
                 numberOfChannels,
                 1u,
                 ExceptionMessages::InclusiveBound,
-                AbstractAudioContext::maxNumberOfChannels(),
+                BaseAudioContext::maxNumberOfChannels(),
                 ExceptionMessages::InclusiveBound));
         return nullptr;
     }
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioBufferSourceNode.cpp b/third_party/WebKit/Source/modules/webaudio/AudioBufferSourceNode.cpp
index f660a33..bcdae9a 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioBufferSourceNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioBufferSourceNode.cpp
@@ -26,9 +26,9 @@
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/frame/UseCounter.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioBufferSourceNode.h"
 #include "modules/webaudio/AudioNodeOutput.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "platform/FloatConversion.h"
 #include "platform/audio/AudioUtilities.h"
 #include "wtf/MathExtras.h"
@@ -344,7 +344,7 @@
     }
 
     // The context must be locked since changing the buffer can re-configure the number of channels that are output.
-    AbstractAudioContext::AutoLocker contextLocker(context());
+    BaseAudioContext::AutoLocker contextLocker(context());
 
     // This synchronizes with process().
     MutexLocker processLocker(m_processLock);
@@ -355,7 +355,7 @@
 
         // This should not be possible since AudioBuffers can't be created with too many channels
         // either.
-        if (numberOfChannels > AbstractAudioContext::maxNumberOfChannels()) {
+        if (numberOfChannels > BaseAudioContext::maxNumberOfChannels()) {
             exceptionState.throwDOMException(
                 NotSupportedError,
                 ExceptionMessages::indexOutsideRange(
@@ -363,7 +363,7 @@
                     numberOfChannels,
                     1u,
                     ExceptionMessages::InclusiveBound,
-                    AbstractAudioContext::maxNumberOfChannels(),
+                    BaseAudioContext::maxNumberOfChannels(),
                     ExceptionMessages::InclusiveBound));
             return;
         }
@@ -508,9 +508,9 @@
 
 double AudioBufferSourceHandler::computePlaybackRate()
 {
-    // Incorporate buffer's sample-rate versus AbstractAudioContext's sample-rate.
+    // Incorporate buffer's sample-rate versus BaseAudioContext's sample-rate.
     // Normally it's not an issue because buffers are loaded at the
-    // AbstractAudioContext's sample-rate, but we can handle it in any case.
+    // BaseAudioContext's sample-rate, but we can handle it in any case.
     double sampleRateFactor = 1.0;
     if (buffer()) {
         // Use doubles to compute this to full accuracy.
@@ -584,7 +584,7 @@
 }
 
 // ----------------------------------------------------------------
-AudioBufferSourceNode::AudioBufferSourceNode(AbstractAudioContext& context)
+AudioBufferSourceNode::AudioBufferSourceNode(BaseAudioContext& context)
     : AudioScheduledSourceNode(context)
     , m_playbackRate(AudioParam::create(context, ParamTypeAudioBufferSourcePlaybackRate, 1.0))
     , m_detune(AudioParam::create(context, ParamTypeAudioBufferSourceDetune, 0.0))
@@ -596,7 +596,7 @@
         m_detune->handler()));
 }
 
-AudioBufferSourceNode* AudioBufferSourceNode::create(AbstractAudioContext& context, ExceptionState& exceptionState)
+AudioBufferSourceNode* AudioBufferSourceNode::create(BaseAudioContext& context, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioBufferSourceNode.h b/third_party/WebKit/Source/modules/webaudio/AudioBufferSourceNode.h
index 70de4a2..9f83f002 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioBufferSourceNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/AudioBufferSourceNode.h
@@ -37,7 +37,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 
 // AudioBufferSourceNode is an AudioNode representing an audio source from an in-memory audio asset represented by an AudioBuffer.
 // It generally will be used for short sounds which require a high degree of scheduling flexibility (can playback in rhythmically perfect ways).
@@ -141,7 +141,7 @@
 class AudioBufferSourceNode final : public AudioScheduledSourceNode {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static AudioBufferSourceNode* create(AbstractAudioContext&, ExceptionState&);
+    static AudioBufferSourceNode* create(BaseAudioContext&, ExceptionState&);
     DECLARE_VIRTUAL_TRACE();
     AudioBufferSourceHandler& audioBufferSourceHandler() const;
 
@@ -162,7 +162,7 @@
     void start(double when, double grainOffset, double grainDuration, ExceptionState&);
 
 private:
-    AudioBufferSourceNode(AbstractAudioContext&);
+    AudioBufferSourceNode(BaseAudioContext&);
 
     Member<AudioParam> m_playbackRate;
     Member<AudioParam> m_detune;
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioContext.cpp b/third_party/WebKit/Source/modules/webaudio/AudioContext.cpp
index 123d777..6e2f7a8 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioContext.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioContext.cpp
@@ -26,7 +26,7 @@
 static unsigned s_hardwareContextCount = 0;
 static unsigned s_contextId = 0;
 
-AbstractAudioContext* AudioContext::create(Document& document, ExceptionState& exceptionState)
+BaseAudioContext* AudioContext::create(Document& document, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
 
@@ -82,7 +82,7 @@
 }
 
 AudioContext::AudioContext(Document& document)
-    : AbstractAudioContext(&document)
+    : BaseAudioContext(&document)
     , m_contextId(s_contextId++)
 {
 }
@@ -97,7 +97,7 @@
 DEFINE_TRACE(AudioContext)
 {
     visitor->trace(m_closeResolver);
-    AbstractAudioContext::trace(visitor);
+    BaseAudioContext::trace(visitor);
 }
 
 ScriptPromise AudioContext::suspendContext(ScriptState* scriptState)
@@ -196,7 +196,7 @@
 
 bool AudioContext::isContextClosed() const
 {
-    return m_closeResolver || AbstractAudioContext::isContextClosed();
+    return m_closeResolver || BaseAudioContext::isContextClosed();
 }
 
 void AudioContext::stopRendering()
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioContext.h b/third_party/WebKit/Source/modules/webaudio/AudioContext.h
index 33fc7684..1dcda97e 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioContext.h
+++ b/third_party/WebKit/Source/modules/webaudio/AudioContext.h
@@ -7,7 +7,7 @@
 
 #include "bindings/core/v8/ScriptPromise.h"
 #include "bindings/core/v8/ScriptPromiseResolver.h"
-#include "modules/webaudio/AbstractAudioContext.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "platform/heap/Handle.h"
 
 namespace blink {
@@ -16,11 +16,11 @@
 class ExceptionState;
 class ScriptState;
 
-// This is an AbstractAudioContext which actually plays sound, unlike an
+// This is an BaseAudioContext which actually plays sound, unlike an
 // OfflineAudioContext which renders sound into a buffer.
-class AudioContext : public AbstractAudioContext {
+class AudioContext : public BaseAudioContext {
 public:
-    static AbstractAudioContext* create(Document&, ExceptionState&);
+    static BaseAudioContext* create(Document&, ExceptionState&);
 
     ~AudioContext() override;
     DECLARE_VIRTUAL_TRACE();
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioContext.idl b/third_party/WebKit/Source/modules/webaudio/AudioContext.idl
index aa56438..7b528c5 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioContext.idl
+++ b/third_party/WebKit/Source/modules/webaudio/AudioContext.idl
@@ -34,7 +34,7 @@
     Constructor,
     ConstructorCallWith=Document,
     DependentLifetime,
-    ImplementedAs=AbstractAudioContext,
+    ImplementedAs=BaseAudioContext,
     NoInterfaceObject,
     RaisesException=Constructor,
 ] interface AudioContext : EventTarget {
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioDestinationNode.cpp b/third_party/WebKit/Source/modules/webaudio/AudioDestinationNode.cpp
index f5eea24..b54d9b0 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioDestinationNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioDestinationNode.cpp
@@ -23,9 +23,9 @@
  */
 
 #include "modules/webaudio/AudioDestinationNode.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioNodeInput.h"
 #include "modules/webaudio/AudioNodeOutput.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "platform/audio/AudioUtilities.h"
 #include "platform/audio/DenormalDisabler.h"
 #include "wtf/Atomics.h"
@@ -107,7 +107,7 @@
 
 // ----------------------------------------------------------------
 
-AudioDestinationNode::AudioDestinationNode(AbstractAudioContext& context)
+AudioDestinationNode::AudioDestinationNode(BaseAudioContext& context)
     : AudioNode(context)
 {
 }
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioDestinationNode.h b/third_party/WebKit/Source/modules/webaudio/AudioDestinationNode.h
index a25e598b..2ecd418 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioDestinationNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/AudioDestinationNode.h
@@ -34,7 +34,7 @@
 namespace blink {
 
 class AudioBus;
-class AbstractAudioContext;
+class BaseAudioContext;
 
 class AudioDestinationHandler : public AudioHandler, public AudioIOCallback {
 public:
@@ -99,7 +99,7 @@
     unsigned long maxChannelCount() const;
 
 protected:
-    AudioDestinationNode(AbstractAudioContext&);
+    AudioDestinationNode(BaseAudioContext&);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioListener.cpp b/third_party/WebKit/Source/modules/webaudio/AudioListener.cpp
index 5badcca3..dacfa90 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioListener.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioListener.cpp
@@ -34,7 +34,7 @@
 
 namespace blink {
 
-AudioListener::AudioListener(AbstractAudioContext& context)
+AudioListener::AudioListener(BaseAudioContext& context)
     : m_positionX(AudioParam::create(context, ParamTypeAudioListenerPositionX, 0.0))
     , m_positionY(AudioParam::create(context, ParamTypeAudioListenerPositionY, 0.0))
     , m_positionZ(AudioParam::create(context, ParamTypeAudioListenerPositionZ, 0.0))
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioListener.h b/third_party/WebKit/Source/modules/webaudio/AudioListener.h
index 457090e..70ffad1 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioListener.h
+++ b/third_party/WebKit/Source/modules/webaudio/AudioListener.h
@@ -45,7 +45,7 @@
 class AudioListener : public GarbageCollectedFinalized<AudioListener>, public ScriptWrappable {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static AudioListener* create(AbstractAudioContext& context)
+    static AudioListener* create(BaseAudioContext& context)
     {
         return new AudioListener(context);
     }
@@ -143,7 +143,7 @@
     DECLARE_TRACE();
 
 private:
-    AudioListener(AbstractAudioContext&);
+    AudioListener(BaseAudioContext&);
 
     void setPosition(const FloatPoint3D&);
     void setOrientation(const FloatPoint3D&);
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioNode.cpp b/third_party/WebKit/Source/modules/webaudio/AudioNode.cpp
index bc6ccd61..bbcd5208 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioNode.cpp
@@ -26,10 +26,10 @@
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/inspector/InstanceCounters.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioNodeInput.h"
 #include "modules/webaudio/AudioNodeOutput.h"
 #include "modules/webaudio/AudioParam.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "wtf/Atomics.h"
 
 #if DEBUG_AUDIONODE_REFERENCES
@@ -110,7 +110,7 @@
     return m_node;
 }
 
-AbstractAudioContext* AudioHandler::context() const
+BaseAudioContext* AudioHandler::context() const
 {
     return m_context;
 }
@@ -208,9 +208,9 @@
 void AudioHandler::setChannelCount(unsigned long channelCount, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
-    if (channelCount > 0 && channelCount <= AbstractAudioContext::maxNumberOfChannels()) {
+    if (channelCount > 0 && channelCount <= BaseAudioContext::maxNumberOfChannels()) {
         if (m_channelCount != channelCount) {
             m_channelCount = channelCount;
             if (m_channelCountMode != Max)
@@ -224,7 +224,7 @@
                 channelCount,
                 1,
                 ExceptionMessages::InclusiveBound,
-                AbstractAudioContext::maxNumberOfChannels(),
+                BaseAudioContext::maxNumberOfChannels(),
                 ExceptionMessages::InclusiveBound));
     }
 }
@@ -246,7 +246,7 @@
 void AudioHandler::setChannelCountMode(const String& mode, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     ChannelCountMode oldMode = m_channelCountMode;
 
@@ -279,7 +279,7 @@
 void AudioHandler::setChannelInterpretation(const String& interpretation, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     AudioBus::ChannelInterpretation oldMode = m_channelInterpretation;
 
@@ -395,7 +395,7 @@
 {
     if (m_isDisabled && m_connectionRefCount > 0) {
         ASSERT(isMainThread());
-        AbstractAudioContext::AutoLocker locker(context());
+        BaseAudioContext::AutoLocker locker(context());
 
         m_isDisabled = false;
         for (auto& output : m_outputs)
@@ -527,7 +527,7 @@
 }
 // ----------------------------------------------------------------
 
-AudioNode::AudioNode(AbstractAudioContext& context)
+AudioNode::AudioNode(BaseAudioContext& context)
     : m_context(context)
     , m_handler(nullptr)
 {
@@ -537,9 +537,9 @@
 void AudioNode::dispose()
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
     handler().dispose();
-    if (context()->contextState() == AbstractAudioContext::Running)
+    if (context()->contextState() == BaseAudioContext::Running)
         context()->deferredTaskHandler().addRenderingOrphanHandler(m_handler.release());
 }
 
@@ -562,7 +562,7 @@
     EventTargetWithInlineData::trace(visitor);
 }
 
-AbstractAudioContext* AudioNode::context() const
+BaseAudioContext* AudioNode::context() const
 {
     return m_context;
 }
@@ -570,7 +570,7 @@
 AudioNode* AudioNode::connect(AudioNode* destination, unsigned outputIndex, unsigned inputIndex, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     if (context()->isContextClosed()) {
         exceptionState.throwDOMException(
@@ -632,7 +632,7 @@
 void AudioNode::connect(AudioParam* param, unsigned outputIndex, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     if (context()->isContextClosed()) {
         exceptionState.throwDOMException(
@@ -699,7 +699,7 @@
 void AudioNode::disconnect()
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     // Disconnect all outgoing connections.
     for (unsigned i = 0; i < numberOfOutputs(); ++i)
@@ -709,7 +709,7 @@
 void AudioNode::disconnect(unsigned outputIndex, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     // Sanity check on the output index.
     if (outputIndex >= numberOfOutputs()) {
@@ -731,7 +731,7 @@
 void AudioNode::disconnect(AudioNode* destination, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     unsigned numberOfDisconnections = 0;
 
@@ -756,7 +756,7 @@
 void AudioNode::disconnect(AudioNode* destination, unsigned outputIndex, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     if (outputIndex >= numberOfOutputs()) {
         // The output index is out of range. Throw an exception.
@@ -791,7 +791,7 @@
 void AudioNode::disconnect(AudioNode* destination, unsigned outputIndex, unsigned inputIndex, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     if (outputIndex >= numberOfOutputs()) {
         exceptionState.throwDOMException(
@@ -831,7 +831,7 @@
 void AudioNode::disconnect(AudioParam* destinationParam, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     // The number of disconnection made.
     unsigned numberOfDisconnections = 0;
@@ -855,7 +855,7 @@
 void AudioNode::disconnect(AudioParam* destinationParam, unsigned outputIndex, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     if (outputIndex >= handler().numberOfOutputs()) {
         // The output index is out of range. Throw an exception.
@@ -883,7 +883,7 @@
 void AudioNode::disconnectWithoutException(unsigned outputIndex)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     // Sanity check input and output indices.
     if (outputIndex >= handler().numberOfOutputs())
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioNode.h b/third_party/WebKit/Source/modules/webaudio/AudioNode.h
index 9d7fda8..2c12012 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/AudioNode.h
@@ -39,14 +39,14 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 class AudioNode;
 class AudioNodeInput;
 class AudioNodeOutput;
 class AudioParam;
 class ExceptionState;
 
-// An AudioNode is the basic building block for handling audio within an AbstractAudioContext.
+// An AudioNode is the basic building block for handling audio within an BaseAudioContext.
 // It may be an audio source, an intermediate processing module, or an audio destination.
 // Each AudioNode can have inputs and/or outputs. An AudioSourceNode has no inputs and a single output.
 // An AudioDestinationNode has one input and no outputs and represents the final destination to the audio hardware.
@@ -105,11 +105,11 @@
     // nullptr after dispose().  We must not call node() in an audio rendering
     // thread.
     AudioNode* node() const;
-    // context() returns a valid object until the AbstractAudioContext dies, and returns
+    // context() returns a valid object until the BaseAudioContext dies, and returns
     // nullptr otherwise.  This always returns a valid object in an audio
     // rendering thread, and inside dispose().  We must not call context() in
     // the destructor.
-    virtual AbstractAudioContext* context() const;
+    virtual BaseAudioContext* context() const;
     void clearContext() { m_context = nullptr; }
 
     enum ChannelCountMode {
@@ -245,10 +245,10 @@
     UntracedMember<AudioNode> m_node;
 
     // This untraced member is safe because this is cleared for all of live
-    // AudioHandlers when the AbstractAudioContext dies.  Do not access m_context
+    // AudioHandlers when the BaseAudioContext dies.  Do not access m_context
     // directly, use context() instead.
     // See http://crbug.com/404527 for the detail.
-    UntracedMember<AbstractAudioContext> m_context;
+    UntracedMember<BaseAudioContext> m_context;
 
     float m_sampleRate;
     Vector<std::unique_ptr<AudioNodeInput>> m_inputs;
@@ -295,7 +295,7 @@
     void disconnect(AudioNode*, unsigned outputIndex, unsigned inputIndex, ExceptionState&);
     void disconnect(AudioParam*, ExceptionState&);
     void disconnect(AudioParam*, unsigned outputIndex, ExceptionState&);
-    AbstractAudioContext* context() const;
+    BaseAudioContext* context() const;
     unsigned numberOfInputs() const;
     unsigned numberOfOutputs() const;
     unsigned long channelCount() const;
@@ -316,7 +316,7 @@
     void disconnectWithoutException(unsigned outputIndex);
 
 protected:
-    explicit AudioNode(AbstractAudioContext&);
+    explicit AudioNode(BaseAudioContext&);
     // This should be called in a constructor.
     void setHandler(PassRefPtr<AudioHandler>);
 
@@ -328,7 +328,7 @@
     // Returns true if the specified AudioParam was connected.
     bool disconnectFromOutputIfConnected(unsigned outputIndex, AudioParam&);
 
-    Member<AbstractAudioContext> m_context;
+    Member<BaseAudioContext> m_context;
     RefPtr<AudioHandler> m_handler;
     // Represents audio node graph with Oilpan references. N-th HeapHashSet
     // represents a set of AudioNode objects connected to this AudioNode's N-th
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioNodeOutput.cpp b/third_party/WebKit/Source/modules/webaudio/AudioNodeOutput.cpp
index ed17124..0a26595 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioNodeOutput.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioNodeOutput.cpp
@@ -22,9 +22,9 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioNodeInput.h"
 #include "modules/webaudio/AudioNodeOutput.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "wtf/PtrUtil.h"
 #include "wtf/Threading.h"
 #include <memory>
@@ -43,7 +43,7 @@
     , m_renderingFanOutCount(0)
     , m_renderingParamFanOutCount(0)
 {
-    ASSERT(numberOfChannels <= AbstractAudioContext::maxNumberOfChannels());
+    DCHECK_LE(numberOfChannels, BaseAudioContext::maxNumberOfChannels());
 
     m_internalBus = AudioBus::create(numberOfChannels, AudioHandler::ProcessingSizeInFrames);
 }
@@ -66,7 +66,7 @@
 
 void AudioNodeOutput::setNumberOfChannels(unsigned numberOfChannels)
 {
-    ASSERT(numberOfChannels <= AbstractAudioContext::maxNumberOfChannels());
+    DCHECK_LE(numberOfChannels, BaseAudioContext::maxNumberOfChannels());
     ASSERT(deferredTaskHandler().isGraphOwner());
 
     m_desiredNumberOfChannels = numberOfChannels;
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioParam.cpp b/third_party/WebKit/Source/modules/webaudio/AudioParam.cpp
index 892c6829..b92edfcd 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioParam.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioParam.cpp
@@ -39,7 +39,7 @@
 const double AudioParamHandler::DefaultSmoothingConstant = 0.05;
 const double AudioParamHandler::SnapThreshold = 0.001;
 
-AudioParamHandler::AudioParamHandler(AbstractAudioContext& context, AudioParamType paramType, double defaultValue, float minValue, float maxValue)
+AudioParamHandler::AudioParamHandler(BaseAudioContext& context, AudioParamType paramType, double defaultValue, float minValue, float maxValue)
     : AudioSummingJunction(context.deferredTaskHandler())
     , m_paramType(paramType)
     , m_intrinsicValue(defaultValue)
@@ -338,13 +338,13 @@
 
 // ----------------------------------------------------------------
 
-AudioParam::AudioParam(AbstractAudioContext& context, AudioParamType paramType, double defaultValue, float minValue, float maxValue)
+AudioParam::AudioParam(BaseAudioContext& context, AudioParamType paramType, double defaultValue, float minValue, float maxValue)
     : m_handler(AudioParamHandler::create(context, paramType, defaultValue, minValue, maxValue))
     , m_context(context)
 {
 }
 
-AudioParam* AudioParam::create(AbstractAudioContext& context, AudioParamType paramType, double defaultValue)
+AudioParam* AudioParam::create(BaseAudioContext& context, AudioParamType paramType, double defaultValue)
 {
     // Default nominal range is most negative float to most positive.  This basically means any
     // value is valid, except that floating-point infinities are excluded.
@@ -352,7 +352,7 @@
     return new AudioParam(context, paramType, defaultValue, -limit, limit);
 }
 
-AudioParam* AudioParam::create(AbstractAudioContext& context, AudioParamType paramType, double defaultValue, float minValue, float maxValue)
+AudioParam* AudioParam::create(BaseAudioContext& context, AudioParamType paramType, double defaultValue, float minValue, float maxValue)
 {
     DCHECK_LE(minValue, maxValue);
     return new AudioParam(context, paramType, defaultValue, minValue, maxValue);
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioParam.h b/third_party/WebKit/Source/modules/webaudio/AudioParam.h
index ebdc00bd..1afd6b33 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioParam.h
+++ b/third_party/WebKit/Source/modules/webaudio/AudioParam.h
@@ -31,9 +31,9 @@
 
 #include "bindings/core/v8/ScriptWrappable.h"
 #include "core/dom/DOMTypedArray.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioParamTimeline.h"
 #include "modules/webaudio/AudioSummingJunction.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "wtf/PassRefPtr.h"
 #include "wtf/ThreadSafeRefCounted.h"
 #include "wtf/text/WTFString.h"
@@ -100,7 +100,7 @@
     static const double SnapThreshold;
 
     static PassRefPtr<AudioParamHandler> create(
-        AbstractAudioContext& context,
+        BaseAudioContext& context,
         AudioParamType paramType,
         double defaultValue,
         float minValue,
@@ -157,7 +157,7 @@
     void updateHistograms(float newValue);
 
 private:
-    AudioParamHandler(AbstractAudioContext&, AudioParamType, double defaultValue, float min, float max);
+    AudioParamHandler(BaseAudioContext&, AudioParamType, double defaultValue, float min, float max);
 
     void warnIfOutsideRange(float value, float minValue, float maxValue);
 
@@ -191,14 +191,14 @@
 class AudioParam final : public GarbageCollectedFinalized<AudioParam>, public ScriptWrappable {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static AudioParam* create(AbstractAudioContext&, AudioParamType, double defaultValue);
-    static AudioParam* create(AbstractAudioContext&, AudioParamType, double defaultValue, float minValue, float maxValue);
+    static AudioParam* create(BaseAudioContext&, AudioParamType, double defaultValue);
+    static AudioParam* create(BaseAudioContext&, AudioParamType, double defaultValue, float minValue, float maxValue);
 
     DECLARE_TRACE();
     // |handler| always returns a valid object.
     AudioParamHandler& handler() const { return *m_handler; }
     // |context| always returns a valid object.
-    AbstractAudioContext* context() const { return m_context; }
+    BaseAudioContext* context() const { return m_context; }
 
     AudioParamType getParamType() const { return handler().getParamType(); }
     void setParamType(AudioParamType);
@@ -219,12 +219,12 @@
     AudioParam* cancelScheduledValues(double startTime, ExceptionState&);
 
 private:
-    AudioParam(AbstractAudioContext&, AudioParamType, double defaultValue, float min, float max);
+    AudioParam(BaseAudioContext&, AudioParamType, double defaultValue, float min, float max);
 
     void warnIfOutsideRange(const String& paramMethd, float value);
 
     RefPtr<AudioParamHandler> m_handler;
-    Member<AbstractAudioContext> m_context;
+    Member<BaseAudioContext> m_context;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.h b/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.h
index 4fee607..679ef89 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.h
+++ b/third_party/WebKit/Source/modules/webaudio/AudioParamTimeline.h
@@ -30,8 +30,8 @@
 #define AudioParamTimeline_h
 
 #include "core/dom/DOMTypedArray.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioDestinationNode.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "wtf/Forward.h"
 #include "wtf/Threading.h"
 #include "wtf/Vector.h"
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioScheduledSourceNode.cpp b/third_party/WebKit/Source/modules/webaudio/AudioScheduledSourceNode.cpp
index 8e479f5..10d92836 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioScheduledSourceNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioScheduledSourceNode.cpp
@@ -27,7 +27,7 @@
 #include "core/dom/CrossThreadTask.h"
 #include "core/dom/ExceptionCode.h"
 #include "modules/EventModules.h"
-#include "modules/webaudio/AbstractAudioContext.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "platform/audio/AudioUtilities.h"
 #include "wtf/MathExtras.h"
 #include <algorithm>
@@ -225,7 +225,7 @@
 
 // ----------------------------------------------------------------
 
-AudioScheduledSourceNode::AudioScheduledSourceNode(AbstractAudioContext& context)
+AudioScheduledSourceNode::AudioScheduledSourceNode(BaseAudioContext& context)
     : AudioSourceNode(context)
     , ActiveScriptWrappable(this)
 {
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioScheduledSourceNode.h b/third_party/WebKit/Source/modules/webaudio/AudioScheduledSourceNode.h
index 39c6d82..3b38e62 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioScheduledSourceNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/AudioScheduledSourceNode.h
@@ -34,7 +34,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 class AudioBus;
 
 class AudioScheduledSourceHandler : public AudioHandler {
@@ -138,7 +138,7 @@
     DEFINE_INLINE_VIRTUAL_TRACE() { AudioSourceNode::trace(visitor); }
 
 protected:
-    explicit AudioScheduledSourceNode(AbstractAudioContext&);
+    explicit AudioScheduledSourceNode(BaseAudioContext&);
     AudioScheduledSourceHandler& audioScheduledSourceHandler() const;
 };
 
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioSourceNode.h b/third_party/WebKit/Source/modules/webaudio/AudioSourceNode.h
index e0c9f39d..16628505 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioSourceNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/AudioSourceNode.h
@@ -33,12 +33,12 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 
 class AudioSourceNode : public AudioNode {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    AudioSourceNode(AbstractAudioContext& context)
+    AudioSourceNode(BaseAudioContext& context)
         : AudioNode(context) { }
 };
 
diff --git a/third_party/WebKit/Source/modules/webaudio/AbstractAudioContext.cpp b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
similarity index 75%
rename from third_party/WebKit/Source/modules/webaudio/AbstractAudioContext.cpp
rename to third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
index f3e0445..2ebf22d 100644
--- a/third_party/WebKit/Source/modules/webaudio/AbstractAudioContext.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
@@ -22,7 +22,7 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "modules/webaudio/AbstractAudioContext.h"
+#include "modules/webaudio/BaseAudioContext.h"
 
 #include "bindings/core/v8/Dictionary.h"
 #include "bindings/core/v8/ExceptionMessages.h"
@@ -87,7 +87,7 @@
 
 } // anonymous namespace
 
-AbstractAudioContext* AbstractAudioContext::create(Document& document, ExceptionState& exceptionState)
+BaseAudioContext* BaseAudioContext::create(Document& document, ExceptionState& exceptionState)
 {
     return AudioContext::create(document, exceptionState);
 }
@@ -96,7 +96,7 @@
 // and OfflineAudioContext respectively.
 
 // Constructor for rendering to the audio hardware.
-AbstractAudioContext::AbstractAudioContext(Document* document)
+BaseAudioContext::BaseAudioContext(Document* document)
     : ActiveScriptWrappable(this)
     , ActiveDOMObject(document)
     , m_destinationNode(nullptr)
@@ -124,7 +124,7 @@
 }
 
 // Constructor for offline (non-realtime) rendering.
-AbstractAudioContext::AbstractAudioContext(Document* document, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
+BaseAudioContext::BaseAudioContext(Document* document, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
     : ActiveScriptWrappable(this)
     , ActiveDOMObject(document)
     , m_destinationNode(nullptr)
@@ -147,18 +147,18 @@
         m_userGestureRequired = true;
 }
 
-AbstractAudioContext::~AbstractAudioContext()
+BaseAudioContext::~BaseAudioContext()
 {
     deferredTaskHandler().contextWillBeDestroyed();
     // AudioNodes keep a reference to their context, so there should be no way to be in the destructor if there are still AudioNodes around.
-    ASSERT(!isDestinationInitialized());
-    ASSERT(!m_activeSourceNodes.size());
-    ASSERT(!m_finishedSourceHandlers.size());
-    ASSERT(!m_isResolvingResumePromises);
-    ASSERT(!m_resumeResolvers.size());
+    DCHECK(!isDestinationInitialized());
+    DCHECK(!m_activeSourceNodes.size());
+    DCHECK(!m_finishedSourceHandlers.size());
+    DCHECK(!m_isResolvingResumePromises);
+    DCHECK(!m_resumeResolvers.size());
 }
 
-void AbstractAudioContext::initialize()
+void BaseAudioContext::initialize()
 {
     if (isDestinationInitialized())
         return;
@@ -173,7 +173,7 @@
     }
 }
 
-void AbstractAudioContext::clear()
+void BaseAudioContext::clear()
 {
     m_destinationNode.clear();
     // The audio rendering thread is dead.  Nobody will schedule AudioHandler
@@ -182,9 +182,9 @@
     m_isCleared = true;
 }
 
-void AbstractAudioContext::uninitialize()
+void BaseAudioContext::uninitialize()
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     if (!isDestinationInitialized())
         return;
@@ -200,37 +200,37 @@
     rejectPendingResolvers();
     didClose();
 
-    ASSERT(m_listener);
+    DCHECK(m_listener);
     m_listener->waitForHRTFDatabaseLoaderThreadCompletion();
 
     clear();
 }
 
-void AbstractAudioContext::stop()
+void BaseAudioContext::stop()
 {
     uninitialize();
 }
 
-bool AbstractAudioContext::hasPendingActivity() const
+bool BaseAudioContext::hasPendingActivity() const
 {
     // There's no pending activity if the audio context has been cleared.
     return !m_isCleared;
 }
 
-AudioDestinationNode* AbstractAudioContext::destination() const
+AudioDestinationNode* BaseAudioContext::destination() const
 {
     // Cannot be called from the audio thread because this method touches objects managed by Oilpan,
     // and the audio thread is not managed by Oilpan.
-    ASSERT(!isAudioThread());
+    DCHECK(!isAudioThread());
     return m_destinationNode;
 }
 
-void AbstractAudioContext::throwExceptionForClosedState(ExceptionState& exceptionState)
+void BaseAudioContext::throwExceptionForClosedState(ExceptionState& exceptionState)
 {
     exceptionState.throwDOMException(InvalidStateError, "AudioContext has been closed.");
 }
 
-AudioBuffer* AbstractAudioContext::createBuffer(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionState& exceptionState)
+AudioBuffer* BaseAudioContext::createBuffer(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionState& exceptionState)
 {
     // It's ok to call createBuffer, even if the context is closed because the AudioBuffer doesn't
     // really "belong" to any particular context.
@@ -278,17 +278,17 @@
     return buffer;
 }
 
-ScriptPromise AbstractAudioContext::decodeAudioData(ScriptState* scriptState, DOMArrayBuffer* audioData, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, ExceptionState& exceptionState)
+ScriptPromise BaseAudioContext::decodeAudioData(ScriptState* scriptState, DOMArrayBuffer* audioData, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback, ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
-    ASSERT(audioData);
+    DCHECK(isMainThread());
+    DCHECK(audioData);
 
     ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
     ScriptPromise promise = resolver->promise();
 
     float rate = isContextClosed() ? closedContextSampleRate() : sampleRate();
 
-    ASSERT(rate > 0);
+    DCHECK_GT(rate, 0);
 
     m_decodeAudioResolvers.add(resolver);
     m_audioDecoder.decodeAsync(audioData, rate, successCallback, errorCallback, resolver, this);
@@ -296,9 +296,9 @@
     return promise;
 }
 
-void AbstractAudioContext::handleDecodeAudioData(AudioBuffer* audioBuffer, ScriptPromiseResolver* resolver, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback)
+void BaseAudioContext::handleDecodeAudioData(AudioBuffer* audioBuffer, ScriptPromiseResolver* resolver, AudioBufferCallback* successCallback, AudioBufferCallback* errorCallback)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     if (audioBuffer) {
         // Resolve promise successfully and run the success callback
@@ -314,13 +314,13 @@
     }
 
     // We've resolved the promise.  Remove it now.
-    ASSERT(m_decodeAudioResolvers.contains(resolver));
+    DCHECK(m_decodeAudioResolvers.contains(resolver));
     m_decodeAudioResolvers.remove(resolver);
 }
 
-AudioBufferSourceNode* AbstractAudioContext::createBufferSource(ExceptionState& exceptionState)
+AudioBufferSourceNode* BaseAudioContext::createBufferSource(ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     AudioBufferSourceNode* node = AudioBufferSourceNode::create(*this, exceptionState);
 
@@ -330,21 +330,21 @@
     return node;
 }
 
-MediaElementAudioSourceNode* AbstractAudioContext::createMediaElementSource(HTMLMediaElement* mediaElement, ExceptionState& exceptionState)
+MediaElementAudioSourceNode* BaseAudioContext::createMediaElementSource(HTMLMediaElement* mediaElement, ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     return MediaElementAudioSourceNode::create(*this, *mediaElement, exceptionState);
 }
 
-MediaStreamAudioSourceNode* AbstractAudioContext::createMediaStreamSource(MediaStream* mediaStream, ExceptionState& exceptionState)
+MediaStreamAudioSourceNode* BaseAudioContext::createMediaStreamSource(MediaStream* mediaStream, ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     return MediaStreamAudioSourceNode::create(*this, *mediaStream, exceptionState);
 }
 
-MediaStreamAudioDestinationNode* AbstractAudioContext::createMediaStreamDestination(ExceptionState& exceptionState)
+MediaStreamAudioDestinationNode* BaseAudioContext::createMediaStreamDestination(ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
@@ -352,30 +352,30 @@
     return MediaStreamAudioDestinationNode::create(*this, 2, exceptionState);
 }
 
-ScriptProcessorNode* AbstractAudioContext::createScriptProcessor(ExceptionState& exceptionState)
+ScriptProcessorNode* BaseAudioContext::createScriptProcessor(ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
     return ScriptProcessorNode::create(*this, exceptionState);
 }
 
-ScriptProcessorNode* AbstractAudioContext::createScriptProcessor(size_t bufferSize, ExceptionState& exceptionState)
+ScriptProcessorNode* BaseAudioContext::createScriptProcessor(size_t bufferSize, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
     return ScriptProcessorNode::create(*this, bufferSize, exceptionState);
 }
 
-ScriptProcessorNode* AbstractAudioContext::createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, ExceptionState& exceptionState)
+ScriptProcessorNode* BaseAudioContext::createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
     return ScriptProcessorNode::create(*this, bufferSize, numberOfInputChannels, exceptionState);
 }
 
-ScriptProcessorNode* AbstractAudioContext::createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, size_t numberOfOutputChannels, ExceptionState& exceptionState)
+ScriptProcessorNode* BaseAudioContext::createScriptProcessor(size_t bufferSize, size_t numberOfInputChannels, size_t numberOfOutputChannels, ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     return ScriptProcessorNode::create(
         *this,
@@ -385,135 +385,135 @@
         exceptionState);
 }
 
-StereoPannerNode* AbstractAudioContext::createStereoPanner(ExceptionState& exceptionState)
+StereoPannerNode* BaseAudioContext::createStereoPanner(ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     return StereoPannerNode::create(*this, exceptionState);
 }
 
-BiquadFilterNode* AbstractAudioContext::createBiquadFilter(ExceptionState& exceptionState)
+BiquadFilterNode* BaseAudioContext::createBiquadFilter(ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     return BiquadFilterNode::create(*this, exceptionState);
 }
 
-WaveShaperNode* AbstractAudioContext::createWaveShaper(ExceptionState& exceptionState)
+WaveShaperNode* BaseAudioContext::createWaveShaper(ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     return WaveShaperNode::create(*this, exceptionState);
 }
 
-PannerNode* AbstractAudioContext::createPanner(ExceptionState& exceptionState)
+PannerNode* BaseAudioContext::createPanner(ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     return PannerNode::create(*this, exceptionState);
 }
 
-ConvolverNode* AbstractAudioContext::createConvolver(ExceptionState& exceptionState)
+ConvolverNode* BaseAudioContext::createConvolver(ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     return ConvolverNode::create(*this, exceptionState);
 }
 
-DynamicsCompressorNode* AbstractAudioContext::createDynamicsCompressor(ExceptionState& exceptionState)
+DynamicsCompressorNode* BaseAudioContext::createDynamicsCompressor(ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     return DynamicsCompressorNode::create(*this, exceptionState);
 }
 
-AnalyserNode* AbstractAudioContext::createAnalyser(ExceptionState& exceptionState)
+AnalyserNode* BaseAudioContext::createAnalyser(ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     return AnalyserNode::create(*this, exceptionState);
 }
 
-GainNode* AbstractAudioContext::createGain(ExceptionState& exceptionState)
+GainNode* BaseAudioContext::createGain(ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     return GainNode::create(*this, exceptionState);
 }
 
-DelayNode* AbstractAudioContext::createDelay(ExceptionState& exceptionState)
+DelayNode* BaseAudioContext::createDelay(ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
     return DelayNode::create(*this, exceptionState);
 }
 
-DelayNode* AbstractAudioContext::createDelay(double maxDelayTime, ExceptionState& exceptionState)
+DelayNode* BaseAudioContext::createDelay(double maxDelayTime, ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     return DelayNode::create(*this, maxDelayTime, exceptionState);
 }
 
-ChannelSplitterNode* AbstractAudioContext::createChannelSplitter(ExceptionState& exceptionState)
+ChannelSplitterNode* BaseAudioContext::createChannelSplitter(ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
     return ChannelSplitterNode::create(*this, exceptionState);
 }
 
-ChannelSplitterNode* AbstractAudioContext::createChannelSplitter(size_t numberOfOutputs, ExceptionState& exceptionState)
+ChannelSplitterNode* BaseAudioContext::createChannelSplitter(size_t numberOfOutputs, ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     return ChannelSplitterNode::create(*this, numberOfOutputs, exceptionState);
 }
 
-ChannelMergerNode* AbstractAudioContext::createChannelMerger(ExceptionState& exceptionState)
+ChannelMergerNode* BaseAudioContext::createChannelMerger(ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
     return ChannelMergerNode::create(*this, exceptionState);
 }
 
-ChannelMergerNode* AbstractAudioContext::createChannelMerger(size_t numberOfInputs, ExceptionState& exceptionState)
+ChannelMergerNode* BaseAudioContext::createChannelMerger(size_t numberOfInputs, ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     return ChannelMergerNode::create(*this, numberOfInputs, exceptionState);
 }
 
-OscillatorNode* AbstractAudioContext::createOscillator(ExceptionState& exceptionState)
+OscillatorNode* BaseAudioContext::createOscillator(ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     return OscillatorNode::create(*this, exceptionState);
 }
 
-PeriodicWave* AbstractAudioContext::createPeriodicWave(DOMFloat32Array* real, DOMFloat32Array* imag, ExceptionState& exceptionState)
+PeriodicWave* BaseAudioContext::createPeriodicWave(DOMFloat32Array* real, DOMFloat32Array* imag, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
     return PeriodicWave::create(*this, real, imag, false, exceptionState);
 }
 
-PeriodicWave* AbstractAudioContext::createPeriodicWave(DOMFloat32Array* real, DOMFloat32Array* imag, const PeriodicWaveConstraints& options, ExceptionState& exceptionState)
+PeriodicWave* BaseAudioContext::createPeriodicWave(DOMFloat32Array* real, DOMFloat32Array* imag, const PeriodicWaveConstraints& options, ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     bool disable = options.hasDisableNormalization() ? options.disableNormalization() : false;
 
     return PeriodicWave::create(*this, real, imag, disable, exceptionState);
 }
 
-IIRFilterNode* AbstractAudioContext::createIIRFilter(Vector<double> feedforwardCoef, Vector<double> feedbackCoef,  ExceptionState& exceptionState)
+IIRFilterNode* BaseAudioContext::createIIRFilter(Vector<double> feedforwardCoef, Vector<double> feedbackCoef,  ExceptionState& exceptionState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     return IIRFilterNode::create(*this, feedforwardCoef, feedbackCoef, exceptionState);
 }
 
-PeriodicWave* AbstractAudioContext::periodicWave(int type)
+PeriodicWave* BaseAudioContext::periodicWave(int type)
 {
     switch (type) {
     case OscillatorHandler::SINE:
@@ -537,12 +537,12 @@
             m_periodicWaveTriangle = PeriodicWave::createTriangle(sampleRate());
         return m_periodicWaveTriangle;
     default:
-        ASSERT_NOT_REACHED();
+        NOTREACHED();
         return nullptr;
     }
 }
 
-void AbstractAudioContext::recordUserGestureState()
+void BaseAudioContext::recordUserGestureState()
 {
     DEFINE_STATIC_LOCAL(EnumerationHistogram, userGestureHistogram, ("WebAudio.UserGesture", UserGestureRecordMax));
 
@@ -561,7 +561,7 @@
     m_userGestureRequired = false;
 }
 
-String AbstractAudioContext::state() const
+String BaseAudioContext::state() const
 {
     // These strings had better match the strings for AudioContextState in AudioContext.idl.
     switch (m_contextState) {
@@ -572,25 +572,25 @@
     case Closed:
         return "closed";
     }
-    ASSERT_NOT_REACHED();
+    NOTREACHED();
     return "";
 }
 
-void AbstractAudioContext::setContextState(AudioContextState newState)
+void BaseAudioContext::setContextState(AudioContextState newState)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     // Validate the transitions.  The valid transitions are Suspended->Running, Running->Suspended,
     // and anything->Closed.
     switch (newState) {
     case Suspended:
-        ASSERT(m_contextState == Running);
+        DCHECK_EQ(m_contextState, Running);
         break;
     case Running:
-        ASSERT(m_contextState == Suspended);
+        DCHECK_EQ(m_contextState, Suspended);
         break;
     case Closed:
-        ASSERT(m_contextState != Closed);
+        DCHECK_NE(m_contextState, Closed);
         break;
     }
 
@@ -603,23 +603,23 @@
 
     // Notify context that state changed
     if (getExecutionContext())
-        getExecutionContext()->postTask(BLINK_FROM_HERE, createSameThreadTask(&AbstractAudioContext::notifyStateChange, wrapPersistent(this)));
+        getExecutionContext()->postTask(BLINK_FROM_HERE, createSameThreadTask(&BaseAudioContext::notifyStateChange, wrapPersistent(this)));
 }
 
-void AbstractAudioContext::notifyStateChange()
+void BaseAudioContext::notifyStateChange()
 {
     dispatchEvent(Event::create(EventTypeNames::statechange));
 }
 
-void AbstractAudioContext::notifySourceNodeFinishedProcessing(AudioHandler* handler)
+void BaseAudioContext::notifySourceNodeFinishedProcessing(AudioHandler* handler)
 {
-    ASSERT(isAudioThread());
+    DCHECK(isAudioThread());
     m_finishedSourceHandlers.append(handler);
 }
 
-void AbstractAudioContext::removeFinishedSourceNodes()
+void BaseAudioContext::removeFinishedSourceNodes()
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
     AutoLocker locker(this);
     // Quadratic worst case, but sizes of both vectors are considered
     // manageable, especially |m_finishedSourceNodes| is likely to be short.
@@ -631,10 +631,10 @@
     m_finishedSourceNodes.clear();
 }
 
-void AbstractAudioContext::releaseFinishedSourceNodes()
+void BaseAudioContext::releaseFinishedSourceNodes()
 {
     ASSERT(isGraphOwner());
-    ASSERT(isAudioThread());
+    DCHECK(isAudioThread());
     bool didRemove = false;
     for (AudioHandler* handler : m_finishedSourceHandlers) {
         for (AudioNode* node : m_activeSourceNodes) {
@@ -649,30 +649,30 @@
         }
     }
     if (didRemove)
-        Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_HERE, crossThreadBind(&AbstractAudioContext::removeFinishedSourceNodes, wrapCrossThreadPersistent(this)));
+        Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_HERE, crossThreadBind(&BaseAudioContext::removeFinishedSourceNodes, wrapCrossThreadPersistent(this)));
 
     m_finishedSourceHandlers.clear();
 }
 
-void AbstractAudioContext::notifySourceNodeStartedProcessing(AudioNode* node)
+void BaseAudioContext::notifySourceNodeStartedProcessing(AudioNode* node)
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
     AutoLocker locker(this);
 
     m_activeSourceNodes.append(node);
     node->handler().makeConnection();
 }
 
-void AbstractAudioContext::releaseActiveSourceNodes()
+void BaseAudioContext::releaseActiveSourceNodes()
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
     for (auto& sourceNode : m_activeSourceNodes)
         sourceNode->handler().breakConnection();
 
     m_activeSourceNodes.clear();
 }
 
-void AbstractAudioContext::handleStoppableSourceNodes()
+void BaseAudioContext::handleStoppableSourceNodes()
 {
     ASSERT(isGraphOwner());
 
@@ -691,9 +691,9 @@
     }
 }
 
-void AbstractAudioContext::handlePreRenderTasks()
+void BaseAudioContext::handlePreRenderTasks()
 {
-    ASSERT(isAudioThread());
+    DCHECK(isAudioThread());
 
     // At the beginning of every render quantum, try to update the internal rendering graph state (from main thread changes).
     // It's OK if the tryLock() fails, we'll just take slightly longer to pick up the changes.
@@ -712,9 +712,9 @@
     }
 }
 
-void AbstractAudioContext::handlePostRenderTasks()
+void BaseAudioContext::handlePostRenderTasks()
 {
-    ASSERT(isAudioThread());
+    DCHECK(isAudioThread());
 
     // Must use a tryLock() here too.  Don't worry, the lock will very rarely be contended and this method is called frequently.
     // The worst that can happen is that there will be some nodes which will take slightly longer than usual to be deleted or removed
@@ -733,9 +733,9 @@
     }
 }
 
-void AbstractAudioContext::resolvePromisesForResumeOnMainThread()
+void BaseAudioContext::resolvePromisesForResumeOnMainThread()
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
     AutoLocker locker(this);
 
     for (auto& resolver : m_resumeResolvers) {
@@ -751,10 +751,10 @@
     m_isResolvingResumePromises = false;
 }
 
-void AbstractAudioContext::resolvePromisesForResume()
+void BaseAudioContext::resolvePromisesForResume()
 {
-    // This runs inside the AbstractAudioContext's lock when handling pre-render tasks.
-    ASSERT(isAudioThread());
+    // This runs inside the BaseAudioContext's lock when handling pre-render tasks.
+    DCHECK(isAudioThread());
     ASSERT(isGraphOwner());
 
     // Resolve any pending promises created by resume(). Only do this if we haven't already started
@@ -762,11 +762,11 @@
     // promises in the main thread.
     if (!m_isResolvingResumePromises && m_resumeResolvers.size() > 0) {
         m_isResolvingResumePromises = true;
-        Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_HERE, crossThreadBind(&AbstractAudioContext::resolvePromisesForResumeOnMainThread, wrapCrossThreadPersistent(this)));
+        Platform::current()->mainThread()->getWebTaskRunner()->postTask(BLINK_FROM_HERE, crossThreadBind(&BaseAudioContext::resolvePromisesForResumeOnMainThread, wrapCrossThreadPersistent(this)));
     }
 }
 
-void AbstractAudioContext::rejectPendingDecodeAudioDataResolvers()
+void BaseAudioContext::rejectPendingDecodeAudioDataResolvers()
 {
     // Now reject any pending decodeAudioData resolvers
     for (auto& resolver : m_decodeAudioResolvers)
@@ -774,9 +774,9 @@
     m_decodeAudioResolvers.clear();
 }
 
-void AbstractAudioContext::rejectPendingResolvers()
+void BaseAudioContext::rejectPendingResolvers()
 {
-    ASSERT(isMainThread());
+    DCHECK(isMainThread());
 
     // Audio context is closing down so reject any resume promises that are still pending.
 
@@ -789,21 +789,21 @@
     rejectPendingDecodeAudioDataResolvers();
 }
 
-const AtomicString& AbstractAudioContext::interfaceName() const
+const AtomicString& BaseAudioContext::interfaceName() const
 {
     return EventTargetNames::AudioContext;
 }
 
-ExecutionContext* AbstractAudioContext::getExecutionContext() const
+ExecutionContext* BaseAudioContext::getExecutionContext() const
 {
     return ActiveDOMObject::getExecutionContext();
 }
 
-void AbstractAudioContext::startRendering()
+void BaseAudioContext::startRendering()
 {
     // This is called for both online and offline contexts.
-    ASSERT(isMainThread());
-    ASSERT(m_destinationNode);
+    DCHECK(isMainThread());
+    DCHECK(m_destinationNode);
 
     recordUserGestureState();
 
@@ -813,7 +813,7 @@
     }
 }
 
-DEFINE_TRACE(AbstractAudioContext)
+DEFINE_TRACE(BaseAudioContext)
 {
     visitor->trace(m_destinationNode);
     visitor->trace(m_listener);
@@ -829,7 +829,7 @@
     ActiveDOMObject::trace(visitor);
 }
 
-SecurityOrigin* AbstractAudioContext::getSecurityOrigin() const
+SecurityOrigin* BaseAudioContext::getSecurityOrigin() const
 {
     if (getExecutionContext())
         return getExecutionContext()->getSecurityOrigin();
diff --git a/third_party/WebKit/Source/modules/webaudio/AbstractAudioContext.h b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.h
similarity index 95%
rename from third_party/WebKit/Source/modules/webaudio/AbstractAudioContext.h
rename to third_party/WebKit/Source/modules/webaudio/BaseAudioContext.h
index 942b7ff..585dec1 100644
--- a/third_party/WebKit/Source/modules/webaudio/AbstractAudioContext.h
+++ b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.h
@@ -22,8 +22,8 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef AbstractAudioContext_h
-#define AbstractAudioContext_h
+#ifndef BaseAudioContext_h
+#define BaseAudioContext_h
 
 #include "bindings/core/v8/ActiveScriptWrappable.h"
 #include "bindings/core/v8/ScriptPromise.h"
@@ -79,11 +79,11 @@
 class StereoPannerNode;
 class WaveShaperNode;
 
-// AbstractAudioContext is the cornerstone of the web audio API and all AudioNodes are created from it.
+// BaseAudioContext is the cornerstone of the web audio API and all AudioNodes are created from it.
 // For thread safety between the audio thread and the main thread, it has a rendering graph locking mechanism.
 
-class MODULES_EXPORT AbstractAudioContext : public EventTargetWithInlineData, public ActiveScriptWrappable, public ActiveDOMObject {
-    USING_GARBAGE_COLLECTED_MIXIN(AbstractAudioContext);
+class MODULES_EXPORT BaseAudioContext : public EventTargetWithInlineData, public ActiveScriptWrappable, public ActiveDOMObject {
+    USING_GARBAGE_COLLECTED_MIXIN(BaseAudioContext);
     DEFINE_WRAPPERTYPEINFO();
 public:
     // The state of an audio context.  On creation, the state is Suspended. The state is Running if
@@ -97,9 +97,9 @@
     };
 
     // Create an AudioContext for rendering to the audio hardware.
-    static AbstractAudioContext* create(Document&, ExceptionState&);
+    static BaseAudioContext* create(Document&, ExceptionState&);
 
-    ~AbstractAudioContext() override;
+    ~BaseAudioContext() override;
 
     DECLARE_VIRTUAL_TRACE();
 
@@ -216,7 +216,7 @@
     // Keeps track of the number of connections made.
     void incrementConnectionCount()
     {
-        ASSERT(isMainThread());
+        DCHECK(isMainThread());
         m_connectionCount++;
     }
 
@@ -268,8 +268,8 @@
     void recordUserGestureState();
 
 protected:
-    explicit AbstractAudioContext(Document*);
-    AbstractAudioContext(Document*, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate);
+    explicit BaseAudioContext(Document*);
+    BaseAudioContext(Document*, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate);
 
     void initialize();
     void uninitialize();
@@ -350,7 +350,7 @@
     // Graph locking.
     RefPtr<DeferredTaskHandler> m_deferredTaskHandler;
 
-    // The state of the AbstractAudioContext.
+    // The state of the BaseAudioContext.
     AudioContextState m_contextState;
 
     AsyncAudioDecoder m_audioDecoder;
@@ -379,4 +379,4 @@
 
 } // namespace blink
 
-#endif // AbstractAudioContext_h
+#endif // BaseAudioContext_h
diff --git a/third_party/WebKit/Source/modules/webaudio/BiquadFilterNode.cpp b/third_party/WebKit/Source/modules/webaudio/BiquadFilterNode.cpp
index 7053583..8daf32d 100644
--- a/third_party/WebKit/Source/modules/webaudio/BiquadFilterNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/BiquadFilterNode.cpp
@@ -30,7 +30,7 @@
 
 namespace blink {
 
-BiquadFilterNode::BiquadFilterNode(AbstractAudioContext& context)
+BiquadFilterNode::BiquadFilterNode(BaseAudioContext& context)
     : AudioNode(context)
     , m_frequency(AudioParam::create(context, ParamTypeBiquadFilterFrequency, 350.0, 0, context.sampleRate() / 2))
     , m_q(AudioParam::create(context, ParamTypeBiquadFilterQ, 1.0))
@@ -54,7 +54,7 @@
     setType("lowpass");
 }
 
-BiquadFilterNode* BiquadFilterNode::create(AbstractAudioContext& context, ExceptionState& exceptionState)
+BiquadFilterNode* BiquadFilterNode::create(BaseAudioContext& context, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
diff --git a/third_party/WebKit/Source/modules/webaudio/BiquadFilterNode.h b/third_party/WebKit/Source/modules/webaudio/BiquadFilterNode.h
index f75c80c..96a56e5 100644
--- a/third_party/WebKit/Source/modules/webaudio/BiquadFilterNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/BiquadFilterNode.h
@@ -31,7 +31,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 class AudioParam;
 
 class BiquadFilterNode final : public AudioNode {
@@ -49,7 +49,7 @@
         ALLPASS = 7
     };
 
-    static BiquadFilterNode* create(AbstractAudioContext&, ExceptionState&);
+    static BiquadFilterNode* create(BaseAudioContext&, ExceptionState&);
 
     DECLARE_VIRTUAL_TRACE();
 
@@ -66,7 +66,7 @@
     void getFrequencyResponse(const DOMFloat32Array* frequencyHz, DOMFloat32Array* magResponse, DOMFloat32Array* phaseResponse);
 
 private:
-    BiquadFilterNode(AbstractAudioContext&);
+    BiquadFilterNode(BaseAudioContext&);
 
     BiquadProcessor* getBiquadProcessor() const;
     bool setType(unsigned); // Returns true on success.
diff --git a/third_party/WebKit/Source/modules/webaudio/ChannelMergerNode.cpp b/third_party/WebKit/Source/modules/webaudio/ChannelMergerNode.cpp
index ecdecdb..c19aad8 100644
--- a/third_party/WebKit/Source/modules/webaudio/ChannelMergerNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/ChannelMergerNode.cpp
@@ -31,9 +31,9 @@
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/ExecutionContext.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioNodeInput.h"
 #include "modules/webaudio/AudioNodeOutput.h"
+#include "modules/webaudio/BaseAudioContext.h"
 
 
 namespace blink {
@@ -94,7 +94,7 @@
 void ChannelMergerHandler::setChannelCount(unsigned long channelCount, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     // channelCount must be 1.
     if (channelCount != 1) {
@@ -107,7 +107,7 @@
 void ChannelMergerHandler::setChannelCountMode(const String& mode, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     // channcelCountMode must be 'explicit'.
     if (mode != "explicit") {
@@ -119,13 +119,13 @@
 
 // ----------------------------------------------------------------
 
-ChannelMergerNode::ChannelMergerNode(AbstractAudioContext& context, unsigned numberOfInputs)
+ChannelMergerNode::ChannelMergerNode(BaseAudioContext& context, unsigned numberOfInputs)
     : AudioNode(context)
 {
     setHandler(ChannelMergerHandler::create(*this, context.sampleRate(), numberOfInputs));
 }
 
-ChannelMergerNode* ChannelMergerNode::create(AbstractAudioContext& context, ExceptionState& exceptionState)
+ChannelMergerNode* ChannelMergerNode::create(BaseAudioContext& context, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
@@ -133,7 +133,7 @@
     return create(context, 6, exceptionState);
 }
 
-ChannelMergerNode* ChannelMergerNode::create(AbstractAudioContext& context, unsigned numberOfInputs, ExceptionState& exceptionState)
+ChannelMergerNode* ChannelMergerNode::create(BaseAudioContext& context, unsigned numberOfInputs, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
@@ -142,7 +142,7 @@
         return nullptr;
     }
 
-    if (!numberOfInputs || numberOfInputs > AbstractAudioContext::maxNumberOfChannels()) {
+    if (!numberOfInputs || numberOfInputs > BaseAudioContext::maxNumberOfChannels()) {
         exceptionState.throwDOMException(
             IndexSizeError,
             ExceptionMessages::indexOutsideRange<size_t>(
@@ -150,7 +150,7 @@
                 numberOfInputs,
                 1,
                 ExceptionMessages::InclusiveBound,
-                AbstractAudioContext::maxNumberOfChannels(),
+                BaseAudioContext::maxNumberOfChannels(),
                 ExceptionMessages::InclusiveBound));
         return nullptr;
     }
diff --git a/third_party/WebKit/Source/modules/webaudio/ChannelMergerNode.h b/third_party/WebKit/Source/modules/webaudio/ChannelMergerNode.h
index 009ba99..2a76ce2 100644
--- a/third_party/WebKit/Source/modules/webaudio/ChannelMergerNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/ChannelMergerNode.h
@@ -34,7 +34,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 
 class ChannelMergerHandler final : public AudioHandler {
 public:
@@ -51,11 +51,11 @@
 class ChannelMergerNode final : public AudioNode {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static ChannelMergerNode* create(AbstractAudioContext&, ExceptionState&);
-    static ChannelMergerNode* create(AbstractAudioContext&, unsigned numberOfInputs, ExceptionState&);
+    static ChannelMergerNode* create(BaseAudioContext&, ExceptionState&);
+    static ChannelMergerNode* create(BaseAudioContext&, unsigned numberOfInputs, ExceptionState&);
 
 private:
-    ChannelMergerNode(AbstractAudioContext&, unsigned numberOfInputs);
+    ChannelMergerNode(BaseAudioContext&, unsigned numberOfInputs);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/ChannelSplitterNode.cpp b/third_party/WebKit/Source/modules/webaudio/ChannelSplitterNode.cpp
index 0b6d715..b4c87c43 100644
--- a/third_party/WebKit/Source/modules/webaudio/ChannelSplitterNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/ChannelSplitterNode.cpp
@@ -26,9 +26,9 @@
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/ExceptionCode.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioNodeInput.h"
 #include "modules/webaudio/AudioNodeOutput.h"
+#include "modules/webaudio/BaseAudioContext.h"
 
 namespace blink {
 
@@ -74,13 +74,13 @@
 
 // ----------------------------------------------------------------
 
-ChannelSplitterNode::ChannelSplitterNode(AbstractAudioContext& context, unsigned numberOfOutputs)
+ChannelSplitterNode::ChannelSplitterNode(BaseAudioContext& context, unsigned numberOfOutputs)
     : AudioNode(context)
 {
     setHandler(ChannelSplitterHandler::create(*this, context.sampleRate(), numberOfOutputs));
 }
 
-ChannelSplitterNode* ChannelSplitterNode::create(AbstractAudioContext& context, ExceptionState& exceptionState)
+ChannelSplitterNode* ChannelSplitterNode::create(BaseAudioContext& context, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
@@ -88,7 +88,7 @@
     return create(context, 6, exceptionState);
 }
 
-ChannelSplitterNode* ChannelSplitterNode::create(AbstractAudioContext& context, unsigned numberOfOutputs, ExceptionState& exceptionState)
+ChannelSplitterNode* ChannelSplitterNode::create(BaseAudioContext& context, unsigned numberOfOutputs, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
@@ -97,7 +97,7 @@
         return nullptr;
     }
 
-    if (!numberOfOutputs || numberOfOutputs > AbstractAudioContext::maxNumberOfChannels()) {
+    if (!numberOfOutputs || numberOfOutputs > BaseAudioContext::maxNumberOfChannels()) {
         exceptionState.throwDOMException(
             IndexSizeError,
             ExceptionMessages::indexOutsideRange<size_t>(
@@ -105,7 +105,7 @@
                 numberOfOutputs,
                 1,
                 ExceptionMessages::InclusiveBound,
-                AbstractAudioContext::maxNumberOfChannels(),
+                BaseAudioContext::maxNumberOfChannels(),
                 ExceptionMessages::InclusiveBound));
         return nullptr;
     }
diff --git a/third_party/WebKit/Source/modules/webaudio/ChannelSplitterNode.h b/third_party/WebKit/Source/modules/webaudio/ChannelSplitterNode.h
index d210c89..1c094f7 100644
--- a/third_party/WebKit/Source/modules/webaudio/ChannelSplitterNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/ChannelSplitterNode.h
@@ -30,7 +30,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 
 class ChannelSplitterHandler final : public AudioHandler {
 public:
@@ -46,11 +46,11 @@
 class ChannelSplitterNode final : public AudioNode {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static ChannelSplitterNode* create(AbstractAudioContext&, ExceptionState&);
-    static ChannelSplitterNode* create(AbstractAudioContext&, unsigned numberOfOutputs, ExceptionState&);
+    static ChannelSplitterNode* create(BaseAudioContext&, ExceptionState&);
+    static ChannelSplitterNode* create(BaseAudioContext&, unsigned numberOfOutputs, ExceptionState&);
 
 private:
-    ChannelSplitterNode(AbstractAudioContext&, unsigned numberOfOutputs);
+    ChannelSplitterNode(BaseAudioContext&, unsigned numberOfOutputs);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/ConvolverNode.cpp b/third_party/WebKit/Source/modules/webaudio/ConvolverNode.cpp
index dee1806..2f2b30e7d 100644
--- a/third_party/WebKit/Source/modules/webaudio/ConvolverNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/ConvolverNode.cpp
@@ -167,13 +167,13 @@
 
 // ----------------------------------------------------------------
 
-ConvolverNode::ConvolverNode(AbstractAudioContext& context)
+ConvolverNode::ConvolverNode(BaseAudioContext& context)
     : AudioNode(context)
 {
     setHandler(ConvolverHandler::create(*this, context.sampleRate()));
 }
 
-ConvolverNode* ConvolverNode::create(AbstractAudioContext& context, ExceptionState& exceptionState)
+ConvolverNode* ConvolverNode::create(BaseAudioContext& context, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
diff --git a/third_party/WebKit/Source/modules/webaudio/ConvolverNode.h b/third_party/WebKit/Source/modules/webaudio/ConvolverNode.h
index d27be4e..bf73e60 100644
--- a/third_party/WebKit/Source/modules/webaudio/ConvolverNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/ConvolverNode.h
@@ -75,7 +75,7 @@
 class MODULES_EXPORT ConvolverNode final : public AudioNode {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static ConvolverNode* create(AbstractAudioContext&, ExceptionState&);
+    static ConvolverNode* create(BaseAudioContext&, ExceptionState&);
 
     AudioBuffer* buffer() const;
     void setBuffer(AudioBuffer*, ExceptionState&);
@@ -83,7 +83,7 @@
     void setNormalize(bool);
 
 private:
-    ConvolverNode(AbstractAudioContext&);
+    ConvolverNode(BaseAudioContext&);
     ConvolverHandler& convolverHandler() const;
 
     FRIEND_TEST_ALL_PREFIXES(ConvolverNodeTest, ReverbLifetime);
diff --git a/third_party/WebKit/Source/modules/webaudio/ConvolverNodeTest.cpp b/third_party/WebKit/Source/modules/webaudio/ConvolverNodeTest.cpp
index ff2545cd..18563b2 100644
--- a/third_party/WebKit/Source/modules/webaudio/ConvolverNodeTest.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/ConvolverNodeTest.cpp
@@ -19,7 +19,7 @@
     EXPECT_FALSE(handler.m_reverb);
     node->setBuffer(AudioBuffer::create(2, 1, 48000), ASSERT_NO_EXCEPTION);
     EXPECT_TRUE(handler.m_reverb);
-    AbstractAudioContext::AutoLocker locker(context);
+    BaseAudioContext::AutoLocker locker(context);
     handler.dispose();
     // m_reverb should live after dispose() because an audio thread is using it.
     EXPECT_TRUE(handler.m_reverb);
diff --git a/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.cpp b/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.cpp
index a6fc982..280a5a5 100644
--- a/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.cpp
@@ -26,7 +26,7 @@
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/ExceptionCode.h"
-#include "modules/webaudio/AbstractAudioContext.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "platform/Logging.h"
 
 namespace blink {
@@ -138,13 +138,13 @@
 
 // ----------------------------------------------------------------
 
-DefaultAudioDestinationNode::DefaultAudioDestinationNode(AbstractAudioContext& context)
+DefaultAudioDestinationNode::DefaultAudioDestinationNode(BaseAudioContext& context)
     : AudioDestinationNode(context)
 {
     setHandler(DefaultAudioDestinationHandler::create(*this));
 }
 
-DefaultAudioDestinationNode* DefaultAudioDestinationNode::create(AbstractAudioContext* context)
+DefaultAudioDestinationNode* DefaultAudioDestinationNode::create(BaseAudioContext* context)
 {
     return new DefaultAudioDestinationNode(*context);
 }
diff --git a/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.h b/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.h
index 4940ac8..ac57af9 100644
--- a/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.h
@@ -31,7 +31,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 class ExceptionState;
 
 class DefaultAudioDestinationHandler final : public AudioDestinationHandler {
@@ -61,10 +61,10 @@
 
 class DefaultAudioDestinationNode final : public AudioDestinationNode {
 public:
-    static DefaultAudioDestinationNode* create(AbstractAudioContext*);
+    static DefaultAudioDestinationNode* create(BaseAudioContext*);
 
 private:
-    explicit DefaultAudioDestinationNode(AbstractAudioContext&);
+    explicit DefaultAudioDestinationNode(BaseAudioContext&);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/DeferredTaskHandler.cpp b/third_party/WebKit/Source/modules/webaudio/DeferredTaskHandler.cpp
index 3decf57..f4f79b8 100644
--- a/third_party/WebKit/Source/modules/webaudio/DeferredTaskHandler.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/DeferredTaskHandler.cpp
@@ -263,7 +263,7 @@
     // Some handlers might live because of their cross thread tasks.
 }
 
-DeferredTaskHandler::AutoLocker::AutoLocker(AbstractAudioContext* context)
+DeferredTaskHandler::AutoLocker::AutoLocker(BaseAudioContext* context)
     : m_handler(context->deferredTaskHandler())
 {
     m_handler.lock();
diff --git a/third_party/WebKit/Source/modules/webaudio/DeferredTaskHandler.h b/third_party/WebKit/Source/modules/webaudio/DeferredTaskHandler.h
index 1594e99..afd32cc 100644
--- a/third_party/WebKit/Source/modules/webaudio/DeferredTaskHandler.h
+++ b/third_party/WebKit/Source/modules/webaudio/DeferredTaskHandler.h
@@ -38,7 +38,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 class OfflineAudioContext;
 class AudioHandler;
 class AudioNodeOutput;
@@ -46,15 +46,15 @@
 
 // DeferredTaskHandler manages the major part of pre- and post- rendering tasks,
 // and provides a lock mechanism against the audio rendering graph. A
-// DeferredTaskHandler object is created when an AbstractAudioContext object is created.
+// DeferredTaskHandler object is created when an BaseAudioContext object is created.
 //
-// DeferredTaskHandler outlives the AbstractAudioContext only if all of the following
+// DeferredTaskHandler outlives the BaseAudioContext only if all of the following
 // conditions match:
 // - An audio rendering thread is running,
 // - It is requested to stop,
 // - The audio rendering thread calls requestToDeleteHandlersOnMainThread(),
 // - It posts a task of deleteHandlersOnMainThread(), and
-// - GC happens and it collects the AbstractAudioContext before the task execution.
+// - GC happens and it collects the BaseAudioContext before the task execution.
 //
 class MODULES_EXPORT DeferredTaskHandler final : public ThreadSafeRefCounted<DeferredTaskHandler> {
 public:
@@ -64,7 +64,7 @@
     void handleDeferredTasks();
     void contextWillBeDestroyed();
 
-    // AbstractAudioContext can pull node(s) at the end of each render quantum even when
+    // BaseAudioContext can pull node(s) at the end of each render quantum even when
     // they are not connected to any downstream nodes.  These two methods are
     // called by the nodes who want to add/remove themselves into/from the
     // automatic pull lists.
@@ -135,7 +135,7 @@
         {
             m_handler.lock();
         }
-        explicit AutoLocker(AbstractAudioContext*);
+        explicit AutoLocker(BaseAudioContext*);
 
         ~AutoLocker() { m_handler.unlock(); }
 
diff --git a/third_party/WebKit/Source/modules/webaudio/DelayNode.cpp b/third_party/WebKit/Source/modules/webaudio/DelayNode.cpp
index eb35ee1..5e9a141 100644
--- a/third_party/WebKit/Source/modules/webaudio/DelayNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/DelayNode.cpp
@@ -35,7 +35,7 @@
 
 const double maximumAllowedDelayTime = 180;
 
-DelayNode::DelayNode(AbstractAudioContext& context, double maxDelayTime)
+DelayNode::DelayNode(BaseAudioContext& context, double maxDelayTime)
     : AudioNode(context)
     , m_delayTime(AudioParam::create(context, ParamTypeDelayDelayTime, 0.0, 0.0, maxDelayTime))
 {
@@ -50,7 +50,7 @@
             maxDelayTime))));
 }
 
-DelayNode* DelayNode::create(AbstractAudioContext& context, ExceptionState& exceptionState)
+DelayNode* DelayNode::create(BaseAudioContext& context, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
@@ -58,7 +58,7 @@
     return create(context, 1, exceptionState);
 }
 
-DelayNode* DelayNode::create(AbstractAudioContext& context, double maxDelayTime, ExceptionState& exceptionState)
+DelayNode* DelayNode::create(BaseAudioContext& context, double maxDelayTime, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
diff --git a/third_party/WebKit/Source/modules/webaudio/DelayNode.h b/third_party/WebKit/Source/modules/webaudio/DelayNode.h
index a697871a..1ebcc41 100644
--- a/third_party/WebKit/Source/modules/webaudio/DelayNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/DelayNode.h
@@ -29,19 +29,19 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 class ExceptionState;
 
 class DelayNode final : public AudioNode {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static DelayNode* create(AbstractAudioContext&, ExceptionState&);
-    static DelayNode* create(AbstractAudioContext&, double maxDelayTime, ExceptionState&);
+    static DelayNode* create(BaseAudioContext&, ExceptionState&);
+    static DelayNode* create(BaseAudioContext&, double maxDelayTime, ExceptionState&);
     DECLARE_VIRTUAL_TRACE();
     AudioParam* delayTime();
 
 private:
-    DelayNode(AbstractAudioContext&, double maxDelayTime);
+    DelayNode(BaseAudioContext&, double maxDelayTime);
 
     Member<AudioParam> m_delayTime;
 };
diff --git a/third_party/WebKit/Source/modules/webaudio/DynamicsCompressorNode.cpp b/third_party/WebKit/Source/modules/webaudio/DynamicsCompressorNode.cpp
index d12764d70..f13f67c 100644
--- a/third_party/WebKit/Source/modules/webaudio/DynamicsCompressorNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/DynamicsCompressorNode.cpp
@@ -126,7 +126,7 @@
 
 // ----------------------------------------------------------------
 
-DynamicsCompressorNode::DynamicsCompressorNode(AbstractAudioContext& context)
+DynamicsCompressorNode::DynamicsCompressorNode(BaseAudioContext& context)
     : AudioNode(context)
     , m_threshold(AudioParam::create(context, ParamTypeDynamicsCompressorThreshold, -24, -100, 0))
     , m_knee(AudioParam::create(context, ParamTypeDynamicsCompressorKnee, 30, 0, 40))
@@ -144,7 +144,7 @@
         m_release->handler()));
 }
 
-DynamicsCompressorNode* DynamicsCompressorNode::create(AbstractAudioContext& context, ExceptionState& exceptionState)
+DynamicsCompressorNode* DynamicsCompressorNode::create(BaseAudioContext& context, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
diff --git a/third_party/WebKit/Source/modules/webaudio/DynamicsCompressorNode.h b/third_party/WebKit/Source/modules/webaudio/DynamicsCompressorNode.h
index 27e2201..25c1ab3 100644
--- a/third_party/WebKit/Source/modules/webaudio/DynamicsCompressorNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/DynamicsCompressorNode.h
@@ -33,7 +33,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 class DynamicsCompressor;
 
 class MODULES_EXPORT DynamicsCompressorHandler final : public AudioHandler {
@@ -81,7 +81,7 @@
 class MODULES_EXPORT DynamicsCompressorNode final : public AudioNode {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static DynamicsCompressorNode* create(AbstractAudioContext&, ExceptionState&);
+    static DynamicsCompressorNode* create(BaseAudioContext&, ExceptionState&);
     DECLARE_VIRTUAL_TRACE();
 
     AudioParam* threshold() const;
@@ -92,7 +92,7 @@
     AudioParam* release() const;
 
 private:
-    DynamicsCompressorNode(AbstractAudioContext&);
+    DynamicsCompressorNode(BaseAudioContext&);
     DynamicsCompressorHandler& dynamicsCompressorHandler() const;
 
     Member<AudioParam> m_threshold;
diff --git a/third_party/WebKit/Source/modules/webaudio/DynamicsCompressorNodeTest.cpp b/third_party/WebKit/Source/modules/webaudio/DynamicsCompressorNodeTest.cpp
index e04a567..4f3379d 100644
--- a/third_party/WebKit/Source/modules/webaudio/DynamicsCompressorNodeTest.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/DynamicsCompressorNodeTest.cpp
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "core/testing/DummyPageHolder.h"
-#include "modules/webaudio/AbstractAudioContext.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "modules/webaudio/DynamicsCompressorNode.h"
 #include "modules/webaudio/OfflineAudioContext.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -18,7 +18,7 @@
     DynamicsCompressorNode* node = context->createDynamicsCompressor(ASSERT_NO_EXCEPTION);
     DynamicsCompressorHandler& handler = node->dynamicsCompressorHandler();
     EXPECT_TRUE(handler.m_dynamicsCompressor);
-    AbstractAudioContext::AutoLocker locker(context);
+    BaseAudioContext::AutoLocker locker(context);
     handler.dispose();
     // m_dynamicsCompressor should live after dispose() because an audio thread
     // is using it.
diff --git a/third_party/WebKit/Source/modules/webaudio/GainNode.cpp b/third_party/WebKit/Source/modules/webaudio/GainNode.cpp
index 01b1380..5921dfb 100644
--- a/third_party/WebKit/Source/modules/webaudio/GainNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/GainNode.cpp
@@ -119,14 +119,14 @@
 
 // ----------------------------------------------------------------
 
-GainNode::GainNode(AbstractAudioContext& context)
+GainNode::GainNode(BaseAudioContext& context)
     : AudioNode(context)
     , m_gain(AudioParam::create(context, ParamTypeGainGain, 1.0))
 {
     setHandler(GainHandler::create(*this, context.sampleRate(), m_gain->handler()));
 }
 
-GainNode* GainNode::create(AbstractAudioContext& context, ExceptionState& exceptionState)
+GainNode* GainNode::create(BaseAudioContext& context, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
diff --git a/third_party/WebKit/Source/modules/webaudio/GainNode.h b/third_party/WebKit/Source/modules/webaudio/GainNode.h
index 7fea960..0f8cffbbd 100644
--- a/third_party/WebKit/Source/modules/webaudio/GainNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/GainNode.h
@@ -32,7 +32,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 
 // GainNode is an AudioNode with one input and one output which applies a gain (volume) change to the audio signal.
 // De-zippering (smoothing) is applied when the gain value is changed dynamically.
@@ -59,13 +59,13 @@
 class GainNode final : public AudioNode {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static GainNode* create(AbstractAudioContext&, ExceptionState&);
+    static GainNode* create(BaseAudioContext&, ExceptionState&);
     DECLARE_VIRTUAL_TRACE();
 
     AudioParam* gain() const;
 
 private:
-    GainNode(AbstractAudioContext&);
+    GainNode(BaseAudioContext&);
 
     Member<AudioParam> m_gain;
 };
diff --git a/third_party/WebKit/Source/modules/webaudio/IIRFilterNode.cpp b/third_party/WebKit/Source/modules/webaudio/IIRFilterNode.cpp
index 98d008e..38bf3bc 100644
--- a/third_party/WebKit/Source/modules/webaudio/IIRFilterNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/IIRFilterNode.cpp
@@ -7,14 +7,14 @@
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/ExceptionCode.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioBasicProcessorHandler.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "platform/Histogram.h"
 #include "wtf/PtrUtil.h"
 
 namespace blink {
 
-IIRFilterNode::IIRFilterNode(AbstractAudioContext& context, const Vector<double> feedforwardCoef, const Vector<double> feedbackCoef)
+IIRFilterNode::IIRFilterNode(BaseAudioContext& context, const Vector<double> feedforwardCoef, const Vector<double> feedbackCoef)
     : AudioNode(context)
 {
     setHandler(AudioBasicProcessorHandler::create(
@@ -30,7 +30,7 @@
 }
 
 IIRFilterNode* IIRFilterNode::create(
-    AbstractAudioContext& context,
+    BaseAudioContext& context,
     const Vector<double> feedforwardCoef,
     const Vector<double> feedbackCoef,
     ExceptionState& exceptionState)
diff --git a/third_party/WebKit/Source/modules/webaudio/IIRFilterNode.h b/third_party/WebKit/Source/modules/webaudio/IIRFilterNode.h
index 761e7e3..1a7f4f3a 100644
--- a/third_party/WebKit/Source/modules/webaudio/IIRFilterNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/IIRFilterNode.h
@@ -11,14 +11,14 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 class ExceptionState;
 
 class IIRFilterNode : public AudioNode {
     DEFINE_WRAPPERTYPEINFO();
 public:
     static IIRFilterNode* create(
-        AbstractAudioContext&,
+        BaseAudioContext&,
         const Vector<double> feedforward,
         const Vector<double> feedback,
         ExceptionState&);
@@ -30,7 +30,7 @@
     void getFrequencyResponse(const DOMFloat32Array* frequencyHz, DOMFloat32Array* magResponse, DOMFloat32Array* phaseResponse, ExceptionState&);
 
 private:
-    IIRFilterNode(AbstractAudioContext&, const Vector<double> denominator, const Vector<double> numerator);
+    IIRFilterNode(BaseAudioContext&, const Vector<double> denominator, const Vector<double> numerator);
 
     IIRProcessor* iirProcessor() const;
 };
diff --git a/third_party/WebKit/Source/modules/webaudio/MediaElementAudioSourceNode.cpp b/third_party/WebKit/Source/modules/webaudio/MediaElementAudioSourceNode.cpp
index f4309bb..9659b09 100644
--- a/third_party/WebKit/Source/modules/webaudio/MediaElementAudioSourceNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/MediaElementAudioSourceNode.cpp
@@ -25,8 +25,8 @@
 #include "core/dom/CrossThreadTask.h"
 #include "core/html/HTMLMediaElement.h"
 #include "core/inspector/ConsoleMessage.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioNodeOutput.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "modules/webaudio/MediaElementAudioSourceNode.h"
 #include "platform/Logging.h"
 #include "platform/audio/AudioUtilities.h"
@@ -72,7 +72,7 @@
 void MediaElementAudioSourceHandler::setFormat(size_t numberOfChannels, float sourceSampleRate)
 {
     if (numberOfChannels != m_sourceNumberOfChannels || sourceSampleRate != m_sourceSampleRate) {
-        if (!numberOfChannels || numberOfChannels > AbstractAudioContext::maxNumberOfChannels() || !AudioUtilities::isValidAudioBufferSampleRate(sourceSampleRate)) {
+        if (!numberOfChannels || numberOfChannels > BaseAudioContext::maxNumberOfChannels() || !AudioUtilities::isValidAudioBufferSampleRate(sourceSampleRate)) {
             // process() will generate silence for these uninitialized values.
             DLOG(ERROR) << "setFormat(" << numberOfChannels << ", " << sourceSampleRate << ") - unhandled format change";
             // Synchronize with process().
@@ -99,7 +99,7 @@
 
         {
             // The context must be locked when changing the number of output channels.
-            AbstractAudioContext::AutoLocker contextLocker(context());
+            BaseAudioContext::AutoLocker contextLocker(context());
 
             // Do any necesssary re-configuration to the output's number of channels.
             output(0).setNumberOfChannels(numberOfChannels);
@@ -201,13 +201,13 @@
 
 // ----------------------------------------------------------------
 
-MediaElementAudioSourceNode::MediaElementAudioSourceNode(AbstractAudioContext& context, HTMLMediaElement& mediaElement)
+MediaElementAudioSourceNode::MediaElementAudioSourceNode(BaseAudioContext& context, HTMLMediaElement& mediaElement)
     : AudioSourceNode(context)
 {
     setHandler(MediaElementAudioSourceHandler::create(*this, mediaElement));
 }
 
-MediaElementAudioSourceNode* MediaElementAudioSourceNode::create(AbstractAudioContext& context, HTMLMediaElement& mediaElement, ExceptionState& exceptionState)
+MediaElementAudioSourceNode* MediaElementAudioSourceNode::create(BaseAudioContext& context, HTMLMediaElement& mediaElement, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
diff --git a/third_party/WebKit/Source/modules/webaudio/MediaElementAudioSourceNode.h b/third_party/WebKit/Source/modules/webaudio/MediaElementAudioSourceNode.h
index 20fa9a6..f1b64e2 100644
--- a/third_party/WebKit/Source/modules/webaudio/MediaElementAudioSourceNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/MediaElementAudioSourceNode.h
@@ -34,7 +34,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 class HTMLMediaElement;
 
 class MediaElementAudioSourceHandler final : public AudioHandler {
@@ -100,7 +100,7 @@
     DEFINE_WRAPPERTYPEINFO();
     USING_GARBAGE_COLLECTED_MIXIN(MediaElementAudioSourceNode);
 public:
-    static MediaElementAudioSourceNode* create(AbstractAudioContext&, HTMLMediaElement&, ExceptionState&);
+    static MediaElementAudioSourceNode* create(BaseAudioContext&, HTMLMediaElement&, ExceptionState&);
     DECLARE_VIRTUAL_TRACE();
     MediaElementAudioSourceHandler& mediaElementAudioSourceHandler() const;
 
@@ -113,7 +113,7 @@
     void unlock() override;
 
 private:
-    MediaElementAudioSourceNode(AbstractAudioContext&, HTMLMediaElement&);
+    MediaElementAudioSourceNode(BaseAudioContext&, HTMLMediaElement&);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/MediaStreamAudioDestinationNode.cpp b/third_party/WebKit/Source/modules/webaudio/MediaStreamAudioDestinationNode.cpp
index efa097e7..ed2c72d3 100644
--- a/third_party/WebKit/Source/modules/webaudio/MediaStreamAudioDestinationNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/MediaStreamAudioDestinationNode.cpp
@@ -26,8 +26,8 @@
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/ExceptionCode.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioNodeInput.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "platform/UUID.h"
 #include "platform/mediastream/MediaStreamCenter.h"
 #include "public/platform/WebRTCPeerConnectionHandler.h"
@@ -103,7 +103,7 @@
     // TODO(hongchan): There might be a data race here since both threads
     // have access to m_mixBus.
     if (!exceptionState.hadException() && this->channelCount() != oldChannelCount && isInitialized()) {
-        AbstractAudioContext::AutoLocker locker(context());
+        BaseAudioContext::AutoLocker locker(context());
         m_mixBus = AudioBus::create(channelCount, ProcessingSizeInFrames);
         m_source->setAudioFormat(channelCount, context()->sampleRate());
     }
@@ -116,13 +116,13 @@
 
 // ----------------------------------------------------------------
 
-MediaStreamAudioDestinationNode::MediaStreamAudioDestinationNode(AbstractAudioContext& context, size_t numberOfChannels)
+MediaStreamAudioDestinationNode::MediaStreamAudioDestinationNode(BaseAudioContext& context, size_t numberOfChannels)
     : AudioBasicInspectorNode(context)
 {
     setHandler(MediaStreamAudioDestinationHandler::create(*this, numberOfChannels));
 }
 
-MediaStreamAudioDestinationNode* MediaStreamAudioDestinationNode::create(AbstractAudioContext& context, size_t numberOfChannels, ExceptionState& exceptionState)
+MediaStreamAudioDestinationNode* MediaStreamAudioDestinationNode::create(BaseAudioContext& context, size_t numberOfChannels, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
diff --git a/third_party/WebKit/Source/modules/webaudio/MediaStreamAudioDestinationNode.h b/third_party/WebKit/Source/modules/webaudio/MediaStreamAudioDestinationNode.h
index 2267b15..abeaf17 100644
--- a/third_party/WebKit/Source/modules/webaudio/MediaStreamAudioDestinationNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/MediaStreamAudioDestinationNode.h
@@ -32,7 +32,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 
 class MediaStreamAudioDestinationHandler final : public AudioBasicInspectorHandler {
 public:
@@ -64,11 +64,11 @@
 class MediaStreamAudioDestinationNode final : public AudioBasicInspectorNode {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static MediaStreamAudioDestinationNode* create(AbstractAudioContext&, size_t numberOfChannels, ExceptionState&);
+    static MediaStreamAudioDestinationNode* create(BaseAudioContext&, size_t numberOfChannels, ExceptionState&);
     MediaStream* stream() const;
 
 private:
-    MediaStreamAudioDestinationNode(AbstractAudioContext&, size_t numberOfChannels);
+    MediaStreamAudioDestinationNode(BaseAudioContext&, size_t numberOfChannels);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/MediaStreamAudioSourceNode.cpp b/third_party/WebKit/Source/modules/webaudio/MediaStreamAudioSourceNode.cpp
index e976165..bc503d7 100644
--- a/third_party/WebKit/Source/modules/webaudio/MediaStreamAudioSourceNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/MediaStreamAudioSourceNode.cpp
@@ -25,8 +25,8 @@
 #include "modules/webaudio/MediaStreamAudioSourceNode.h"
 
 #include "core/dom/ExceptionCode.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioNodeOutput.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "platform/Logging.h"
 #include "wtf/Locker.h"
 #include <memory>
@@ -61,7 +61,7 @@
 {
     if (numberOfChannels != m_sourceNumberOfChannels || sourceSampleRate != sampleRate()) {
         // The sample-rate must be equal to the context's sample-rate.
-        if (!numberOfChannels || numberOfChannels > AbstractAudioContext::maxNumberOfChannels() || sourceSampleRate != sampleRate()) {
+        if (!numberOfChannels || numberOfChannels > BaseAudioContext::maxNumberOfChannels() || sourceSampleRate != sampleRate()) {
             // process() will generate silence for these uninitialized values.
             DLOG(ERROR) << "setFormat(" << numberOfChannels << ", " << sourceSampleRate << ") - unhandled format change";
             m_sourceNumberOfChannels = 0;
@@ -75,7 +75,7 @@
 
         {
             // The context must be locked when changing the number of output channels.
-            AbstractAudioContext::AutoLocker contextLocker(context());
+            BaseAudioContext::AutoLocker contextLocker(context());
 
             // Do any necesssary re-configuration to the output's number of channels.
             output(0).setNumberOfChannels(numberOfChannels);
@@ -111,13 +111,13 @@
 
 // ----------------------------------------------------------------
 
-MediaStreamAudioSourceNode::MediaStreamAudioSourceNode(AbstractAudioContext& context, MediaStream& mediaStream, MediaStreamTrack* audioTrack, std::unique_ptr<AudioSourceProvider> audioSourceProvider)
+MediaStreamAudioSourceNode::MediaStreamAudioSourceNode(BaseAudioContext& context, MediaStream& mediaStream, MediaStreamTrack* audioTrack, std::unique_ptr<AudioSourceProvider> audioSourceProvider)
     : AudioSourceNode(context)
 {
     setHandler(MediaStreamAudioSourceHandler::create(*this, mediaStream, audioTrack, std::move(audioSourceProvider)));
 }
 
-MediaStreamAudioSourceNode* MediaStreamAudioSourceNode::create(AbstractAudioContext& context, MediaStream& mediaStream, ExceptionState& exceptionState)
+MediaStreamAudioSourceNode* MediaStreamAudioSourceNode::create(BaseAudioContext& context, MediaStream& mediaStream, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
diff --git a/third_party/WebKit/Source/modules/webaudio/MediaStreamAudioSourceNode.h b/third_party/WebKit/Source/modules/webaudio/MediaStreamAudioSourceNode.h
index d0f448d..9b22353 100644
--- a/third_party/WebKit/Source/modules/webaudio/MediaStreamAudioSourceNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/MediaStreamAudioSourceNode.h
@@ -35,7 +35,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 
 class MediaStreamAudioSourceHandler final : public AudioHandler {
 public:
@@ -73,7 +73,7 @@
     DEFINE_WRAPPERTYPEINFO();
     USING_GARBAGE_COLLECTED_MIXIN(MediaStreamAudioSourceNode);
 public:
-    static MediaStreamAudioSourceNode* create(AbstractAudioContext&, MediaStream&, ExceptionState&);
+    static MediaStreamAudioSourceNode* create(BaseAudioContext&, MediaStream&, ExceptionState&);
     DECLARE_VIRTUAL_TRACE();
     MediaStreamAudioSourceHandler& mediaStreamAudioSourceHandler() const;
 
@@ -83,7 +83,7 @@
     void setFormat(size_t numberOfChannels, float sampleRate) override;
 
 private:
-    MediaStreamAudioSourceNode(AbstractAudioContext&, MediaStream&, MediaStreamTrack*, std::unique_ptr<AudioSourceProvider>);
+    MediaStreamAudioSourceNode(BaseAudioContext&, MediaStream&, MediaStreamTrack*, std::unique_ptr<AudioSourceProvider>);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.cpp b/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.cpp
index d8db167..442ccda 100644
--- a/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.cpp
@@ -57,7 +57,7 @@
         return nullptr;
     }
 
-    if (numberOfChannels > AbstractAudioContext::maxNumberOfChannels()) {
+    if (numberOfChannels > BaseAudioContext::maxNumberOfChannels()) {
         exceptionState.throwDOMException(
             IndexSizeError,
             ExceptionMessages::indexOutsideRange<unsigned>(
@@ -65,7 +65,7 @@
                 numberOfChannels,
                 0,
                 ExceptionMessages::InclusiveBound,
-                AbstractAudioContext::maxNumberOfChannels(),
+                BaseAudioContext::maxNumberOfChannels(),
                 ExceptionMessages::InclusiveBound));
         return nullptr;
     }
@@ -114,7 +114,7 @@
 }
 
 OfflineAudioContext::OfflineAudioContext(Document* document, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionState& exceptionState)
-    : AbstractAudioContext(document, numberOfChannels, numberOfFrames, sampleRate)
+    : BaseAudioContext(document, numberOfChannels, numberOfFrames, sampleRate)
     , m_isRenderingStarted(false)
     , m_totalRenderFrames(numberOfFrames)
 {
@@ -144,7 +144,7 @@
     visitor->trace(m_renderTarget);
     visitor->trace(m_completeResolver);
     visitor->trace(m_scheduledSuspends);
-    AbstractAudioContext::trace(visitor);
+    BaseAudioContext::trace(visitor);
 }
 
 ScriptPromise OfflineAudioContext::startOfflineRendering(ScriptState* scriptState)
@@ -205,7 +205,7 @@
 ScriptPromise OfflineAudioContext::suspendContext(ScriptState* scriptState)
 {
     // This CANNOT be called on OfflineAudioContext; this is only to implement
-    // the pure virtual interface from AbstractAudioContext.
+    // the pure virtual interface from BaseAudioContext.
     RELEASE_NOTREACHED();
 
     return ScriptPromise();
diff --git a/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.h b/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.h
index e347a644..a3051138 100644
--- a/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.h
+++ b/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.h
@@ -26,7 +26,7 @@
 #define OfflineAudioContext_h
 
 #include "modules/ModulesExport.h"
-#include "modules/webaudio/AbstractAudioContext.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "wtf/HashMap.h"
 
 namespace blink {
@@ -34,7 +34,7 @@
 class ExceptionState;
 class OfflineAudioDestinationHandler;
 
-class MODULES_EXPORT OfflineAudioContext final : public AbstractAudioContext {
+class MODULES_EXPORT OfflineAudioContext final : public BaseAudioContext {
     DEFINE_WRAPPERTYPEINFO();
 public:
     static OfflineAudioContext* create(ExecutionContext*, unsigned numberOfChannels, unsigned numberOfFrames, float sampleRate, ExceptionState&);
@@ -51,7 +51,7 @@
     ScriptPromise suspendContext(ScriptState*, double);
     ScriptPromise resumeContext(ScriptState*) final;
 
-    // This is to implement the pure virtual method from AbstractAudioContext.
+    // This is to implement the pure virtual method from BaseAudioContext.
     // CANNOT be called from an OfflineAudioContext.
     ScriptPromise suspendContext(ScriptState*) final;
 
@@ -64,7 +64,7 @@
     // Fire completion event when the rendering is finished.
     void fireCompletionEvent();
 
-    // This is same with the online version in AbstractAudioContext class except
+    // This is same with the online version in BaseAudioContext class except
     // for returning a boolean value after checking the scheduled suspends.
     bool handlePreOfflineRenderTasks();
 
diff --git a/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp b/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp
index eda9d5e..32c5a6f 100644
--- a/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp
@@ -23,9 +23,9 @@
  */
 
 #include "core/dom/CrossThreadTask.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioNodeInput.h"
 #include "modules/webaudio/AudioNodeOutput.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "modules/webaudio/OfflineAudioContext.h"
 #include "modules/webaudio/OfflineAudioDestinationNode.h"
 #include "platform/audio/AudioBus.h"
@@ -314,13 +314,13 @@
 
 // ----------------------------------------------------------------
 
-OfflineAudioDestinationNode::OfflineAudioDestinationNode(AbstractAudioContext& context, AudioBuffer* renderTarget)
+OfflineAudioDestinationNode::OfflineAudioDestinationNode(BaseAudioContext& context, AudioBuffer* renderTarget)
     : AudioDestinationNode(context)
 {
     setHandler(OfflineAudioDestinationHandler::create(*this, renderTarget));
 }
 
-OfflineAudioDestinationNode* OfflineAudioDestinationNode::create(AbstractAudioContext* context, AudioBuffer* renderTarget)
+OfflineAudioDestinationNode* OfflineAudioDestinationNode::create(BaseAudioContext* context, AudioBuffer* renderTarget)
 {
     return new OfflineAudioDestinationNode(*context, renderTarget);
 }
diff --git a/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.h b/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.h
index b4a4716..6eb2259 100644
--- a/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.h
@@ -35,7 +35,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 class AudioBus;
 class OfflineAudioContext;
 
@@ -117,10 +117,10 @@
 
 class OfflineAudioDestinationNode final : public AudioDestinationNode {
 public:
-    static OfflineAudioDestinationNode* create(AbstractAudioContext*, AudioBuffer* renderTarget);
+    static OfflineAudioDestinationNode* create(BaseAudioContext*, AudioBuffer* renderTarget);
 
 private:
-    OfflineAudioDestinationNode(AbstractAudioContext&, AudioBuffer* renderTarget);
+    OfflineAudioDestinationNode(BaseAudioContext&, AudioBuffer* renderTarget);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/OscillatorNode.cpp b/third_party/WebKit/Source/modules/webaudio/OscillatorNode.cpp
index ae98a06..ebbbd472 100644
--- a/third_party/WebKit/Source/modules/webaudio/OscillatorNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/OscillatorNode.cpp
@@ -330,7 +330,7 @@
 
 // ----------------------------------------------------------------
 
-OscillatorNode::OscillatorNode(AbstractAudioContext& context)
+OscillatorNode::OscillatorNode(BaseAudioContext& context)
     : AudioScheduledSourceNode(context)
     // Use musical pitch standard A440 as a default.
     , m_frequency(AudioParam::create(context, ParamTypeOscillatorFrequency, 440,
@@ -342,7 +342,7 @@
     setHandler(OscillatorHandler::create(*this, context.sampleRate(), m_frequency->handler(), m_detune->handler()));
 }
 
-OscillatorNode* OscillatorNode::create(AbstractAudioContext& context, ExceptionState& exceptionState)
+OscillatorNode* OscillatorNode::create(BaseAudioContext& context, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
diff --git a/third_party/WebKit/Source/modules/webaudio/OscillatorNode.h b/third_party/WebKit/Source/modules/webaudio/OscillatorNode.h
index f515946e..9714472f 100644
--- a/third_party/WebKit/Source/modules/webaudio/OscillatorNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/OscillatorNode.h
@@ -34,7 +34,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 class ExceptionState;
 class PeriodicWave;
 
@@ -99,7 +99,7 @@
 class OscillatorNode final : public AudioScheduledSourceNode {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static OscillatorNode* create(AbstractAudioContext&, ExceptionState&);
+    static OscillatorNode* create(BaseAudioContext&, ExceptionState&);
     DECLARE_VIRTUAL_TRACE();
 
     String type() const;
@@ -109,7 +109,7 @@
     void setPeriodicWave(PeriodicWave*);
 
 private:
-    OscillatorNode(AbstractAudioContext&);
+    OscillatorNode(BaseAudioContext&);
     OscillatorHandler& oscillatorHandler() const;
 
     Member<AudioParam> m_frequency;
diff --git a/third_party/WebKit/Source/modules/webaudio/PannerNode.cpp b/third_party/WebKit/Source/modules/webaudio/PannerNode.cpp
index 44ccd79b..5f4d35f 100644
--- a/third_party/WebKit/Source/modules/webaudio/PannerNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/PannerNode.cpp
@@ -27,10 +27,10 @@
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/ExecutionContext.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioBufferSourceNode.h"
 #include "modules/webaudio/AudioNodeInput.h"
 #include "modules/webaudio/AudioNodeOutput.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "platform/Histogram.h"
 #include "platform/audio/HRTFPanner.h"
 #include "wtf/MathExtras.h"
@@ -134,7 +134,7 @@
         // HRTFDatabase should be loaded before proceeding when the panning model is HRTF.
         if (m_panningModel == Panner::PanningModelHRTF && !listener()->isHRTFDatabaseLoaded()) {
             if (context()->hasRealtimeConstraint()) {
-                // Some AbstractAudioContexts cannot block on the HRTFDatabase loader.
+                // Some BaseAudioContexts cannot block on the HRTFDatabase loader.
                 destination->zero();
                 return;
             }
@@ -563,7 +563,7 @@
 void PannerHandler::setChannelCount(unsigned long channelCount, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     // A PannerNode only supports 1 or 2 channels
     if (channelCount > 0 && channelCount <= 2) {
@@ -588,7 +588,7 @@
 void PannerHandler::setChannelCountMode(const String& mode, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     ChannelCountMode oldMode = m_channelCountMode;
 
@@ -640,7 +640,7 @@
 }
 // ----------------------------------------------------------------
 
-PannerNode::PannerNode(AbstractAudioContext& context)
+PannerNode::PannerNode(BaseAudioContext& context)
     : AudioNode(context)
     , m_positionX(AudioParam::create(context, ParamTypePannerPositionX, 0.0))
     , m_positionY(AudioParam::create(context, ParamTypePannerPositionY, 0.0))
@@ -660,7 +660,7 @@
         m_orientationZ->handler()));
 }
 
-PannerNode* PannerNode::create(AbstractAudioContext& context, ExceptionState& exceptionState)
+PannerNode* PannerNode::create(BaseAudioContext& context, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
diff --git a/third_party/WebKit/Source/modules/webaudio/PannerNode.h b/third_party/WebKit/Source/modules/webaudio/PannerNode.h
index ca5fde4..3eda63e 100644
--- a/third_party/WebKit/Source/modules/webaudio/PannerNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/PannerNode.h
@@ -38,7 +38,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 
 // PannerNode is an AudioNode with one input and one output.
 // It positions a sound in 3D space, with the exact effect dependent on the panning model.
@@ -123,7 +123,7 @@
         AudioParamHandler& orientationY,
         AudioParamHandler& orientationZ);
 
-    // AbstractAudioContext's listener
+    // BaseAudioContext's listener
     AudioListener* listener();
 
     bool setPanningModel(unsigned); // Returns true on success.
@@ -207,7 +207,7 @@
 class PannerNode final : public AudioNode {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static PannerNode* create(AbstractAudioContext&, ExceptionState&);
+    static PannerNode* create(BaseAudioContext&, ExceptionState&);
     PannerHandler& pannerHandler() const;
 
     DECLARE_VIRTUAL_TRACE();
@@ -242,7 +242,7 @@
     void setConeOuterGain(double);
 
 private:
-    PannerNode(AbstractAudioContext&);
+    PannerNode(BaseAudioContext&);
 
     Member<AudioParam> m_positionX;
     Member<AudioParam> m_positionY;
diff --git a/third_party/WebKit/Source/modules/webaudio/PeriodicWave.cpp b/third_party/WebKit/Source/modules/webaudio/PeriodicWave.cpp
index fdd7ebd..69321b1 100644
--- a/third_party/WebKit/Source/modules/webaudio/PeriodicWave.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/PeriodicWave.cpp
@@ -29,7 +29,7 @@
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/ExceptionCode.h"
-#include "modules/webaudio/AbstractAudioContext.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "modules/webaudio/OscillatorNode.h"
 #include "modules/webaudio/PeriodicWave.h"
 #include "platform/audio/FFTFrame.h"
@@ -52,7 +52,7 @@
 using namespace VectorMath;
 
 PeriodicWave* PeriodicWave::create(
-    AbstractAudioContext& context,
+    BaseAudioContext& context,
     DOMFloat32Array* real,
     DOMFloat32Array* imag,
     bool disableNormalization,
diff --git a/third_party/WebKit/Source/modules/webaudio/PeriodicWave.h b/third_party/WebKit/Source/modules/webaudio/PeriodicWave.h
index a5629b9..1e34ba64 100644
--- a/third_party/WebKit/Source/modules/webaudio/PeriodicWave.h
+++ b/third_party/WebKit/Source/modules/webaudio/PeriodicWave.h
@@ -38,7 +38,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 class ExceptionState;
 
 class PeriodicWave final : public GarbageCollectedFinalized<PeriodicWave>, public ScriptWrappable {
@@ -51,7 +51,7 @@
 
     // Creates an arbitrary periodic wave given the frequency components (Fourier coefficients).
     static PeriodicWave* create(
-        AbstractAudioContext&,
+        BaseAudioContext&,
         DOMFloat32Array* real,
         DOMFloat32Array* imag,
         bool normalize,
diff --git a/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNode.cpp b/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNode.cpp
index 35604ca..935354e 100644
--- a/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNode.cpp
@@ -27,11 +27,11 @@
 #include "core/dom/CrossThreadTask.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/ExecutionContext.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioBuffer.h"
 #include "modules/webaudio/AudioNodeInput.h"
 #include "modules/webaudio/AudioNodeOutput.h"
 #include "modules/webaudio/AudioProcessingEvent.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "public/platform/Platform.h"
 
 namespace blink {
@@ -49,7 +49,7 @@
     if (m_bufferSize < ProcessingSizeInFrames)
         m_bufferSize = ProcessingSizeInFrames;
 
-    ASSERT(numberOfInputChannels <= AbstractAudioContext::maxNumberOfChannels());
+    DCHECK_LE(numberOfInputChannels, BaseAudioContext::maxNumberOfChannels());
 
     addInput();
     addOutput(numberOfOutputChannels);
@@ -213,7 +213,7 @@
 void ScriptProcessorHandler::setChannelCount(unsigned long channelCount, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     if (channelCount != m_channelCount) {
         exceptionState.throwDOMException(
@@ -225,7 +225,7 @@
 void ScriptProcessorHandler::setChannelCountMode(const String& mode, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     if ((mode == "max") || (mode == "clamped-max")) {
         exceptionState.throwDOMException(
@@ -236,7 +236,7 @@
 
 // ----------------------------------------------------------------
 
-ScriptProcessorNode::ScriptProcessorNode(AbstractAudioContext& context, float sampleRate, size_t bufferSize, unsigned numberOfInputChannels, unsigned numberOfOutputChannels)
+ScriptProcessorNode::ScriptProcessorNode(BaseAudioContext& context, float sampleRate, size_t bufferSize, unsigned numberOfInputChannels, unsigned numberOfOutputChannels)
     : AudioNode(context)
     , ActiveScriptWrappable(this)
 {
@@ -260,7 +260,7 @@
 }
 
 ScriptProcessorNode* ScriptProcessorNode::create(
-    AbstractAudioContext& context,
+    BaseAudioContext& context,
     ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
@@ -271,7 +271,7 @@
 }
 
 ScriptProcessorNode* ScriptProcessorNode::create(
-    AbstractAudioContext& context,
+    BaseAudioContext& context,
     size_t bufferSize,
     ExceptionState& exceptionState)
 {
@@ -282,7 +282,7 @@
 }
 
 ScriptProcessorNode* ScriptProcessorNode::create(
-    AbstractAudioContext& context,
+    BaseAudioContext& context,
     size_t bufferSize,
     unsigned numberOfInputChannels,
     ExceptionState& exceptionState)
@@ -294,7 +294,7 @@
 }
 
 ScriptProcessorNode* ScriptProcessorNode::create(
-    AbstractAudioContext& context,
+    BaseAudioContext& context,
     size_t bufferSize,
     unsigned numberOfInputChannels,
     unsigned numberOfOutputChannels,
@@ -314,21 +314,21 @@
         return nullptr;
     }
 
-    if (numberOfInputChannels > AbstractAudioContext::maxNumberOfChannels()) {
+    if (numberOfInputChannels > BaseAudioContext::maxNumberOfChannels()) {
         exceptionState.throwDOMException(
             IndexSizeError,
             "number of input channels (" + String::number(numberOfInputChannels)
             + ") exceeds maximum ("
-            + String::number(AbstractAudioContext::maxNumberOfChannels()) + ").");
+            + String::number(BaseAudioContext::maxNumberOfChannels()) + ").");
         return nullptr;
     }
 
-    if (numberOfOutputChannels > AbstractAudioContext::maxNumberOfChannels()) {
+    if (numberOfOutputChannels > BaseAudioContext::maxNumberOfChannels()) {
         exceptionState.throwDOMException(
             IndexSizeError,
             "number of output channels (" + String::number(numberOfInputChannels)
             + ") exceeds maximum ("
-            + String::number(AbstractAudioContext::maxNumberOfChannels()) + ").");
+            + String::number(BaseAudioContext::maxNumberOfChannels()) + ").");
         return nullptr;
     }
 
diff --git a/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNode.h b/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNode.h
index 28a186c..a018e487 100644
--- a/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNode.h
@@ -36,7 +36,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 class AudioBuffer;
 
 // ScriptProcessorNode is an AudioNode which allows for arbitrary synthesis or processing directly using JavaScript.
@@ -103,10 +103,10 @@
     // latency. Higher numbers will be necessary to avoid audio breakup and
     // glitches.
     // The value chosen must carefully balance between latency and audio quality.
-    static ScriptProcessorNode* create(AbstractAudioContext&, ExceptionState&);
-    static ScriptProcessorNode* create(AbstractAudioContext&, size_t bufferSize, ExceptionState&);
-    static ScriptProcessorNode* create(AbstractAudioContext&, size_t bufferSize, unsigned numberOfInputChannels, ExceptionState&);
-    static ScriptProcessorNode* create(AbstractAudioContext&, size_t bufferSize, unsigned numberOfInputChannels, unsigned numberOfOutputChannels, ExceptionState&);
+    static ScriptProcessorNode* create(BaseAudioContext&, ExceptionState&);
+    static ScriptProcessorNode* create(BaseAudioContext&, size_t bufferSize, ExceptionState&);
+    static ScriptProcessorNode* create(BaseAudioContext&, size_t bufferSize, unsigned numberOfInputChannels, ExceptionState&);
+    static ScriptProcessorNode* create(BaseAudioContext&, size_t bufferSize, unsigned numberOfInputChannels, unsigned numberOfOutputChannels, ExceptionState&);
 
     DEFINE_ATTRIBUTE_EVENT_LISTENER(audioprocess);
     size_t bufferSize() const;
@@ -117,7 +117,7 @@
     DEFINE_INLINE_VIRTUAL_TRACE() { AudioNode::trace(visitor); }
 
 private:
-    ScriptProcessorNode(AbstractAudioContext&, float sampleRate, size_t bufferSize, unsigned numberOfInputChannels, unsigned numberOfOutputChannels);
+    ScriptProcessorNode(BaseAudioContext&, float sampleRate, size_t bufferSize, unsigned numberOfInputChannels, unsigned numberOfOutputChannels);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNodeTest.cpp b/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNodeTest.cpp
index d22af2d..51d8108 100644
--- a/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNodeTest.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/ScriptProcessorNodeTest.cpp
@@ -18,7 +18,7 @@
     ScriptProcessorHandler& handler = static_cast<ScriptProcessorHandler&>(node->handler());
     EXPECT_EQ(2u, handler.m_inputBuffers.size());
     EXPECT_EQ(2u, handler.m_outputBuffers.size());
-    AbstractAudioContext::AutoLocker locker(context);
+    BaseAudioContext::AutoLocker locker(context);
     handler.dispose();
     // Buffers should live after dispose() because an audio thread is using
     // them.
diff --git a/third_party/WebKit/Source/modules/webaudio/StereoPannerNode.cpp b/third_party/WebKit/Source/modules/webaudio/StereoPannerNode.cpp
index b957b8fe..4962c83 100644
--- a/third_party/WebKit/Source/modules/webaudio/StereoPannerNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/StereoPannerNode.cpp
@@ -7,9 +7,9 @@
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/ExecutionContext.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioNodeInput.h"
 #include "modules/webaudio/AudioNodeOutput.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "platform/audio/StereoPanner.h"
 #include "wtf/MathExtras.h"
 
@@ -83,7 +83,7 @@
 void StereoPannerHandler::setChannelCount(unsigned long channelCount, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     // A PannerNode only supports 1 or 2 channels
     if (channelCount > 0 && channelCount <= 2) {
@@ -108,7 +108,7 @@
 void StereoPannerHandler::setChannelCountMode(const String& mode, ExceptionState& exceptionState)
 {
     ASSERT(isMainThread());
-    AbstractAudioContext::AutoLocker locker(context());
+    BaseAudioContext::AutoLocker locker(context());
 
     ChannelCountMode oldMode = m_channelCountMode;
 
@@ -134,14 +134,14 @@
 
 // ----------------------------------------------------------------
 
-StereoPannerNode::StereoPannerNode(AbstractAudioContext& context)
+StereoPannerNode::StereoPannerNode(BaseAudioContext& context)
     : AudioNode(context)
     , m_pan(AudioParam::create(context, ParamTypeStereoPannerPan, 0, -1, 1))
 {
     setHandler(StereoPannerHandler::create(*this, context.sampleRate(), m_pan->handler()));
 }
 
-StereoPannerNode* StereoPannerNode::create(AbstractAudioContext& context, ExceptionState& exceptionState)
+StereoPannerNode* StereoPannerNode::create(BaseAudioContext& context, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
diff --git a/third_party/WebKit/Source/modules/webaudio/StereoPannerNode.h b/third_party/WebKit/Source/modules/webaudio/StereoPannerNode.h
index 4837c43..c450d47 100644
--- a/third_party/WebKit/Source/modules/webaudio/StereoPannerNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/StereoPannerNode.h
@@ -14,7 +14,7 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 
 // StereoPannerNode is an AudioNode with one input and one output. It is
 // specifically designed for equal-power stereo panning.
@@ -43,13 +43,13 @@
 class StereoPannerNode final : public AudioNode {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static StereoPannerNode* create(AbstractAudioContext&, ExceptionState&);
+    static StereoPannerNode* create(BaseAudioContext&, ExceptionState&);
     DECLARE_VIRTUAL_TRACE();
 
     AudioParam* pan() const;
 
 private:
-    StereoPannerNode(AbstractAudioContext&);
+    StereoPannerNode(BaseAudioContext&);
 
     Member<AudioParam> m_pan;
 };
diff --git a/third_party/WebKit/Source/modules/webaudio/StereoPannerNodeTest.cpp b/third_party/WebKit/Source/modules/webaudio/StereoPannerNodeTest.cpp
index 2f02f608..204d29e 100644
--- a/third_party/WebKit/Source/modules/webaudio/StereoPannerNodeTest.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/StereoPannerNodeTest.cpp
@@ -17,7 +17,7 @@
     StereoPannerNode* node = context->createStereoPanner(ASSERT_NO_EXCEPTION);
     StereoPannerHandler& handler = static_cast<StereoPannerHandler&>(node->handler());
     EXPECT_TRUE(handler.m_stereoPanner);
-    AbstractAudioContext::AutoLocker locker(context);
+    BaseAudioContext::AutoLocker locker(context);
     handler.dispose();
     // m_stereoPanner should live after dispose() because an audio thread is
     // using it.
diff --git a/third_party/WebKit/Source/modules/webaudio/WaveShaperNode.cpp b/third_party/WebKit/Source/modules/webaudio/WaveShaperNode.cpp
index ae9ae322..c0046ed 100644
--- a/third_party/WebKit/Source/modules/webaudio/WaveShaperNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/WaveShaperNode.cpp
@@ -25,14 +25,14 @@
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/ExceptionCode.h"
-#include "modules/webaudio/AbstractAudioContext.h"
 #include "modules/webaudio/AudioBasicProcessorHandler.h"
+#include "modules/webaudio/BaseAudioContext.h"
 #include "modules/webaudio/WaveShaperNode.h"
 #include "wtf/PtrUtil.h"
 
 namespace blink {
 
-WaveShaperNode::WaveShaperNode(AbstractAudioContext& context)
+WaveShaperNode::WaveShaperNode(BaseAudioContext& context)
     : AudioNode(context)
 {
     setHandler(AudioBasicProcessorHandler::create(AudioHandler::NodeTypeWaveShaper, *this, context.sampleRate(), wrapUnique(new WaveShaperProcessor(context.sampleRate(), 1))));
@@ -40,7 +40,7 @@
     handler().initialize();
 }
 
-WaveShaperNode* WaveShaperNode::create(AbstractAudioContext& context, ExceptionState& exceptionState)
+WaveShaperNode* WaveShaperNode::create(BaseAudioContext& context, ExceptionState& exceptionState)
 {
     DCHECK(isMainThread());
 
@@ -86,7 +86,7 @@
     // This is to synchronize with the changes made in
     // AudioBasicProcessorNode::checkNumberOfChannelsForInput() where we can
     // initialize() and uninitialize().
-    AbstractAudioContext::AutoLocker contextLocker(context());
+    BaseAudioContext::AutoLocker contextLocker(context());
 
     if (type == "none") {
         getWaveShaperProcessor()->setOversample(WaveShaperProcessor::OverSampleNone);
diff --git a/third_party/WebKit/Source/modules/webaudio/WaveShaperNode.h b/third_party/WebKit/Source/modules/webaudio/WaveShaperNode.h
index bfaf39f9..b089ca88 100644
--- a/third_party/WebKit/Source/modules/webaudio/WaveShaperNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/WaveShaperNode.h
@@ -31,13 +31,13 @@
 
 namespace blink {
 
-class AbstractAudioContext;
+class BaseAudioContext;
 class ExceptionState;
 
 class WaveShaperNode final : public AudioNode {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static WaveShaperNode* create(AbstractAudioContext&, ExceptionState&);
+    static WaveShaperNode* create(BaseAudioContext&, ExceptionState&);
 
     // setCurve() is called on the main thread.
     void setCurve(DOMFloat32Array*, ExceptionState&);
@@ -47,7 +47,7 @@
     String oversample() const;
 
 private:
-    explicit WaveShaperNode(AbstractAudioContext&);
+    explicit WaveShaperNode(BaseAudioContext&);
 
     WaveShaperProcessor* getWaveShaperProcessor() const;
 };
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContext.h b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContext.h
index 68959acd..9867f46 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContext.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContext.h
@@ -32,7 +32,6 @@
 
     CanvasRenderingContext::ContextType getContextType() const override { return CanvasRenderingContext::ContextWebgl2; }
     ImageBitmap* transferToImageBitmap(ExceptionState&) final;
-    unsigned version() const override { return 2; }
     String contextName() const override { return "WebGL2RenderingContext"; }
     void registerContextExtensions() override;
     void setCanvasGetContextResult(RenderingContext&) final;
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
index a9e38544..7580935 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
@@ -115,7 +115,7 @@
 };
 
 WebGL2RenderingContextBase::WebGL2RenderingContextBase(HTMLCanvasElement* passedCanvas, std::unique_ptr<WebGraphicsContext3DProvider> contextProvider, const WebGLContextAttributes& requestedAttributes)
-    : WebGLRenderingContextBase(passedCanvas, std::move(contextProvider), requestedAttributes)
+    : WebGLRenderingContextBase(passedCanvas, std::move(contextProvider), requestedAttributes, 2)
 {
     m_supportedInternalFormatsStorage.insert(kSupportedInternalFormatsStorage, kSupportedInternalFormatsStorage + WTF_ARRAY_LENGTH(kSupportedInternalFormatsStorage));
     m_supportedInternalFormatsStorage.insert(kCompressedTextureFormatsETC2EAC, kCompressedTextureFormatsETC2EAC + WTF_ARRAY_LENGTH(kCompressedTextureFormatsETC2EAC));
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.cpp
index c2509ac..846ddbb 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.cpp
@@ -123,12 +123,12 @@
 }
 
 WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, std::unique_ptr<WebGraphicsContext3DProvider> contextProvider, const WebGLContextAttributes& requestedAttributes)
-    : WebGLRenderingContextBase(passedCanvas, std::move(contextProvider), requestedAttributes)
+    : WebGLRenderingContextBase(passedCanvas, std::move(contextProvider), requestedAttributes, 1)
 {
 }
 
 WebGLRenderingContext::WebGLRenderingContext(OffscreenCanvas* passedOffscreenCanvas, std::unique_ptr<WebGraphicsContext3DProvider> contextProvider, const WebGLContextAttributes& requestedAttributes)
-    : WebGLRenderingContextBase(passedOffscreenCanvas, std::move(contextProvider), requestedAttributes)
+    : WebGLRenderingContextBase(passedOffscreenCanvas, std::move(contextProvider), requestedAttributes, 1)
 {
 }
 
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.h
index d3d7b2bd..de964da 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContext.h
@@ -53,7 +53,6 @@
 
     CanvasRenderingContext::ContextType getContextType() const override { return CanvasRenderingContext::ContextWebgl; }
     ImageBitmap* transferToImageBitmap(ExceptionState&) final;
-    unsigned version() const override { return 1; }
     String contextName() const override { return "WebGLRenderingContext"; }
     void registerContextExtensions() override;
     void setCanvasGetContextResult(RenderingContext&) final;
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index f516c0d..ebed1a6 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -885,15 +885,21 @@
 
 } // namespace
 
-WebGLRenderingContextBase::WebGLRenderingContextBase(OffscreenCanvas* passedOffscreenCanvas, std::unique_ptr<WebGraphicsContext3DProvider> contextProvider, const WebGLContextAttributes& requestedAttributes)
-    : WebGLRenderingContextBase(nullptr, passedOffscreenCanvas, std::move(contextProvider), requestedAttributes)
+WebGLRenderingContextBase::WebGLRenderingContextBase(OffscreenCanvas* passedOffscreenCanvas,
+    std::unique_ptr<WebGraphicsContext3DProvider> contextProvider,
+    const WebGLContextAttributes& requestedAttributes, unsigned version)
+    : WebGLRenderingContextBase(nullptr, passedOffscreenCanvas, std::move(contextProvider), requestedAttributes, version)
 { }
 
-WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCanvas, std::unique_ptr<WebGraphicsContext3DProvider> contextProvider, const WebGLContextAttributes& requestedAttributes)
-    : WebGLRenderingContextBase(passedCanvas, nullptr, std::move(contextProvider), requestedAttributes)
+WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCanvas,
+    std::unique_ptr<WebGraphicsContext3DProvider> contextProvider,
+    const WebGLContextAttributes& requestedAttributes, unsigned version)
+    : WebGLRenderingContextBase(passedCanvas, nullptr, std::move(contextProvider), requestedAttributes, version)
 { }
 
-WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCanvas, OffscreenCanvas* passedOffscreenCanvas, std::unique_ptr<WebGraphicsContext3DProvider> contextProvider, const WebGLContextAttributes& requestedAttributes)
+WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCanvas,
+    OffscreenCanvas* passedOffscreenCanvas, std::unique_ptr<WebGraphicsContext3DProvider> contextProvider,
+    const WebGLContextAttributes& requestedAttributes, unsigned version)
     : CanvasRenderingContext(passedCanvas, passedOffscreenCanvas)
     , m_isHidden(false)
     , m_contextLostMode(NotLostContext)
@@ -913,6 +919,7 @@
     , m_isOESTextureHalfFloatFormatsTypesAdded(false)
     , m_isWebGLDepthTextureFormatsTypesAdded(false)
     , m_isEXTsRGBFormatsTypesAdded(false)
+    , m_version(version)
 {
     ASSERT(contextProvider);
 
@@ -952,6 +959,14 @@
     bool wantStencilBuffer = m_requestedAttributes.stencil();
     bool wantAntialiasing = m_requestedAttributes.antialias();
     DrawingBuffer::PreserveDrawingBuffer preserve = m_requestedAttributes.preserveDrawingBuffer() ? DrawingBuffer::Preserve : DrawingBuffer::Discard;
+    DrawingBuffer::WebGLVersion webGLVersion = DrawingBuffer::WebGL1;
+    if (version() == 1) {
+        webGLVersion = DrawingBuffer::WebGL1;
+    } else if (version() == 2) {
+        webGLVersion = DrawingBuffer::WebGL2;
+    } else {
+        NOTREACHED();
+    }
     return DrawingBuffer::create(
         std::move(contextProvider),
         clampedCanvasSize(),
@@ -960,7 +975,8 @@
         wantDepthBuffer,
         wantStencilBuffer,
         wantAntialiasing,
-        preserve);
+        preserve,
+        webGLVersion);
 }
 
 void WebGLRenderingContextBase::initializeNewContext()
@@ -5482,10 +5498,6 @@
     for (size_t i = 0; i < string.length(); ++i) {
         // line-continuation character \ is supported in WebGL 2.0.
         if (isWebGL2OrHigher() && string[i] == '\\') {
-            if (i + 1 >= string.length() || (string[i + 1] != '\n' && string[i + 1] != '\r')) {
-                synthesizeGLError(GL_INVALID_VALUE, "shaderSource", "line-continuation character is not immediately preceding a new-line");
-                return false;
-            }
             continue;
         }
         if (!validateCharacter(string[i])) {
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
index a78cbf82..5d31262 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -131,7 +131,6 @@
 public:
     ~WebGLRenderingContextBase() override;
 
-    virtual unsigned version() const = 0;
     virtual String contextName() const = 0;
     virtual void registerContextExtensions() = 0;
 
@@ -143,6 +142,8 @@
     static std::unique_ptr<WebGraphicsContext3DProvider> createWebGraphicsContext3DProvider(ScriptState*, WebGLContextAttributes, unsigned webGLVersion);
     static void forceNextWebGLContextCreationToFail();
 
+    unsigned version() const { return m_version; }
+
     int drawingBufferWidth() const;
     int drawingBufferHeight() const;
 
@@ -430,8 +431,8 @@
     friend class ScopedTexture2DRestorer;
     friend class ScopedFramebufferRestorer;
 
-    WebGLRenderingContextBase(HTMLCanvasElement*, std::unique_ptr<WebGraphicsContext3DProvider>, const WebGLContextAttributes&);
-    WebGLRenderingContextBase(OffscreenCanvas*, std::unique_ptr<WebGraphicsContext3DProvider>, const WebGLContextAttributes&);
+    WebGLRenderingContextBase(HTMLCanvasElement*, std::unique_ptr<WebGraphicsContext3DProvider>, const WebGLContextAttributes&, unsigned);
+    WebGLRenderingContextBase(OffscreenCanvas*, std::unique_ptr<WebGraphicsContext3DProvider>, const WebGLContextAttributes&, unsigned);
     PassRefPtr<DrawingBuffer> createDrawingBuffer(std::unique_ptr<WebGraphicsContext3DProvider>);
     void setupFlags();
 
@@ -1107,10 +1108,12 @@
     static const char* getTexImageFunctionName(TexImageFunctionID);
 
 private:
-    WebGLRenderingContextBase(HTMLCanvasElement*, OffscreenCanvas*, std::unique_ptr<WebGraphicsContext3DProvider>, const WebGLContextAttributes&);
+    WebGLRenderingContextBase(HTMLCanvasElement*, OffscreenCanvas*, std::unique_ptr<WebGraphicsContext3DProvider>, const WebGLContextAttributes&, unsigned);
     static std::unique_ptr<WebGraphicsContext3DProvider> createContextProviderInternal(HTMLCanvasElement*, ScriptState*, WebGLContextAttributes, unsigned);
     void texImageCanvasByGPU(HTMLCanvasElement*, GLuint, GLenum, GLenum, GLint);
     void texImageBitmapByGPU(ImageBitmap*, GLuint, GLenum, GLenum, GLint, bool);
+
+    const unsigned m_version;
 };
 
 DEFINE_TYPE_CASTS(WebGLRenderingContextBase, CanvasRenderingContext, context, context->is3d(), context.is3d());
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
index d5afa1e..e0c6480 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -106,7 +106,6 @@
 ImageRenderingPixelated status=stable
 IndexedDBExperimental status=experimental
 InertTopControls status=experimental
-InputDeviceCapabilities status=stable
 InputEvent status=experimental
 InputModeAttribute status=experimental
 InputMultipleFieldsUI status=stable
@@ -155,8 +154,7 @@
 OverlayScrollbars
 PagePopup status=stable
 PaintOptimizations status=stable
-PassiveDocumentEventListeners
-PassiveEventListeners status=stable
+PassiveDocumentEventListeners status=experimental
 PassPaintVisualRectToCompositor
 PathOpsSVGClipping status=stable
 PaymentRequest status=experimental
diff --git a/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp b/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp
index 7a5173e..592c323 100644
--- a/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp
@@ -39,6 +39,7 @@
 #include "public/platform/WebURL.h"
 #include "public/platform/WebURLLoadTiming.h"
 #include "wtf/Allocator.h"
+#include "wtf/Assertions.h"
 #include "wtf/PtrUtil.h"
 #include "wtf/RefPtr.h"
 #include <memory>
@@ -76,39 +77,54 @@
         m_resourceResponse = &m_resourceResponseAllocation;
     }
 
-    WebURLResponsePrivateImpl(const WebURLResponsePrivate* p)
-        : m_resourceResponseAllocation(*p->m_resourceResponse)
+    WebURLResponsePrivateImpl(const WebURLResponsePrivate& p)
+        : m_resourceResponseAllocation(*p.m_resourceResponse)
     {
         m_resourceResponse = &m_resourceResponseAllocation;
     }
 
-    virtual void dispose() { delete this; }
+    ~WebURLResponsePrivateImpl() override {}
 
 private:
-    virtual ~WebURLResponsePrivateImpl() { }
-
     ResourceResponse m_resourceResponseAllocation;
 };
 
-void WebURLResponse::initialize()
+WebURLResponse::~WebURLResponse()
 {
-    assign(new WebURLResponsePrivateImpl());
 }
 
-void WebURLResponse::reset()
+WebURLResponse::WebURLResponse()
+    : m_owningPrivate(new WebURLResponsePrivateImpl())
+    , m_private(m_owningPrivate.get())
 {
-    assign(0);
 }
 
-void WebURLResponse::assign(const WebURLResponse& r)
+WebURLResponse::WebURLResponse(const WebURLResponse& r)
+    : m_owningPrivate(new WebURLResponsePrivateImpl(*r.m_private))
+    , m_private(m_owningPrivate.get())
 {
+}
+
+WebURLResponse::WebURLResponse(const WebURL& url)
+    : WebURLResponse()
+{
+    setURL(url);
+}
+
+WebURLResponse& WebURLResponse::operator=(const WebURLResponse& r)
+{
+    // Copying subclasses that have different m_private ownership semantics
+    // via this operator is just not supported.
+    DCHECK(m_owningPrivate);
+    DCHECK(m_private->m_resourceResponse);
     if (&r != this)
-        assign(r.m_private ? new WebURLResponsePrivateImpl(r.m_private) : 0);
+        *m_private->m_resourceResponse = *r.m_private->m_resourceResponse;
+    return *this;
 }
 
 bool WebURLResponse::isNull() const
 {
-    return !m_private || m_private->m_resourceResponse->isNull();
+    return m_private->m_resourceResponse->isNull();
 }
 
 WebURL WebURLResponse::url() const
@@ -342,17 +358,13 @@
 
 ResourceResponse& WebURLResponse::toMutableResourceResponse()
 {
-    ASSERT(m_private);
-    ASSERT(m_private->m_resourceResponse);
-
+    DCHECK(m_private->m_resourceResponse);
     return *m_private->m_resourceResponse;
 }
 
 const ResourceResponse& WebURLResponse::toResourceResponse() const
 {
-    ASSERT(m_private);
-    ASSERT(m_private->m_resourceResponse);
-
+    DCHECK(m_private->m_resourceResponse);
     return *m_private->m_resourceResponse;
 }
 
@@ -511,15 +523,10 @@
     m_private->m_resourceResponse->setExtraData(ExtraDataContainer::create(extraData));
 }
 
-void WebURLResponse::assign(WebURLResponsePrivate* p)
+WebURLResponse::WebURLResponse(WebURLResponsePrivate* p)
+    : m_private(p)
 {
-    // Subclasses may call this directly so a self-assignment check is needed
-    // here as well as in the public assign method.
-    if (m_private == p)
-        return;
-    if (m_private)
-        m_private->dispose();
-    m_private = p;
+    DCHECK(p);
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebURLResponsePrivate.h b/third_party/WebKit/Source/platform/exported/WebURLResponsePrivate.h
index 81cb5c06..1f068fa 100644
--- a/third_party/WebKit/Source/platform/exported/WebURLResponsePrivate.h
+++ b/third_party/WebKit/Source/platform/exported/WebURLResponsePrivate.h
@@ -41,10 +41,8 @@
 class WebURLResponsePrivate {
     WTF_MAKE_NONCOPYABLE(WebURLResponsePrivate);
 public:
-    WebURLResponsePrivate() : m_resourceResponse(0) { }
-
-    // Called by WebURLResponse when it no longer needs this object.
-    virtual void dispose() = 0;
+    WebURLResponsePrivate() : m_resourceResponse(nullptr) {}
+    virtual ~WebURLResponsePrivate() {}
 
     ResourceResponse* m_resourceResponse;
 };
diff --git a/third_party/WebKit/Source/platform/exported/WrappedResourceResponse.h b/third_party/WebKit/Source/platform/exported/WrappedResourceResponse.h
index 0f9c75a..806600a 100644
--- a/third_party/WebKit/Source/platform/exported/WrappedResourceResponse.h
+++ b/third_party/WebKit/Source/platform/exported/WrappedResourceResponse.h
@@ -37,44 +37,27 @@
 
 namespace blink {
 
+// WrappedResourceResponse doesn't take ownership of given ResourceResponse,
+// but just holds a pointer to it. It is not copyable (as WebURLResponsePrivate
+// is non-copyable).
 class WrappedResourceResponse : public WebURLResponse {
 public:
-    ~WrappedResourceResponse()
-    {
-        reset(); // Need to drop reference to m_handle
-    }
+    ~WrappedResourceResponse() {}
 
-    WrappedResourceResponse() { }
-
-    WrappedResourceResponse(ResourceResponse& resourceResponse)
-    {
-        bind(resourceResponse);
-    }
-
-    WrappedResourceResponse(const ResourceResponse& resourceResponse)
-    {
-        bind(resourceResponse);
-    }
-
-    void bind(ResourceResponse& resourceResponse)
+    explicit WrappedResourceResponse(ResourceResponse& resourceResponse)
+        : WebURLResponse(&m_handle)
     {
         m_handle.m_resourceResponse = &resourceResponse;
-        assign(&m_handle);
     }
 
-    void bind(const ResourceResponse& resourceResponse)
+    explicit WrappedResourceResponse(const ResourceResponse& resourceResponse)
+        : WrappedResourceResponse(const_cast<ResourceResponse&>(resourceResponse))
     {
-        bind(*const_cast<ResourceResponse*>(&resourceResponse));
     }
 
 private:
-    class Handle : public WebURLResponsePrivate {
-        DISALLOW_NEW();
-    public:
-        virtual void dispose() { m_resourceResponse = 0; }
-    };
-
-    Handle m_handle;
+    // This is pointed by m_private.
+    WebURLResponsePrivate m_handle;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
index f921797..11b5738 100644
--- a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
+++ b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
@@ -72,7 +72,7 @@
 void RecordingImageBufferSurface::fallBackToRasterCanvas(FallbackReason reason)
 {
     ASSERT(m_fallbackFactory);
-    DCHECK(reason != FallbackReasonUnknown);
+    CHECK(reason != FallbackReasonUnknown);
 
     if (m_fallbackSurface) {
         ASSERT(!m_currentFrame);
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
index 40ecd354..da950babf 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
@@ -11,8 +11,11 @@
 #include "cc/playback/display_item_list_settings.h"
 #include "cc/playback/drawing_display_item.h"
 #include "cc/playback/transform_display_item.h"
+#include "cc/trees/clip_node.h"
+#include "cc/trees/effect_node.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/property_tree.h"
+#include "cc/trees/transform_node.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/graphics/paint/ClipPaintPropertyNode.h"
 #include "platform/graphics/paint/DisplayItem.h"
@@ -236,7 +239,7 @@
     transformTree.clear();
     cc::TransformNode& transformNode = *transformTree.Node(transformTree.Insert(cc::TransformNode(), kRealRootNodeId));
     DCHECK_EQ(transformNode.id, kSecondaryRootNodeId);
-    transformNode.data.source_node_id = transformNode.parent_id;
+    transformNode.source_node_id = transformNode.parent_id;
     transformTree.SetTargetId(transformNode.id, kRealRootNodeId);
     transformTree.SetContentTargetId(transformNode.id, kRealRootNodeId);
 
@@ -253,8 +256,8 @@
     cc::EffectNode& effectNode = *effectTree.Node(effectTree.Insert(cc::EffectNode(), kRealRootNodeId));
     DCHECK_EQ(effectNode.id, kSecondaryRootNodeId);
     effectNode.owner_id = ownerId;
-    effectNode.data.clip_id = clipNode.id;
-    effectNode.data.has_render_surface = true;
+    effectNode.clip_id = clipNode.id;
+    effectNode.has_render_surface = true;
 
     cc::ScrollTree& scrollTree = propertyTrees->scroll_tree;
     scrollTree.clear();
@@ -345,9 +348,11 @@
         , m_rootLayer(rootLayer) {}
 
     int compositorIdForTransformNode(const TransformPaintPropertyNode*);
+    int compositorIdForClipNode(const ClipPaintPropertyNode*);
 
 private:
     cc::TransformTree& transformTree() { return m_propertyTrees.transform_tree; }
+    cc::ClipTree& clipTree() { return m_propertyTrees.clip_tree; }
 
     // Property trees which should be updated by the manager.
     cc::PropertyTrees& m_propertyTrees;
@@ -356,8 +361,9 @@
     // have any actual children, but at present must exist in the tree.
     cc::Layer* m_rootLayer;
 
-    // Map from Blink-side transform nodes to cc transform node indices.
+    // Maps from Blink-side property tree nodes to cc property node indices.
     HashMap<const TransformPaintPropertyNode*, int> m_transformNodeMap;
+    HashMap<const ClipPaintPropertyNode*, int> m_clipNodeMap;
 };
 
 int PropertyTreeManager::compositorIdForTransformNode(const TransformPaintPropertyNode* transformNode)
@@ -376,15 +382,15 @@
     cc::TransformNode& compositorNode = *transformTree().Node(id);
     transformTree().SetTargetId(id, kRealRootNodeId);
     transformTree().SetContentTargetId(id, kRealRootNodeId);
-    compositorNode.data.source_node_id = parentId;
+    compositorNode.source_node_id = parentId;
 
     FloatPoint3D origin = transformNode->origin();
-    compositorNode.data.pre_local.matrix().setTranslate(
+    compositorNode.pre_local.matrix().setTranslate(
         -origin.x(), -origin.y(), -origin.z());
-    compositorNode.data.local.matrix() = TransformationMatrix::toSkMatrix44(transformNode->matrix());
-    compositorNode.data.post_local.matrix().setTranslate(
+    compositorNode.local.matrix() = TransformationMatrix::toSkMatrix44(transformNode->matrix());
+    compositorNode.post_local.matrix().setTranslate(
         origin.x(), origin.y(), origin.z());
-    compositorNode.data.needs_local_transform_update = true;
+    compositorNode.needs_local_transform_update = true;
 
     m_rootLayer->AddChild(dummyLayer);
     dummyLayer->SetTransformTreeIndex(id);
@@ -399,6 +405,43 @@
     return id;
 }
 
+int PropertyTreeManager::compositorIdForClipNode(const ClipPaintPropertyNode* clipNode)
+{
+    if (!clipNode)
+        return kSecondaryRootNodeId;
+
+    auto it = m_clipNodeMap.find(clipNode);
+    if (it != m_clipNodeMap.end())
+        return it->value;
+
+    scoped_refptr<cc::Layer> dummyLayer = cc::Layer::Create();
+    int parentId = compositorIdForClipNode(clipNode->parent());
+    int id = clipTree().Insert(cc::ClipNode(), parentId);
+
+    cc::ClipNode& compositorNode = *clipTree().Node(id);
+    compositorNode.owner_id = dummyLayer->id();
+
+    // TODO(jbroman): Don't discard rounded corners.
+    compositorNode.clip = clipNode->clipRect().rect();
+    compositorNode.transform_id = compositorIdForTransformNode(clipNode->localTransformSpace());
+    compositorNode.target_id = kRealRootNodeId;
+    compositorNode.applies_local_clip = true;
+    compositorNode.layers_are_clipped = true;
+    compositorNode.layers_are_clipped_when_surfaces_disabled = true;
+
+    m_rootLayer->AddChild(dummyLayer);
+    dummyLayer->SetTransformTreeIndex(compositorNode.transform_id);
+    dummyLayer->SetClipTreeIndex(id);
+    dummyLayer->SetEffectTreeIndex(kSecondaryRootNodeId);
+    dummyLayer->SetScrollTreeIndex(kRealRootNodeId);
+    dummyLayer->set_property_tree_sequence_number(kPropertyTreeSequenceNumber);
+
+    auto result = m_clipNodeMap.set(clipNode, id);
+    DCHECK(result.isNewEntry);
+    clipTree().set_needs_update(true);
+    return id;
+}
+
 } // namespace
 
 void PaintArtifactCompositor::updateInLayerListMode(const PaintArtifact& paintArtifact)
@@ -421,12 +464,14 @@
         scoped_refptr<cc::Layer> layer = layerForPaintChunk(paintArtifact, paintChunk, layerOffset);
 
         int transformId = propertyTreeManager.compositorIdForTransformNode(paintChunk.properties.transform.get());
+        int clipId = propertyTreeManager.compositorIdForClipNode(paintChunk.properties.clip.get());
+
         layer->set_offset_to_transform_parent(layerOffset);
 
         m_rootLayer->AddChild(layer);
         layer->set_property_tree_sequence_number(kPropertyTreeSequenceNumber);
         layer->SetTransformTreeIndex(transformId);
-        layer->SetClipTreeIndex(kSecondaryRootNodeId);
+        layer->SetClipTreeIndex(clipId);
         layer->SetEffectTreeIndex(kSecondaryRootNodeId);
         layer->SetScrollTreeIndex(kRealRootNodeId);
 
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp
index 457411c..4640c277 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp
@@ -8,6 +8,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "cc/layers/layer.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/trees/clip_node.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_settings.h"
 #include "platform/RuntimeEnabledFeatures.h"
@@ -518,6 +519,171 @@
         contentLayerAt(1)->transform_tree_index());
 }
 
+TEST_F(PaintArtifactCompositorTestWithPropertyTrees, OneClip)
+{
+    RefPtr<ClipPaintPropertyNode> clip = ClipPaintPropertyNode::create(
+        nullptr, FloatRoundedRect(100, 100, 300, 200));
+
+    TestPaintArtifact artifact;
+    artifact.chunk(nullptr, clip, nullptr)
+        .rectDrawing(FloatRect(220, 80, 300, 200), Color::black);
+    update(artifact.build());
+
+    ASSERT_EQ(1u, contentLayerCount());
+    const cc::Layer* layer = contentLayerAt(0);
+    EXPECT_THAT(layer->GetPicture(),
+        Pointee(drawsRectangle(FloatRect(0, 0, 300, 200), Color::black)));
+    EXPECT_EQ(translation(220, 80), layer->screen_space_transform());
+
+    const cc::ClipNode* clipNode = propertyTrees().clip_tree.Node(layer->clip_tree_index());
+    EXPECT_TRUE(clipNode->applies_local_clip);
+    EXPECT_TRUE(clipNode->layers_are_clipped);
+    EXPECT_EQ(gfx::RectF(100, 100, 300, 200), clipNode->clip);
+}
+
+TEST_F(PaintArtifactCompositorTestWithPropertyTrees, NestedClips)
+{
+    RefPtr<ClipPaintPropertyNode> clip1 = ClipPaintPropertyNode::create(
+        nullptr, FloatRoundedRect(100, 100, 700, 700));
+    RefPtr<ClipPaintPropertyNode> clip2 = ClipPaintPropertyNode::create(
+        nullptr, FloatRoundedRect(200, 200, 700, 100), clip1);
+
+    TestPaintArtifact artifact;
+    artifact.chunk(nullptr, clip1, nullptr)
+        .rectDrawing(FloatRect(300, 350, 100, 100), Color::white);
+    artifact.chunk(nullptr, clip2, nullptr)
+        .rectDrawing(FloatRect(300, 350, 100, 100), Color::lightGray);
+    artifact.chunk(nullptr, clip1, nullptr)
+        .rectDrawing(FloatRect(300, 350, 100, 100), Color::darkGray);
+    artifact.chunk(nullptr, clip2, nullptr)
+        .rectDrawing(FloatRect(300, 350, 100, 100), Color::black);
+    update(artifact.build());
+
+    ASSERT_EQ(4u, contentLayerCount());
+
+    const cc::Layer* whiteLayer = contentLayerAt(0);
+    EXPECT_THAT(whiteLayer->GetPicture(),
+        Pointee(drawsRectangle(FloatRect(0, 0, 100, 100), Color::white)));
+    EXPECT_EQ(translation(300, 350), whiteLayer->screen_space_transform());
+
+    const cc::Layer* lightGrayLayer = contentLayerAt(1);
+    EXPECT_THAT(lightGrayLayer->GetPicture(),
+        Pointee(drawsRectangle(FloatRect(0, 0, 100, 100), Color::lightGray)));
+    EXPECT_EQ(translation(300, 350), lightGrayLayer->screen_space_transform());
+
+    const cc::Layer* darkGrayLayer = contentLayerAt(2);
+    EXPECT_THAT(darkGrayLayer->GetPicture(),
+        Pointee(drawsRectangle(FloatRect(0, 0, 100, 100), Color::darkGray)));
+    EXPECT_EQ(translation(300, 350), darkGrayLayer->screen_space_transform());
+
+    const cc::Layer* blackLayer = contentLayerAt(3);
+    EXPECT_THAT(blackLayer->GetPicture(),
+        Pointee(drawsRectangle(FloatRect(0, 0, 100, 100), Color::black)));
+    EXPECT_EQ(translation(300, 350), blackLayer->screen_space_transform());
+
+    EXPECT_EQ(whiteLayer->clip_tree_index(), darkGrayLayer->clip_tree_index());
+    const cc::ClipNode* outerClip = propertyTrees().clip_tree.Node(whiteLayer->clip_tree_index());
+    EXPECT_TRUE(outerClip->applies_local_clip);
+    EXPECT_TRUE(outerClip->layers_are_clipped);
+    EXPECT_EQ(gfx::RectF(100, 100, 700, 700), outerClip->clip);
+
+    EXPECT_EQ(lightGrayLayer->clip_tree_index(), blackLayer->clip_tree_index());
+    const cc::ClipNode* innerClip = propertyTrees().clip_tree.Node(blackLayer->clip_tree_index());
+    EXPECT_TRUE(innerClip->applies_local_clip);
+    EXPECT_TRUE(innerClip->layers_are_clipped);
+    EXPECT_EQ(gfx::RectF(200, 200, 700, 100), innerClip->clip);
+    EXPECT_EQ(outerClip->id, innerClip->parent_id);
+}
+
+TEST_F(PaintArtifactCompositorTestWithPropertyTrees, DeeplyNestedClips)
+{
+    Vector<RefPtr<ClipPaintPropertyNode>> clips;
+    for (unsigned i = 1; i <= 10; i++) {
+        clips.append(ClipPaintPropertyNode::create(
+            nullptr, FloatRoundedRect(5 * i, 0, 100, 200 - 10 * i),
+            clips.isEmpty() ? nullptr : clips.last()));
+    }
+
+    TestPaintArtifact artifact;
+    artifact.chunk(nullptr, clips.last(), nullptr)
+        .rectDrawing(FloatRect(0, 0, 200, 200), Color::white);
+    update(artifact.build());
+
+    // Check the drawing layer.
+    ASSERT_EQ(1u, contentLayerCount());
+    const cc::Layer* drawingLayer = contentLayerAt(0);
+    EXPECT_THAT(drawingLayer->GetPicture(),
+        Pointee(drawsRectangle(FloatRect(0, 0, 200, 200), Color::white)));
+    EXPECT_EQ(gfx::Transform(), drawingLayer->screen_space_transform());
+
+    // Check the clip nodes.
+    const cc::ClipNode* clipNode = propertyTrees().clip_tree.Node(drawingLayer->clip_tree_index());
+    for (auto it = clips.rbegin(); it != clips.rend(); ++it) {
+        const ClipPaintPropertyNode* paintClipNode = it->get();
+        EXPECT_TRUE(clipNode->applies_local_clip);
+        EXPECT_TRUE(clipNode->layers_are_clipped);
+        EXPECT_EQ(paintClipNode->clipRect().rect(), clipNode->clip);
+        clipNode = propertyTrees().clip_tree.Node(clipNode->parent_id);
+    }
+}
+
+TEST_F(PaintArtifactCompositorTestWithPropertyTrees, SiblingClips)
+{
+    RefPtr<ClipPaintPropertyNode> commonClip = ClipPaintPropertyNode::create(
+        nullptr, FloatRoundedRect(0, 0, 800, 600));
+    RefPtr<ClipPaintPropertyNode> clip1 = ClipPaintPropertyNode::create(
+        nullptr, FloatRoundedRect(0, 0, 400, 600), commonClip);
+    RefPtr<ClipPaintPropertyNode> clip2 = ClipPaintPropertyNode::create(
+        nullptr, FloatRoundedRect(400, 0, 400, 600), commonClip);
+
+    TestPaintArtifact artifact;
+    artifact.chunk(nullptr, clip1, nullptr)
+        .rectDrawing(FloatRect(0, 0, 640, 480), Color::white);
+    artifact.chunk(nullptr, clip2, nullptr)
+        .rectDrawing(FloatRect(0, 0, 640, 480), Color::black);
+    update(artifact.build());
+
+    ASSERT_EQ(2u, contentLayerCount());
+
+    const cc::Layer* whiteLayer = contentLayerAt(0);
+    EXPECT_THAT(whiteLayer->GetPicture(),
+        Pointee(drawsRectangle(FloatRect(0, 0, 640, 480), Color::white)));
+    EXPECT_EQ(gfx::Transform(), whiteLayer->screen_space_transform());
+    const cc::ClipNode* whiteClip = propertyTrees().clip_tree.Node(whiteLayer->clip_tree_index());
+    EXPECT_TRUE(whiteClip->applies_local_clip);
+    EXPECT_TRUE(whiteClip->layers_are_clipped);
+    ASSERT_EQ(gfx::RectF(0, 0, 400, 600), whiteClip->clip);
+
+    const cc::Layer* blackLayer = contentLayerAt(1);
+    EXPECT_THAT(blackLayer->GetPicture(),
+        Pointee(drawsRectangle(FloatRect(0, 0, 640, 480), Color::black)));
+    EXPECT_EQ(gfx::Transform(), blackLayer->screen_space_transform());
+    const cc::ClipNode* blackClip = propertyTrees().clip_tree.Node(blackLayer->clip_tree_index());
+    EXPECT_TRUE(blackClip->applies_local_clip);
+    EXPECT_TRUE(blackClip->layers_are_clipped);
+    ASSERT_EQ(gfx::RectF(400, 0, 400, 600), blackClip->clip);
+
+    EXPECT_EQ(whiteClip->parent_id, blackClip->parent_id);
+    const cc::ClipNode* commonClipNode = propertyTrees().clip_tree.Node(whiteClip->parent_id);
+    EXPECT_TRUE(commonClipNode->applies_local_clip);
+    EXPECT_TRUE(commonClipNode->layers_are_clipped);
+    ASSERT_EQ(gfx::RectF(0, 0, 800, 600), commonClipNode->clip);
+}
+
+TEST_F(PaintArtifactCompositorTestWithPropertyTrees, ForeignLayerPassesThrough)
+{
+    scoped_refptr<cc::Layer> layer = cc::Layer::Create();
+
+    TestPaintArtifact artifact;
+    artifact.chunk(PaintChunkProperties())
+        .foreignLayer(FloatPoint(50, 100), IntSize(400, 300), layer);
+    update(artifact.build());
+
+    ASSERT_EQ(1u, contentLayerCount());
+    EXPECT_EQ(layer, contentLayerAt(0));
+    EXPECT_EQ(gfx::Size(400, 300), layer->bounds());
+    EXPECT_EQ(translation(50, 100), layer->screen_space_transform());
+}
 
 } // namespace
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp
index 6b4d710d..d8f5af2 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp
@@ -81,7 +81,10 @@
 
 } // namespace
 
-PassRefPtr<DrawingBuffer> DrawingBuffer::create(std::unique_ptr<WebGraphicsContext3DProvider> contextProvider, const IntSize& size, bool premultipliedAlpha, bool wantAlphaChannel, bool wantDepthBuffer, bool wantStencilBuffer, bool wantAntialiasing, PreserveDrawingBuffer preserve)
+PassRefPtr<DrawingBuffer> DrawingBuffer::create(std::unique_ptr<WebGraphicsContext3DProvider> contextProvider,
+    const IntSize& size, bool premultipliedAlpha, bool wantAlphaChannel,
+    bool wantDepthBuffer, bool wantStencilBuffer, bool wantAntialiasing,
+    PreserveDrawingBuffer preserve, WebGLVersion webGLVersion)
 {
     ASSERT(contextProvider);
 
@@ -112,7 +115,9 @@
     if (discardFramebufferSupported)
         extensionsUtil->ensureExtensionEnabled("GL_EXT_discard_framebuffer");
 
-    RefPtr<DrawingBuffer> drawingBuffer = adoptRef(new DrawingBuffer(std::move(contextProvider), std::move(extensionsUtil), discardFramebufferSupported, wantAlphaChannel, premultipliedAlpha, preserve, wantDepthBuffer, wantStencilBuffer));
+    RefPtr<DrawingBuffer> drawingBuffer = adoptRef(new DrawingBuffer(std::move(contextProvider), std::move(extensionsUtil),
+        discardFramebufferSupported, wantAlphaChannel, premultipliedAlpha,
+        preserve, webGLVersion, wantDepthBuffer, wantStencilBuffer));
     if (!drawingBuffer->initialize(size, multisampleSupported)) {
         drawingBuffer->beginDestruction();
         return PassRefPtr<DrawingBuffer>();
@@ -132,9 +137,11 @@
     bool wantAlphaChannel,
     bool premultipliedAlpha,
     PreserveDrawingBuffer preserve,
+    WebGLVersion webGLVersion,
     bool wantDepth,
     bool wantStencil)
     : m_preserveDrawingBuffer(preserve)
+    , m_webGLVersion(webGLVersion)
     , m_contextProvider(std::move(contextProvider))
     , m_gl(m_contextProvider->contextGL())
     , m_extensionsUtil(std::move(extensionsUtil))
@@ -284,7 +291,8 @@
             m_gl->DiscardFramebufferEXT(GL_FRAMEBUFFER, 3, attachments);
         }
     } else {
-        m_gl->CopyTextureCHROMIUM(m_colorBuffer.textureId, frontColorBufferMailbox->textureInfo.textureId, frontColorBufferMailbox->textureInfo.parameters.internalColorFormat, GL_UNSIGNED_BYTE, GL_FALSE, GL_FALSE, GL_FALSE);
+        m_gl->CopySubTextureCHROMIUM(m_colorBuffer.textureId, frontColorBufferMailbox->textureInfo.textureId,
+            0, 0, 0, 0, m_size.width(), m_size.height(), GL_FALSE, GL_FALSE, GL_FALSE);
     }
 
     restoreFramebufferBindings();
@@ -477,6 +485,7 @@
             m_antiAliasingMode = ScreenSpaceAntialiasing;
         }
     }
+    m_storageTextureSupported = m_webGLVersion > WebGL1 || m_extensionsUtil->supportsExtension("GL_EXT_texture_storage");
     m_sampleCount = std::min(4, maxSampleCount);
 
     m_gl->GenFramebuffers(1, &m_fbo);
@@ -799,7 +808,7 @@
         // multisampled renderbuffers and the alpha channel can be overwritten.
         // Clear the alpha channel of |m_fbo|.
         if (defaultBufferRequiresAlphaChannelToBePreserved()
-            && contextProvider()->getCapabilities().disable_webgl_multisampling_color_mask_usage) {
+            && contextProvider()->getCapabilities().disable_multisampling_color_mask_usage) {
             m_gl->ClearColor(0, 0, 0, 1);
             m_gl->ColorMask(false, false, false, true);
             m_gl->Clear(GL_COLOR_BUFFER_BIT);
@@ -941,10 +950,21 @@
     }
 }
 
-void DrawingBuffer::texImage2DResourceSafe(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLint unpackAlignment)
+void DrawingBuffer::allocateConditionallyImmutableTexture(GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type)
 {
-    ASSERT(unpackAlignment == 1 || unpackAlignment == 2 || unpackAlignment == 4 || unpackAlignment == 8);
-    m_gl->TexImage2D(target, level, internalformat, width, height, border, format, type, 0);
+    if (m_storageTextureSupported) {
+        GLenum internalStorageFormat = GL_NONE;
+        if (internalformat == GL_RGB) {
+            internalStorageFormat = GL_RGB8;
+        } else if (internalformat == GL_RGBA) {
+            internalStorageFormat = GL_RGBA8;
+        } else {
+            NOTREACHED();
+        }
+        m_gl->TexStorage2DEXT(GL_TEXTURE_2D, 1, internalStorageFormat, width, height);
+        return;
+    }
+    m_gl->TexImage2D(target, 0, internalformat, width, height, border, format, type, 0);
 }
 
 void DrawingBuffer::deleteChromiumImageForTexture(TextureInfo* info)
@@ -1006,13 +1026,13 @@
 
 DrawingBuffer::TextureInfo DrawingBuffer::createDefaultTextureAndAllocateMemory(const IntSize& size)
 {
-    TextureParameters parameters = defaultTextureParameters();
-    GLuint textureId = createColorTexture(parameters);
-    texImage2DResourceSafe(parameters.target, 0, parameters.creationInternalColorFormat, size.width(), size.height(), 0, parameters.colorFormat, GL_UNSIGNED_BYTE);
-
     DrawingBuffer::TextureInfo info;
-    info.textureId = textureId;
+    TextureParameters parameters = defaultTextureParameters();
     info.parameters = parameters;
+    info.textureId = createColorTexture(parameters);
+    allocateConditionallyImmutableTexture(parameters.target, parameters.creationInternalColorFormat,
+        size.width(), size.height(), 0, parameters.colorFormat, GL_UNSIGNED_BYTE);
+    info.immutable = m_storageTextureSupported;
     return info;
 }
 
@@ -1020,11 +1040,19 @@
 {
     ASSERT(info->textureId);
     if (!RuntimeEnabledFeatures::webGLImageChromiumEnabled()) {
+        if (info->immutable) {
+            DCHECK(m_storageTextureSupported);
+            m_gl->DeleteTextures(1, &info->textureId);
+            info->textureId = createColorTexture(info->parameters);
+        }
         m_gl->BindTexture(info->parameters.target, info->textureId);
-        texImage2DResourceSafe(info->parameters.target, 0, info->parameters.creationInternalColorFormat, size.width(), size.height(), 0, info->parameters.colorFormat, GL_UNSIGNED_BYTE);
+        allocateConditionallyImmutableTexture(info->parameters.target, info->parameters.creationInternalColorFormat,
+            size.width(), size.height(), 0, info->parameters.colorFormat, GL_UNSIGNED_BYTE);
+        info->immutable = m_storageTextureSupported;
         return;
     }
 
+    DCHECK(!info->immutable);
     deleteChromiumImageForTexture(info);
     info->imageId = m_gl->CreateGpuMemoryBufferImageCHROMIUM(size.width(), size.height(), info->parameters.creationInternalColorFormat, GC3D_SCANOUT_CHROMIUM);
     if (info->imageId) {
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h
index e0a19da5..c6d86e4e 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h
@@ -72,6 +72,10 @@
         Preserve,
         Discard
     };
+    enum WebGLVersion {
+        WebGL1,
+        WebGL2,
+    };
 
     static PassRefPtr<DrawingBuffer> create(
         std::unique_ptr<WebGraphicsContext3DProvider>,
@@ -81,7 +85,8 @@
         bool wantDepthBuffer,
         bool wantStencilBuffer,
         bool wantAntialiasing,
-        PreserveDrawingBuffer);
+        PreserveDrawingBuffer,
+        WebGLVersion);
     static void forceNextDrawingBufferCreationToFail();
 
     ~DrawingBuffer() override;
@@ -227,6 +232,7 @@
         bool wantAlphaChannel,
         bool premultipliedAlpha,
         PreserveDrawingBuffer,
+        WebGLVersion,
         bool wantsDepth,
         bool wantsStencil);
 
@@ -253,6 +259,7 @@
         DISALLOW_NEW();
         GLuint textureId = 0;
         GLuint imageId = 0;
+        bool immutable = false;
 
         // A GpuMemoryBuffer is a concept that the compositor understands. and
         // is able to operate on. The id is scoped to renderer process.
@@ -321,9 +328,8 @@
     // Helper function to flip a bitmap vertically.
     void flipVertically(uint8_t* data, int width, int height);
 
-    // Helper to texImage2D with pixel==0 case: pixels are initialized to 0.
-    // By default, alignment is 4, the OpenGL default setting.
-    void texImage2DResourceSafe(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLint alignment = 4);
+    // Allocate a storage texture if possible. Otherwise, allocate a regular texture.
+    void allocateConditionallyImmutableTexture(GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type);
     // Allocate buffer storage to be sent to compositor using either texImage2D or CHROMIUM_image based on available support.
     void deleteChromiumImageForTexture(TextureInfo*);
 
@@ -358,6 +364,7 @@
     GLenum getMultisampledRenderbufferFormat();
 
     const PreserveDrawingBuffer m_preserveDrawingBuffer;
+    const WebGLVersion m_webGLVersion;
     bool m_scissorEnabled = false;
     GLuint m_texture2DBinding = 0;
     GLuint m_drawFramebufferBinding = 0;
@@ -376,6 +383,7 @@
     const bool m_wantAlphaChannel;
     const bool m_premultipliedAlpha;
     bool m_hasImplicitStencilBuffer = false;
+    bool m_storageTextureSupported = false;
     struct FrontBufferInfo {
         TextureInfo texInfo;
         WebExternalTextureMailbox mailbox;
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp
index e8ac977..2c55c92 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp
@@ -230,7 +230,9 @@
     }
 
     DrawingBufferForTests(std::unique_ptr<WebGraphicsContext3DProvider> contextProvider, std::unique_ptr<Extensions3DUtil> extensionsUtil, PreserveDrawingBuffer preserve)
-        : DrawingBuffer(std::move(contextProvider), std::move(extensionsUtil), false /* discardFramebufferSupported */, true /* wantAlphaChannel */, false /* premultipliedAlpha */, preserve, false /* wantDepth */, false /* wantStencil */)
+        : DrawingBuffer(std::move(contextProvider), std::move(extensionsUtil), false /* discardFramebufferSupported */,
+            true /* wantAlphaChannel */, false /* premultipliedAlpha */, preserve, WebGL1,
+            false /* wantDepth */, false /* wantStencil */)
         , m_live(0)
     { }
 
@@ -727,7 +729,8 @@
             wantDepthBuffer,
             wantStencilBuffer,
             wantAntialiasing,
-            preserve);
+            preserve,
+            DrawingBuffer::WebGL1);
 
         // When we request a depth or a stencil buffer, we will get both.
         EXPECT_EQ(cases[i].requestDepth || cases[i].requestStencil, drawingBuffer->hasDepthBuffer());
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp
index c786690..12eeecba 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.cpp
@@ -132,6 +132,7 @@
 {
     switch (type) {
         DEBUG_STRING_CASE(ForeignLayerPlugin);
+        DEBUG_STRING_CASE(ForeignLayerVideo);
         DEFAULT_CASE;
     }
 }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
index 94f60a1..05778d1 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
@@ -121,7 +121,8 @@
 
         ForeignLayerFirst,
         ForeignLayerPlugin = ForeignLayerFirst,
-        ForeignLayerLast = ForeignLayerPlugin,
+        ForeignLayerVideo,
+        ForeignLayerLast = ForeignLayerVideo,
 
         ClipFirst,
         ClipBoxPaintPhaseFirst = ClipFirst,
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.cpp b/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.cpp
index 4558b88..d75455f 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.cpp
@@ -32,7 +32,7 @@
     return true;
 }
 
-DrawingRecorder::DrawingRecorder(GraphicsContext& context, const DisplayItemClient& displayItemClient, DisplayItem::Type displayItemType, const FloatRect& cullRect)
+DrawingRecorder::DrawingRecorder(GraphicsContext& context, const DisplayItemClient& displayItemClient, DisplayItem::Type displayItemType, const FloatRect& floatCullRect)
     : m_context(context)
     , m_displayItemClient(displayItemClient)
     , m_displayItemType(displayItemType)
@@ -55,6 +55,9 @@
     context.setInDrawingRecorder(true);
 #endif
 
+    // Use the enclosing int rect, since pixel-snapping may be applied to the bounds of the object during painting. Potentially expanding
+    // the cull rect by a pixel or two also does not affect correctness, and is very unlikely to matter for performance.
+    IntRect cullRect = enclosingIntRect(floatCullRect);
     context.beginRecording(cullRect);
 
 #if ENABLE(ASSERT)
@@ -63,13 +66,12 @@
         // cull rect clipping is enabled, make this explicit. This allows us to identify potential
         // incorrect cull rects that might otherwise be masked due to Skia internal optimizations.
         context.save();
-        IntRect verificationClip = enclosingIntRect(cullRect);
         // Expand the verification clip by one pixel to account for Skia's SkCanvas::getClipBounds()
         // expansion, used in testing cull rects.
         // TODO(schenney) This is not the best place to do this. Ideally, we would expand by one pixel
         // in device (pixel) space, but to do that we would need to add the verification mode to Skia.
-        verificationClip.inflate(1);
-        context.clipRect(verificationClip, NotAntiAliased, SkRegion::kIntersect_Op);
+        cullRect.inflate(1);
+        context.clipRect(cullRect, NotAntiAliased, SkRegion::kIntersect_Op);
     }
 #endif
 }
diff --git a/third_party/WebKit/Source/platform/testing/URLTestHelpers.cpp b/third_party/WebKit/Source/platform/testing/URLTestHelpers.cpp
index 4462fdde..06e4ac4 100644
--- a/third_party/WebKit/Source/platform/testing/URLTestHelpers.cpp
+++ b/third_party/WebKit/Source/platform/testing/URLTestHelpers.cpp
@@ -72,7 +72,6 @@
     timing.initialize();
 
     WebURLResponse response;
-    response.initialize();
     response.setMIMEType("image/png");
     response.setHTTPStatusCode(404);
     response.setLoadTiming(timing);
diff --git a/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.cpp b/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.cpp
index b840999..287d11b 100644
--- a/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.cpp
+++ b/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.cpp
@@ -22,6 +22,18 @@
 {
 }
 
+static cc::LayerTreeSettings settingsForLayerListPolicy(WebLayerTreeViewImplForTesting::LayerListPolicy policy)
+{
+    cc::LayerTreeSettings settings = WebLayerTreeViewImplForTesting::defaultLayerTreeSettings();
+    settings.use_layer_lists = policy == WebLayerTreeViewImplForTesting::UseLayerLists;
+    return settings;
+}
+
+WebLayerTreeViewImplForTesting::WebLayerTreeViewImplForTesting(LayerListPolicy policy)
+    : WebLayerTreeViewImplForTesting(settingsForLayerListPolicy(policy))
+{
+}
+
 WebLayerTreeViewImplForTesting::WebLayerTreeViewImplForTesting(const cc::LayerTreeSettings& settings)
 {
     cc::LayerTreeHost::InitParams params;
@@ -48,6 +60,11 @@
     return settings;
 }
 
+bool WebLayerTreeViewImplForTesting::hasLayer(const WebLayer& layer)
+{
+    return layer.ccLayer()->layer_tree_host() == m_layerTreeHost.get();
+}
+
 void WebLayerTreeViewImplForTesting::setRootLayer(const blink::WebLayer& root)
 {
     m_layerTreeHost->SetRootLayer(static_cast<const cc_blink::WebLayerImpl*>(&root)->layer());
diff --git a/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.h b/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.h
index 8cb8694..25ec408 100644
--- a/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.h
+++ b/third_party/WebKit/Source/platform/testing/WebLayerTreeViewImplForTesting.h
@@ -28,11 +28,14 @@
     WTF_MAKE_NONCOPYABLE(WebLayerTreeViewImplForTesting);
 public:
     WebLayerTreeViewImplForTesting();
+    enum LayerListPolicy { DontUseLayerLists, UseLayerLists };
+    explicit WebLayerTreeViewImplForTesting(LayerListPolicy);
     explicit WebLayerTreeViewImplForTesting(const cc::LayerTreeSettings&);
     ~WebLayerTreeViewImplForTesting() override;
 
     static cc::LayerTreeSettings defaultLayerTreeSettings();
     cc::LayerTreeHost* layerTreeHost() { return m_layerTreeHost.get(); }
+    bool hasLayer(const WebLayer&);
 
     // blink::WebLayerTreeView implementation.
     void setRootLayer(const blink::WebLayer&) override;
diff --git a/third_party/WebKit/Source/platform/text/SegmentedString.cpp b/third_party/WebKit/Source/platform/text/SegmentedString.cpp
index ec3507e..944a177 100644
--- a/third_party/WebKit/Source/platform/text/SegmentedString.cpp
+++ b/third_party/WebKit/Source/platform/text/SegmentedString.cpp
@@ -87,22 +87,21 @@
         return;
     }
 
-    prepend(SegmentedString(String(&c, 1)));
+    prepend(SegmentedString(String(&c, 1)), PrependType::Unconsume);
 }
 
-void SegmentedString::prepend(const SegmentedSubstring& s)
+void SegmentedString::prepend(const SegmentedSubstring& s, PrependType type)
 {
     ASSERT(!s.numberOfCharactersConsumed());
     if (!s.length())
         return;
 
-    // FIXME: We're assuming that the prepend were originally consumed by
-    //        this SegmentedString. We're also ASSERTing that s is a fresh
-    //        SegmentedSubstring. These assumptions are sufficient for our
-    //        current use, but we might need to handle the more elaborate
-    //        cases in the future.
+    // FIXME: We're also ASSERTing that s is a fresh SegmentedSubstring.
+    //        The assumption is sufficient for our current use, but we might
+    //        need to handle the more elaborate cases in the future.
     m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
-    m_numberOfCharactersConsumedPriorToCurrentString -= s.length();
+    if (type == PrependType::Unconsume)
+        m_numberOfCharactersConsumedPriorToCurrentString -= s.length();
     if (!m_currentString.length()) {
         m_currentString = s;
         updateAdvanceFunctionPointers();
@@ -136,15 +135,15 @@
     m_currentChar = m_currentString.length() ? m_currentString.getCurrentChar() : 0;
 }
 
-void SegmentedString::prepend(const SegmentedString& s)
+void SegmentedString::prepend(const SegmentedString& s, PrependType type)
 {
     if (s.isComposite()) {
         Deque<SegmentedSubstring>::const_reverse_iterator it = s.m_substrings.rbegin();
         Deque<SegmentedSubstring>::const_reverse_iterator e = s.m_substrings.rend();
         for (; it != e; ++it)
-            prepend(*it);
+            prepend(*it, type);
     }
-    prepend(s.m_currentString);
+    prepend(s.m_currentString, type);
     m_currentChar = m_currentString.length() ? m_currentString.getCurrentChar() : 0;
 }
 
diff --git a/third_party/WebKit/Source/platform/text/SegmentedString.h b/third_party/WebKit/Source/platform/text/SegmentedString.h
index cd71e6a..8a80cdb1 100644
--- a/third_party/WebKit/Source/platform/text/SegmentedString.h
+++ b/third_party/WebKit/Source/platform/text/SegmentedString.h
@@ -211,7 +211,11 @@
     void close();
 
     void append(const SegmentedString&);
-    void prepend(const SegmentedString&);
+    enum class PrependType {
+        NewInput = 0,
+        Unconsume = 1,
+    };
+    void prepend(const SegmentedString&, PrependType);
 
     bool excludeLineNumbers() const { return m_currentString.excludeLineNumbers(); }
     void setExcludeLineNumbers();
@@ -323,7 +327,7 @@
     };
 
     void append(const SegmentedSubstring&);
-    void prepend(const SegmentedSubstring&);
+    void prepend(const SegmentedSubstring&, PrependType);
 
     void advance8();
     void advance16();
@@ -399,7 +403,7 @@
         LookAheadResult result = DidNotMatch;
         if (consumedString.startsWith(string, caseSensitivity))
             result = DidMatch;
-        prepend(SegmentedString(consumedString));
+        prepend(SegmentedString(consumedString), PrependType::Unconsume);
         return result;
     }
 
diff --git a/third_party/WebKit/Source/platform/v8_inspector/DebuggerScript.js b/third_party/WebKit/Source/platform/v8_inspector/DebuggerScript.js
index 85d214e0..5b534f3 100644
--- a/third_party/WebKit/Source/platform/v8_inspector/DebuggerScript.js
+++ b/third_party/WebKit/Source/platform/v8_inspector/DebuggerScript.js
@@ -92,9 +92,9 @@
 
 /**
  * @param {Object} object
- * @return {?GeneratorObjectDetails}
+ * @return {?RawLocation}
  */
-DebuggerScript.getGeneratorObjectDetails = function(object)
+DebuggerScript.getGeneratorObjectLocation = function(object)
 {
     var mirror = MakeMirror(object, true /* transient */);
     if (!mirror.isGenerator())
@@ -103,21 +103,16 @@
     var funcMirror = generatorMirror.func();
     if (!funcMirror.resolved())
         return null;
-    var result = {
-        "function": funcMirror.value(),
-        "functionName": funcMirror.debugName(),
-        "status": generatorMirror.status()
-    };
-    var script = funcMirror.script();
     var location = generatorMirror.sourceLocation() || funcMirror.sourceLocation();
+    var script = funcMirror.script();
     if (script && location) {
-        result["location"] = {
-            "scriptId": String(script.id()),
-            "lineNumber": location.line,
-            "columnNumber": location.column
+        return {
+            scriptId: "" + script.id(),
+            lineNumber: location.line,
+            columnNumber: location.column
         };
     }
-    return result;
+    return null;
 }
 
 /**
diff --git a/third_party/WebKit/Source/platform/v8_inspector/InjectedScript.cpp b/third_party/WebKit/Source/platform/v8_inspector/InjectedScript.cpp
index cd467e6..c2bcdab1 100644
--- a/third_party/WebKit/Source/platform/v8_inspector/InjectedScript.cpp
+++ b/third_party/WebKit/Source/platform/v8_inspector/InjectedScript.cpp
@@ -52,7 +52,6 @@
 using blink::protocol::Array;
 using blink::protocol::Debugger::CallFrame;
 using blink::protocol::Debugger::FunctionDetails;
-using blink::protocol::Debugger::GeneratorObjectDetails;
 using blink::protocol::Runtime::PropertyDescriptor;
 using blink::protocol::Runtime::InternalPropertyDescriptor;
 using blink::protocol::Runtime::RemoteObject;
diff --git a/third_party/WebKit/Source/platform/v8_inspector/InjectedScriptSource.js b/third_party/WebKit/Source/platform/v8_inspector/InjectedScriptSource.js
index bac0f5f7..743cc06f 100644
--- a/third_party/WebKit/Source/platform/v8_inspector/InjectedScriptSource.js
+++ b/third_party/WebKit/Source/platform/v8_inspector/InjectedScriptSource.js
@@ -212,6 +212,15 @@
 
     /**
      * @param {*} object
+     * @return {boolean}
+     */
+    _shouldPassByValue: function(object)
+    {
+        return typeof object === "object" && InjectedScriptHost.subtype(object) === "internal#location";
+    },
+
+    /**
+     * @param {*} object
      * @param {string} groupName
      * @param {boolean} canAccessInspectedGlobalObject
      * @param {boolean} forceValueType
@@ -716,6 +725,13 @@
         return;
     }
 
+    if (injectedScript._shouldPassByValue(object)) {
+        this.value = object;
+        this.subtype = injectedScript._subtype(object);
+        this.description = injectedScript._describeIncludingPrimitives(object);
+        return;
+    }
+
     object = /** @type {!Object} */ (object);
 
     if (!doNotBind)
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8Console.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8Console.cpp
index 921dcbff..7cf80d6 100644
--- a/third_party/WebKit/Source/platform/v8_inspector/V8Console.cpp
+++ b/third_party/WebKit/Source/platform/v8_inspector/V8Console.cpp
@@ -265,13 +265,13 @@
 {
     v8::Local<v8::String> funcName = toV8StringInternalized(context->GetIsolate(), name);
     v8::Local<v8::Function> func;
-    if (!v8::Function::New(context, callback, console).ToLocal(&func))
+    if (!v8::Function::New(context, callback, console, 0, v8::ConstructorBehavior::kThrow).ToLocal(&func))
         return;
     func->SetName(funcName);
     if (description) {
         v8::Local<v8::String> returnValue = toV8String(context->GetIsolate(), description);
         v8::Local<v8::Function> toStringFunction;
-        if (v8::Function::New(context, returnDataCallback, returnValue).ToLocal(&toStringFunction))
+        if (v8::Function::New(context, returnDataCallback, returnValue, 0, v8::ConstructorBehavior::kThrow).ToLocal(&toStringFunction))
             func->Set(toV8StringInternalized(context->GetIsolate(), "toString"), toStringFunction);
     }
     if (!console->Set(context, funcName, func).FromMaybe(false))
@@ -676,7 +676,7 @@
     DCHECK(success);
 
     if (hasMemoryAttribute)
-        console->SetAccessorProperty(toV8StringInternalized(isolate, "memory"), v8::Function::New(isolate, V8Console::memoryGetterCallback, console), v8::Function::New(isolate, V8Console::memorySetterCallback), static_cast<v8::PropertyAttribute>(v8::None), v8::DEFAULT);
+        console->SetAccessorProperty(toV8StringInternalized(isolate, "memory"), v8::Function::New(context, V8Console::memoryGetterCallback, console, 0, v8::ConstructorBehavior::kThrow).ToLocalChecked(), v8::Function::New(context, V8Console::memorySetterCallback, v8::Local<v8::Value>(), 0, v8::ConstructorBehavior::kThrow).ToLocalChecked(), static_cast<v8::PropertyAttribute>(v8::None), v8::DEFAULT);
 
     console->SetPrivate(context, inspectedContextPrivateKey(isolate), v8::External::New(isolate, inspectedContext));
     return console;
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp
index e1dbb81..53ccca1 100644
--- a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp
+++ b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp
@@ -27,7 +27,6 @@
 using blink::protocol::Debugger::CallFrame;
 using blink::protocol::Runtime::ExceptionDetails;
 using blink::protocol::Debugger::FunctionDetails;
-using blink::protocol::Debugger::GeneratorObjectDetails;
 using blink::protocol::Runtime::ScriptId;
 using blink::protocol::Runtime::StackTrace;
 using blink::protocol::Runtime::RemoteObject;
@@ -633,34 +632,6 @@
     *details = std::move(functionDetails);
 }
 
-void V8DebuggerAgentImpl::getGeneratorObjectDetails(ErrorString* errorString, const String16& objectId, std::unique_ptr<GeneratorObjectDetails>* outDetails)
-{
-    if (!checkEnabled(errorString))
-        return;
-    InjectedScript::ObjectScope scope(errorString, m_debugger, m_session->contextGroupId(), objectId);
-    if (!scope.initialize())
-        return;
-    if (!scope.object()->IsObject()) {
-        *errorString = "Value with given id is not an Object";
-        return;
-    }
-    v8::Local<v8::Object> object = scope.object().As<v8::Object>();
-
-    v8::Local<v8::Object> detailsObject;
-    v8::Local<v8::Value> detailsValue = debugger().generatorObjectDetails(object);
-    if (hasInternalError(errorString, !detailsValue->IsObject() || !detailsValue->ToObject(scope.context()).ToLocal(&detailsObject)))
-        return;
-
-    if (!scope.injectedScript()->wrapObjectProperty(errorString, detailsObject, toV8StringInternalized(m_isolate, "function"), scope.objectGroupName()))
-        return;
-
-    protocol::ErrorSupport errors;
-    std::unique_ptr<GeneratorObjectDetails> protocolDetails = GeneratorObjectDetails::parse(toProtocolValue(scope.context(), detailsObject).get(), &errors);
-    if (hasInternalError(errorString, !protocolDetails))
-        return;
-    *outDetails = std::move(protocolDetails);
-}
-
 void V8DebuggerAgentImpl::schedulePauseOnNextStatement(const String16& breakReason, std::unique_ptr<protocol::DictionaryValue> data)
 {
     if (!enabled() || m_scheduledDebuggerStep == StepInto || m_javaScriptPauseScheduled || debugger().isPaused() || !debugger().breakpointsActivated())
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.h b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.h
index 65f2c84..fdae2de 100644
--- a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.h
+++ b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.h
@@ -95,9 +95,6 @@
     void getFunctionDetails(ErrorString*,
         const String16& functionId,
         std::unique_ptr<protocol::Debugger::FunctionDetails>*) override;
-    void getGeneratorObjectDetails(ErrorString*,
-        const String16& objectId,
-        std::unique_ptr<protocol::Debugger::GeneratorObjectDetails>*) override;
     void pause(ErrorString*) override;
     void resume(ErrorString*) override;
     void stepOver(ErrorString*) override;
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerImpl.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerImpl.cpp
index 8091b318..e945af4 100644
--- a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerImpl.cpp
+++ b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerImpl.cpp
@@ -314,7 +314,7 @@
 
     v8::HandleScope scope(m_isolate);
     v8::Local<v8::Function> breakFunction;
-    if (!v8::Function::New(m_isolate->GetCurrentContext(), &V8DebuggerImpl::breakProgramCallback, v8::External::New(m_isolate, this)).ToLocal(&breakFunction))
+    if (!v8::Function::New(m_isolate->GetCurrentContext(), &V8DebuggerImpl::breakProgramCallback, v8::External::New(m_isolate, this), 0, v8::ConstructorBehavior::kThrow).ToLocal(&breakFunction))
         return;
     v8::Debug::Call(debuggerContext(), breakFunction).ToLocalChecked();
 }
@@ -668,17 +668,14 @@
             properties->Set(properties->Length(), entries);
         }
     }
-    return properties;
-}
-
-v8::Local<v8::Value> V8DebuggerImpl::generatorObjectDetails(v8::Local<v8::Object>& object)
-{
-    if (!enabled()) {
-        NOTREACHED();
-        return v8::Local<v8::Value>::New(m_isolate, v8::Undefined(m_isolate));
+    if (value->IsGeneratorObject()) {
+        v8::Local<v8::Value> location = generatorObjectLocation(v8::Local<v8::Object>::Cast(value));
+        if (location->IsObject()) {
+            properties->Set(properties->Length(), v8InternalizedString("[[GeneratorLocation]]"));
+            properties->Set(properties->Length(), location);
+        }
     }
-    v8::Local<v8::Value> argv[] = { object };
-    return callDebuggerMethod("getGeneratorObjectDetails", 1, argv).ToLocalChecked();
+    return properties;
 }
 
 v8::Local<v8::Value> V8DebuggerImpl::collectionEntries(v8::Local<v8::Context> context, v8::Local<v8::Object> object)
@@ -704,6 +701,22 @@
     return entries;
 }
 
+v8::Local<v8::Value> V8DebuggerImpl::generatorObjectLocation(v8::Local<v8::Object> object)
+{
+    if (!enabled()) {
+        NOTREACHED();
+        return v8::Null(m_isolate);
+    }
+    v8::Local<v8::Value> argv[] = { object };
+    v8::Local<v8::Value> location = callDebuggerMethod("getGeneratorObjectLocation", 1, argv).ToLocalChecked();
+    if (!location->IsObject())
+        return v8::Null(m_isolate);
+    v8::Local<v8::Context> context = m_debuggerContext.Get(m_isolate);
+    if (!location.As<v8::Object>()->SetPrivate(context, V8InjectedScriptHost::internalLocationPrivate(m_isolate), v8::True(m_isolate)).FromMaybe(false))
+        return v8::Null(m_isolate);
+    return location;
+}
+
 bool V8DebuggerImpl::isPaused()
 {
     return !m_pausedContext.IsEmpty();
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerImpl.h b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerImpl.h
index e4da436..1ce6d5b 100644
--- a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerImpl.h
+++ b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerImpl.h
@@ -106,7 +106,6 @@
 
     v8::MaybeLocal<v8::Value> functionScopes(v8::Local<v8::Function>);
     v8::MaybeLocal<v8::Array> internalProperties(v8::Local<v8::Context>, v8::Local<v8::Value>);
-    v8::Local<v8::Value> generatorObjectDetails(v8::Local<v8::Object>&);
 
     v8::Isolate* isolate() const { return m_isolate; }
     V8DebuggerClient* client() { return m_client; }
@@ -176,6 +175,7 @@
     using ContextsByGroupMap = protocol::HashMap<int, std::unique_ptr<ContextByIdMap>>;
 
     v8::Local<v8::Value> collectionEntries(v8::Local<v8::Context>, v8::Local<v8::Object>);
+    v8::Local<v8::Value> generatorObjectLocation(v8::Local<v8::Object>);
 
     v8::Isolate* m_isolate;
     V8DebuggerClient* m_client;
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.cpp
index 85800be..1ef3bbba 100644
--- a/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.cpp
+++ b/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.cpp
@@ -19,7 +19,7 @@
 {
     v8::Local<v8::String> funcName = toV8StringInternalized(context->GetIsolate(), name);
     v8::Local<v8::Function> func;
-    if (!v8::Function::New(context, callback, external).ToLocal(&func))
+    if (!v8::Function::New(context, callback, external, 0, v8::ConstructorBehavior::kThrow).ToLocal(&func))
         return;
     func->SetName(funcName);
     if (!obj->Set(context, funcName, func).FromMaybe(false))
@@ -59,6 +59,11 @@
     return v8::Private::ForApi(isolate, toV8StringInternalized(isolate, "V8InjectedScriptHost#internalEntry"));
 }
 
+v8::Local<v8::Private> V8InjectedScriptHost::internalLocationPrivate(v8::Isolate* isolate)
+{
+    return v8::Private::ForApi(isolate, toV8StringInternalized(isolate, "V8InjectedScriptHost#internalLocation"));
+}
+
 void V8InjectedScriptHost::internalConstructorNameCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
 {
     if (info.Length() < 1 || !info[0]->IsObject())
@@ -137,6 +142,10 @@
             info.GetReturnValue().Set(toV8StringInternalized(isolate, "internal#entry"));
             return;
         }
+        if (obj->HasPrivate(isolate->GetCurrentContext(), internalLocationPrivate(isolate)).FromMaybe(false)) {
+            info.GetReturnValue().Set(toV8StringInternalized(isolate, "internal#location"));
+            return;
+        }
     }
     String16 subtype = unwrapDebugger(info)->client()->valueSubtype(value);
     if (!subtype.isEmpty()) {
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.h b/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.h
index 151ce90..9a25824 100644
--- a/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.h
+++ b/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.h
@@ -23,6 +23,7 @@
     static v8::Local<v8::Object> create(v8::Local<v8::Context>, V8DebuggerImpl*);
 
     static v8::Local<v8::Private> internalEntryPrivate(v8::Isolate*);
+    static v8::Local<v8::Private> internalLocationPrivate(v8::Isolate*);
 
 private:
     static void internalConstructorNameCallback(const v8::FunctionCallbackInfo<v8::Value>&);
diff --git a/third_party/WebKit/Source/platform/v8_inspector/debugger_script_externs.js b/third_party/WebKit/Source/platform/v8_inspector/debugger_script_externs.js
index 25d0754..cf2a045 100644
--- a/third_party/WebKit/Source/platform/v8_inspector/debugger_script_externs.js
+++ b/third_party/WebKit/Source/platform/v8_inspector/debugger_script_externs.js
@@ -19,14 +19,6 @@
 var RawLocation;
 
 /** @typedef {{
-        function: function(),
-        functionName: string,
-        status: string,
-        location: (!RawLocation|undefined)
-    }} */
-var GeneratorObjectDetails;
-
-/** @typedef {{
         id: number,
         name: string,
         sourceURL: (string|undefined),
diff --git a/third_party/WebKit/Source/platform/v8_inspector/js_protocol.json b/third_party/WebKit/Source/platform/v8_inspector/js_protocol.json
index 6ab35586..9cbc9361 100644
--- a/third_party/WebKit/Source/platform/v8_inspector/js_protocol.json
+++ b/third_party/WebKit/Source/platform/v8_inspector/js_protocol.json
@@ -365,18 +365,6 @@
                 "description": "Information about the function."
             },
             {
-                "id": "GeneratorObjectDetails",
-                "hidden": true,
-                "type": "object",
-                "properties": [
-                    { "name": "function", "$ref": "Runtime.RemoteObject", "description": "Generator function." },
-                    { "name": "functionName", "type": "string", "description": "Name of the generator function." },
-                    { "name": "status", "type": "string", "enum": ["running", "suspended", "closed"], "description": "Current generator object status." },
-                    { "name": "location", "$ref": "Location", "optional": true, "description": "If suspended, location where generator function was suspended (e.g. location of the last 'yield'). Otherwise, location of the generator function." }
-                ],
-                "description": "Information about the generator object."
-            },
-            {
                 "id": "CallFrame",
                 "type": "object",
                 "properties": [
@@ -579,17 +567,6 @@
                 "description": "Returns detailed information on given function."
             },
             {
-                "name": "getGeneratorObjectDetails",
-                "hidden": true,
-                "parameters": [
-                    { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "Id of the generator object to get details for." }
-                ],
-                "returns": [
-                    { "name": "details", "$ref": "GeneratorObjectDetails", "description": "Information about the generator object." }
-                ],
-                "description": "Returns detailed information on given generator object."
-            },
-            {
                 "name": "setPauseOnExceptions",
                 "parameters": [
                     { "name": "state", "type": "string", "enum": ["none", "uncaught", "all"], "description": "Pause on exceptions mode." }
diff --git a/third_party/WebKit/Source/web/AssociatedURLLoaderTest.cpp b/third_party/WebKit/Source/web/AssociatedURLLoaderTest.cpp
index e29d874..f1a6a401 100644
--- a/third_party/WebKit/Source/web/AssociatedURLLoaderTest.cpp
+++ b/third_party/WebKit/Source/web/AssociatedURLLoaderTest.cpp
@@ -77,7 +77,6 @@
     KURL RegisterMockedUrl(const std::string& urlRoot, const WTF::String& filename)
     {
         WebURLResponse response;
-        response.initialize();
         response.setMIMEType("text/html");
         WTF::String localPath = m_baseFilePath;
         localPath.append(filename);
@@ -241,7 +240,6 @@
 
         WebString headerNameString(WebString::fromUTF8(headerName));
         m_expectedResponse = WebURLResponse();
-        m_expectedResponse.initialize();
         m_expectedResponse.setMIMEType("text/html");
         m_expectedResponse.setHTTPStatusCode(200);
         m_expectedResponse.addHTTPHeaderField("Access-Control-Allow-Origin", "*");
@@ -294,7 +292,6 @@
     request.setURL(url);
 
     m_expectedResponse = WebURLResponse();
-    m_expectedResponse.initialize();
     m_expectedResponse.setMIMEType("text/html");
     m_expectedResponse.setHTTPStatusCode(200);
     Platform::current()->getURLLoaderMockFactory()->registerURL(url, m_expectedResponse, m_frameFilePath);
@@ -332,7 +329,6 @@
     request.setRequestContext(WebURLRequest::RequestContextScript);
 
     m_expectedResponse = WebURLResponse();
-    m_expectedResponse.initialize();
     m_expectedResponse.setMIMEType("text/html");
     m_expectedResponse.setHTTPStatusCode(200);
     Platform::current()->getURLLoaderMockFactory()->registerURL(url, m_expectedResponse, m_frameFilePath);
@@ -358,7 +354,6 @@
     request.setURL(url);
 
     m_expectedResponse = WebURLResponse();
-    m_expectedResponse.initialize();
     m_expectedResponse.setMIMEType("text/html");
     m_expectedResponse.setHTTPStatusCode(200);
     m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*");
@@ -385,7 +380,6 @@
     request.setURL(url);
 
     m_expectedResponse = WebURLResponse();
-    m_expectedResponse.initialize();
     m_expectedResponse.setMIMEType("text/html");
     m_expectedResponse.setHTTPStatusCode(200);
     m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*");
@@ -418,7 +412,6 @@
     request.setURL(url);
 
     m_expectedResponse = WebURLResponse();
-    m_expectedResponse.initialize();
     m_expectedResponse.setMIMEType("text/html");
     m_expectedResponse.setHTTPStatusCode(0);
     m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*");
@@ -450,7 +443,6 @@
     request.setURL(url);
 
     m_expectedRedirectResponse = WebURLResponse();
-    m_expectedRedirectResponse.initialize();
     m_expectedRedirectResponse.setMIMEType("text/html");
     m_expectedRedirectResponse.setHTTPStatusCode(301);
     m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect);
@@ -461,7 +453,6 @@
     m_expectedNewRequest.setURL(redirectURL);
 
     m_expectedResponse = WebURLResponse();
-    m_expectedResponse.initialize();
     m_expectedResponse.setMIMEType("text/html");
     m_expectedResponse.setHTTPStatusCode(200);
     Platform::current()->getURLLoaderMockFactory()->registerURL(redirectURL, m_expectedResponse, m_frameFilePath);
@@ -488,7 +479,6 @@
     request.setURL(url);
 
     m_expectedRedirectResponse = WebURLResponse();
-    m_expectedRedirectResponse.initialize();
     m_expectedRedirectResponse.setMIMEType("text/html");
     m_expectedRedirectResponse.setHTTPStatusCode(301);
     m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect);
@@ -499,7 +489,6 @@
     m_expectedNewRequest.setURL(redirectURL);
 
     m_expectedResponse = WebURLResponse();
-    m_expectedResponse.initialize();
     m_expectedResponse.setMIMEType("text/html");
     m_expectedResponse.setHTTPStatusCode(200);
     Platform::current()->getURLLoaderMockFactory()->registerURL(redirectURL, m_expectedResponse, m_frameFilePath);
@@ -527,7 +516,6 @@
     request.setURL(url);
 
     m_expectedRedirectResponse = WebURLResponse();
-    m_expectedRedirectResponse.initialize();
     m_expectedRedirectResponse.setMIMEType("text/html");
     m_expectedRedirectResponse.setHTTPStatusCode(301);
     m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect);
@@ -538,7 +526,6 @@
     m_expectedNewRequest.setURL(redirectURL);
 
     m_expectedResponse = WebURLResponse();
-    m_expectedResponse.initialize();
     m_expectedResponse.setMIMEType("text/html");
     m_expectedResponse.setHTTPStatusCode(200);
     Platform::current()->getURLLoaderMockFactory()->registerURL(redirectURL, m_expectedResponse, m_frameFilePath);
@@ -572,7 +559,6 @@
 
     // Create a redirect response that allows the redirect to pass the access control checks.
     m_expectedRedirectResponse = WebURLResponse();
-    m_expectedRedirectResponse.initialize();
     m_expectedRedirectResponse.setMIMEType("text/html");
     m_expectedRedirectResponse.setHTTPStatusCode(301);
     m_expectedRedirectResponse.setHTTPHeaderField("Location", redirect);
@@ -585,7 +571,6 @@
     m_expectedNewRequest.setHTTPHeaderField("accept", "application/json");
 
     m_expectedResponse = WebURLResponse();
-    m_expectedResponse.initialize();
     m_expectedResponse.setMIMEType("text/html");
     m_expectedResponse.setHTTPStatusCode(200);
     m_expectedResponse.addHTTPHeaderField("access-control-allow-origin", "*");
@@ -699,7 +684,6 @@
 
     WebString headerNameString(WebString::fromUTF8("non-whitelisted"));
     m_expectedResponse = WebURLResponse();
-    m_expectedResponse.initialize();
     m_expectedResponse.setMIMEType("text/html");
     m_expectedResponse.setHTTPStatusCode(200);
     m_expectedResponse.addHTTPHeaderField("Access-Control-Allow-Origin", "*");
diff --git a/third_party/WebKit/Source/web/InspectorOverlay.cpp b/third_party/WebKit/Source/web/InspectorOverlay.cpp
index 795309b6..25e495b5 100644
--- a/third_party/WebKit/Source/web/InspectorOverlay.cpp
+++ b/third_party/WebKit/Source/web/InspectorOverlay.cpp
@@ -389,8 +389,7 @@
     LocalFrame* frame = toLocalFrame(overlayPage()->mainFrame());
     frame->view()->resize(viewportSize);
     overlayPage()->frameHost().visualViewport().setSize(viewportSize);
-    float windowToViewportScale = m_webViewImpl->chromeClient().windowToViewportScalar(1.0f);
-    frame->setPageZoomFactor(windowToViewportScale);
+    frame->setPageZoomFactor(windowToViewportScale());
 
     reset(viewportSize, visibleRectInDocument.location());
 
@@ -446,7 +445,7 @@
     if (!m_highlightQuad)
         return;
 
-    InspectorHighlight highlight;
+    InspectorHighlight highlight(windowToViewportScale());
     highlight.appendQuad(*m_highlightQuad, m_quadHighlightConfig.content, m_quadHighlightConfig.contentOutline);
     evaluateInOverlay("drawHighlight", highlight.asProtocolValue());
 }
@@ -463,6 +462,11 @@
         evaluateInOverlay("drawViewSize", "");
 }
 
+float InspectorOverlay::windowToViewportScale() const
+{
+    return m_webViewImpl->chromeClient().windowToViewportScalar(1.0f);
+}
+
 Page* InspectorOverlay::overlayPage()
 {
     if (m_overlayPage)
@@ -544,8 +548,7 @@
 
     // The zoom factor in the overlay frame already has been multiplied by the window to viewport scale
     // (aka device scale factor), so cancel it.
-    float windowToViewportScale = m_webViewImpl->chromeClient().windowToViewportScalar(1.0f);
-    resetData->setNumber("pageZoomFactor", m_webViewImpl->mainFrameImpl()->frame()->pageZoomFactor() / windowToViewportScale);
+    resetData->setNumber("pageZoomFactor", m_webViewImpl->mainFrameImpl()->frame()->pageZoomFactor() / windowToViewportScale());
 
     resetData->setNumber("scrollX", documentScrollOffset.x());
     resetData->setNumber("scrollY", documentScrollOffset.y());
diff --git a/third_party/WebKit/Source/web/InspectorOverlay.h b/third_party/WebKit/Source/web/InspectorOverlay.h
index c9daa2b..30f1d91 100644
--- a/third_party/WebKit/Source/web/InspectorOverlay.h
+++ b/third_party/WebKit/Source/web/InspectorOverlay.h
@@ -120,6 +120,8 @@
     void drawPausedInDebuggerMessage();
     void drawViewSize();
 
+    float windowToViewportScale() const;
+
     Page* overlayPage();
     LocalFrame* overlayMainFrame();
     void reset(const IntSize& viewportSize, const IntPoint& documentScrollOffset);
diff --git a/third_party/WebKit/Source/web/WebDataSourceImpl.cpp b/third_party/WebKit/Source/web/WebDataSourceImpl.cpp
index 1cf7e7b4..6a086e9a 100644
--- a/third_party/WebKit/Source/web/WebDataSourceImpl.cpp
+++ b/third_party/WebKit/Source/web/WebDataSourceImpl.cpp
@@ -59,7 +59,6 @@
 
 const WebURLResponse& WebDataSourceImpl::response() const
 {
-    m_responseWrapper.bind(DocumentLoader::response());
     return m_responseWrapper;
 }
 
@@ -135,6 +134,7 @@
 
 WebDataSourceImpl::WebDataSourceImpl(LocalFrame* frame, const ResourceRequest& request, const SubstituteData& data)
     : DocumentLoader(frame, request, data)
+    , m_responseWrapper(DocumentLoader::response())
 {
 }
 
diff --git a/third_party/WebKit/Source/web/WebEmbeddedWorkerImplTest.cpp b/third_party/WebKit/Source/web/WebEmbeddedWorkerImplTest.cpp
index bb6f205f..5373f46 100644
--- a/third_party/WebKit/Source/web/WebEmbeddedWorkerImplTest.cpp
+++ b/third_party/WebKit/Source/web/WebEmbeddedWorkerImplTest.cpp
@@ -67,7 +67,6 @@
 
         WebURL scriptURL = URLTestHelpers::toKURL("https://www.example.com/sw.js");
         WebURLResponse response;
-        response.initialize();
         response.setMIMEType("text/javascript");
         response.setHTTPStatusCode(200);
         Platform::current()->getURLLoaderMockFactory()->registerURL(scriptURL, response, "");
@@ -167,7 +166,6 @@
 {
     WebURL scriptURL = URLTestHelpers::toKURL("https://www.example.com/sw-404.js");
     WebURLResponse response;
-    response.initialize();
     response.setMIMEType("text/javascript");
     response.setHTTPStatusCode(404);
     WebURLError error;
diff --git a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
index 063029b..1ce4ec7 100644
--- a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
+++ b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
@@ -838,7 +838,7 @@
 #endif
 
     bool isUnmodifiedMenuKey = !(event.modifiers & WebInputEvent::InputModifiers) && event.windowsKeyCode == VKEY_APPS;
-    bool isShiftF10 = event.modifiers == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10;
+    bool isShiftF10 = (event.modifiers & WebInputEvent::InputModifiers) == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10;
     if ((isUnmodifiedMenuKey || isShiftF10) && event.type == contextMenuTriggeringEventType) {
         view()->sendContextMenuEvent(event);
         return WebInputEventResult::HandledSystem;
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
index 73a6abc..c8a165a 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -1488,8 +1488,6 @@
         PermissionController::provideTo(*m_frame, m_client ? m_client->permissionClient() : nullptr);
     if (RuntimeEnabledFeatures::webVREnabled())
         VRController::provideTo(*m_frame, m_client ? m_client->serviceRegistry() : nullptr);
-    if (RuntimeEnabledFeatures::wakeLockEnabled())
-        ScreenWakeLock::provideTo(*m_frame, m_client ? m_client->serviceRegistry(): nullptr);
     if (RuntimeEnabledFeatures::audioOutputDevicesEnabled())
         provideAudioOutputDeviceClientTo(*m_frame, AudioOutputDeviceClientImpl::create());
     if (RuntimeEnabledFeatures::installedAppEnabled())
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp
index 3e92e32a..62a586d0d 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -1134,7 +1134,7 @@
 #endif
 
     bool isUnmodifiedMenuKey = !(event.modifiers & WebInputEvent::InputModifiers) && event.windowsKeyCode == VKEY_APPS;
-    bool isShiftF10 = event.modifiers == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10;
+    bool isShiftF10 = (event.modifiers & WebInputEvent::InputModifiers) == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10;
     if ((isUnmodifiedMenuKey || isShiftF10) && event.type == contextMenuTriggeringEventType) {
         sendContextMenuEvent(event);
         return WebInputEventResult::HandledSystem;
diff --git a/third_party/WebKit/Source/web/tests/FrameSerializerTest.cpp b/third_party/WebKit/Source/web/tests/FrameSerializerTest.cpp
index 50e3a2c..5ad77bd 100644
--- a/third_party/WebKit/Source/web/tests/FrameSerializerTest.cpp
+++ b/third_party/WebKit/Source/web/tests/FrameSerializerTest.cpp
@@ -105,7 +105,6 @@
         error.domain = "FrameSerializerTest";
 
         WebURLResponse response;
-        response.initialize();
         response.setMIMEType("text/html");
         response.setHTTPStatusCode(statusCode);
 
diff --git a/third_party/WebKit/Source/web/tests/FrameTestHelpers.cpp b/third_party/WebKit/Source/web/tests/FrameTestHelpers.cpp
index 750fc500..7cc4987 100644
--- a/third_party/WebKit/Source/web/tests/FrameTestHelpers.cpp
+++ b/third_party/WebKit/Source/web/tests/FrameTestHelpers.cpp
@@ -35,6 +35,7 @@
 #include "platform/testing/WebLayerTreeViewImplForTesting.h"
 #include "public/platform/Platform.h"
 #include "public/platform/WebData.h"
+#include "public/platform/WebSecurityOrigin.h"
 #include "public/platform/WebString.h"
 #include "public/platform/WebThread.h"
 #include "public/platform/WebURLLoaderMockFactory.h"
@@ -124,6 +125,7 @@
     WebURLRequest urlRequest;
     urlRequest.initialize();
     urlRequest.setURL(URLTestHelpers::toKURL(url));
+    urlRequest.setRequestorOrigin(WebSecurityOrigin::createUnique());
     frame->loadRequest(urlRequest);
     pumpPendingRequestsForFrameToLoad(frame);
 }
diff --git a/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp b/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp
index 667b098..13d13fe 100644
--- a/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp
+++ b/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp
@@ -633,8 +633,8 @@
     mainResource.complete("<iframe id=frame sandbox=allow-scripts src=iframe.html></iframe>");
     frameResource.complete(
         "<script>"
-        "window.addEventListener('touchstart', function(){});"
-        "document.addEventListener('touchstart', function(){});"
+        "window.addEventListener('touchstart', function(){}, {passive: false});"
+        "document.addEventListener('touchstart', function(){}, {passive: false});"
         "</script>");
     auto* frameElement = toHTMLIFrameElement(document().getElementById("frame"));
     frameElement->setAttribute(styleAttr, "transform: translateY(480px)");
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index 2c5d98d..0b2963d 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -208,7 +208,6 @@
     void registerMockedHttpURLLoadWithCSP(const std::string& fileName, const std::string& csp, bool reportOnly = false)
     {
         WebURLResponse response;
-        response.initialize();
         response.setMIMEType("text/html");
         response.addHTTPHeaderField(reportOnly ? WebString("Content-Security-Policy-Report-Only") : WebString("Content-Security-Policy"), WebString::fromUTF8(csp));
         std::string fullString = m_baseURL + fileName;
@@ -3323,6 +3322,7 @@
     WebURLRequest request;
     request.initialize();
     request.setURL(toKURL(m_baseURL + "fixed_layout.html"));
+    request.setRequestorOrigin(WebSecurityOrigin::createUnique());
     webViewHelper.webView()->mainFrame()->loadRequest(request);
     // start reload before first request is delivered.
     FrameTestHelpers::reloadFrameIgnoringCache(webViewHelper.webView()->mainFrame());
@@ -5074,7 +5074,6 @@
     error.domain = "WebFrameTest";
     std::string errorURL = "http://0.0.0.0";
     WebURLResponse response;
-    response.initialize();
     response.setURL(URLTestHelpers::toKURL(errorURL));
     response.setMIMEType("text/html");
     response.setHTTPStatusCode(500);
@@ -5720,14 +5719,12 @@
     char redirect[] = "http://internal.test/first_party.html";
     WebURL redirectURL(toKURL(redirect));
     WebURLResponse redirectResponse;
-    redirectResponse.initialize();
     redirectResponse.setMIMEType("text/html");
     redirectResponse.setHTTPStatusCode(302);
     redirectResponse.setHTTPHeaderField("Location", redirect);
     Platform::current()->getURLLoaderMockFactory()->registerURL(testURL, redirectResponse, filePath);
 
     WebURLResponse finalResponse;
-    finalResponse.initialize();
     finalResponse.setMIMEType("text/html");
     Platform::current()->getURLLoaderMockFactory()->registerURL(redirectURL, finalResponse, filePath);
 
@@ -6293,6 +6290,7 @@
     WebURLRequest request;
     request.initialize();
     request.setURL(toKURL(url));
+    request.setRequestorOrigin(WebSecurityOrigin::createUnique());
     frame->loadRequest(request);
 
     // Before commit, there is no history item.
@@ -8812,6 +8810,7 @@
     URLTestHelpers::registerMockedURLLoad(toKURL(redirectURL), "foo.html");
     request.initialize();
     request.setURL(toKURL("javascript:location='" + redirectURL + "'"));
+    request.setRequestorOrigin(WebSecurityOrigin::createUnique());
     helper.webViewImpl()->mainFrame()->toWebLocalFrame()->loadRequest(request);
 
     // Normally, the result of the JS url replaces the existing contents on the
diff --git a/third_party/WebKit/Source/web/tests/WebURLResponseTest.cpp b/third_party/WebKit/Source/web/tests/WebURLResponseTest.cpp
index 4ffd6a86..8f1d8e4 100644
--- a/third_party/WebKit/Source/web/tests/WebURLResponseTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebURLResponseTest.cpp
@@ -30,6 +30,8 @@
 
 #include "public/platform/WebURLResponse.h"
 
+#include "platform/weborigin/KURL.h"
+#include "public/platform/WebURL.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
@@ -60,7 +62,6 @@
         TestExtraData* extraData = new TestExtraData(&alive);
         EXPECT_TRUE(alive);
 
-        urlResponse.initialize();
         urlResponse.setExtraData(extraData);
         EXPECT_EQ(extraData, urlResponse.getExtraData());
         {
@@ -75,4 +76,17 @@
     EXPECT_FALSE(alive);
 }
 
+TEST(WebURLResponseTest, NewInstanceIsNull)
+{
+    WebURLResponse instance;
+    EXPECT_TRUE(instance.isNull());
+}
+
+TEST(WebURLResponseTest, NotNullAfterSetURL)
+{
+    WebURLResponse instance;
+    instance.setURL(KURL(ParsedURLString, "http://localhost/"));
+    EXPECT_FALSE(instance.isNull());
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/web/tests/data/touch-event-handler.html b/third_party/WebKit/Source/web/tests/data/touch-event-handler.html
index 208be23..4d4b8c1 100644
--- a/third_party/WebKit/Source/web/tests/data/touch-event-handler.html
+++ b/third_party/WebKit/Source/web/tests/data/touch-event-handler.html
@@ -3,8 +3,7 @@
 <head>
   <script type="text/javascript">
       window.addEventListener('touchstart', function(event) {
-      });
+      }, {passive: false});
   </script>
 </head>
-
 </html>
diff --git a/third_party/WebKit/Source/web/tests/sim/SimTest.cpp b/third_party/WebKit/Source/web/tests/sim/SimTest.cpp
index 95c4bdfd..984f7a1 100644
--- a/third_party/WebKit/Source/web/tests/sim/SimTest.cpp
+++ b/third_party/WebKit/Source/web/tests/sim/SimTest.cpp
@@ -7,6 +7,7 @@
 #include "core/dom/Document.h"
 #include "platform/LayoutTestSupport.h"
 #include "platform/scroll/ScrollbarTheme.h"
+#include "public/platform/WebSecurityOrigin.h"
 #include "public/web/WebCache.h"
 #include "web/WebLocalFrameImpl.h"
 #include "web/WebViewImpl.h"
@@ -42,6 +43,7 @@
     WebURLRequest request;
     request.initialize();
     request.setURL(KURL(ParsedURLString, url));
+    request.setRequestorOrigin(WebSecurityOrigin::createUnique());
     webView().mainFrameImpl()->loadRequest(request);
 }
 
diff --git a/third_party/WebKit/Source/wtf/VectorTest.cpp b/third_party/WebKit/Source/wtf/VectorTest.cpp
index 74b08ca..aa7509b1 100644
--- a/third_party/WebKit/Source/wtf/VectorTest.cpp
+++ b/third_party/WebKit/Source/wtf/VectorTest.cpp
@@ -27,6 +27,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "wtf/HashSet.h"
+#include "wtf/Optional.h"
 #include "wtf/PtrUtil.h"
 #include "wtf/text/WTFString.h"
 #include <memory>
@@ -688,6 +689,15 @@
     EXPECT_EQ(3, vector3[2]);
 }
 
+TEST(VectorTest, Optional)
+{
+    Optional<Vector<int>> vector;
+    EXPECT_FALSE(vector);
+    vector.emplace(3);
+    EXPECT_TRUE(vector);
+    EXPECT_EQ(3u, vector->size());
+}
+
 static_assert(VectorTraits<int>::canCopyWithMemcpy, "int should be copied with memcopy.");
 static_assert(VectorTraits<char>::canCopyWithMemcpy, "char should be copied with memcpy.");
 static_assert(VectorTraits<LChar>::canCopyWithMemcpy, "LChar should be copied with memcpy.");
diff --git a/third_party/WebKit/Source/wtf/allocator/PartitionAllocator.h b/third_party/WebKit/Source/wtf/allocator/PartitionAllocator.h
index e10e16f..470ed96d 100644
--- a/third_party/WebKit/Source/wtf/allocator/PartitionAllocator.h
+++ b/third_party/WebKit/Source/wtf/allocator/PartitionAllocator.h
@@ -155,6 +155,7 @@
         ASSERT(location); \
         return location; \
     } \
+    void* operator new(size_t, void* location) { return location; } \
 private: \
 typedef int __thisIsHereToForceASemicolonAfterThisMacro
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py
index 8f56c40..947cf91 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py
@@ -330,3 +330,6 @@
         self._discard_working_directory_changes()
         self._run_git(['checkout', '-q', self._branch_tracking_remote_master()])
         self._discard_local_commits()
+
+    def get_issue_number(self):
+        return str(self._run_git(['cl', 'issue']).split()[2])
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py
index 9f662cd..77632028 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py
@@ -31,7 +31,7 @@
 import unittest
 
 from webkitpy.common.system.executive import Executive, ScriptError
-from webkitpy.common.system.executive_mock import MockExecutive
+from webkitpy.common.system.executive_mock import MockExecutive, MockExecutive2
 from webkitpy.common.system.filesystem import FileSystem
 from webkitpy.common.system.filesystem_mock import MockFileSystem
 from webkitpy.common.checkout.scm.detection import detect_scm_system
@@ -254,3 +254,11 @@
 
         scm._run_git = lambda args: 'Date: 2013-02-08 01:55:21 -0800'
         self.assertEqual(scm.timestamp_of_revision('some-path', '12345'), '2013-02-08T09:55:21Z')
+
+    def test_get_issue_number(self):
+        scm = Git(cwd='.', executive=MockExecutive2(output='Issue number: 12345 (http://crrev.com/12345)'))
+        issue_number = scm.get_issue_number()
+        self.assertEqual(issue_number, '12345')
+        scm2 = Git(cwd='.', executive=MockExecutive2(output='Issue number: None (None)'))
+        issue_number = scm2.get_issue_number()
+        self.assertEqual(issue_number, 'None')
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/test.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/test.py
index ccd37df..6697e3d 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/test.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/test.py
@@ -431,6 +431,24 @@
         if self._operating_system == 'linux' and self._version != 'linux32':
             self._architecture = 'x86_64'
 
+        self.all_systems = (('mac10.10', 'x86'),
+                            ('mac10.11', 'x86'),
+                            ('win7', 'x86'),
+                            ('win10', 'x86'),
+                            ('linux32', 'x86'),
+                            ('precise', 'x86_64'),
+                            ('trusty', 'x86_64'))
+
+        self.all_build_types = ('debug', 'release')
+
+        # To avoid surprises when introducing new macros, these are
+        # intentionally fixed in time.
+        self.configuration_specifier_macros_dict = {
+            'mac': ['mac10.10', 'mac10.11'],
+            'win': ['win7', 'win10'],
+            'linux': ['linux32', 'precise', 'trusty']
+        }
+
     def buildbot_archives_baselines(self):
         return self._name != 'test-win-win7'
 
@@ -528,33 +546,16 @@
         # By default, we assume we want to test every graphics type in
         # every configuration on every system.
         test_configurations = []
-        for version, architecture in self._all_systems():
-            for build_type in self._all_build_types():
+        for version, architecture in self.all_systems:
+            for build_type in self.all_build_types:
                 test_configurations.append(TestConfiguration(
                     version=version,
                     architecture=architecture,
                     build_type=build_type))
         return test_configurations
 
-    def _all_systems(self):
-        return (('mac10.10', 'x86'),
-                ('mac10.11', 'x86'),
-                ('win7', 'x86'),
-                ('win10', 'x86'),
-                ('linux32', 'x86'),
-                ('precise', 'x86_64'),
-                ('trusty', 'x86_64'))
-
-    def _all_build_types(self):
-        return ('debug', 'release')
-
     def configuration_specifier_macros(self):
-        """To avoid surprises when introducing new macros, these are intentionally fixed in time."""
-        return {
-            'mac': ['mac10.10', 'mac10.11'],
-            'win': ['win7', 'win10'],
-            'linux': ['linux32', 'precise', 'trusty']
-        }
+        return self.configuration_specifier_macros_dict
 
     def virtual_test_suites(self):
         return [
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py
index d56f1682..b65acb6 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py
@@ -5,6 +5,7 @@
 """Pull latest revisions of a W3C test repo and make a local commit."""
 
 import argparse
+import time
 
 from webkitpy.common.webkit_finder import WebKitFinder
 
@@ -12,6 +13,8 @@
 WPT_DEST_NAME = 'wpt'
 CSS_DEST_NAME = 'csswg-test'
 
+POLL_DELAY_SECONDS = 300
+
 
 class DepsUpdater(object):
 
@@ -24,6 +27,7 @@
         self.allow_local_commits = False
         self.keep_w3c_repos_around = False
         self.target = None
+        self.auto_update = False
 
     def main(self, argv=None):
         self.parse_args(argv)
@@ -60,6 +64,19 @@
 
         self.commit_changes_if_needed(chromium_commitish, import_commitish)
 
+        if self.auto_update:
+            self.check_run(['git', 'cl', 'upload', '-f'])
+            self.run(['git', 'cl', 'set-commit', '--dry-run'])
+            while True:
+                time.sleep(POLL_DELAY_SECONDS)
+                _, out = self.run(['git', 'cl', 'try-results'])
+                results = self.parse_try_job_results(out)
+                if results['Started'] or results['Scheduled']:
+                    continue
+                if results['Failures']:
+                    return 1
+                break
+            self.run(['git', 'cl', 'land', '-f'])
         return 0
 
     def parse_args(self, argv):
@@ -73,12 +90,15 @@
                             help='leave the w3c repos around that were imported previously.')
         parser.add_argument('target', choices=['css', 'wpt'],
                             help='Target repository.  "css" for csswg-test, "wpt" for web-platform-tests.')
+        parser.add_argument('--auto-update', action='store_true',
+                            help='uploads CL and initiates commit queue.')
 
         args = parser.parse_args(argv)
         self.allow_local_commits = args.allow_local_commits
         self.keep_w3c_repos_around = args.keep_w3c_repos_around
         self.verbose = args.verbose
         self.target = args.target
+        self.auto_update = args.auto_update
 
     def checkout_is_okay(self):
         git_diff_retcode, _ = self.run(['git', 'diff', '--quiet', 'HEAD'], exit_on_failure=False)
@@ -222,3 +242,42 @@
 
     def print_(self, msg):
         self.host.print_(msg)
+
+    def parse_try_job_results(self, results):
+        """Parses try job results from Rietveld.
+
+        Turns the output from git cl try-results into a usable format.
+
+        Args:
+            results: The stdout obtained by running git cl try-results.
+
+        Returns:
+            A dict mapping result type (e.g. Success, Failure)
+            to list of bots with that result type. The list of builders
+            is represented as a set and any bots with both success and
+            failure results are not included in failures.
+
+        Raises:
+            AttributeError: An unexpected result was found.
+        """
+        sets = {}
+        for line in results.splitlines():
+            line = line.strip()
+            if line[-1] == ':':
+                result_type = line[:-1]
+                sets[result_type] = set()
+            elif line.split()[0] == 'Total:':
+                break
+            else:
+                sets[result_type].add(line.split()[0])
+            print sets
+        sets['Failures'] -= sets['Successes']
+        sets['Started'] -= sets['Successes']
+        sets['Started'] -= sets['Failures']
+        return sets
+
+    def check_run(self, command):
+        return_code, out = self.run(command)
+        if return_code:
+            raise Exception('%s failed with exit code %d.' % ' '.join(command), return_code)
+        return out
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater_unittest.py
new file mode 100644
index 0000000..50da6a5b
--- /dev/null
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater_unittest.py
@@ -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.
+
+import unittest
+
+from webkitpy.w3c.deps_updater import DepsUpdater
+from webkitpy.common.host_mock import MockHost
+
+
+class DepsUpdaterTest(unittest.TestCase):
+
+    def test_parse_try_job_results(self):
+        output = """Successes:
+linux_builder     http://example.com/linux_builder/builds/222
+mac_builder       http://example.com/mac_builder/builds/222
+win_builder       http://example.com/win_builder/builds/222
+Failures:
+android_builder   http://example.com/android_builder/builds/111
+chromeos_builder  http://example.com/chromeos_builder/builds/111
+win_builder       http://example.com/win_builder/builds/111
+Started:
+chromeos_generic  http://example.com/chromeos_generic/builds/111
+chromeos_daisy    http://example.com/chromeos_daisy/builds/111
+Total: 8 tryjobs
+"""
+        host = MockHost()
+        updater = DepsUpdater(host)
+        self.assertEqual(updater.parse_try_job_results(output), {
+            'Successes': set([
+                'mac_builder',
+                'win_builder',
+                'linux_builder'
+            ]),
+            'Failures': set([
+                'android_builder',
+                'chromeos_builder'
+            ]),
+            'Started': set([
+                'chromeos_generic',
+                'chromeos_daisy'
+            ])
+        })
diff --git a/third_party/WebKit/public/blink_headers.gypi b/third_party/WebKit/public/blink_headers.gypi
index 1c38838..b7e9a2b 100644
--- a/third_party/WebKit/public/blink_headers.gypi
+++ b/third_party/WebKit/public/blink_headers.gypi
@@ -252,6 +252,7 @@
       "platform/modules/indexeddb/WebIDBKeyPath.h",
       "platform/modules/indexeddb/WebIDBKeyRange.h",
       "platform/modules/indexeddb/WebIDBMetadata.h",
+      "platform/modules/indexeddb/WebIDBObserver.h",
       "platform/modules/indexeddb/WebIDBTypes.h",
       "platform/modules/indexeddb/WebIDBValue.h",
       "platform/modules/installedapp/WebInstalledAppClient.h",
diff --git a/third_party/WebKit/public/platform/WebFrameScheduler.h b/third_party/WebKit/public/platform/WebFrameScheduler.h
index 6d11c0f..558cecd 100644
--- a/third_party/WebKit/public/platform/WebFrameScheduler.h
+++ b/third_party/WebKit/public/platform/WebFrameScheduler.h
@@ -47,11 +47,11 @@
 
     // Tells the scheduler a resource load has started. The scheduler may make
     // policy decisions based on this.
-    virtual void incrementPendingResourceLoadCount() { }
+    virtual void didStartLoading(unsigned long identifier) { }
 
-    // Tells the scheduler a resource load has started. The scheduler may make
+    // Tells the scheduler a resource load has stopped. The scheduler may make
     // policy decisions based on this.
-    virtual void decrementPendingResourceLoadCount() { }
+    virtual void didStopLoading(unsigned long identifier) { }
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/public/platform/WebURLResponse.h b/third_party/WebKit/public/platform/WebURLResponse.h
index 7ab714f..243be1e 100644
--- a/third_party/WebKit/public/platform/WebURLResponse.h
+++ b/third_party/WebKit/public/platform/WebURLResponse.h
@@ -37,6 +37,7 @@
 #include "public/platform/WebString.h"
 #include "public/platform/WebVector.h"
 #include "public/platform/modules/serviceworker/WebServiceWorkerResponseType.h"
+#include <memory>
 
 namespace blink {
 
@@ -135,25 +136,12 @@
         virtual ~ExtraData() { }
     };
 
-    ~WebURLResponse() { reset(); }
+    BLINK_PLATFORM_EXPORT ~WebURLResponse();
 
-    WebURLResponse() : m_private(0) { }
-    WebURLResponse(const WebURLResponse& r) : m_private(0) { assign(r); }
-    WebURLResponse& operator=(const WebURLResponse& r)
-    {
-        assign(r);
-        return *this;
-    }
-
-    explicit WebURLResponse(const WebURL& url) : m_private(0)
-    {
-        initialize();
-        setURL(url);
-    }
-
-    BLINK_PLATFORM_EXPORT void initialize();
-    BLINK_PLATFORM_EXPORT void reset();
-    BLINK_PLATFORM_EXPORT void assign(const WebURLResponse&);
+    BLINK_PLATFORM_EXPORT WebURLResponse();
+    BLINK_PLATFORM_EXPORT WebURLResponse(const WebURLResponse&);
+    BLINK_PLATFORM_EXPORT explicit WebURLResponse(const WebURL&);
+    BLINK_PLATFORM_EXPORT WebURLResponse& operator=(const WebURLResponse&);
 
     BLINK_PLATFORM_EXPORT bool isNull() const;
 
@@ -305,9 +293,17 @@
     BLINK_PLATFORM_EXPORT void setExtraData(ExtraData*);
 
 protected:
-    BLINK_PLATFORM_EXPORT void assign(WebURLResponsePrivate*);
+    // Permit subclasses to set arbitrary WebURLResponsePrivate pointer as
+    // |m_private|. Parameter must be non-null. |m_owningPrivate| is not set
+    // in this case.
+    BLINK_PLATFORM_EXPORT explicit WebURLResponse(WebURLResponsePrivate*);
 
 private:
+    // If this instance owns WebURLResponsePrivate |m_owningPrivate| is
+    // non-null and is pointed by |m_private|.
+    std::unique_ptr<WebURLResponsePrivate> m_owningPrivate;
+
+    // Should never be null.
     WebURLResponsePrivate* m_private;
 };
 
diff --git a/third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabase.h b/third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabase.h
index 4752309..d4e80d2 100644
--- a/third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabase.h
+++ b/third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabase.h
@@ -30,7 +30,10 @@
 #include "public/platform/WebCommon.h"
 #include "public/platform/modules/indexeddb/WebIDBCursor.h"
 #include "public/platform/modules/indexeddb/WebIDBMetadata.h"
+#include "public/platform/modules/indexeddb/WebIDBObserver.h"
 #include "public/platform/modules/indexeddb/WebIDBTypes.h"
+#include <set>
+#include <vector>
 
 namespace blink {
 
@@ -40,6 +43,7 @@
 class WebIDBKey;
 class WebIDBKeyPath;
 class WebIDBKeyRange;
+class WebIDBObserver;
 
 class WebIDBDatabase {
 public:
@@ -61,6 +65,9 @@
 
     typedef WebVector<WebIDBKey> WebIndexKeys;
 
+    virtual int32_t addObserver(std::unique_ptr<WebIDBObserver>, long long transactionId) = 0;
+    virtual bool containsObserverId(int32_t id) const = 0;
+    virtual void removeObservers(const std::vector<int32_t>& observerIdsToRemove) = 0;
     virtual void get(long long transactionId, long long objectStoreId, long long indexId, const WebIDBKeyRange&, bool keyOnly, WebIDBCallbacks*) = 0;
     virtual void getAll(long long transactionId, long long objectStoreId, long long indexId, const WebIDBKeyRange&, long long maxCount, bool keyOnly, WebIDBCallbacks*) = 0;
     virtual void put(long long transactionId, long long objectStoreId, const WebData& value, const WebVector<WebBlobInfo>&, const WebIDBKey&, WebIDBPutMode, WebIDBCallbacks*, const WebVector<long long>& indexIds, const WebVector<WebIndexKeys>&) = 0;
diff --git a/third_party/WebKit/public/platform/modules/indexeddb/WebIDBObserver.h b/third_party/WebKit/public/platform/modules/indexeddb/WebIDBObserver.h
new file mode 100644
index 0000000..0f93212
--- /dev/null
+++ b/third_party/WebKit/public/platform/modules/indexeddb/WebIDBObserver.h
@@ -0,0 +1,19 @@
+// 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.
+
+// This class makes the blink::IDBObserver visible to the content layer by holding a reference to it.
+
+#ifndef WebIDBObserver_h
+#define WebIDBObserver_h
+
+namespace blink {
+
+class WebIDBObserver {
+public:
+    virtual ~WebIDBObserver() {}
+};
+
+} // namespace blink
+
+#endif // WebIDBObserver_h
diff --git a/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerError.h b/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerError.h
index 21582b6..a5963c9 100644
--- a/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerError.h
+++ b/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerError.h
@@ -44,6 +44,7 @@
         ErrorTypeNavigation,
         ErrorTypeNetwork,
         ErrorTypeNotFound,
+        ErrorTypeScriptEvaluateFailed,
         ErrorTypeSecurity,
         ErrorTypeState,
         ErrorTypeTimeout,
diff --git a/third_party/boringssl/BUILD.generated.gni b/third_party/boringssl/BUILD.generated.gni
index cdbe0c9..5d1aa79 100644
--- a/third_party/boringssl/BUILD.generated.gni
+++ b/third_party/boringssl/BUILD.generated.gni
@@ -288,7 +288,6 @@
   "src/ssl/dtls_record.c",
   "src/ssl/handshake_client.c",
   "src/ssl/handshake_server.c",
-  "src/ssl/pqueue/pqueue.c",
   "src/ssl/s3_both.c",
   "src/ssl/s3_enc.c",
   "src/ssl/s3_lib.c",
diff --git a/third_party/boringssl/BUILD.generated_tests.gni b/third_party/boringssl/BUILD.generated_tests.gni
index 8b7ea3cc..16bddff0 100644
--- a/third_party/boringssl/BUILD.generated_tests.gni
+++ b/third_party/boringssl/BUILD.generated_tests.gni
@@ -522,18 +522,6 @@
     deps = invoker.deps
   }
 
-  executable("boringssl_pqueue_test") {
-    sources = [
-      "src/ssl/pqueue/pqueue_test.c",
-    ]
-    sources += _test_support_sources
-    if (defined(invoker.configs_exclude)) {
-      configs -= invoker.configs_exclude
-    }
-    configs += invoker.configs
-    deps = invoker.deps
-  }
-
   executable("boringssl_ssl_test") {
     sources = [
       "src/ssl/ssl_test.cc",
@@ -582,7 +570,6 @@
       ":boringssl_pkcs7_test",
       ":boringssl_pkcs8_test",
       ":boringssl_poly1305_test",
-      ":boringssl_pqueue_test",
       ":boringssl_refcount_test",
       ":boringssl_rsa_test",
       ":boringssl_spake25519_test",
diff --git a/third_party/boringssl/boringssl.gypi b/third_party/boringssl/boringssl.gypi
index 65a483e..399fb58 100644
--- a/third_party/boringssl/boringssl.gypi
+++ b/third_party/boringssl/boringssl.gypi
@@ -16,7 +16,6 @@
       'src/ssl/dtls_record.c',
       'src/ssl/handshake_client.c',
       'src/ssl/handshake_server.c',
-      'src/ssl/pqueue/pqueue.c',
       'src/ssl/s3_both.c',
       'src/ssl/s3_enc.c',
       'src/ssl/s3_lib.c',
diff --git a/third_party/boringssl/boringssl_tests.gypi b/third_party/boringssl/boringssl_tests.gypi
index 8542e5c2..1076214f 100644
--- a/third_party/boringssl/boringssl_tests.gypi
+++ b/third_party/boringssl/boringssl_tests.gypi
@@ -595,20 +595,6 @@
       'msvs_disabled_warnings': [ 4267, ],
     },
     {
-      'target_name': 'boringssl_pqueue_test',
-      'type': 'executable',
-      'dependencies': [
-        'boringssl.gyp:boringssl',
-      ],
-      'sources': [
-        'src/ssl/pqueue/pqueue_test.c',
-        '<@(boringssl_test_support_sources)',
-      ],
-      # TODO(davidben): Fix size_t truncations in BoringSSL.
-      # https://crbug.com/429039
-      'msvs_disabled_warnings': [ 4267, ],
-    },
-    {
       'target_name': 'boringssl_ssl_test',
       'type': 'executable',
       'dependencies': [
@@ -671,7 +657,6 @@
       'boringssl_pkcs7_test',
       'boringssl_pkcs8_test',
       'boringssl_poly1305_test',
-      'boringssl_pqueue_test',
       'boringssl_refcount_test',
       'boringssl_rsa_test',
       'boringssl_spake25519_test',
diff --git a/third_party/boringssl/err_data.c b/third_party/boringssl/err_data.c
index 32976ad..14f2dc1 100644
--- a/third_party/boringssl/err_data.c
+++ b/third_party/boringssl/err_data.c
@@ -74,51 +74,51 @@
     0xc3a8845,
     0xc3b00ea,
     0x10320845,
-    0x1032939a,
-    0x103313a6,
-    0x103393bf,
-    0x103413d2,
-    0x10348e7a,
+    0x103293ab,
+    0x103313b7,
+    0x103393d0,
+    0x103413e3,
+    0x10348e8b,
     0x10350c19,
-    0x103593e5,
-    0x103613fa,
-    0x1036940d,
-    0x1037142c,
-    0x10379445,
-    0x1038145a,
-    0x10389478,
-    0x10391487,
-    0x103994a3,
-    0x103a14be,
-    0x103a94cd,
-    0x103b14e9,
-    0x103b9504,
-    0x103c151b,
+    0x103593f6,
+    0x1036140b,
+    0x1036941e,
+    0x1037143d,
+    0x10379456,
+    0x1038146b,
+    0x10389489,
+    0x10391498,
+    0x103994b4,
+    0x103a14cf,
+    0x103a94de,
+    0x103b14fa,
+    0x103b9515,
+    0x103c152c,
     0x103c80ea,
-    0x103d152c,
-    0x103d9540,
-    0x103e155f,
-    0x103e956e,
-    0x103f1585,
-    0x103f9598,
+    0x103d153d,
+    0x103d9551,
+    0x103e1570,
+    0x103e957f,
+    0x103f1596,
+    0x103f95a9,
     0x10400bea,
-    0x104095ab,
-    0x104115c9,
-    0x104195dc,
-    0x104215f6,
-    0x10429606,
-    0x1043161a,
-    0x10439630,
-    0x10441648,
-    0x1044965d,
-    0x10451671,
-    0x10459683,
+    0x104095bc,
+    0x104115da,
+    0x104195ed,
+    0x10421607,
+    0x10429617,
+    0x1043162b,
+    0x10439641,
+    0x10441659,
+    0x1044966e,
+    0x10451682,
+    0x10459694,
     0x104605fb,
     0x1046893f,
-    0x10471698,
-    0x104796af,
-    0x104816c4,
-    0x104896d2,
+    0x104716a9,
+    0x104796c0,
+    0x104816d5,
+    0x104896e3,
     0x14320bcd,
     0x14328bdb,
     0x14330bea,
@@ -126,51 +126,51 @@
     0x143400ac,
     0x143480ea,
     0x18320083,
-    0x18328ed0,
+    0x18328ee1,
     0x183300ac,
-    0x18338ee6,
-    0x18340efa,
+    0x18338ef7,
+    0x18340f0b,
     0x183480ea,
-    0x18350f0f,
-    0x18358f27,
-    0x18360f3c,
-    0x18368f50,
-    0x18370f74,
-    0x18378f8a,
-    0x18380f9e,
-    0x18388fae,
+    0x18350f20,
+    0x18358f38,
+    0x18360f4d,
+    0x18368f61,
+    0x18370f85,
+    0x18378f9b,
+    0x18380faf,
+    0x18388fbf,
     0x18390a57,
-    0x18398fbe,
-    0x183a0fd3,
-    0x183a8fe7,
+    0x18398fcf,
+    0x183a0fe4,
+    0x183a8ff8,
     0x183b0c25,
-    0x183b8ff4,
-    0x183c1006,
-    0x183c9011,
-    0x183d1021,
-    0x183d9032,
-    0x183e1043,
-    0x183e9055,
-    0x183f107e,
-    0x183f9097,
-    0x184010af,
+    0x183b9005,
+    0x183c1017,
+    0x183c9022,
+    0x183d1032,
+    0x183d9043,
+    0x183e1054,
+    0x183e9066,
+    0x183f108f,
+    0x183f90a8,
+    0x184010c0,
     0x184086d3,
-    0x203210d6,
-    0x243210e2,
+    0x203210e7,
+    0x243210f3,
     0x24328985,
-    0x243310f4,
-    0x24339101,
-    0x2434110e,
-    0x24349120,
-    0x2435112f,
-    0x2435914c,
-    0x24361159,
-    0x24369167,
-    0x24371175,
-    0x24379183,
-    0x2438118c,
-    0x24389199,
-    0x243911ac,
+    0x24331105,
+    0x24339112,
+    0x2434111f,
+    0x24349131,
+    0x24351140,
+    0x2435915d,
+    0x2436116a,
+    0x24369178,
+    0x24371186,
+    0x24379194,
+    0x2438119d,
+    0x243891aa,
+    0x243911bd,
     0x28320c0d,
     0x28328c25,
     0x28330bea,
@@ -178,42 +178,42 @@
     0x28340c19,
     0x283480ac,
     0x283500ea,
-    0x2c32274a,
-    0x2c32a758,
-    0x2c33276a,
-    0x2c33a77c,
-    0x2c342790,
-    0x2c34a7a2,
-    0x2c3527bd,
-    0x2c35a7cf,
-    0x2c3627e2,
+    0x2c322799,
+    0x2c32a7a7,
+    0x2c3327b9,
+    0x2c33a7cb,
+    0x2c3427df,
+    0x2c34a7f1,
+    0x2c35280c,
+    0x2c35a81e,
+    0x2c362831,
     0x2c36832d,
-    0x2c3727ef,
-    0x2c37a801,
-    0x2c382814,
-    0x2c38a82b,
-    0x2c392839,
-    0x2c39a849,
-    0x2c3a285b,
-    0x2c3aa86f,
-    0x2c3b2880,
-    0x2c3ba89f,
-    0x2c3c28b3,
-    0x2c3ca8c9,
-    0x2c3d28e2,
-    0x2c3da8ff,
-    0x2c3e2910,
-    0x2c3ea91e,
-    0x2c3f2936,
-    0x2c3fa94e,
-    0x2c40295b,
-    0x2c4090d6,
-    0x2c41296c,
-    0x2c41a97f,
-    0x2c4210af,
-    0x2c42a990,
+    0x2c37283e,
+    0x2c37a850,
+    0x2c382863,
+    0x2c38a87a,
+    0x2c392888,
+    0x2c39a898,
+    0x2c3a28aa,
+    0x2c3aa8be,
+    0x2c3b28cf,
+    0x2c3ba8ee,
+    0x2c3c2902,
+    0x2c3ca918,
+    0x2c3d2931,
+    0x2c3da94e,
+    0x2c3e295f,
+    0x2c3ea96d,
+    0x2c3f2985,
+    0x2c3fa99d,
+    0x2c4029aa,
+    0x2c4090e7,
+    0x2c4129bb,
+    0x2c41a9ce,
+    0x2c4210c0,
+    0x2c42a9df,
     0x2c430720,
-    0x2c43a891,
+    0x2c43a8e0,
     0x30320000,
     0x30328015,
     0x3033001f,
@@ -319,211 +319,214 @@
     0x3c340cb3,
     0x3c348cdd,
     0x3c350cf8,
-    0x3c358d0d,
-    0x3c360d26,
-    0x3c368d3e,
-    0x3c370d4f,
-    0x3c378d5d,
-    0x3c380d6a,
-    0x3c388d7e,
+    0x3c358d1e,
+    0x3c360d37,
+    0x3c368d4f,
+    0x3c370d60,
+    0x3c378d6e,
+    0x3c380d7b,
+    0x3c388d8f,
     0x3c390c25,
-    0x3c398d92,
-    0x3c3a0da6,
+    0x3c398da3,
+    0x3c3a0db7,
     0x3c3a88ff,
-    0x3c3b0db6,
-    0x3c3b8dd1,
-    0x3c3c0de3,
-    0x3c3c8df9,
-    0x3c3d0e03,
-    0x3c3d8e17,
-    0x3c3e0e25,
-    0x3c3e8e4a,
+    0x3c3b0dc7,
+    0x3c3b8de2,
+    0x3c3c0df4,
+    0x3c3c8e0a,
+    0x3c3d0e14,
+    0x3c3d8e28,
+    0x3c3e0e36,
+    0x3c3e8e5b,
     0x3c3f0c4e,
-    0x3c3f8e33,
+    0x3c3f8e44,
     0x3c4000ac,
     0x3c4080ea,
     0x3c410cce,
-    0x403216e9,
-    0x403296ff,
-    0x4033172d,
-    0x40339737,
-    0x4034174e,
-    0x4034976c,
-    0x4035177c,
-    0x4035978e,
-    0x4036179b,
-    0x403697a7,
-    0x403717bc,
-    0x403797ce,
-    0x403817d9,
-    0x403897eb,
-    0x40390e7a,
-    0x403997fb,
-    0x403a180e,
-    0x403a982f,
-    0x403b1840,
-    0x403b9850,
+    0x3c418d0d,
+    0x403216fa,
+    0x40329710,
+    0x4033173e,
+    0x40339748,
+    0x4034175f,
+    0x4034977d,
+    0x4035178d,
+    0x4035979f,
+    0x403617ac,
+    0x403697b8,
+    0x403717cd,
+    0x403797df,
+    0x403817ea,
+    0x403897fc,
+    0x40390e8b,
+    0x4039980c,
+    0x403a181f,
+    0x403a9840,
+    0x403b1851,
+    0x403b9861,
     0x403c0064,
     0x403c8083,
-    0x403d185c,
-    0x403d9872,
-    0x403e1881,
-    0x403e9894,
-    0x403f18ae,
-    0x403f98bc,
-    0x404018d1,
-    0x404098e5,
-    0x40411902,
-    0x4041991d,
-    0x40421936,
-    0x40429949,
-    0x4043195d,
-    0x40439975,
-    0x4044198c,
+    0x403d186d,
+    0x403d9883,
+    0x403e1892,
+    0x403e98a5,
+    0x403f18bf,
+    0x403f98cd,
+    0x404018e2,
+    0x404098f6,
+    0x40411913,
+    0x4041992e,
+    0x40421947,
+    0x4042995a,
+    0x4043196e,
+    0x40439986,
+    0x4044199d,
     0x404480ac,
-    0x404519a1,
-    0x404599b3,
-    0x404619d7,
-    0x404699f7,
-    0x40471a05,
-    0x40479a19,
-    0x40481a2e,
-    0x40489a47,
-    0x40491a5e,
-    0x40499a78,
-    0x404a1a8f,
-    0x404a9aad,
-    0x404b1ac5,
-    0x404b9adc,
-    0x404c1af2,
-    0x404c9b04,
-    0x404d1b25,
-    0x404d9b47,
-    0x404e1b5b,
-    0x404e9b68,
-    0x404f1b7f,
-    0x404f9b8f,
-    0x40501b9f,
-    0x40509bb3,
-    0x40511bce,
-    0x40519bde,
-    0x40521bf5,
-    0x40529c07,
-    0x40531c1f,
-    0x40539c32,
-    0x40541c47,
-    0x40549c6a,
-    0x40551c78,
-    0x40559c95,
-    0x40561ca2,
-    0x40569cbb,
-    0x40571cd3,
-    0x40579ce6,
-    0x40581cfb,
-    0x40589d0d,
-    0x40591d1d,
-    0x40599d36,
-    0x405a1d4a,
-    0x405a9d5a,
-    0x405b1d72,
-    0x405b9d83,
-    0x405c1d96,
-    0x405c9da7,
-    0x405d1db4,
-    0x405d9dcb,
-    0x405e1deb,
+    0x404519b2,
+    0x404599c4,
+    0x404619e8,
+    0x40469a08,
+    0x40471a16,
+    0x40479a2a,
+    0x40481a3f,
+    0x40489a58,
+    0x40491a6f,
+    0x40499a89,
+    0x404a1aa0,
+    0x404a9abe,
+    0x404b1ad6,
+    0x404b9aed,
+    0x404c1b03,
+    0x404c9b15,
+    0x404d1b36,
+    0x404d9b58,
+    0x404e1b6c,
+    0x404e9b79,
+    0x404f1b90,
+    0x404f9ba0,
+    0x40501bca,
+    0x40509bde,
+    0x40511bf9,
+    0x40519c09,
+    0x40521c20,
+    0x40529c32,
+    0x40531c4a,
+    0x40539c5d,
+    0x40541c72,
+    0x40549c95,
+    0x40551ca3,
+    0x40559cc0,
+    0x40561ccd,
+    0x40569ce6,
+    0x40571cfe,
+    0x40579d11,
+    0x40581d26,
+    0x40589d38,
+    0x40591d48,
+    0x40599d61,
+    0x405a1d75,
+    0x405a9d85,
+    0x405b1d9d,
+    0x405b9dae,
+    0x405c1dc1,
+    0x405c9dd2,
+    0x405d1ddf,
+    0x405d9df6,
+    0x405e1e16,
     0x405e8a95,
-    0x405f1e0c,
-    0x405f9e19,
-    0x40601e27,
-    0x40609e49,
-    0x40611e71,
-    0x40619e86,
-    0x40621e9d,
-    0x40629eae,
-    0x40631ebf,
-    0x40639ed4,
-    0x40641eeb,
-    0x40649efc,
-    0x40651f17,
-    0x40659f2e,
-    0x40661f46,
-    0x40669f70,
-    0x40671f9b,
-    0x40679fbc,
-    0x40681fcf,
-    0x40689ff0,
-    0x40692022,
-    0x4069a050,
-    0x406a2071,
-    0x406aa091,
-    0x406b2219,
-    0x406ba23c,
-    0x406c2252,
-    0x406ca47e,
-    0x406d24ad,
-    0x406da4d5,
-    0x406e24ee,
-    0x406ea506,
-    0x406f2525,
-    0x406fa53a,
-    0x4070254d,
-    0x4070a56a,
+    0x405f1e37,
+    0x405f9e44,
+    0x40601e52,
+    0x40609e74,
+    0x40611e9c,
+    0x40619eb1,
+    0x40621ec8,
+    0x40629ed9,
+    0x40631eea,
+    0x40639eff,
+    0x40641f16,
+    0x40649f27,
+    0x40651f42,
+    0x40659f59,
+    0x40661f71,
+    0x40669f9b,
+    0x40671fc6,
+    0x40679fe7,
+    0x40681ffa,
+    0x4068a01b,
+    0x4069204d,
+    0x4069a07b,
+    0x406a209c,
+    0x406aa0bc,
+    0x406b2244,
+    0x406ba267,
+    0x406c227d,
+    0x406ca4a9,
+    0x406d24d8,
+    0x406da500,
+    0x406e2519,
+    0x406ea531,
+    0x406f2550,
+    0x406fa565,
+    0x40702578,
+    0x4070a595,
     0x40710800,
-    0x4071a57c,
-    0x4072258f,
-    0x4072a5a8,
-    0x407325c0,
-    0x4073935c,
-    0x407425d4,
-    0x4074a5ee,
-    0x407525ff,
-    0x4075a613,
-    0x40762621,
-    0x40769199,
-    0x40772646,
-    0x4077a668,
-    0x40782683,
-    0x4078a698,
-    0x407926af,
-    0x4079a6c5,
-    0x407a26d1,
-    0x407aa6e4,
-    0x407b26f9,
-    0x407ba70b,
-    0x407c2720,
-    0x407ca729,
-    0x407d200b,
-    0x41f42144,
-    0x41f921d6,
-    0x41fe20c9,
-    0x41fea2a5,
-    0x41ff2396,
-    0x4203215d,
-    0x4208217f,
-    0x4208a1bb,
-    0x420920ad,
-    0x4209a1f5,
-    0x420a2104,
-    0x420aa0e4,
-    0x420b2124,
-    0x420ba19d,
-    0x420c23b2,
-    0x420ca272,
-    0x420d228c,
-    0x420da2c3,
-    0x421222dd,
-    0x42172379,
-    0x4217a31f,
-    0x421c2341,
-    0x421f22fc,
-    0x422123c9,
-    0x4226235c,
-    0x422b2462,
-    0x422ba42b,
-    0x422c244a,
-    0x422ca405,
-    0x422d23e4,
+    0x4071a5a7,
+    0x407225ba,
+    0x4072a5d3,
+    0x407325eb,
+    0x4073936d,
+    0x407425ff,
+    0x4074a619,
+    0x4075262a,
+    0x4075a63e,
+    0x4076264c,
+    0x407691aa,
+    0x40772671,
+    0x4077a693,
+    0x407826ae,
+    0x4078a6e7,
+    0x407926fe,
+    0x4079a714,
+    0x407a2720,
+    0x407aa733,
+    0x407b2748,
+    0x407ba75a,
+    0x407c276f,
+    0x407ca778,
+    0x407d2036,
+    0x407d9bb0,
+    0x407e26c3,
+    0x41f4216f,
+    0x41f92201,
+    0x41fe20f4,
+    0x41fea2d0,
+    0x41ff23c1,
+    0x42032188,
+    0x420821aa,
+    0x4208a1e6,
+    0x420920d8,
+    0x4209a220,
+    0x420a212f,
+    0x420aa10f,
+    0x420b214f,
+    0x420ba1c8,
+    0x420c23dd,
+    0x420ca29d,
+    0x420d22b7,
+    0x420da2ee,
+    0x42122308,
+    0x421723a4,
+    0x4217a34a,
+    0x421c236c,
+    0x421f2327,
+    0x422123f4,
+    0x42262387,
+    0x422b248d,
+    0x422ba456,
+    0x422c2475,
+    0x422ca430,
+    0x422d240f,
     0x4432072b,
     0x4432873a,
     0x44330746,
@@ -541,104 +544,104 @@
     0x44390800,
     0x4439880e,
     0x443a0821,
-    0x4c3211c3,
-    0x4c3291d3,
-    0x4c3311e6,
-    0x4c339206,
+    0x4c3211d4,
+    0x4c3291e4,
+    0x4c3311f7,
+    0x4c339217,
     0x4c3400ac,
     0x4c3480ea,
-    0x4c351212,
-    0x4c359220,
-    0x4c36123c,
-    0x4c36924f,
-    0x4c37125e,
-    0x4c37926c,
-    0x4c381281,
-    0x4c38928d,
-    0x4c3912ad,
-    0x4c3992d7,
-    0x4c3a12f0,
-    0x4c3a9309,
+    0x4c351223,
+    0x4c359231,
+    0x4c36124d,
+    0x4c369260,
+    0x4c37126f,
+    0x4c37927d,
+    0x4c381292,
+    0x4c38929e,
+    0x4c3912be,
+    0x4c3992e8,
+    0x4c3a1301,
+    0x4c3a931a,
     0x4c3b05fb,
-    0x4c3b9322,
-    0x4c3c1334,
-    0x4c3c9343,
-    0x4c3d135c,
-    0x4c3d936b,
-    0x4c3e1378,
-    0x503229a2,
-    0x5032a9b1,
-    0x503329bc,
-    0x5033a9cc,
-    0x503429e5,
-    0x5034a9ff,
-    0x50352a0d,
-    0x5035aa23,
-    0x50362a35,
-    0x5036aa4b,
-    0x50372a64,
-    0x5037aa77,
-    0x50382a8f,
-    0x5038aaa0,
-    0x50392ab5,
-    0x5039aac9,
-    0x503a2ae9,
-    0x503aaaff,
-    0x503b2b17,
-    0x503bab29,
-    0x503c2b45,
-    0x503cab5c,
-    0x503d2b75,
-    0x503dab8b,
-    0x503e2b98,
-    0x503eabae,
-    0x503f2bc0,
+    0x4c3b9333,
+    0x4c3c1345,
+    0x4c3c9354,
+    0x4c3d136d,
+    0x4c3d937c,
+    0x4c3e1389,
+    0x503229f1,
+    0x5032aa00,
+    0x50332a0b,
+    0x5033aa1b,
+    0x50342a34,
+    0x5034aa4e,
+    0x50352a5c,
+    0x5035aa72,
+    0x50362a84,
+    0x5036aa9a,
+    0x50372ab3,
+    0x5037aac6,
+    0x50382ade,
+    0x5038aaef,
+    0x50392b04,
+    0x5039ab18,
+    0x503a2b38,
+    0x503aab4e,
+    0x503b2b66,
+    0x503bab78,
+    0x503c2b94,
+    0x503cabab,
+    0x503d2bc4,
+    0x503dabda,
+    0x503e2be7,
+    0x503eabfd,
+    0x503f2c0f,
     0x503f8382,
-    0x50402bd3,
-    0x5040abe3,
-    0x50412bfd,
-    0x5041ac0c,
-    0x50422c26,
-    0x5042ac43,
-    0x50432c53,
-    0x5043ac63,
-    0x50442c72,
+    0x50402c22,
+    0x5040ac32,
+    0x50412c4c,
+    0x5041ac5b,
+    0x50422c75,
+    0x5042ac92,
+    0x50432ca2,
+    0x5043acb2,
+    0x50442cc1,
     0x5044843f,
-    0x50452c86,
-    0x5045aca4,
-    0x50462cb7,
-    0x5046accd,
-    0x50472cdf,
-    0x5047acf4,
-    0x50482d1a,
-    0x5048ad28,
-    0x50492d3b,
-    0x5049ad50,
-    0x504a2d66,
-    0x504aad76,
-    0x504b2d96,
-    0x504bada9,
-    0x504c2dcc,
-    0x504cadfa,
-    0x504d2e0c,
-    0x504dae29,
-    0x504e2e44,
-    0x504eae60,
-    0x504f2e72,
-    0x504fae89,
-    0x50502e98,
+    0x50452cd5,
+    0x5045acf3,
+    0x50462d06,
+    0x5046ad1c,
+    0x50472d2e,
+    0x5047ad43,
+    0x50482d69,
+    0x5048ad77,
+    0x50492d8a,
+    0x5049ad9f,
+    0x504a2db5,
+    0x504aadc5,
+    0x504b2de5,
+    0x504badf8,
+    0x504c2e1b,
+    0x504cae49,
+    0x504d2e5b,
+    0x504dae78,
+    0x504e2e93,
+    0x504eaeaf,
+    0x504f2ec1,
+    0x504faed8,
+    0x50502ee7,
     0x505086ef,
-    0x50512eab,
-    0x58320eb8,
-    0x68320e7a,
+    0x50512efa,
+    0x58320ec9,
+    0x68320e8b,
     0x68328c25,
     0x68330c38,
-    0x68338e88,
-    0x68340e98,
+    0x68338e99,
+    0x68340ea9,
     0x683480ea,
-    0x6c320e56,
+    0x6c320e67,
     0x6c328bfc,
-    0x6c330e61,
+    0x6c330e72,
     0x74320a0b,
     0x78320970,
     0x78328985,
@@ -665,7 +668,7 @@
     0x783d0b19,
     0x783d8b2e,
     0x783e0a84,
-    0x7c3210c5,
+    0x7c3210d6,
 };
 
 const size_t kOpenSSLReasonValuesLen = sizeof(kOpenSSLReasonValues) / sizeof(kOpenSSLReasonValues[0]);
@@ -844,6 +847,7 @@
     "GROUP_MISMATCH\0"
     "I2D_ECPKPARAMETERS_FAILURE\0"
     "INCOMPATIBLE_OBJECTS\0"
+    "INVALID_COFACTOR\0"
     "INVALID_COMPRESSED_POINT\0"
     "INVALID_COMPRESSION_BIT\0"
     "INVALID_ENCODING\0"
@@ -1025,6 +1029,7 @@
     "INAPPROPRIATE_FALLBACK\0"
     "INVALID_COMMAND\0"
     "INVALID_MESSAGE\0"
+    "INVALID_OUTER_RECORD_TYPE\0"
     "INVALID_SSL_SESSION\0"
     "INVALID_TICKET_KEYS_LENGTH\0"
     "LENGTH_MISMATCH\0"
@@ -1133,6 +1138,7 @@
     "UNSUPPORTED_COMPRESSION_ALGORITHM\0"
     "UNSUPPORTED_ELLIPTIC_CURVE\0"
     "UNSUPPORTED_PROTOCOL\0"
+    "UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY\0"
     "WRONG_CERTIFICATE_TYPE\0"
     "WRONG_CIPHER_RETURNED\0"
     "WRONG_CURVE\0"
diff --git a/third_party/boringssl/win-x86_64/crypto/chacha/chacha-x86_64.asm b/third_party/boringssl/win-x86_64/crypto/chacha/chacha-x86_64.asm
index 0ecbe95..afebd2e 100644
--- a/third_party/boringssl/win-x86_64/crypto/chacha/chacha-x86_64.asm
+++ b/third_party/boringssl/win-x86_64/crypto/chacha/chacha-x86_64.asm
@@ -1091,10 +1091,10 @@
 
 
 
-	vbroadcasti128	ymm11,YMMWORD[$L$sigma]
-	vbroadcasti128	ymm3,YMMWORD[rcx]
-	vbroadcasti128	ymm15,YMMWORD[16+rcx]
-	vbroadcasti128	ymm7,YMMWORD[r8]
+	vbroadcasti128	ymm11,XMMWORD[$L$sigma]
+	vbroadcasti128	ymm3,XMMWORD[rcx]
+	vbroadcasti128	ymm15,XMMWORD[16+rcx]
+	vbroadcasti128	ymm7,XMMWORD[r8]
 	lea	rcx,[256+rsp]
 	lea	rax,[512+rsp]
 	lea	r10,[$L$rot16]
@@ -1161,7 +1161,7 @@
 $L$oop_enter8x:
 	vmovdqa	YMMWORD[64+rsp],ymm14
 	vmovdqa	YMMWORD[96+rsp],ymm15
-	vbroadcasti128	ymm15,YMMWORD[r10]
+	vbroadcasti128	ymm15,XMMWORD[r10]
 	vmovdqa	YMMWORD[(512-512)+rax],ymm4
 	mov	eax,10
 	jmp	NEAR $L$oop8x
@@ -1179,7 +1179,7 @@
 	vpslld	ymm14,ymm0,12
 	vpsrld	ymm0,ymm0,20
 	vpor	ymm0,ymm14,ymm0
-	vbroadcasti128	ymm14,YMMWORD[r11]
+	vbroadcasti128	ymm14,XMMWORD[r11]
 	vpaddd	ymm13,ymm13,ymm5
 	vpxor	ymm1,ymm13,ymm1
 	vpslld	ymm15,ymm1,12
@@ -1196,7 +1196,7 @@
 	vpslld	ymm15,ymm0,7
 	vpsrld	ymm0,ymm0,25
 	vpor	ymm0,ymm15,ymm0
-	vbroadcasti128	ymm15,YMMWORD[r10]
+	vbroadcasti128	ymm15,XMMWORD[r10]
 	vpaddd	ymm13,ymm13,ymm5
 	vpxor	ymm1,ymm13,ymm1
 	vpslld	ymm14,ymm1,7
@@ -1217,7 +1217,7 @@
 	vpslld	ymm14,ymm2,12
 	vpsrld	ymm2,ymm2,20
 	vpor	ymm2,ymm14,ymm2
-	vbroadcasti128	ymm14,YMMWORD[r11]
+	vbroadcasti128	ymm14,XMMWORD[r11]
 	vpaddd	ymm13,ymm13,ymm7
 	vpxor	ymm3,ymm13,ymm3
 	vpslld	ymm15,ymm3,12
@@ -1234,7 +1234,7 @@
 	vpslld	ymm15,ymm2,7
 	vpsrld	ymm2,ymm2,25
 	vpor	ymm2,ymm15,ymm2
-	vbroadcasti128	ymm15,YMMWORD[r10]
+	vbroadcasti128	ymm15,XMMWORD[r10]
 	vpaddd	ymm13,ymm13,ymm7
 	vpxor	ymm3,ymm13,ymm3
 	vpslld	ymm14,ymm3,7
@@ -1251,7 +1251,7 @@
 	vpslld	ymm14,ymm1,12
 	vpsrld	ymm1,ymm1,20
 	vpor	ymm1,ymm14,ymm1
-	vbroadcasti128	ymm14,YMMWORD[r11]
+	vbroadcasti128	ymm14,XMMWORD[r11]
 	vpaddd	ymm13,ymm13,ymm4
 	vpxor	ymm2,ymm13,ymm2
 	vpslld	ymm15,ymm2,12
@@ -1268,7 +1268,7 @@
 	vpslld	ymm15,ymm1,7
 	vpsrld	ymm1,ymm1,25
 	vpor	ymm1,ymm15,ymm1
-	vbroadcasti128	ymm15,YMMWORD[r10]
+	vbroadcasti128	ymm15,XMMWORD[r10]
 	vpaddd	ymm13,ymm13,ymm4
 	vpxor	ymm2,ymm13,ymm2
 	vpslld	ymm14,ymm2,7
@@ -1289,7 +1289,7 @@
 	vpslld	ymm14,ymm3,12
 	vpsrld	ymm3,ymm3,20
 	vpor	ymm3,ymm14,ymm3
-	vbroadcasti128	ymm14,YMMWORD[r11]
+	vbroadcasti128	ymm14,XMMWORD[r11]
 	vpaddd	ymm13,ymm13,ymm6
 	vpxor	ymm0,ymm13,ymm0
 	vpslld	ymm15,ymm0,12
@@ -1306,7 +1306,7 @@
 	vpslld	ymm15,ymm3,7
 	vpsrld	ymm3,ymm3,25
 	vpor	ymm3,ymm15,ymm3
-	vbroadcasti128	ymm15,YMMWORD[r10]
+	vbroadcasti128	ymm15,XMMWORD[r10]
 	vpaddd	ymm13,ymm13,ymm6
 	vpxor	ymm0,ymm13,ymm0
 	vpslld	ymm14,ymm0,7
diff --git a/third_party/harfbuzz-ng/BUILD.gn b/third_party/harfbuzz-ng/BUILD.gn
index 0d6fcbc..4b88d7c 100644
--- a/third_party/harfbuzz-ng/BUILD.gn
+++ b/third_party/harfbuzz-ng/BUILD.gn
@@ -181,6 +181,11 @@
         "src/hb-coretext.h",
       ]
       defines += [ "HAVE_CORETEXT" ]
+      libs = [
+        "CoreFoundation.framework",
+        "CoreGraphics.framework",
+        "CoreText.framework",
+      ]
     }
 
     # When without -fvisibility=hidden for pango to use the harfbuzz
diff --git a/tools/android/loading/sandwich.py b/tools/android/loading/sandwich.py
index 7cb0834..40419431 100755
--- a/tools/android/loading/sandwich.py
+++ b/tools/android/loading/sandwich.py
@@ -218,6 +218,7 @@
   setup_path = os.path.join(args.output, _SANDWICH_SETUP_FILENAME)
   with open(setup_path) as file_input:
     setup = yaml.load(file_input)
+  android_device = None
   if setup['sandwich_runner']['android_device_serial']:
     android_device = device_setup.GetDeviceFromSerial(
         setup['sandwich_runner']['android_device_serial'])
diff --git a/tools/android/loading/task_manager.py b/tools/android/loading/task_manager.py
index 0ae1f7a5..f132eb1 100644
--- a/tools/android/loading/task_manager.py
+++ b/tools/android/loading/task_manager.py
@@ -64,6 +64,7 @@
 import common_util
 
 
+_TASK_LOGS_DIR_NAME = 'logs'
 _TASK_GRAPH_DOTFILE_NAME = 'tasks_graph.dot'
 _TASK_GRAPH_PNG_NAME = 'tasks_graph.png'
 _TASK_RESUME_ARGUMENTS_FILE = 'resume.txt'
@@ -467,9 +468,11 @@
 
   log_filename = datetime.datetime.now().strftime(
       _TASK_EXECUTION_LOG_NAME_FORMAT)
+  log_path = os.path.join(args.output, _TASK_LOGS_DIR_NAME, log_filename)
+  if not os.path.isdir(os.path.dirname(log_path)):
+    os.makedirs(os.path.dirname(log_path))
   formatter = logging.Formatter('[%(asctime)s] %(levelname)s: %(message)s')
-  handler = logging.FileHandler(
-      os.path.join(args.output, log_filename), mode='a')
+  handler = logging.FileHandler(log_path, mode='a')
   handler.setFormatter(formatter)
   logging.getLogger().addHandler(handler)
   logging.info(
diff --git a/tools/clang/blink_gc_plugin/tests/base_class_must_define_virtual_trace.h b/tools/clang/blink_gc_plugin/tests/base_class_must_define_virtual_trace.h
index 16558bb8..fbd26d73 100644
--- a/tools/clang/blink_gc_plugin/tests/base_class_must_define_virtual_trace.h
+++ b/tools/clang/blink_gc_plugin/tests/base_class_must_define_virtual_trace.h
@@ -10,12 +10,12 @@
 namespace blink {
 
 class PartBase {
-    DISALLOW_ALLOCATION();
+    DISALLOW_NEW();
     // Missing virtual trace.
 };
 
 class PartDerived : public PartBase {
-    DISALLOW_ALLOCATION();
+    DISALLOW_NEW();
 public:
     virtual void trace(Visitor*);
 };
diff --git a/tools/clang/blink_gc_plugin/tests/class_requires_trace_method.h b/tools/clang/blink_gc_plugin/tests/class_requires_trace_method.h
index 782d80e1..4a442b72 100644
--- a/tools/clang/blink_gc_plugin/tests/class_requires_trace_method.h
+++ b/tools/clang/blink_gc_plugin/tests/class_requires_trace_method.h
@@ -12,7 +12,7 @@
 class HeapObject;
 
 class PartObject {
-    DISALLOW_ALLOCATION();
+    DISALLOW_NEW();
 private:
     Member<HeapObject> m_obj;
 };
diff --git a/tools/clang/blink_gc_plugin/tests/class_requires_trace_method_tmpl.h b/tools/clang/blink_gc_plugin/tests/class_requires_trace_method_tmpl.h
index b24b1dd..70cab61 100644
--- a/tools/clang/blink_gc_plugin/tests/class_requires_trace_method_tmpl.h
+++ b/tools/clang/blink_gc_plugin/tests/class_requires_trace_method_tmpl.h
@@ -12,11 +12,11 @@
 class HeapObject : public GarbageCollected<HeapObject> { };
 
 class PartObjectA {
-    DISALLOW_ALLOCATION();
+    DISALLOW_NEW();
 };
 
 class PartObjectB {
-    DISALLOW_ALLOCATION();
+    DISALLOW_NEW();
 public:
     void trace(Visitor* visitor) { visitor->trace(m_obj); }
 private:
diff --git a/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.h b/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.h
index 4d9e692a..7700b82 100644
--- a/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.h
+++ b/tools/clang/blink_gc_plugin/tests/fields_illegal_tracing.h
@@ -30,7 +30,7 @@
 class PartObject;
 
 class PartObject {
-    DISALLOW_ALLOCATION();
+    DISALLOW_NEW();
 public:
     void trace(Visitor*);
 private:
diff --git a/tools/clang/blink_gc_plugin/tests/fields_require_tracing.h b/tools/clang/blink_gc_plugin/tests/fields_require_tracing.h
index 60caa68..1819411 100644
--- a/tools/clang/blink_gc_plugin/tests/fields_require_tracing.h
+++ b/tools/clang/blink_gc_plugin/tests/fields_require_tracing.h
@@ -13,7 +13,7 @@
 class PartObject;
 
 class PartBObject {
-    DISALLOW_ALLOCATION();
+    DISALLOW_NEW();
 public:
     void trace(Visitor*);
 private:
@@ -22,7 +22,7 @@
 };
 
 class PartObject {
-    DISALLOW_ALLOCATION();
+    DISALLOW_NEW();
 public:
     void trace(Visitor*);
 private:
diff --git a/tools/clang/blink_gc_plugin/tests/heap/stubs.h b/tools/clang/blink_gc_plugin/tests/heap/stubs.h
index fff4a78..813ab127 100644
--- a/tools/clang/blink_gc_plugin/tests/heap/stubs.h
+++ b/tools/clang/blink_gc_plugin/tests/heap/stubs.h
@@ -139,7 +139,7 @@
 
 using namespace WTF;
 
-#define DISALLOW_ALLOCATION()                   \
+#define DISALLOW_NEW()                   \
     private:                                    \
     void* operator new(size_t) = delete;        \
     void* operator new(size_t, void*) = delete;
diff --git a/tools/clang/blink_gc_plugin/tests/member_in_offheap_class.h b/tools/clang/blink_gc_plugin/tests/member_in_offheap_class.h
index 5a59c7e..2a7c868 100644
--- a/tools/clang/blink_gc_plugin/tests/member_in_offheap_class.h
+++ b/tools/clang/blink_gc_plugin/tests/member_in_offheap_class.h
@@ -28,7 +28,7 @@
 };
 
 class PartObject {
-    DISALLOW_ALLOCATION();
+    DISALLOW_NEW();
 public:
     void trace(Visitor*);
 private:
diff --git a/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.h b/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.h
index b412561..6f47bafe 100644
--- a/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.h
+++ b/tools/clang/blink_gc_plugin/tests/own_ptr_to_gc_managed_class.h
@@ -12,7 +12,7 @@
 class HeapObject;
 
 class PartObject {
-    DISALLOW_ALLOCATION();
+    DISALLOW_NEW();
 private:
     OwnPtr<HeapObject> m_obj;
 };
diff --git a/tools/clang/blink_gc_plugin/tests/persistent_field_in_gc_managed_class.h b/tools/clang/blink_gc_plugin/tests/persistent_field_in_gc_managed_class.h
index 0ae2b27..a90f63c 100644
--- a/tools/clang/blink_gc_plugin/tests/persistent_field_in_gc_managed_class.h
+++ b/tools/clang/blink_gc_plugin/tests/persistent_field_in_gc_managed_class.h
@@ -12,7 +12,7 @@
 class HeapObject;
 
 class PartObject {
-    DISALLOW_ALLOCATION();
+    DISALLOW_NEW();
 private:
     Persistent<HeapObject> m_obj;
 };
diff --git a/tools/clang/blink_gc_plugin/tests/raw_ptr_to_gc_managed_class.h b/tools/clang/blink_gc_plugin/tests/raw_ptr_to_gc_managed_class.h
index 987001d..18fa9fa4 100644
--- a/tools/clang/blink_gc_plugin/tests/raw_ptr_to_gc_managed_class.h
+++ b/tools/clang/blink_gc_plugin/tests/raw_ptr_to_gc_managed_class.h
@@ -12,7 +12,7 @@
 class HeapObject;
 
 class PartObject {
-    DISALLOW_ALLOCATION();
+    DISALLOW_NEW();
 private:
     PartObject();
 
diff --git a/tools/clang/blink_gc_plugin/tests/raw_ptr_to_gc_managed_class_error.h b/tools/clang/blink_gc_plugin/tests/raw_ptr_to_gc_managed_class_error.h
index 2fa73a2..f4921c4 100644
--- a/tools/clang/blink_gc_plugin/tests/raw_ptr_to_gc_managed_class_error.h
+++ b/tools/clang/blink_gc_plugin/tests/raw_ptr_to_gc_managed_class_error.h
@@ -12,7 +12,7 @@
 class HeapObject;
 
 class PartObject {
-    DISALLOW_ALLOCATION();
+    DISALLOW_NEW();
 private:
     PartObject();
 
diff --git a/tools/clang/blink_gc_plugin/tests/ref_ptr_to_gc_managed_class.h b/tools/clang/blink_gc_plugin/tests/ref_ptr_to_gc_managed_class.h
index 0dba311..c3df7f8 100644
--- a/tools/clang/blink_gc_plugin/tests/ref_ptr_to_gc_managed_class.h
+++ b/tools/clang/blink_gc_plugin/tests/ref_ptr_to_gc_managed_class.h
@@ -12,7 +12,7 @@
 class HeapObject;
 
 class PartObject {
-    DISALLOW_ALLOCATION();
+    DISALLOW_NEW();
 private:
     RefPtr<HeapObject> m_obj;
 };
diff --git a/tools/clang/blink_gc_plugin/tests/stack_allocated.h b/tools/clang/blink_gc_plugin/tests/stack_allocated.h
index ed773266..88c01ab1 100644
--- a/tools/clang/blink_gc_plugin/tests/stack_allocated.h
+++ b/tools/clang/blink_gc_plugin/tests/stack_allocated.h
@@ -12,7 +12,7 @@
 class HeapObject;
 
 class PartObject {
-    DISALLOW_ALLOCATION();
+    DISALLOW_NEW();
 private:
     Member<HeapObject> m_obj; // Needs tracing.
 };
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc
index 5796ada2..eceb4f03 100644
--- a/tools/gn/setup.cc
+++ b/tools/gn/setup.cc
@@ -514,7 +514,7 @@
       if (dotfile_name_.empty()) {
         Err(Location(), "Could not load dotfile.",
             "The file \"" + FilePathToUTF8(dot_file_path) +
-            "\" cound't be loaded.").PrintToStdout();
+            "\" couldn't be loaded.").PrintToStdout();
         return false;
       }
     }
@@ -624,7 +624,7 @@
   dotfile_input_file_.reset(new InputFile(SourceFile("//.gn")));
   if (!dotfile_input_file_->Load(dotfile_name_)) {
     Err(Location(), "Could not load dotfile.",
-        "The file \"" + FilePathToUTF8(dotfile_name_) + "\" cound't be loaded")
+        "The file \"" + FilePathToUTF8(dotfile_name_) + "\" couldn't be loaded")
         .PrintToStdout();
     return false;
   }
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index fab8491..34d789c3 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -616,6 +616,19 @@
   </summary>
 </histogram>
 
+<histogram name="AppBanners.BeforeInstallEvent"
+    enum="AppBannersBeforeInstallEvent">
+  <owner>dominickn@chromium.org</owner>
+  <summary>
+    App banners promote an application related to the current website, and are
+    requested specifically through the current page's HTML.  This stat tracks
+    usage of the BeforeInstallPromptEvent, which allows developers to control
+    when an app banner appears. The events in this histogram are not mutually
+    exclusive - for example, preventDefault() must be called if prompt() is
+    called.
+  </summary>
+</histogram>
+
 <histogram name="AppBanners.DismissEvent" enum="AppBannersDismissEvent">
   <owner>dfalcantara@chromium.org</owner>
   <summary>
@@ -8984,6 +8997,36 @@
   </summary>
 </histogram>
 
+<histogram name="DirectWrite.Fonts.Proxy.FamilyCount" units="families">
+  <owner>kulshin@chromium.org</owner>
+  <summary>
+    The number of font families as seen by the font proxy in the renderer.
+  </summary>
+</histogram>
+
+<histogram name="DirectWrite.Fonts.Proxy.FontProxyError"
+    enum="DirectWriteFontProxyError">
+  <owner>kulshin@chromium.org</owner>
+  <summary>
+    The errors encountered by the DirectWrite font proxy while loading fonts.
+  </summary>
+</histogram>
+
+<histogram name="DirectWrite.Fonts.Proxy.LastResortFontCount" units="fonts">
+  <owner>kulshin@chromium.org</owner>
+  <summary>
+    The number of last resort fallback fonts found on the system as seen by the
+    browser.
+  </summary>
+</histogram>
+
+<histogram name="DirectWrite.Fonts.Proxy.LastResortFontFileCount" units="files">
+  <owner>kulshin@chromium.org</owner>
+  <summary>
+    The number of font files found for a last resort fallback font.
+  </summary>
+</histogram>
+
 <histogram name="DirectWrite.Fonts.Proxy.LoaderType"
     enum="DirectWriteFontLoaderType">
   <owner>kulshin@chromium.org</owner>
@@ -9012,6 +9055,14 @@
   </summary>
 </histogram>
 
+<histogram name="DirectWrite.Fonts.Proxy.MessageFilterError"
+    enum="DirectWriteMessageFilterError">
+  <owner>kulshin@chromium.org</owner>
+  <summary>
+    Errors, if any, encountered by the DirectWrite font proxy message filter.
+  </summary>
+</histogram>
+
 <histogram name="DisabledExtension.ExtensionWipedStatus" enum="BooleanWiped">
   <obsolete>
     Deprecated 04/2016 as doesn't have data nor owner.
@@ -31367,6 +31418,9 @@
 </histogram>
 
 <histogram name="Net.SSLServerKeyExchangeHash" enum="SSLHashAlgorithm">
+  <obsolete>
+    Replaced by Net.SSLSignatureAlgorithm.
+  </obsolete>
   <owner>davidben@chromium.org</owner>
   <summary>
     For each SSL connection with a full handshake using a DHE- or ECDHE-based
@@ -31386,6 +31440,15 @@
   </summary>
 </histogram>
 
+<histogram name="Net.SSLSignatureAlgorithm" enum="SSLSignatureAlgorithm">
+  <summary>
+    For each SSL connection with a full handshake using a DHE- or ECDHE-based
+    key exchange, the signature algorithm used to authenticate the peer. In TLS
+    1.2, this is the signature on the ServerKeyExchange message. (Note: Although
+    the ECDSA values specify a curve, the curve is only enforced in TLS 1.3.)
+  </summary>
+</histogram>
+
 <histogram name="Net.SSLv3FallbackToRenegoPatchedServer"
     enum="TLSRenegotiationPatched">
   <obsolete>
@@ -33853,6 +33916,48 @@
   </summary>
 </histogram>
 
+<histogram name="Network.Shill.WiFi.SuspendDurationWoWOffConnected"
+    units="seconds">
+  <owner>semenzato@chromium.org</owner>
+  <owner>kirtika@chromium.org</owner>
+  <summary>
+    Time spent in suspended state, on a resume, for the case when wake on wifi
+    is  disabled (WoWOff), and after resume, the NIC is found to be already
+    connected.
+  </summary>
+</histogram>
+
+<histogram name="Network.Shill.WiFi.SuspendDurationWoWOffDisconnected"
+    units="seconds">
+  <owner>semenzato@chromium.org</owner>
+  <owner>kirtika@chromium.org</owner>
+  <summary>
+    Time spent in suspended state, on a resume, for the case when wake on wifi
+    is  enabled (WoWOff), and after resume, the NIC is found to be disconnected.
+  </summary>
+</histogram>
+
+<histogram name="Network.Shill.WiFi.SuspendDurationWoWOnConnected"
+    units="seconds">
+  <owner>semenzato@chromium.org</owner>
+  <owner>kirtika@chromium.org</owner>
+  <summary>
+    Time spent in suspended state, on a resume, for the case when wake on wifi
+    is  enabled (WoWOn), and after resume, the NIC is found to be already
+    connected.
+  </summary>
+</histogram>
+
+<histogram name="Network.Shill.WiFi.SuspendDurationWoWOnDisconnected"
+    units="seconds">
+  <owner>semenzato@chromium.org</owner>
+  <owner>kirtika@chromium.org</owner>
+  <summary>
+    Time spent in suspended state, on a resume, for the case when wake on wifi
+    is  enabled (WoWOn), and after resume, the NIC is found to be disconnected.
+  </summary>
+</histogram>
+
 <histogram name="Network.Shill.Wifi.TimeOnline" units="seconds">
   <owner>quiche@chromium.org</owner>
   <summary>
@@ -45782,6 +45887,15 @@
   </summary>
 </histogram>
 
+<histogram name="RendererScheduler.ExpectedTaskQueueingDuration" units="ms">
+  <owner>tdresser@chromium.org</owner>
+  <summary>
+    The estimated queueing duration which would be observed for additional high
+    priority tasks posted to the RendererScheduler. Recorded for each 1000 ms
+    window.
+  </summary>
+</histogram>
+
 <histogram name="RendererScheduler.TaskQueueManager.DelayedTaskLateness"
     units="ms">
   <owner>alexclarke@chromium.org</owner>
@@ -55610,6 +55724,16 @@
   </summary>
 </histogram>
 
+<histogram name="Storage.BlacklistedImportantSites.Reason"
+    enum="ClearDataSiteBlacklistReason">
+  <owner>dmurph@chromium.org</owner>
+  <summary>
+    This is recorded for every site that the user blacklists when they when they
+    clear browsing data. It indicates which signals were used to show the given
+    site to the user that the user then chose to exclude from clearing.
+  </summary>
+</histogram>
+
 <histogram name="Storage.Blob.Broken" enum="BooleanBroken">
   <owner>dmurph@chromium.org</owner>
   <summary>
@@ -65543,6 +65667,15 @@
   <int value="15" label="RESULT_WSC_NOT_AVAILABLE"/>
 </enum>
 
+<enum name="AppBannersBeforeInstallEvent" type="int">
+  <int value="1" label="Event created and dispatched"/>
+  <int value="2" label="Showing the banner"/>
+  <int value="3" label="preventDefault() not called"/>
+  <int value="4" label="preventDefault() called"/>
+  <int value="5" label="prompt() called after preventDefault()"/>
+  <int value="6" label="prompt() not called after preventDefault()"/>
+</enum>
+
 <enum name="AppBannersDismissEvent" type="int">
   <int value="41" label="Error/unknown reason for dismissal"/>
   <int value="42" label="User opened the application after installing it"/>
@@ -68526,6 +68659,17 @@
   <int value="613" label="X_Takri"/>
 </enum>
 
+<enum name="ClearDataSiteBlacklistReason" type="int">
+  <int value="0" label="Durable"/>
+  <int value="1" label="Notifications"/>
+  <int value="2" label="Engagement"/>
+  <int value="3" label="Notifications and Engagement"/>
+  <int value="4" label="Durable and Engagement"/>
+  <int value="5" label="Notifications and Durable"/>
+  <int value="6" label="Notifications, Durable, and Engagement"/>
+  <int value="7" label="Unknown"/>
+</enum>
+
 <enum name="ClientAppId" type="int">
   <int value="0" label="Other"/>
   <int value="1" label="Gmail"/>
@@ -70606,12 +70750,29 @@
   <int value="2" label="Non-file loader"/>
 </enum>
 
+<enum name="DirectWriteFontProxyError" type="int">
+  <int value="0" label="FindFamily: send failed"/>
+  <int value="1" label="GetFamilyCount: send failed"/>
+  <int value="2" label="CreateEnumeratorFromKey: invalid key"/>
+  <int value="3" label="CreateEnumeratorFromKey: family index out of range"/>
+  <int value="4" label="GetFontFiles: send failed"/>
+  <int value="5" label="FontfileStream: failed to created mapped file"/>
+</enum>
+
 <enum name="DirectWriteLoadFamilyResult" type="int">
   <int value="0" label="Success: single family"/>
   <int value="1" label="Success: matched from collection"/>
   <int value="2" label="Error: multiple families"/>
   <int value="3" label="Error: no families"/>
-  <int value="4" label="Error: failed to create colleciton"/>
+  <int value="4" label="Error: failed to create collection"/>
+</enum>
+
+<enum name="DirectWriteMessageFilterError" type="int">
+  <int value="0" label="OnGetFontFiles: GetFont failed"/>
+  <int value="1" label="OnGetFontFiles: AddFilesForFont failed"/>
+  <int value="2" label="OnGetFontFiles: GetFontFamily failed"/>
+  <int value="3" label="InitializeDirectWrite: GetSystemFontCollection failed"/>
+  <int value="4" label="MapCharacters: could not find family"/>
 </enum>
 
 <enum name="DistillableType" type="int">
@@ -91111,6 +91272,9 @@
 </enum>
 
 <enum name="SSLHashAlgorithm" type="int">
+  <obsolete>
+    Removed June 2016.
+  </obsolete>
   <int value="0" label="None (unused)"/>
   <int value="1" label="MD5"/>
   <int value="2" label="SHA-1"/>
@@ -91216,6 +91380,17 @@
       label="Displayed clock interstitial. (DISPLAYED_CLOCK_INTERSTITIAL)"/>
 </enum>
 
+<enum name="SSLSignatureAlgorithm" type="int">
+  <int value="513" label="rsa_pkcs1_sha1"/>
+  <int value="515" label="ecdsa_sha1"/>
+  <int value="1025" label="rsa_pkcs1_sha256"/>
+  <int value="1027" label="ecdsa_secp256r1_sha256"/>
+  <int value="1281" label="rsa_pkcs1_sha384"/>
+  <int value="1283" label="ecdsa_secp384r1_sha384"/>
+  <int value="1537" label="rsa_pkcs1_sha512"/>
+  <int value="1539" label="ecdsa_secp521r1_sha512"/>
+</enum>
+
 <enum name="StarsLaunchLocation" type="int">
   <int value="0" label="All Items"/>
   <int value="1" label="Uncategorized"/>
@@ -98264,9 +98439,6 @@
 
 <histogram_suffixes name="PageLoadMetricsClients.Reload" separator="."
     ordering="prefix">
-  <obsolete>
-    Deprecated in favor of LoadType.Reload.
-  </obsolete>
   <suffix name="Clients.Reload"
       label="PageLoadMetrics from a page that is reloaded"/>
   <affected-histogram
diff --git a/tools/perf/benchmarks/battor.py b/tools/perf/benchmarks/battor.py
index d5fb768..a69b125c 100644
--- a/tools/perf/benchmarks/battor.py
+++ b/tools/perf/benchmarks/battor.py
@@ -17,7 +17,7 @@
     options.config.enable_battor_trace = True
     options.config.enable_chrome_trace = True
     options.config.chrome_trace_config.SetDefaultOverheadFilter()
-    options.SetTimelineBasedMetric('powerMetric')
+    options.SetTimelineBasedMetrics(['powerMetric'])
     return options
 
   @classmethod
@@ -105,7 +105,7 @@
     options.config.enable_battor_trace = True
     options.config.enable_chrome_trace = False
     options.config.chrome_trace_config.SetDefaultOverheadFilter()
-    options.SetTimelineBasedMetric('powerMetric')
+    options.SetTimelineBasedMetrics(['powerMetric'])
     return options
 
   @classmethod
diff --git a/tools/perf/benchmarks/benchmark_smoke_unittest.py b/tools/perf/benchmarks/benchmark_smoke_unittest.py
index 25ddfbe..249ef6b 100644
--- a/tools/perf/benchmarks/benchmark_smoke_unittest.py
+++ b/tools/perf/benchmarks/benchmark_smoke_unittest.py
@@ -19,10 +19,10 @@
 from telemetry.testing import options_for_unittests
 from telemetry.testing import progress_reporter
 
-
 from benchmarks import image_decoding
 from benchmarks import indexeddb_perf
 from benchmarks import jetstream
+from benchmarks import kraken
 from benchmarks import memory
 from benchmarks import octane
 from benchmarks import rasterize_and_record_micro
@@ -90,7 +90,8 @@
     speedometer,  # Takes 101 seconds.
     jetstream,  # Take 206 seconds.
     text_selection,  # Always fails on cq bot.
-    memory  # Flaky on bots, crbug.com/513767.
+    memory,  # Flaky on bots, crbug.com/513767.
+    kraken,  # Flaky on Android, crbug.com/626174.
 }
 
 
diff --git a/tools/perf/benchmarks/memory_infra.py b/tools/perf/benchmarks/memory_infra.py
index c72a7083..f371f44 100644
--- a/tools/perf/benchmarks/memory_infra.py
+++ b/tools/perf/benchmarks/memory_infra.py
@@ -41,7 +41,7 @@
     tbm_options = timeline_based_measurement.Options(
         overhead_level=trace_memory)
     tbm_options.config.enable_android_graphics_memtrack = True
-    tbm_options.SetTimelineBasedMetric('memoryMetric')
+    tbm_options.SetTimelineBasedMetrics(['memoryMetric'])
     return tbm_options
 
 
@@ -181,7 +181,7 @@
     category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter(
         ','.join(['-*'] + v8_categories + memory_categories))
     options = timeline_based_measurement.Options(category_filter)
-    options.SetTimelineBasedMetric('v8AndMemoryMetrics')
+    options.SetTimelineBasedMetrics(['v8AndMemoryMetrics'])
     return options
 
   @classmethod
diff --git a/tools/perf/benchmarks/page_cycler_v2.py b/tools/perf/benchmarks/page_cycler_v2.py
index ca998855..2e51532 100644
--- a/tools/perf/benchmarks/page_cycler_v2.py
+++ b/tools/perf/benchmarks/page_cycler_v2.py
@@ -17,7 +17,11 @@
 from telemetry.web_perf import timeline_based_measurement
 
 
+# crbug.com/619254
+@benchmark.Disabled('reference')
 class _PageCyclerV2(perf_benchmark.PerfBenchmark):
+  options = {'pageset_repeat': 2}
+
   def CreateTimelineBasedMeasurementOptions(self):
     cat_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter(
         filter_string='blink.console,navigation,blink.user_timing,loading')
@@ -28,23 +32,9 @@
 
     tbm_options = timeline_based_measurement.Options(
         overhead_level=cat_filter)
-    tbm_options.SetTimelineBasedMetric('firstPaintMetric')
+    tbm_options.SetTimelineBasedMetrics(['firstPaintMetric'])
     return tbm_options
 
-# crbug.com/619254
-@benchmark.Disabled('reference')
-class PageCyclerV2Typical25(_PageCyclerV2):
-  """Page load time benchmark for a 25 typical web pages.
-
-  Designed to represent typical, not highly optimized or highly popular web
-  sites. Runs against pages recorded in June, 2014.
-  """
-  options = {'pageset_repeat': 2}
-
-  @classmethod
-  def Name(cls):
-    return 'page_cycler_v2.typical_25'
-
   @classmethod
   def ShouldDisable(cls, possible_browser):
     # crbug.com/616781
@@ -54,7 +44,50 @@
       return True
     return False
 
+
+class PageCyclerV2Typical25(_PageCyclerV2):
+  """Page load time benchmark for a 25 typical web pages.
+
+  Designed to represent typical, not highly optimized or highly popular web
+  sites. Runs against pages recorded in June, 2014.
+  """
+
+  @classmethod
+  def Name(cls):
+    return 'page_cycler_v2.typical_25'
+
   def CreateStorySet(self, options):
     return page_sets.Typical25PageSet(run_no_page_interactions=True,
         cache_temperatures=[
           cache_temperature.PCV1_COLD, cache_temperature.PCV1_WARM])
+
+
+class PageCyclerV2IntlArFaHe(_PageCyclerV2):
+  """Page load time for a variety of pages in Arabic, Farsi and Hebrew.
+
+  Runs against pages recorded in April, 2013.
+  """
+  page_set = page_sets.IntlArFaHePageSet
+
+  @classmethod
+  def Name(cls):
+    return 'page_cycler_v2.intl_ar_fa_he'
+
+  def CreateStorySet(self, options):
+    return page_sets.IntlArFaHePageSet(cache_temperatures=[
+          cache_temperature.PCV1_COLD, cache_temperature.PCV1_WARM])
+
+
+class PageCyclerV2IntlJaZh(_PageCyclerV2):
+  """Page load time benchmark for a variety of pages in Japanese and Chinese.
+
+  Runs against pages recorded in April, 2013.
+  """
+
+  @classmethod
+  def Name(cls):
+    return 'page_cycler_v2.intl_ja_zh'
+
+  def CreateStorySet(self, options):
+    return page_sets.IntlJaZhPageSet(cache_temperatures=[
+          cache_temperature.PCV1_COLD, cache_temperature.PCV1_WARM])
diff --git a/tools/perf/benchmarks/system_health.py b/tools/perf/benchmarks/system_health.py
index 25d43106..c53960f 100644
--- a/tools/perf/benchmarks/system_health.py
+++ b/tools/perf/benchmarks/system_health.py
@@ -28,7 +28,7 @@
     options.config.chrome_trace_config.SetCategoryFilter(
         chrome_trace_category_filter.ChromeTraceCategoryFilter(','.join(
             self.TRACING_CATEGORIES)))
-    options.SetTimelineBasedMetric('systemHealthMetrics')
+    options.SetTimelineBasedMetrics(['systemHealthMetrics'])
     return options
 
   @classmethod
@@ -64,9 +64,6 @@
   """
 
   def SetExtraBrowserOptions(self, options):
-    # TODO(petrcermak): Remove this and switch to log-on-retry
-    # (http://crbug.com/623058).
-    options.logging_verbosity = options.NON_VERBOSE_LOGGING
     options.AppendExtraBrowserArgs([
         # TODO(perezju): Temporary workaround to disable periodic memory dumps.
         # See: http://crbug.com/513692
@@ -78,7 +75,7 @@
         chrome_trace_category_filter.ChromeTraceCategoryFilter(
             '-*,disabled-by-default-memory-infra'))
     options.config.enable_android_graphics_memtrack = True
-    options.SetTimelineBasedMetric('memoryMetric')
+    options.SetTimelineBasedMetrics(['memoryMetric'])
     return options
 
   @classmethod
@@ -114,7 +111,6 @@
         possible_browser.browser_type == 'reference' and
         possible_browser.platform.GetDeviceTypeName() == 'Nexus 5X')
 
-
 @benchmark.Enabled('android-webview')
 class WebviewStartupSystemHealthBenchmark(perf_benchmark.PerfBenchmark):
   """Webview startup time benchmark
@@ -128,7 +124,7 @@
 
   def CreateTimelineBasedMeasurementOptions(self):
     options = timeline_based_measurement.Options()
-    options.SetTimelineBasedMetric('webviewStartupMetric')
+    options.SetTimelineBasedMetrics(['webviewStartupMetric'])
     options.config.enable_atrace_trace = True
     options.config.enable_chrome_trace = False
     options.config.atrace_config.app_name = 'org.chromium.webview_shell'
diff --git a/tools/perf/benchmarks/tracing.py b/tools/perf/benchmarks/tracing.py
index e09c324..71adb584 100644
--- a/tools/perf/benchmarks/tracing.py
+++ b/tools/perf/benchmarks/tracing.py
@@ -19,7 +19,7 @@
   def CreateTimelineBasedMeasurementOptions(self):
     options = timeline_based_measurement.Options(
         timeline_based_measurement.DEBUG_OVERHEAD_LEVEL)
-    options.SetTimelineBasedMetric('tracingMetric')
+    options.SetTimelineBasedMetrics(['tracingMetric'])
     return options
 
   @classmethod
@@ -43,7 +43,7 @@
     memory_dump_config = chrome_trace_config.MemoryDumpConfig()
     memory_dump_config.AddTrigger('background', 200)
     options.config.chrome_trace_config.SetMemoryDumpConfig(memory_dump_config)
-    options.SetTimelineBasedMetric('tracingMetric')
+    options.SetTimelineBasedMetrics(['tracingMetric'])
     return options
 
   @classmethod
diff --git a/tools/perf/benchmarks/v8.py b/tools/perf/benchmarks/v8.py
index 9ff18a3..6d7eb7ac 100644
--- a/tools/perf/benchmarks/v8.py
+++ b/tools/perf/benchmarks/v8.py
@@ -26,7 +26,7 @@
   category_filter.AddIncludedCategory('blink.console')
   category_filter.AddDisabledByDefault('disabled-by-default-v8.compile')
   options = timeline_based_measurement.Options(category_filter)
-  options.SetTimelineBasedMetric('executionMetric')
+  options.SetTimelineBasedMetrics(['executionMetric'])
   return options
 
 
@@ -105,7 +105,7 @@
     options = timeline_based_measurement.Options(category_filter)
     # TODO(ulan): Add frame time discrepancy once it is ported to TBMv2,
     # see crbug.com/606841.
-    options.SetTimelineBasedMetric('v8AndMemoryMetrics')
+    options.SetTimelineBasedMetrics(['v8AndMemoryMetrics'])
     return options
 
   @classmethod
@@ -214,7 +214,7 @@
     memory_dump_config = chrome_trace_config.MemoryDumpConfig()
     memory_dump_config.AddTrigger('light', 20)
     options.config.chrome_trace_config.SetMemoryDumpConfig(memory_dump_config)
-    options.SetTimelineBasedMetric('memoryMetric')
+    options.SetTimelineBasedMetrics(['memoryMetric'])
     return options
 
   page_set = page_sets.Top10MobileMemoryPageSet
diff --git a/tools/perf/page_sets/intl_ar_fa_he.py b/tools/perf/page_sets/intl_ar_fa_he.py
index 9299745e..cc8f597 100644
--- a/tools/perf/page_sets/intl_ar_fa_he.py
+++ b/tools/perf/page_sets/intl_ar_fa_he.py
@@ -1,6 +1,7 @@
 # Copyright 2014 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
+from telemetry.page import cache_temperature as cache_temperature_module
 from telemetry.page import page as page_module
 from telemetry.page import shared_page_state
 from telemetry import story
@@ -8,10 +9,11 @@
 
 class IntlArFaHePage(page_module.Page):
 
-  def __init__(self, url, page_set):
+  def __init__(self, url, page_set, cache_temperature=None):
     super(IntlArFaHePage, self).__init__(
         url=url, page_set=page_set,
-        shared_page_state_class=shared_page_state.SharedDesktopPageState)
+        shared_page_state_class=shared_page_state.SharedDesktopPageState,
+        cache_temperature=cache_temperature)
     self.archive_data_file = 'data/intl_ar_fa_he.json'
 
 
@@ -19,10 +21,12 @@
 
   """ Popular pages in right-to-left languages Arabic, Farsi and Hebrew. """
 
-  def __init__(self):
+  def __init__(self, cache_temperatures=None):
     super(IntlArFaHePageSet, self).__init__(
       archive_data_file='data/intl_ar_fa_he.json',
       cloud_storage_bucket=story.PARTNER_BUCKET)
+    if cache_temperatures is None:
+      cache_temperatures = [cache_temperature_module.ANY]
 
     urls_list = [
       'http://msn.co.il/',
@@ -36,4 +40,5 @@
     ]
 
     for url in urls_list:
-      self.AddStory(IntlArFaHePage(url, self))
+      for temp in cache_temperatures:
+        self.AddStory(IntlArFaHePage(url, self, cache_temperature=temp))
diff --git a/tools/perf/page_sets/intl_ja_zh.py b/tools/perf/page_sets/intl_ja_zh.py
index 984f8b8..10c7ccc3 100644
--- a/tools/perf/page_sets/intl_ja_zh.py
+++ b/tools/perf/page_sets/intl_ja_zh.py
@@ -1,6 +1,7 @@
 # Copyright 2014 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
+from telemetry.page import cache_temperature as cache_temperature_module
 from telemetry.page import page as page_module
 from telemetry.page import shared_page_state
 from telemetry import story
@@ -8,20 +9,23 @@
 
 class IntlJaZhPage(page_module.Page):
 
-  def __init__(self, url, page_set):
+  def __init__(self, url, page_set, cache_temperature=None):
     super(IntlJaZhPage, self).__init__(
         url=url, page_set=page_set,
-        shared_page_state_class=shared_page_state.SharedDesktopPageState)
+        shared_page_state_class=shared_page_state.SharedDesktopPageState,
+        cache_temperature=cache_temperature)
 
 
 class IntlJaZhPageSet(story.StorySet):
 
   """ Popular pages in Japanese and Chinese. """
 
-  def __init__(self):
+  def __init__(self, cache_temperatures=None):
     super(IntlJaZhPageSet, self).__init__(
       archive_data_file='data/intl_ja_zh.json',
       cloud_storage_bucket=story.PARTNER_BUCKET)
+    if cache_temperatures is None:
+      cache_temperatures = [cache_temperature_module.ANY]
 
     urls_list = [
       # Why: #5 Japanese site
@@ -55,4 +59,5 @@
     ]
 
     for url in urls_list:
-      self.AddStory(IntlJaZhPage(url, self))
+      for temp in cache_temperatures:
+        self.AddStory(IntlJaZhPage(url, self, cache_temperature=temp))
diff --git a/tools/roll_webrtc.py b/tools/roll_webrtc.py
index 4291c38..fde94f7 100755
--- a/tools/roll_webrtc.py
+++ b/tools/roll_webrtc.py
@@ -166,7 +166,7 @@
   description = [ '-m', 'Roll ' + webrtc_str ]
   description.extend(['-m', 'Changes: %s' % webrtc_changelog_url])
   description.extend(['-m', 'TBR='])
-  description.extend(['-m', 'CQ_EXTRA_TRYBOTS=%s' % EXTRA_TRYBOTS])
+  description.extend(['-m', 'CQ_INCLUDE_TRYBOTS=%s' % EXTRA_TRYBOTS])
   return description
 
 
diff --git a/ui/app_list/BUILD.gn b/ui/app_list/BUILD.gn
index 2fc2728..d4433b5 100644
--- a/ui/app_list/BUILD.gn
+++ b/ui/app_list/BUILD.gn
@@ -178,39 +178,6 @@
       "//ui/views",
     ]
   }
-
-  if (is_mac) {
-    sources += [
-      "cocoa/app_list_pager_view.h",
-      "cocoa/app_list_pager_view.mm",
-      "cocoa/app_list_view_controller.h",
-      "cocoa/app_list_view_controller.mm",
-      "cocoa/app_list_window_controller.h",
-      "cocoa/app_list_window_controller.mm",
-      "cocoa/apps_collection_view_drag_manager.h",
-      "cocoa/apps_collection_view_drag_manager.mm",
-      "cocoa/apps_grid_controller.h",
-      "cocoa/apps_grid_controller.mm",
-      "cocoa/apps_grid_view_item.h",
-      "cocoa/apps_grid_view_item.mm",
-      "cocoa/apps_pagination_model_observer.h",
-      "cocoa/apps_search_box_controller.h",
-      "cocoa/apps_search_box_controller.mm",
-      "cocoa/apps_search_results_controller.h",
-      "cocoa/apps_search_results_controller.mm",
-      "cocoa/apps_search_results_model_bridge.h",
-      "cocoa/apps_search_results_model_bridge.mm",
-      "cocoa/item_drag_controller.h",
-      "cocoa/item_drag_controller.mm",
-      "cocoa/scroll_view_with_no_scrollbars.h",
-      "cocoa/scroll_view_with_no_scrollbars.mm",
-    ]
-    deps += [ "//third_party/google_toolbox_for_mac" ]
-    libs = [
-      "AppKit.framework",
-      "QuartzCore.framework",
-    ]
-  }
 }
 
 static_library("test_support") {
@@ -325,16 +292,4 @@
       "//ui/views:test_support",
     ]
   }
-
-  if (is_mac) {
-    sources += [
-      "cocoa/app_list_view_controller_unittest.mm",
-      "cocoa/app_list_window_controller_unittest.mm",
-      "cocoa/apps_grid_controller_unittest.mm",
-      "cocoa/apps_search_box_controller_unittest.mm",
-      "cocoa/apps_search_results_controller_unittest.mm",
-      "cocoa/test/apps_grid_controller_test_helper.h",
-      "cocoa/test/apps_grid_controller_test_helper.mm",
-    ]
-  }
 }
diff --git a/ui/app_list/PRESUBMIT.py b/ui/app_list/PRESUBMIT.py
index 73df615..e788678 100644
--- a/ui/app_list/PRESUBMIT.py
+++ b/ui/app_list/PRESUBMIT.py
@@ -12,14 +12,9 @@
   r'.*\.(cc|h)$',
 )
 
-EXCLUDE = (
-  # Objective C confuses everything.
-  r'.*/cocoa/.*',
-)
-
 def CheckChangeLintsClean(input_api, output_api):
   """Makes sure that the ui/app_list/ code is cpplint clean."""
-  black_list = input_api.DEFAULT_BLACK_LIST + EXCLUDE
+  black_list = input_api.DEFAULT_BLACK_LIST
   sources = lambda x: input_api.FilterSourceFile(
     x, white_list = INCLUDE_CPP_FILES_ONLY, black_list = black_list)
   return input_api.canned_checks.CheckChangeLintsClean(
diff --git a/ui/app_list/app_list.gyp b/ui/app_list/app_list.gyp
index 392303a3..59c0532 100644
--- a/ui/app_list/app_list.gyp
+++ b/ui/app_list/app_list.gyp
@@ -55,29 +55,6 @@
         'app_list_switches.h',
         'app_list_view_delegate.cc',
         'app_list_view_delegate.h',
-        'cocoa/app_list_pager_view.h',
-        'cocoa/app_list_pager_view.mm',
-        'cocoa/app_list_view_controller.h',
-        'cocoa/app_list_view_controller.mm',
-        'cocoa/app_list_window_controller.h',
-        'cocoa/app_list_window_controller.mm',
-        'cocoa/apps_collection_view_drag_manager.h',
-        'cocoa/apps_collection_view_drag_manager.mm',
-        'cocoa/apps_grid_controller.h',
-        'cocoa/apps_grid_controller.mm',
-        'cocoa/apps_grid_view_item.h',
-        'cocoa/apps_grid_view_item.mm',
-        'cocoa/apps_pagination_model_observer.h',
-        'cocoa/apps_search_box_controller.h',
-        'cocoa/apps_search_box_controller.mm',
-        'cocoa/apps_search_results_controller.h',
-        'cocoa/apps_search_results_controller.mm',
-        'cocoa/apps_search_results_model_bridge.h',
-        'cocoa/apps_search_results_model_bridge.mm',
-        'cocoa/item_drag_controller.h',
-        'cocoa/item_drag_controller.mm',
-        'cocoa/scroll_view_with_no_scrollbars.h',
-        'cocoa/scroll_view_with_no_scrollbars.mm',
         'folder_image.cc',
         'folder_image.h',
         'pagination_controller.cc',
@@ -206,20 +183,6 @@
             ['exclude', 'views/'],
           ],
         }],
-        ['OS=="mac"', {
-          'dependencies': [
-            '../../third_party/google_toolbox_for_mac/google_toolbox_for_mac.gyp:google_toolbox_for_mac',
-          ],
-          'link_settings': {
-            'libraries': [
-              '$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework',
-            ],
-          },
-        }, {  # OS!="mac"
-          'sources/': [
-            ['exclude', 'cocoa/'],
-          ],
-        }],
       ],
       # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
       'msvs_disabled_warnings': [ 4267, ],
@@ -265,13 +228,6 @@
         # Note: sources list duplicated in GN build.
         'app_list_item_list_unittest.cc',
         'app_list_model_unittest.cc',
-        'cocoa/app_list_view_controller_unittest.mm',
-        'cocoa/app_list_window_controller_unittest.mm',
-        'cocoa/apps_grid_controller_unittest.mm',
-        'cocoa/apps_search_box_controller_unittest.mm',
-        'cocoa/apps_search_results_controller_unittest.mm',
-        'cocoa/test/apps_grid_controller_test_helper.h',
-        'cocoa/test/apps_grid_controller_test_helper.mm',
         'folder_image_unittest.cc',
         'pagination_model_unittest.cc',
         'search/history_data_store_unittest.cc',
@@ -304,22 +260,6 @@
             ['exclude', 'views/'],
           ]
         }],
-        ['OS=="mac"', {
-          'dependencies': [
-            '../events/events.gyp:events_test_support',
-            '../gfx/gfx.gyp:gfx_test_support',
-          ],
-          'conditions': [
-            ['component=="static_library"', {
-              # Needed to link to Obj-C static libraries.
-              'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-ObjC']},
-            }],
-          ],
-        }, {  # OS!="mac"
-          'sources/': [
-            ['exclude', 'cocoa/'],
-          ],
-        }],
       ],
       # Disable c4267 warnings until we fix size_t to int truncations.
       'msvs_disabled_warnings': [ 4267, ],
diff --git a/ui/app_list/cocoa/app_list_pager_view.h b/ui/app_list/cocoa/app_list_pager_view.h
deleted file mode 100644
index 0dcc44d..0000000
--- a/ui/app_list/cocoa/app_list_pager_view.h
+++ /dev/null
@@ -1,43 +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.
-
-#ifndef UI_APP_LIST_COCOA_APP_LIST_PAGER_VIEW_H_
-#define UI_APP_LIST_COCOA_APP_LIST_PAGER_VIEW_H_
-
-#import <Cocoa/Cocoa.h>
-
-#import "ui/base/cocoa/tracking_area.h"
-
-@class AppListPagerView;
-
-// Delegate to obtain the visible portion of a page and respond to clicks.
-@protocol AppListPagerDelegate<NSObject>
-
-// Returns the portion of a page that is visible, in the range (-1.0, 1.0].
-// Positive indicates the left side is visible, negative indicates the right.
-- (CGFloat)visiblePortionOfPage:(int)page;
-
-// Invoked when the pager is clicked.
-- (void)onPagerClicked:(AppListPagerView*)sender;
-
-@end
-
-// AppListPagerView draws a button strip with buttons representing pages, and a
-// highlight that mirrors the visible portion of the page.
-@interface AppListPagerView : NSSegmentedControl {
- @private
-  // Used to auto-select a segment on hover.
-  ui::ScopedCrTrackingArea trackingArea_;
-
-  // The segment currently highlighted with a mouse hover, or -1 for none.
-  NSInteger hoveredSegment_;
-}
-
-// Returns -1 if |locationInWindow| is not over a segment. Otherwise returns the
-// segment index and highlights it.
-- (NSInteger)findAndHighlightSegmentAtLocation:(NSPoint)locationInWindow;
-
-@end
-
-#endif  // UI_APP_LIST_COCOA_APP_LIST_PAGER_VIEW_H_
diff --git a/ui/app_list/cocoa/app_list_pager_view.mm b/ui/app_list/cocoa/app_list_pager_view.mm
deleted file mode 100644
index 82e33f6..0000000
--- a/ui/app_list/cocoa/app_list_pager_view.mm
+++ /dev/null
@@ -1,167 +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.
-
-#import "ui/app_list/cocoa/app_list_pager_view.h"
-
-#include "base/mac/foundation_util.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
-
-namespace {
-
-const CGFloat kButtonHeight = 6;
-const CGFloat kButtonCornerRadius = 2;
-const CGFloat kButtonStripPadding = 20;
-
-}  // namespace
-
-@interface AppListPagerView ()
-
-@property(assign, nonatomic) NSInteger hoveredSegment;
-
-- (NSInteger)segmentUnderLocation:(NSPoint)locationInWindow;
-
-@end
-
-@interface AppListPagerCell : NSSegmentedCell;
-@end
-
-@implementation AppListPagerView
-
-@synthesize hoveredSegment = hoveredSegment_;
-
-+ (Class)cellClass {
-  return [AppListPagerCell class];
-}
-
-- (id)init {
-  if ((self = [super initWithFrame:NSZeroRect])) {
-    trackingArea_.reset(
-        [[CrTrackingArea alloc] initWithRect:NSZeroRect
-                                     options:NSTrackingInVisibleRect |
-                                             NSTrackingMouseEnteredAndExited |
-                                             NSTrackingMouseMoved |
-                                             NSTrackingActiveInKeyWindow
-                                       owner:self
-                                    userInfo:nil]);
-    [self addTrackingArea:trackingArea_.get()];
-    hoveredSegment_ = -1;
-  }
-  return self;
-}
-
-- (NSInteger)findAndHighlightSegmentAtLocation:(NSPoint)locationInWindow {
-  NSInteger segment = [self segmentUnderLocation:locationInWindow];
-  [self setHoveredSegment:segment];
-  return segment;
-}
-
-- (void)setHoveredSegment:(NSInteger)segment {
-  if (segment == hoveredSegment_)
-    return;
-
-  hoveredSegment_ = segment;
-  [self setNeedsDisplay:YES];
-  return;
-}
-
-- (NSInteger)segmentUnderLocation:(NSPoint)locationInWindow {
-  if ([self segmentCount] == 0)
-    return -1;
-
-  NSPoint pointInView = [self convertPoint:locationInWindow
-                                  fromView:nil];
-  if (![self mouse:pointInView inRect:[self bounds]])
-    return -1;
-
-  CGFloat segmentWidth = [self bounds].size.width / [self segmentCount];
-  return pointInView.x / segmentWidth;
-}
-
-- (BOOL)isHoveredForSegment:(NSInteger)segment {
-  return segment == hoveredSegment_;
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
-  [self setHoveredSegment:-1];
-}
-
-- (void)mouseMoved:(NSEvent*)theEvent {
-  [self findAndHighlightSegmentAtLocation:[theEvent locationInWindow]];
-}
-
-- (void)mouseDown:(NSEvent*)theEvent {
-  // Temporarily clear the highlight to give feedback.
-  [self setHoveredSegment:-1];
-}
-
-// The stock NSSegmentedControl ignores any clicks outside the non-default
-// control height, so process all clicks here.
-- (void)mouseUp:(NSEvent*)theEvent {
-  [self findAndHighlightSegmentAtLocation:[theEvent locationInWindow]];
-  if (hoveredSegment_ < 0)
-    return;
-
-  [self setSelectedSegment:hoveredSegment_];
-  [[self target] performSelector:[self action]
-                      withObject:self];
-}
-
-@end
-
-@implementation AppListPagerCell
-
-- (void)drawWithFrame:(NSRect)cellFrame
-               inView:(NSView*)controlView {
-  // Draw nothing if there are less than two segments.
-  if ([self segmentCount] < 2)
-    return;
-
-  cellFrame.size.width /= [self segmentCount];
-  for (NSInteger i = 0; i < [self segmentCount]; ++i) {
-    [self drawSegment:i
-              inFrame:cellFrame
-             withView:controlView];
-    cellFrame.origin.x += cellFrame.size.width;
-  }
-}
-
-- (void)drawSegment:(NSInteger)segment
-            inFrame:(NSRect)frame
-           withView:(NSView*)controlView {
-  gfx::ScopedNSGraphicsContextSaveGState context;
-  NSRect clipRect = NSMakeRect(
-      frame.origin.x + kButtonStripPadding / 2,
-      floor(frame.origin.y + (frame.size.height - kButtonHeight) / 2),
-      frame.size.width - kButtonStripPadding,
-      kButtonHeight);
-  [[NSBezierPath bezierPathWithRoundedRect:clipRect
-                                   xRadius:kButtonCornerRadius
-                                   yRadius:kButtonCornerRadius] addClip];
-
-  AppListPagerView* pagerControl =
-      base::mac::ObjCCastStrict<AppListPagerView>(controlView);
-  SkColor backgroundColor = [pagerControl hoveredSegment] == segment ?
-      app_list::kPagerHoverColor :
-      app_list::kPagerNormalColor;
-
-  [skia::SkColorToSRGBNSColor(backgroundColor) set];
-  NSRectFill(frame);
-
-  if (![[self target] conformsToProtocol:@protocol(AppListPagerDelegate)])
-    return;
-
-  CGFloat selectedRatio = [[self target] visiblePortionOfPage:segment];
-  if (selectedRatio == 0.0)
-    return;
-
-  [skia::SkColorToSRGBNSColor(app_list::kPagerSelectedColor) set];
-  if (selectedRatio < 0)
-    frame.origin.x += frame.size.width + frame.size.width * selectedRatio;
-  frame.size.width *= fabs(selectedRatio);
-  NSRectFill(frame);
-}
-
-@end
diff --git a/ui/app_list/cocoa/app_list_view_controller.h b/ui/app_list/cocoa/app_list_view_controller.h
deleted file mode 100644
index 664f6a5..0000000
--- a/ui/app_list/cocoa/app_list_view_controller.h
+++ /dev/null
@@ -1,81 +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.
-
-#ifndef UI_APP_LIST_COCOA_APP_LIST_VIEW_CONTROLLER_H_
-#define UI_APP_LIST_COCOA_APP_LIST_VIEW_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include <memory>
-
-#include "base/mac/scoped_nsobject.h"
-#include "ui/app_list/app_list_export.h"
-#import "ui/app_list/cocoa/apps_pagination_model_observer.h"
-#import "ui/app_list/cocoa/apps_search_box_controller.h"
-#import "ui/app_list/cocoa/apps_search_results_controller.h"
-
-namespace app_list {
-class AppListViewDelegate;
-class AppListModel;
-class AppListModelObserverBridge;
-}
-
-@class AppListPagerView;
-@class AppsGridController;
-
-// Controller for the top-level view of the app list UI. It creates and hosts an
-// AppsGridController (displaying an AppListModel), pager control to navigate
-// between pages in the grid, and search entry box with a pop up menu.
-APP_LIST_EXPORT
-@interface AppListViewController : NSViewController<AppsPaginationModelObserver,
-                                                    AppsSearchBoxDelegate,
-                                                    AppsSearchResultsDelegate,
-                                                    NSTextViewDelegate> {
- @private
-  base::scoped_nsobject<AppsGridController> appsGridController_;
-  base::scoped_nsobject<AppListPagerView> pagerControl_;
-  base::scoped_nsobject<AppsSearchBoxController> appsSearchBoxController_;
-  base::scoped_nsobject<AppsSearchResultsController>
-      appsSearchResultsController_;
-
-  // If set, a message displayed above the app list grid.
-  base::scoped_nsobject<NSTextView> messageText_;
-  base::scoped_nsobject<NSScrollView> messageScrollView_;
-
-  // Subview for drawing the background.
-  base::scoped_nsobject<NSView> backgroundView_;
-
-  // Subview of |backgroundView_| that slides out when search results are shown.
-  base::scoped_nsobject<NSView> contentsView_;
-
-  // Progress indicator that is visible while the delegate is NULL.
-  base::scoped_nsobject<NSProgressIndicator> loadingIndicator_;
-
-  app_list::AppListViewDelegate* delegate_;  // Weak. Owned by AppListService.
-
-  std::unique_ptr<app_list::AppListModelObserverBridge>
-      app_list_model_observer_bridge_;
-  BOOL showingSearchResults_;
-}
-
-@property(readonly, nonatomic) AppsSearchBoxController*
-    searchBoxController;
-
-- (app_list::AppListViewDelegate*)delegate;
-- (void)setDelegate:(app_list::AppListViewDelegate*)newDelegate;
-- (void)onProfilesChanged;
-
-@end
-
-@interface AppListViewController (TestingAPI)
-
-@property(nonatomic, readonly) BOOL showingSearchResults;
-
-- (AppsGridController*)appsGridController;
-- (NSSegmentedControl*)pagerControl;
-- (NSView*)backgroundView;
-
-@end
-
-#endif  // UI_APP_LIST_COCOA_APP_LIST_VIEW_CONTROLLER_H_
diff --git a/ui/app_list/cocoa/app_list_view_controller.mm b/ui/app_list/cocoa/app_list_view_controller.mm
deleted file mode 100644
index a05c6c0..0000000
--- a/ui/app_list/cocoa/app_list_view_controller.mm
+++ /dev/null
@@ -1,608 +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.
-
-#import "ui/app_list/cocoa/app_list_view_controller.h"
-
-#include <stddef.h>
-
-#include "base/mac/foundation_util.h"
-#include "base/mac/mac_util.h"
-#include "base/macros.h"
-#include "base/strings/string_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_model.h"
-#include "ui/app_list/app_list_view_delegate.h"
-#include "ui/app_list/app_list_view_delegate_observer.h"
-#import "ui/app_list/cocoa/app_list_pager_view.h"
-#import "ui/app_list/cocoa/apps_grid_controller.h"
-#include "ui/app_list/search_box_model.h"
-#import "ui/base/cocoa/flipped_view.h"
-#import "ui/gfx/image/image_skia_util_mac.h"
-#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
-
-namespace {
-
-// The roundedness of the corners of the bubble.
-const CGFloat kBubbleCornerRadius = 3;
-
-// Height of the pager.
-const CGFloat kPagerPreferredHeight = 57;
-
-// Height of separator line drawn between the searchbox and grid view.
-const CGFloat kTopSeparatorSize = 1;
-
-// Height of the search input.
-const CGFloat kSearchInputHeight = 48;
-
-// Minimum margin on either side of the pager. If the pager grows beyond this,
-// the segment size is reduced.
-const CGFloat kMinPagerMargin = 40;
-// Maximum width of a single segment.
-const CGFloat kMaxSegmentWidth = 80;
-
-// Duration of the animation for sliding in and out search results.
-const NSTimeInterval kResultsAnimationDuration = 0.2;
-
-// Properties of the message rectangle, if it is shown.
-const NSRect kMessageRect = {{12, 12}, {370, 91}};
-const CGFloat kMessageCornerRadius = 2;
-const CGFloat kSpacingBelowMessageTitle = 6;
-const SkColor kMessageBackgroundColor = SkColorSetRGB(0xFF, 0xFD, 0xE7);
-const SkColor kMessageStrokeColor = SkColorSetARGB(0x3d, 0x00, 0x00, 0x00);
-// The inset should be 16px, but NSTextView has its own inset of 3.
-const CGFloat kMessageTextInset = 13;
-
-}  // namespace
-
-@interface BackgroundView : FlippedView;
-@end
-
-@implementation BackgroundView
-
-- (void)drawRect:(NSRect)dirtyRect {
-  gfx::ScopedNSGraphicsContextSaveGState context;
-  NSRect boundsRect = [self bounds];
-  NSRect searchAreaRect = NSMakeRect(0, 0,
-                                     NSWidth(boundsRect), kSearchInputHeight);
-  NSRect separatorRect = NSMakeRect(0, NSMaxY(searchAreaRect),
-                                    NSWidth(boundsRect), kTopSeparatorSize);
-
-  [[NSBezierPath bezierPathWithRoundedRect:boundsRect
-                                   xRadius:kBubbleCornerRadius
-                                   yRadius:kBubbleCornerRadius] addClip];
-
-  [skia::SkColorToSRGBNSColor(app_list::kContentsBackgroundColor) set];
-  NSRectFill(boundsRect);
-  [skia::SkColorToSRGBNSColor(app_list::kSearchBoxBackground) set];
-  NSRectFill(searchAreaRect);
-  [skia::SkColorToSRGBNSColor(app_list::kTopSeparatorColor) set];
-  NSRectFill(separatorRect);
-}
-
-@end
-
-@interface MessageBackgroundView : FlippedView
-@end
-
-@implementation MessageBackgroundView
-
-- (void)drawRect:(NSRect)dirtyRect {
-  NSRect boundsRect = [self bounds];
-  gfx::ScopedNSGraphicsContextSaveGState context;
-  [[NSBezierPath bezierPathWithRoundedRect:boundsRect
-                                   xRadius:kMessageCornerRadius
-                                   yRadius:kMessageCornerRadius] addClip];
-
-  [skia::SkColorToSRGBNSColor(kMessageStrokeColor) set];
-  NSRectFill(boundsRect);
-
-  [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(boundsRect, 1, 1)
-                                   xRadius:kMessageCornerRadius
-                                   yRadius:kMessageCornerRadius] addClip];
-  [skia::SkColorToSRGBNSColor(kMessageBackgroundColor) set];
-  NSRectFill(boundsRect);
-}
-
-@end
-
-@interface AppListViewController ()
-
-- (void)updateMessage;
-- (void)loadAndSetView;
-- (void)revealSearchResults:(BOOL)show;
-
-@end
-
-namespace app_list {
-
-class AppListModelObserverBridge : public AppListViewDelegateObserver {
- public:
-  AppListModelObserverBridge(AppListViewController* parent);
-  ~AppListModelObserverBridge() override;
-
- private:
-  // Overridden from app_list::AppListViewDelegateObserver:
-  void OnProfilesChanged() override;
-  void OnShutdown() override;
-
-  AppListViewController* parent_;  // Weak. Owns us.
-
-  DISALLOW_COPY_AND_ASSIGN(AppListModelObserverBridge);
-};
-
-AppListModelObserverBridge::AppListModelObserverBridge(
-    AppListViewController* parent)
-    : parent_(parent) {
-  [parent_ delegate]->AddObserver(this);
-}
-
-AppListModelObserverBridge::~AppListModelObserverBridge() {
-  [parent_ delegate]->RemoveObserver(this);
-}
-
-void AppListModelObserverBridge::OnProfilesChanged() {
-  [parent_ onProfilesChanged];
-}
-
-void AppListModelObserverBridge::OnShutdown() {
-  [parent_ setDelegate:nil];
-}
-
-}  // namespace app_list
-
-@implementation AppListViewController
-
-- (id)init {
-  if ((self = [super init])) {
-    appsGridController_.reset([[AppsGridController alloc] init]);
-    [self loadAndSetView];
-
-    [self totalPagesChanged];
-    [self selectedPageChanged:0];
-    [appsGridController_ setPaginationObserver:self];
-  }
-  return self;
-}
-
-- (void)dealloc {
-  // Ensure that setDelegate(NULL) has been called before destruction, because
-  // dealloc can be called at odd times, and Objective C destruction order does
-  // not properly tear down these dependencies.
-  DCHECK(delegate_ == NULL);
-  [appsGridController_ setPaginationObserver:nil];
-  [super dealloc];
-}
-
-- (AppsSearchBoxController*)searchBoxController {
-  return appsSearchBoxController_;
-}
-
-- (BOOL)showingSearchResults {
-  return showingSearchResults_;
-}
-
-- (AppsGridController*)appsGridController {
-  return appsGridController_;
-}
-
-- (NSSegmentedControl*)pagerControl {
-  return pagerControl_;
-}
-
-- (NSView*)backgroundView {
-  return backgroundView_;
-}
-
-- (app_list::AppListViewDelegate*)delegate {
-  return delegate_;
-}
-
-- (void)setDelegate:(app_list::AppListViewDelegate*)newDelegate {
-  if (delegate_) {
-    // Ensure the search box is cleared when switching profiles.
-    if ([self searchBoxModel])
-      [self searchBoxModel]->SetText(base::string16());
-
-    // First clean up, in reverse order.
-    app_list_model_observer_bridge_.reset();
-    [appsSearchResultsController_ setDelegate:nil];
-    [appsSearchBoxController_ setDelegate:nil];
-    [appsGridController_ setDelegate:nil];
-    [messageText_ setDelegate:nil];
-  }
-  delegate_ = newDelegate;
-  if (delegate_) {
-    [loadingIndicator_ stopAnimation:self];
-  } else {
-    [loadingIndicator_ startAnimation:self];
-    return;
-  }
-
-  [appsGridController_ setDelegate:delegate_];
-  [appsSearchBoxController_ setDelegate:self];
-  [appsSearchResultsController_ setDelegate:self];
-  app_list_model_observer_bridge_.reset(
-      new app_list::AppListModelObserverBridge(self));
-  [self onProfilesChanged];
-  [self updateMessage];
-}
-
-- (void)updateMessage {
-  if (![AppsGridController hasFewerRows])
-    return;
-
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  NSFont* messageFont = rb.GetFontWithDelta(0).GetNativeFont();
-  NSFont* titleFont = rb.GetFontWithDelta(2).GetNativeFont();
-
-  base::string16 title = delegate_->GetMessageTitle();
-  size_t messageBreak;
-  base::string16 messageFull = delegate_->GetMessageText(&messageBreak);
-  base::string16 shortcutName = delegate_->GetAppsShortcutName();
-  base::string16 learnMore = delegate_->GetLearnMoreText();
-  base::string16 learnMoreUrl = delegate_->GetLearnMoreLink();
-
-  base::string16 messagePre = messageFull.substr(0, messageBreak);
-  base::string16 messagePost = messageFull.substr(messageBreak);
-
-  NSURL* linkURL = [NSURL URLWithString:base::SysUTF16ToNSString(learnMoreUrl)];
-  gfx::ImageSkia* icon = delegate_->GetAppsIcon();
-
-  // Shift the baseline up so that the graphics align centered. 4 looks nice. It
-  // happens to be the image size minus the font size, but that's a coincidence.
-  const CGFloat kBaselineShift = 4;
-  base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
-      [[NSMutableParagraphStyle alloc] init]);
-  [paragraphStyle setLineSpacing:kSpacingBelowMessageTitle + kBaselineShift];
-
-  NSNumber* baselineOffset = [NSNumber numberWithFloat:kBaselineShift];
-  base::scoped_nsobject<NSMutableAttributedString> text(
-      [[NSMutableAttributedString alloc]
-          initWithString:base::SysUTF16ToNSString(title)
-              attributes:@{
-                NSParagraphStyleAttributeName : paragraphStyle,
-                NSFontAttributeName : titleFont
-              }]);
-
-  NSDictionary* defaultAttributes = @{
-    NSFontAttributeName : messageFont,
-    NSBaselineOffsetAttributeName : baselineOffset
-  };
-
-  base::scoped_nsobject<NSAttributedString> lineBreak(
-      [[NSAttributedString alloc] initWithString:@"\n"
-                                      attributes:defaultAttributes]);
-  base::scoped_nsobject<NSAttributedString> space([[NSAttributedString alloc]
-      initWithString:@" "
-          attributes:defaultAttributes]);
-  base::scoped_nsobject<NSAttributedString> messagePreString(
-      [[NSAttributedString alloc]
-          initWithString:base::SysUTF16ToNSString(messagePre)
-              attributes:defaultAttributes]);
-  base::scoped_nsobject<NSAttributedString> messagePostString(
-      [[NSAttributedString alloc]
-          initWithString:base::SysUTF16ToNSString(messagePost)
-              attributes:defaultAttributes]);
-
-  // NSUnderlineStyleNone is broken.
-  base::scoped_nsobject<NSAttributedString> learnMoreString(
-      [[NSAttributedString alloc]
-          initWithString:base::SysUTF16ToNSString(learnMore)
-              attributes:@{
-                NSParagraphStyleAttributeName : paragraphStyle,
-                NSFontAttributeName : messageFont,
-                NSLinkAttributeName : linkURL,
-                NSBaselineOffsetAttributeName : baselineOffset,
-                NSUnderlineStyleAttributeName :
-                    [NSNumber numberWithInt:NSUnderlineStyleNone]
-              }]);
-  base::scoped_nsobject<NSAttributedString> shortcutStringText(
-      [[NSAttributedString alloc]
-          initWithString:base::SysUTF16ToNSString(shortcutName)
-              attributes:defaultAttributes]);
-  base::scoped_nsobject<NSMutableAttributedString> shortcutString(
-      [[NSMutableAttributedString alloc] init]);
-  if (icon) {
-    NSImage* image = gfx::NSImageFromImageSkia(*icon);
-    // The image has a bunch of representations. Ensure the smallest is used.
-    // (Going smaller would make pixels all manky, so don't do that).
-    [image setSize:NSMakeSize(16, 16)];
-
-    base::scoped_nsobject<NSTextAttachmentCell> attachmentCell(
-        [[NSTextAttachmentCell alloc] initImageCell:image]);
-    base::scoped_nsobject<NSTextAttachment> attachment(
-        [[NSTextAttachment alloc] init]);
-    [attachment setAttachmentCell:attachmentCell];
-    [shortcutString
-        appendAttributedString:[NSAttributedString
-                                   attributedStringWithAttachment:attachment]];
-    [shortcutString appendAttributedString:space];
-  }
-  [shortcutString appendAttributedString:shortcutStringText];
-
-  [text appendAttributedString:lineBreak];
-  [text appendAttributedString:messagePreString];
-  [text appendAttributedString:shortcutString];
-  [text appendAttributedString:messagePostString];
-  [text appendAttributedString:space];
-  [text appendAttributedString:learnMoreString];
-
-  [[messageText_ textStorage] setAttributedString:text];
-  [messageText_ sizeToFit];
-
-  // If the user scroller preference is to always show scrollbars, and the
-  // translated message is long, the scroll track may be present. This means
-  // text will be under the scroller. We only want vertical scrolling, but
-  // reducing the width puts the scroll track in a weird spot. So, increase the
-  // width of the scroll view to move the track into the padding towards the
-  // message background border, then reduce the width of the text view. The
-  // non-overlay scroller still looks kinda weird but hopefully not many will
-  // actually see it.
-  CGFloat overlap =
-      NSWidth([messageText_ bounds]) - [messageScrollView_ contentSize].width;
-  if (overlap > 0) {
-    NSRect rect = [messageScrollView_ frame];
-    rect.size.width += kMessageTextInset - 2;
-    [messageScrollView_ setFrame:rect];
-    overlap -= kMessageTextInset - 2;
-    DCHECK_GT(overlap, 0);
-    rect = [messageText_ frame];
-    rect.size.width -= overlap;
-    [messageText_ setFrame:rect];
-    [messageText_ sizeToFit];
-
-    // And after doing all that for some reason Cocoa scrolls to the bottom. So
-    // fix that.
-    [[messageScrollView_ documentView] scrollPoint:NSMakePoint(0, 0)];
-  }
-
-  [messageText_ setDelegate:self];
-}
-
-- (void)loadAndSetView {
-  pagerControl_.reset([[AppListPagerView alloc] init]);
-  [pagerControl_ setTarget:appsGridController_];
-  [pagerControl_ setAction:@selector(onPagerClicked:)];
-
-  NSRect gridFrame = [[appsGridController_ view] frame];
-
-  base::scoped_nsobject<NSView> messageTextBackground;
-  if ([AppsGridController hasFewerRows]) {
-    messageTextBackground.reset(
-        [[MessageBackgroundView alloc] initWithFrame:kMessageRect]);
-    NSRect frameRect =
-        NSInsetRect(kMessageRect, kMessageTextInset, kMessageTextInset);
-    messageText_.reset([[NSTextView alloc] initWithFrame:frameRect]);
-    // Provide a solid background here (as well as the background) so that
-    // subpixel AA works.
-    [messageText_
-        setBackgroundColor:skia::SkColorToSRGBNSColor(kMessageBackgroundColor)];
-    [messageText_ setDrawsBackground:YES];
-    [messageText_ setEditable:NO];
-    // Ideally setSelectable:NO would also be set here, but that disables mouse
-    // events completely, breaking the "Learn more" link. Instead, selection is
-    // "disabled" via a delegate method which Apple's documentation suggests. In
-    // reality, selection still happens, it just disappears once the mouse is
-    // released. To avoid the selection appearing, also set selected text to
-    // have no special attributes. Sadly, the mouse cursor still displays an
-    // I-beam, but hacking cursor rectangles on the view so that the "Learn
-    // More" link is still correctly handled is too hard.
-    [messageText_ setSelectedTextAttributes:@{}];
-    gridFrame.origin.y += NSMaxY([messageTextBackground frame]);
-  }
-
-  [[appsGridController_ view] setFrame:gridFrame];
-
-  NSRect contentsRect =
-      NSMakeRect(0, kSearchInputHeight + kTopSeparatorSize, NSWidth(gridFrame),
-                 NSMaxY(gridFrame) + kPagerPreferredHeight -
-                     [AppsGridController scrollerPadding]);
-
-  contentsView_.reset([[FlippedView alloc] initWithFrame:contentsRect]);
-
-  // The contents view contains animations both from an NSCollectionView and the
-  // app list's own transitive drag layers. On Mavericks, the subviews need to
-  // have access to a compositing layer they can share. Otherwise the compositor
-  // makes tearing artifacts. However, doing this on Mountain Lion or earler
-  // results in flickering whilst an item is installing.
-  if (base::mac::IsOSMavericksOrLater())
-    [contentsView_ setWantsLayer:YES];
-
-  backgroundView_.reset(
-      [[BackgroundView alloc] initWithFrame:
-              NSMakeRect(0, 0, NSMaxX(contentsRect), NSMaxY(contentsRect))]);
-  appsSearchBoxController_.reset(
-      [[AppsSearchBoxController alloc] initWithFrame:
-          NSMakeRect(0, 0, NSWidth(contentsRect), kSearchInputHeight)]);
-  appsSearchResultsController_.reset(
-      [[AppsSearchResultsController alloc] initWithAppsSearchResultsFrameSize:
-          [contentsView_ bounds].size]);
-  base::scoped_nsobject<NSView> containerView(
-      [[NSView alloc] initWithFrame:[backgroundView_ frame]]);
-
-  loadingIndicator_.reset(
-      [[NSProgressIndicator alloc] initWithFrame:NSZeroRect]);
-  [loadingIndicator_ setStyle:NSProgressIndicatorSpinningStyle];
-  [loadingIndicator_ sizeToFit];
-  NSRect indicatorRect = [loadingIndicator_ frame];
-  indicatorRect.origin.x = NSWidth(contentsRect) / 2 - NSMidX(indicatorRect);
-  indicatorRect.origin.y = NSHeight(contentsRect) / 2 - NSMidY(indicatorRect);
-  [loadingIndicator_ setFrame:indicatorRect];
-  [loadingIndicator_ setDisplayedWhenStopped:NO];
-  [loadingIndicator_ startAnimation:self];
-
-  if (messageText_) {
-    [contentsView_ addSubview:messageTextBackground];
-
-    // Add a scroll view in case the translation is long and doesn't fit. Mac
-    // likes to hide scrollbars, so add to the height so the user can see part
-    // of the next line of text: just extend out into the padding towards the
-    // text background's border. Subtract at least 2: one for the border stroke
-    // and one for a bit of padding.
-    NSRect frameRect = [messageText_ frame];
-    frameRect.size.height += kMessageTextInset - 2;
-    messageScrollView_.reset([[NSScrollView alloc] initWithFrame:frameRect]);
-    [messageScrollView_ setHasVerticalScroller:YES];
-    [messageScrollView_ setAutohidesScrollers:YES];
-
-    // Now the message is going into an NSScrollView, origin should be 0, 0.
-    frameRect = [messageText_ frame];
-    frameRect.origin = NSMakePoint(0, 0);
-    [messageText_ setFrame:frameRect];
-
-    [messageScrollView_ setDocumentView:messageText_];
-    [contentsView_ addSubview:messageScrollView_];
-  }
-  [contentsView_ addSubview:[appsGridController_ view]];
-  [contentsView_ addSubview:pagerControl_];
-  [contentsView_ addSubview:loadingIndicator_];
-  [backgroundView_ addSubview:contentsView_];
-  [backgroundView_ addSubview:[appsSearchResultsController_ view]];
-  [backgroundView_ addSubview:[appsSearchBoxController_ view]];
-  [containerView addSubview:backgroundView_];
-  [self setView:containerView];
-}
-
-- (void)revealSearchResults:(BOOL)show {
-  if (show == showingSearchResults_)
-    return;
-
-  showingSearchResults_ = show;
-  NSSize contentsSize = [contentsView_ frame].size;
-  NSRect resultsTargetRect = NSMakeRect(
-      0, kSearchInputHeight + kTopSeparatorSize,
-      contentsSize.width, contentsSize.height);
-  NSRect contentsTargetRect = resultsTargetRect;
-
-  // Shows results by sliding the grid and pager down to the bottom of the view.
-  // Hides results by collapsing the search results container to a height of 0.
-  if (show)
-    contentsTargetRect.origin.y += NSHeight(contentsTargetRect);
-  else
-    resultsTargetRect.size.height = 0;
-
-  [[NSAnimationContext currentContext] setDuration:kResultsAnimationDuration];
-  [[contentsView_ animator] setFrame:contentsTargetRect];
-  [[[appsSearchResultsController_ view] animator] setFrame:resultsTargetRect];
-}
-
-- (void)totalPagesChanged {
-  size_t pageCount = [appsGridController_ pageCount];
-  [pagerControl_ setSegmentCount:pageCount];
-
-  NSRect viewFrame = [[pagerControl_ superview] bounds];
-  CGFloat segmentWidth = std::min(
-      kMaxSegmentWidth,
-      (viewFrame.size.width - 2 * kMinPagerMargin) / pageCount);
-
-  for (size_t i = 0; i < pageCount; ++i) {
-    [pagerControl_ setWidth:segmentWidth
-                 forSegment:i];
-    [[pagerControl_ cell] setTag:i
-                      forSegment:i];
-  }
-
-  // Center in view.
-  [pagerControl_ sizeToFit];
-  [pagerControl_ setFrame:
-      NSMakeRect(NSMidX(viewFrame) - NSMidX([pagerControl_ bounds]),
-                 viewFrame.size.height - kPagerPreferredHeight,
-                 [pagerControl_ bounds].size.width,
-                 kPagerPreferredHeight)];
-}
-
-- (void)selectedPageChanged:(int)newSelected {
-  [pagerControl_ selectSegmentWithTag:newSelected];
-}
-
-- (void)pageVisibilityChanged {
-  [pagerControl_ setNeedsDisplay:YES];
-}
-
-- (NSInteger)pagerSegmentAtLocation:(NSPoint)locationInWindow {
-  return [pagerControl_ findAndHighlightSegmentAtLocation:locationInWindow];
-}
-
-- (app_list::SearchBoxModel*)searchBoxModel {
-  app_list::AppListModel* appListModel = [appsGridController_ model];
-  return appListModel ? appListModel->search_box() : NULL;
-}
-
-- (app_list::AppListViewDelegate*)appListDelegate {
-  return [self delegate];
-}
-
-- (BOOL)control:(NSControl*)control
-               textView:(NSTextView*)textView
-    doCommandBySelector:(SEL)command {
-  if (showingSearchResults_)
-    return [appsSearchResultsController_ handleCommandBySelector:command];
-
-  // If anything has been written, let the search view handle it.
-  if ([[control stringValue] length] > 0)
-    return NO;
-
-  // Handle escape.
-  if (command == @selector(complete:) ||
-      command == @selector(cancel:) ||
-      command == @selector(cancelOperation:)) {
-    if (delegate_)
-      delegate_->Dismiss();
-    return YES;
-  }
-
-  // Possibly handle grid navigation.
-  return [appsGridController_ handleCommandBySelector:command];
-}
-
-- (void)modelTextDidChange {
-  app_list::SearchBoxModel* searchBoxModel = [self searchBoxModel];
-  if (!searchBoxModel || !delegate_)
-    return;
-
-  base::string16 query;
-  base::TrimWhitespace(searchBoxModel->text(), base::TRIM_ALL, &query);
-  BOOL shouldShowSearch = !query.empty();
-  [self revealSearchResults:shouldShowSearch];
-  if (shouldShowSearch)
-    delegate_->StartSearch();
-  else
-    delegate_->StopSearch();
-}
-
-- (app_list::AppListModel*)appListModel {
-  return [appsGridController_ model];
-}
-
-- (void)openResult:(app_list::SearchResult*)result {
-  if (delegate_) {
-    delegate_->OpenSearchResult(
-        result, false /* auto_launch */, 0 /* event flags */);
-  }
-}
-
-- (void)onProfilesChanged {
-  [appsSearchBoxController_ rebuildMenu];
-}
-
-// NSTextViewDelegate implementation.
-
-- (BOOL)textView:(NSTextView*)textView
-    clickedOnLink:(id)link
-          atIndex:(NSUInteger)charIndex {
-  DCHECK(delegate_);
-  delegate_->OpenLearnMoreLink();
-  return YES;
-}
-
-- (NSArray*)textView:(NSTextView*)aTextView
-    willChangeSelectionFromCharacterRanges:(NSArray*)oldSelectedCharRanges
-                         toCharacterRanges:(NSArray*)newSelectedCharRanges {
-  return oldSelectedCharRanges;
-}
-
-@end
diff --git a/ui/app_list/cocoa/app_list_view_controller_unittest.mm b/ui/app_list/cocoa/app_list_view_controller_unittest.mm
deleted file mode 100644
index 2c23574..0000000
--- a/ui/app_list/cocoa/app_list_view_controller_unittest.mm
+++ /dev/null
@@ -1,98 +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 "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#import "testing/gtest_mac.h"
-#import "ui/app_list/cocoa/app_list_view_controller.h"
-#import "ui/app_list/cocoa/apps_grid_controller.h"
-#import "ui/app_list/cocoa/test/apps_grid_controller_test_helper.h"
-#include "ui/app_list/test/app_list_test_model.h"
-#include "ui/app_list/test/app_list_test_view_delegate.h"
-
-namespace app_list {
-namespace test {
-
-class AppListViewControllerTest : public AppsGridControllerTestHelper {
- public:
-  AppListViewControllerTest() {}
-
-  void SetUp() override {
-    app_list_view_controller_.reset([[AppListViewController alloc] init]);
-    delegate_.reset(new AppListTestViewDelegate);
-    [app_list_view_controller_ setDelegate:delegate_.get()];
-    SetUpWithGridController([app_list_view_controller_ appsGridController]);
-    [[test_window() contentView] addSubview:[app_list_view_controller_ view]];
-  }
-
-  void TearDown() override {
-    [app_list_view_controller_ setDelegate:NULL];
-    app_list_view_controller_.reset();
-    AppsGridControllerTestHelper::TearDown();
-  }
-
-  void ReplaceTestModel(int item_count) {
-    [app_list_view_controller_ setDelegate:NULL];
-    delegate_.reset(new AppListTestViewDelegate);
-    delegate_->ReplaceTestModel(item_count);
-    [app_list_view_controller_ setDelegate:delegate_.get()];
-  }
-
-  AppListTestModel* model() { return delegate_->GetTestModel(); }
-
- protected:
-  std::unique_ptr<AppListTestViewDelegate> delegate_;
-  base::scoped_nsobject<AppListViewController> app_list_view_controller_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AppListViewControllerTest);
-};
-
-TEST_VIEW(AppListViewControllerTest, [app_list_view_controller_ view]);
-
-// Test that adding and removing pages updates the pager.
-TEST_F(AppListViewControllerTest, PagerSegmentCounts) {
-  NSSegmentedControl* pager = [app_list_view_controller_ pagerControl];
-  EXPECT_EQ(1, [pager segmentCount]);
-
-  ReplaceTestModel(kItemsPerPage * 2);
-  EXPECT_EQ(2, [pager segmentCount]);
-  model()->PopulateApps(1);
-  EXPECT_EQ(3, [pager segmentCount]);
-
-  ReplaceTestModel(1);
-  EXPECT_EQ(1, [pager segmentCount]);
-}
-
-// Test that clicking the pager changes pages.
-TEST_F(AppListViewControllerTest, PagerChangingPage) {
-  NSSegmentedControl* pager = [app_list_view_controller_ pagerControl];
-  ReplaceTestModel(kItemsPerPage * 3);
-  EXPECT_EQ(3, [pager segmentCount]);
-
-  EXPECT_EQ(0, [pager selectedSegment]);
-  EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(1.0, [apps_grid_controller_ visiblePortionOfPage:0]);
-  EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:1]);
-
-  // Emulate a click on the second segment to navigate to the second page.
-  [pager setSelectedSegment:1];
-  [[pager target] performSelector:[pager action]
-                       withObject:pager];
-
-  EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(1, [pager selectedSegment]);
-  EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:0]);
-  EXPECT_EQ(1.0, [apps_grid_controller_ visiblePortionOfPage:1]);
-
-  // Replace with a single page model, and ensure we go back to the first page.
-  ReplaceTestModel(1);
-  EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(0, [pager selectedSegment]);
-  EXPECT_EQ(1, [pager segmentCount]);
-  EXPECT_EQ(1.0, [apps_grid_controller_ visiblePortionOfPage:0]);
-}
-
-}  // namespace test
-}  // namespace app_list
diff --git a/ui/app_list/cocoa/app_list_window_controller.h b/ui/app_list/cocoa/app_list_window_controller.h
deleted file mode 100644
index 052682ff..0000000
--- a/ui/app_list/cocoa/app_list_window_controller.h
+++ /dev/null
@@ -1,26 +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.
-
-#ifndef UI_APP_LIST_COCOA_APP_LIST_WINDOW_CONTROLLER_H_
-#define UI_APP_LIST_COCOA_APP_LIST_WINDOW_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "ui/app_list/app_list_export.h"
-
-@class AppListViewController;
-
-// Controller for the app list NSWindow.
-APP_LIST_EXPORT
-@interface AppListWindowController : NSWindowController<NSWindowDelegate> {
- @private
-  base::scoped_nsobject<AppListViewController> appListViewController_;
-}
-
-- (AppListViewController*)appListViewController;
-
-@end
-
-#endif  // UI_APP_LIST_COCOA_APP_LIST_WINDOW_CONTROLLER_H_
diff --git a/ui/app_list/cocoa/app_list_window_controller.mm b/ui/app_list/cocoa/app_list_window_controller.mm
deleted file mode 100644
index 5eae08d7..0000000
--- a/ui/app_list/cocoa/app_list_window_controller.mm
+++ /dev/null
@@ -1,82 +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.
-
-#import "ui/app_list/cocoa/app_list_window_controller.h"
-
-#include "ui/app_list/app_list_view_delegate.h"
-#import "ui/app_list/cocoa/app_list_view_controller.h"
-#import "ui/app_list/cocoa/apps_grid_controller.h"
-#import "ui/app_list/cocoa/apps_search_box_controller.h"
-#include "ui/base/cocoa/window_size_constants.h"
-
-@interface AppListWindow : NSWindow;
-@end
-
-@implementation AppListWindow
-
-// If we initialize a window with NSBorderlessWindowMask, it will not accept key
-// events (among other things) unless canBecomeKeyWindow is overridden.
-- (BOOL)canBecomeKeyWindow {
-  return YES;
-}
-
-- (BOOL)canBecomeMainWindow {
-  return YES;
-}
-
-// On Mavericks with the "Displays have separate Spaces" option, OSX has stopped
-// switching out of the fullscreen space when activating a window in the non-
-// active application, other than by clicking its Dock icon. Since the app
-// launcher Dock icon is not Chrome, this can leave a user in fullscreen with
-// the app launcher window obscured. Overriding this private method allows the
-// app launcher to appear on top of other applications in fullscreen. Then,
-// since clicking that window will make Chrome active, subsequent window
-// activations will successfully switch the user out of the fullscreen space.
-- (BOOL)_allowedInOtherAppsFullScreenSpaceWithCollectionBehavior:
-    (NSUInteger)collectionBehavior {
-  return YES;
-}
-
-@end
-
-@implementation AppListWindowController;
-
-- (id)init {
-  base::scoped_nsobject<NSWindow> controlledWindow(
-      [[AppListWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater
-                                       styleMask:NSBorderlessWindowMask
-                                         backing:NSBackingStoreBuffered
-                                           defer:NO]);
-  [controlledWindow setReleasedWhenClosed:NO];
-  [controlledWindow setBackgroundColor:[NSColor clearColor]];
-  [controlledWindow setOpaque:NO];
-  [controlledWindow setHasShadow:YES];
-  [controlledWindow setLevel:NSDockWindowLevel];
-  [controlledWindow
-      setCollectionBehavior:NSWindowCollectionBehaviorMoveToActiveSpace];
-
-  if ((self = [super initWithWindow:controlledWindow])) {
-    appListViewController_.reset([[AppListViewController alloc] init]);
-    [[self window] setFrame:[[appListViewController_ view] bounds]
-                    display:NO];
-    [[self window] setContentView:[appListViewController_ view]];
-    [[self window] setDelegate:self];
-  }
-  return self;
-}
-
-- (AppListViewController*)appListViewController {
-  return appListViewController_;
-}
-
-- (void)windowDidResignMain:(NSNotification*)notification {
-  if ([appListViewController_ delegate])
-    [appListViewController_ delegate]->Dismiss();
-}
-
-- (void)windowWillClose:(NSNotification*)notification {
-  [[appListViewController_ searchBoxController] clearSearch];
-}
-
-@end
diff --git a/ui/app_list/cocoa/app_list_window_controller_unittest.mm b/ui/app_list/cocoa/app_list_window_controller_unittest.mm
deleted file mode 100644
index 2f857da..0000000
--- a/ui/app_list/cocoa/app_list_window_controller_unittest.mm
+++ /dev/null
@@ -1,95 +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.
-
-#import "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#include "base/strings/utf_string_conversions.h"
-#import "testing/gtest_mac.h"
-#include "ui/app_list/app_list_view_delegate.h"
-#import "ui/app_list/cocoa/app_list_view_controller.h"
-#import "ui/app_list/cocoa/app_list_window_controller.h"
-#include "ui/app_list/search_box_model.h"
-#include "ui/app_list/test/app_list_test_view_delegate.h"
-#import "ui/gfx/test/ui_cocoa_test_helper.h"
-
-namespace {
-
-class AppListWindowControllerTest : public ui::CocoaTest {
- public:
-  AppListWindowControllerTest();
-
- protected:
-  void TearDown() override;
-
-  base::scoped_nsobject<AppListWindowController> controller_;
-
-  app_list::test::AppListTestViewDelegate* delegate() {
-    return delegate_.get();
-  }
-
- private:
-  std::unique_ptr<app_list::test::AppListTestViewDelegate> delegate_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppListWindowControllerTest);
-};
-
-AppListWindowControllerTest::AppListWindowControllerTest()
-    : delegate_(new app_list::test::AppListTestViewDelegate) {
-  Init();
-  controller_.reset([[AppListWindowController alloc] init]);
-  [[controller_ appListViewController] setDelegate:delegate()];
-}
-
-void AppListWindowControllerTest::TearDown() {
-  EXPECT_TRUE(controller_.get());
-  [[controller_ window] close];
-  [[controller_ appListViewController] setDelegate:NULL];
-  controller_.reset();
-  ui::CocoaTest::TearDown();
-}
-
-}  // namespace
-
-// Test showing, hiding and closing the app list window.
-TEST_F(AppListWindowControllerTest, ShowHideCloseRelease) {
-  EXPECT_TRUE([controller_ window]);
-  [[controller_ window] makeKeyAndOrderFront:nil];
-  EXPECT_TRUE([[controller_ window] isVisible]);
-  EXPECT_TRUE([[[controller_ window] contentView] superview]);
-  [[controller_ window] close];  // Hide.
-  EXPECT_FALSE([[controller_ window] isVisible]);
-  [[controller_ window] makeKeyAndOrderFront:nil];
-}
-
-// Test that the key bound to cancel (usually Escape) asks the controller to
-// dismiss the window.
-TEST_F(AppListWindowControllerTest, DismissWithEscape) {
-  [[controller_ window] makeKeyAndOrderFront:nil];
-  EXPECT_EQ(0, delegate()->dismiss_count());
-  [[controller_ window] cancelOperation:controller_];
-  EXPECT_EQ(1, delegate()->dismiss_count());
-}
-
-// Test that search results are cleared when the window closes, not when a
-// search result is selected. If cleared upon selection, the animation showing
-// the results sliding away is seen as the window closes, which looks weird.
-TEST_F(AppListWindowControllerTest, CloseClearsSearch) {
-  [[controller_ window] makeKeyAndOrderFront:nil];
-  app_list::SearchBoxModel* model = delegate()->GetModel()->search_box();
-  AppListViewController* view_controller = [controller_ appListViewController];
-
-  EXPECT_FALSE([view_controller showingSearchResults]);
-
-  const base::string16 search_text(base::ASCIIToUTF16("test"));
-  model->SetText(search_text);
-  EXPECT_TRUE([view_controller showingSearchResults]);
-
-  EXPECT_EQ(0, delegate()->open_search_result_count());
-  [view_controller openResult:nil];
-  EXPECT_EQ(1, delegate()->open_search_result_count());
-
-  EXPECT_TRUE([view_controller showingSearchResults]);
-  [[controller_ window] close];  // Hide.
-  EXPECT_FALSE([view_controller showingSearchResults]);
-}
diff --git a/ui/app_list/cocoa/apps_collection_view_drag_manager.h b/ui/app_list/cocoa/apps_collection_view_drag_manager.h
deleted file mode 100644
index 94e74791..0000000
--- a/ui/app_list/cocoa/apps_collection_view_drag_manager.h
+++ /dev/null
@@ -1,65 +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.
-
-#ifndef UI_APP_LIST_COCOA_APPS_COLLECTION_VIEW_DRAG_MANAGER_H_
-#define UI_APP_LIST_COCOA_APPS_COLLECTION_VIEW_DRAG_MANAGER_H_
-
-#import <Cocoa/Cocoa.h>
-#include <stddef.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "ui/app_list/app_list_export.h"
-
-@class AppsGridController;
-@class ItemDragController;
-
-// Manager for the state associated with dragging an NSCollectionViewItem in the
-// AppsGridController. It is also a factory for the NSCollectionView pages in
-// the grid, allowing items to be dragged between pages.
-APP_LIST_EXPORT
-@interface AppsCollectionViewDragManager : NSObject {
- @private
-  base::scoped_nsobject<ItemDragController> itemDragController_;
-  AppsGridController* gridController_;  // Weak. Owns us.
-
-  NSSize cellSize_;
-  size_t rows_;
-  size_t columns_;
-
-  // Index of the last known position of the item currently being dragged.
-  size_t itemDragIndex_;
-
-  // Model index of the item being dragged, or NSNotFound if nothing was hit on
-  // the last mouseDown.
-  size_t itemHitIndex_;
-
-  // Location in the window of the last mouseDown event.
-  NSPoint mouseDownLocation_;
-
-  // Whether the current mouse action has converted into an item drag.
-  BOOL dragging_;
-}
-
-- (id)initWithCellSize:(NSSize)cellSize
-                  rows:(size_t)rows
-               columns:(size_t)columns
-        gridController:(AppsGridController*)gridController;
-
-// Make an empty NSCollectionView with draggable items in the given |pageFrame|.
-- (NSCollectionView*)makePageWithFrame:(NSRect)pageFrame;
-
-- (void)cancelDrag;
-
-@end
-
-@interface AppsCollectionViewDragManager (TestingAPI)
-
-- (void)onMouseDownInPage:(NSCollectionView*)page
-                withEvent:(NSEvent*)theEvent;
-- (void)onMouseDragged:(NSEvent*)theEvent;
-- (void)onMouseUp:(NSEvent*)theEvent;
-
-@end
-
-#endif  // UI_APP_LIST_COCOA_APPS_COLLECTION_VIEW_DRAG_MANAGER_H_
diff --git a/ui/app_list/cocoa/apps_collection_view_drag_manager.mm b/ui/app_list/cocoa/apps_collection_view_drag_manager.mm
deleted file mode 100644
index 74e23c4..0000000
--- a/ui/app_list/cocoa/apps_collection_view_drag_manager.mm
+++ /dev/null
@@ -1,263 +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.
-
-#import "ui/app_list/cocoa/apps_collection_view_drag_manager.h"
-
-#include "base/logging.h"
-#include "base/mac/foundation_util.h"
-#import "ui/app_list/cocoa/apps_grid_controller.h"
-#import "ui/app_list/cocoa/apps_grid_view_item.h"
-#import "ui/app_list/cocoa/item_drag_controller.h"
-
-namespace {
-
-// Distance cursor must travel in either x or y direction to start a drag.
-const CGFloat kDragThreshold = 5;
-
-}  // namespace
-
-@interface AppsCollectionViewDragManager ()
-
-// Returns the item index that |theEvent| would hit in the page at |pageIndex|
-// or NSNotFound if no item is hit.
-- (size_t)itemIndexForPage:(size_t)pageIndex
-              hitWithEvent:(NSEvent*)theEvent;
-
-- (void)initiateDrag:(NSEvent*)theEvent;
-- (void)updateDrag:(NSEvent*)theEvent;
-- (void)completeDrag;
-
-- (NSMenu*)menuForEvent:(NSEvent*)theEvent
-                 inPage:(NSCollectionView*)page;
-
-@end
-
-// An NSCollectionView that forwards mouse events to the factory they share.
-@interface GridCollectionView : NSCollectionView {
- @private
-  AppsCollectionViewDragManager* factory_;
-}
-
-@property(assign, nonatomic) AppsCollectionViewDragManager* factory;
-
-@end
-
-@implementation AppsCollectionViewDragManager
-
-- (id)initWithCellSize:(NSSize)cellSize
-                  rows:(size_t)rows
-               columns:(size_t)columns
-        gridController:(AppsGridController*)gridController {
-  if ((self = [super init])) {
-    cellSize_ = cellSize;
-    rows_ = rows;
-    columns_ = columns;
-    gridController_ = gridController;
-  }
-  return self;
-}
-
-- (NSCollectionView*)makePageWithFrame:(NSRect)pageFrame {
-  base::scoped_nsobject<GridCollectionView> itemCollectionView(
-      [[GridCollectionView alloc] initWithFrame:pageFrame]);
-  [itemCollectionView setFactory:self];
-  [itemCollectionView setMaxNumberOfRows:rows_];
-  [itemCollectionView setMinItemSize:cellSize_];
-  [itemCollectionView setMaxItemSize:cellSize_];
-  [itemCollectionView setSelectable:YES];
-  [itemCollectionView setFocusRingType:NSFocusRingTypeNone];
-  [itemCollectionView setBackgroundColors:
-      [NSArray arrayWithObject:[NSColor clearColor]]];
-  [itemCollectionView setDelegate:gridController_];
-
-  base::scoped_nsobject<AppsGridViewItem> itemPrototype(
-      [[AppsGridViewItem alloc] initWithSize:cellSize_]);
-  [[itemPrototype button] setTarget:gridController_];
-  [[itemPrototype button] setAction:@selector(onItemClicked:)];
-
-  [itemCollectionView setItemPrototype:itemPrototype];
-  return itemCollectionView.autorelease();
-}
-
-- (void)onMouseDownInPage:(NSCollectionView*)page
-                withEvent:(NSEvent*)theEvent {
-  size_t pageIndex = [gridController_ pageIndexForCollectionView:page];
-  itemHitIndex_ = [self itemIndexForPage:pageIndex
-                            hitWithEvent:theEvent];
-  if (itemHitIndex_ == NSNotFound)
-    return;
-
-  mouseDownLocation_ = [theEvent locationInWindow];
-  [[[gridController_ itemAtIndex:itemHitIndex_] view] mouseDown:theEvent];
-}
-
-- (void)onMouseDragged:(NSEvent*)theEvent {
-  if (itemHitIndex_ == NSNotFound)
-    return;
-
-  if (dragging_) {
-    [self updateDrag:theEvent];
-    return;
-  }
-
-  NSPoint mouseLocation = [theEvent locationInWindow];
-  CGFloat deltaX = mouseLocation.x - mouseDownLocation_.x;
-  CGFloat deltaY = mouseLocation.y - mouseDownLocation_.y;
-  if (deltaX * deltaX + deltaY * deltaY > kDragThreshold * kDragThreshold) {
-    [self initiateDrag:theEvent];
-    return;
-  }
-
-  [[[gridController_ itemAtIndex:itemHitIndex_] view] mouseDragged:theEvent];
-}
-
-- (void)onMouseUp:(NSEvent*)theEvent {
-  if (itemHitIndex_ == NSNotFound)
-    return;
-
-  if (dragging_) {
-    [self completeDrag];
-    return;
-  }
-
-  [[[gridController_ itemAtIndex:itemHitIndex_] view] mouseUp:theEvent];
-}
-
-- (size_t)itemIndexForPage:(size_t)pageIndex
-              hitWithEvent:(NSEvent*)theEvent {
-  NSCollectionView* page =
-      [gridController_ collectionViewAtPageIndex:pageIndex];
-  NSPoint pointInView = [page convertPoint:[theEvent locationInWindow]
-                                  fromView:nil];
-
-  const size_t itemsInPage = [[page content] count];
-  for (size_t indexInPage = 0; indexInPage < itemsInPage; ++indexInPage) {
-    if ([page mouse:pointInView
-             inRect:[page frameForItemAtIndex:indexInPage]]) {
-      return indexInPage + pageIndex * rows_ * columns_;
-    }
-  }
-
-  return NSNotFound;
-}
-
-- (void)initiateDrag:(NSEvent*)theEvent {
-  DCHECK_LT(itemHitIndex_, [gridController_ itemCount]);
-  dragging_ = YES;
-
-  if (!itemDragController_) {
-    itemDragController_.reset(
-        [[ItemDragController alloc] initWithGridCellSize:cellSize_]);
-    [[[gridController_ view] superview] addSubview:[itemDragController_ view]];
-  }
-
-  [itemDragController_ initiate:[gridController_ itemAtIndex:itemHitIndex_]
-              mouseDownLocation:mouseDownLocation_
-                currentLocation:[theEvent locationInWindow]
-                      timestamp:[theEvent timestamp]];
-
-  itemDragIndex_ = itemHitIndex_;
-  [self updateDrag:theEvent];
-}
-
-- (void)updateDrag:(NSEvent*)theEvent {
-  [itemDragController_ update:[theEvent locationInWindow]
-                    timestamp:[theEvent timestamp]];
-  [gridController_ maybeChangePageForPoint:[theEvent locationInWindow]];
-
-  size_t visiblePage = [gridController_ visiblePage];
-  size_t itemIndexOver = [self itemIndexForPage:visiblePage
-                                   hitWithEvent:theEvent];
-  DCHECK_NE(0u, [gridController_ itemCount]);
-  if (itemIndexOver == NSNotFound) {
-    if (visiblePage != [gridController_ pageCount] - 1)
-      return;
-
-    // If nothing was hit, but the last page is shown, move to the end.
-    itemIndexOver = [gridController_ itemCount] - 1;
-  }
-
-  if (itemDragIndex_ == itemIndexOver)
-    return;
-
-  [gridController_ moveItemInView:itemDragIndex_
-                      toItemIndex:itemIndexOver];
-  // A new item may be created when moving between pages. Ensure it is hidden.
-  [[[gridController_ itemAtIndex:itemIndexOver] button] setHidden:YES];
-  itemDragIndex_ = itemIndexOver;
-}
-
-- (void)cancelDrag {
-  if (!dragging_)
-    return;
-
-  [gridController_ moveItemInView:itemDragIndex_
-                      toItemIndex:itemHitIndex_];
-  itemDragIndex_ = itemHitIndex_;
-  [self completeDrag];
-  itemHitIndex_ = NSNotFound;  // Ignore future mouse events for this drag.
-}
-
-- (void)completeDrag {
-  DCHECK_GE(itemDragIndex_, 0u);
-  [gridController_ cancelScrollTimer];
-  AppsGridViewItem* item = [gridController_ itemAtIndex:itemDragIndex_];
-
-  // The item could still be animating in the NSCollectionView, so ask it where
-  // it would place the item.
-  NSCollectionView* pageView = base::mac::ObjCCastStrict<NSCollectionView>(
-      [[item view] superview]);
-  size_t indexInPage = itemDragIndex_ % (rows_ * columns_);
-  NSPoint targetOrigin = [[[itemDragController_ view] superview]
-      convertPoint:[pageView frameForItemAtIndex:indexInPage].origin
-          fromView:pageView];
-
-  [itemDragController_ complete:item
-                   targetOrigin:targetOrigin];
-  [gridController_ moveItemWithIndex:itemHitIndex_
-                        toModelIndex:itemDragIndex_];
-
-  dragging_ = NO;
-}
-
-- (NSMenu*)menuForEvent:(NSEvent*)theEvent
-                 inPage:(NSCollectionView*)page {
-  size_t pageIndex = [gridController_ pageIndexForCollectionView:page];
-  size_t itemIndex = [self itemIndexForPage:pageIndex
-                               hitWithEvent:theEvent];
-  if (itemIndex == NSNotFound)
-    return nil;
-
-  return [[gridController_ itemAtIndex:itemIndex] contextMenu];
-}
-
-@end
-
-@implementation GridCollectionView
-
-@synthesize factory = factory_;
-
-- (NSMenu*)menuForEvent:(NSEvent*)theEvent {
-  return [factory_ menuForEvent:theEvent
-                         inPage:self];
-}
-
-- (void)mouseDown:(NSEvent*)theEvent {
-  [factory_ onMouseDownInPage:self
-                    withEvent:theEvent];
-}
-
-- (void)mouseDragged:(NSEvent*)theEvent {
-  [factory_ onMouseDragged:theEvent];
-}
-
-- (void)mouseUp:(NSEvent*)theEvent {
-  [factory_ onMouseUp:theEvent];
-}
-
-- (BOOL)acceptsFirstResponder {
-  return NO;
-}
-
-@end
diff --git a/ui/app_list/cocoa/apps_grid_controller.h b/ui/app_list/cocoa/apps_grid_controller.h
deleted file mode 100644
index f1a1b83..0000000
--- a/ui/app_list/cocoa/apps_grid_controller.h
+++ /dev/null
@@ -1,127 +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.
-
-#ifndef UI_APP_LIST_COCOA_APPS_GRID_CONTROLLER_H_
-#define UI_APP_LIST_COCOA_APPS_GRID_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/mac/scoped_nsobject.h"
-#include "ui/app_list/app_list_export.h"
-#import "ui/app_list/cocoa/app_list_pager_view.h"
-#import "ui/app_list/cocoa/scroll_view_with_no_scrollbars.h"
-
-namespace app_list {
-class AppListModel;
-class AppListViewDelegate;
-class AppsGridDelegateBridge;
-}
-
-@class AppsGridViewItem;
-@protocol AppsPaginationModelObserver;
-@class AppsCollectionViewDragManager;
-
-// Controls a grid of views, representing AppListItemList sub models.
-APP_LIST_EXPORT
-@interface AppsGridController : NSViewController<GestureScrollDelegate,
-                                                 AppListPagerDelegate,
-                                                 NSCollectionViewDelegate> {
- @private
-  app_list::AppListViewDelegate* delegate_;  // Weak. Owned by view controller.
-  std::unique_ptr<app_list::AppsGridDelegateBridge> bridge_;
-
-  base::scoped_nsobject<AppsCollectionViewDragManager> dragManager_;
-  base::scoped_nsobject<NSMutableArray> pages_;
-  base::scoped_nsobject<NSMutableArray> items_;
-  base::scoped_nsobject<NSTimer> scrollWhileDraggingTimer_;
-
-  id<AppsPaginationModelObserver> paginationObserver_;
-
-  // Index of the currently visible page.
-  size_t visiblePage_;
-  // The page to which the view is currently animating a scroll.
-  size_t targetScrollPage_;
-  // The page to start scrolling to when the timer expires.
-  size_t scheduledScrollPage_;
-
-  // Whether we are currently animating a scroll to the nearest page.
-  BOOL animatingScroll_;
-}
-
-@property(assign, nonatomic) id<AppsPaginationModelObserver> paginationObserver;
-
-+ (void)setScrollAnimationDuration:(NSTimeInterval)duration;
-
-// The amount the grid view has been extended to hold the sometimes present
-// invisible scroller that allows for gesture scrolling.
-+ (CGFloat)scrollerPadding;
-
-// Whether the grid is configured with fewer rows than normal.
-+ (BOOL)hasFewerRows;
-
-- (NSCollectionView*)collectionViewAtPageIndex:(size_t)pageIndex;
-- (size_t)pageIndexForCollectionView:(NSCollectionView*)page;
-
-- (AppsGridViewItem*)itemAtIndex:(size_t)itemIndex;
-
-- (app_list::AppListModel*)model;
-
-- (void)setDelegate:(app_list::AppListViewDelegate*)newDelegate;
-
-- (size_t)visiblePage;
-
-// Calls item->Activate for the currently selected item by simulating a click.
-- (void)activateSelection;
-
-// Return the number of pages of icons in the grid.
-- (size_t)pageCount;
-
-// Return the number of items over all pages in the grid.
-- (size_t)itemCount;
-
-// Scroll to a page in the grid view with an animation.
-- (void)scrollToPage:(size_t)pageIndex;
-
-// Start a timer to scroll to a new page, if |locationInWindow| is to the left
-// or the right of the view, or if it is over a pager segment. Cancels any
-// existing timer if the target page changes.
-- (void)maybeChangePageForPoint:(NSPoint)locationInWindow;
-
-// Cancel a timer that may have been set by maybeChangePageForPoint().
-- (void)cancelScrollTimer;
-
-// Moves an item within the view only, for dragging or in response to model
-// changes.
-- (void)moveItemInView:(size_t)fromIndex
-           toItemIndex:(size_t)toIndex;
-
-// Moves an item in the item model. Does not adjust the view.
-- (void)moveItemWithIndex:(size_t)itemIndex
-             toModelIndex:(size_t)modelIndex;
-
-// Return the index of the selected item.
-- (NSUInteger)selectedItemIndex;
-
-// Moves the selection to the given index.
-- (void)selectItemAtIndex:(NSUInteger)index;
-
-// Handle key actions. Similar to doCommandBySelector from NSResponder but that
-// requires this class to be in the responder chain. Instead this method is
-// invoked by the AppListViewController.
-// Returns YES if this handled navigation or launched an app.
-- (BOOL)handleCommandBySelector:(SEL)command;
-
-@end
-
-@interface AppsGridController(TestingAPI)
-
-- (AppsCollectionViewDragManager*)dragManager;
-- (size_t)scheduledScrollPage;
-
-@end
-
-#endif  // UI_APP_LIST_COCOA_APPS_GRID_CONTROLLER_H_
diff --git a/ui/app_list/cocoa/apps_grid_controller.mm b/ui/app_list/cocoa/apps_grid_controller.mm
deleted file mode 100644
index 455c441..0000000
--- a/ui/app_list/cocoa/apps_grid_controller.mm
+++ /dev/null
@@ -1,709 +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.
-
-#import "ui/app_list/cocoa/apps_grid_controller.h"
-
-#include "base/command_line.h"
-#include "base/mac/foundation_util.h"
-#include "base/macros.h"
-#include "ui/app_list/app_list_item.h"
-#include "ui/app_list/app_list_model.h"
-#include "ui/app_list/app_list_model_observer.h"
-#include "ui/app_list/app_list_view_delegate.h"
-#import "ui/app_list/cocoa/apps_collection_view_drag_manager.h"
-#import "ui/app_list/cocoa/apps_grid_view_item.h"
-#import "ui/app_list/cocoa/apps_pagination_model_observer.h"
-#include "ui/base/models/list_model_observer.h"
-
-namespace {
-
-// OSX app list has hardcoded columns for now.
-const int kFixedColumns = 4;
-
-// Padding space in pixels for fixed layout.
-const CGFloat kGridTopPadding = 1;
-const CGFloat kLeftRightPadding = 21;
-const CGFloat kScrollerPadding = 16;
-
-// Preferred tile size when showing in fixed layout. These should be even
-// numbers to ensure that if they are grown 50% they remain integers.
-const CGFloat kPreferredTileWidth = 88;
-const CGFloat kPreferredTileHeight = 98;
-
-const CGFloat kViewWidth =
-    kFixedColumns * kPreferredTileWidth + 2 * kLeftRightPadding;
-
-const NSTimeInterval kScrollWhileDraggingDelay = 1.0;
-NSTimeInterval g_scroll_duration = 0.18;
-
-const char kTestType[] = "test-type";
-
-int DetermineFixedRowCount() {
-  // This needs to be called before a delegate exists, since it is needed to
-  // determine the height of the view.
-  return [AppsGridController hasFewerRows] ? 3 : 4;
-}
-
-int RowCount() {
-  static const int row_count = DetermineFixedRowCount();
-  return row_count;
-}
-
-int ItemsPerPage() {
-  return RowCount() * kFixedColumns;
-}
-
-CGFloat ViewHeight() {
-  return RowCount() * kPreferredTileHeight;
-}
-
-}  // namespace
-
-@interface AppsGridController ()
-
-- (void)scrollToPageWithTimer:(size_t)targetPage;
-- (void)onTimer:(NSTimer*)theTimer;
-
-// Cancel a currently running scroll animation.
-- (void)cancelScrollAnimation;
-
-// Index of the page with the most content currently visible.
-- (size_t)nearestPageIndex;
-
-// Bootstrap the views this class controls.
-- (void)loadAndSetView;
-
-- (void)boundsDidChange:(NSNotification*)notification;
-
-// Action for buttons in the grid.
-- (void)onItemClicked:(id)sender;
-
-- (AppsGridViewItem*)itemAtPageIndex:(size_t)pageIndex
-                         indexInPage:(size_t)indexInPage;
-
-// Return the button of the selected item.
-- (NSButton*)selectedButton;
-
-// The scroll view holding the grid pages.
-- (NSScrollView*)gridScrollView;
-
-- (NSView*)pagesContainerView;
-
-// Create any new pages after updating |items_|.
-- (void)updatePages:(size_t)startItemIndex;
-
-- (void)updatePageContent:(size_t)pageIndex
-               resetModel:(BOOL)resetModel;
-
-// Bridged methods for AppListItemListObserver.
-- (void)listItemAdded:(size_t)index
-                 item:(app_list::AppListItem*)item;
-
-- (void)listItemRemoved:(size_t)index;
-
-- (void)listItemMovedFromIndex:(size_t)fromIndex
-                  toModelIndex:(size_t)toIndex;
-
-// Moves the selection by |indexDelta| items.
-- (BOOL)moveSelectionByDelta:(int)indexDelta;
-
-@end
-
-namespace app_list {
-
-class AppsGridDelegateBridge : public AppListItemListObserver {
- public:
-  AppsGridDelegateBridge(AppsGridController* parent) : parent_(parent) {}
-
- private:
-  // Overridden from AppListItemListObserver:
-  void OnListItemAdded(size_t index, AppListItem* item) override {
-    [parent_ listItemAdded:index
-                      item:item];
-  }
-  void OnListItemRemoved(size_t index, AppListItem* item) override {
-    [parent_ listItemRemoved:index];
-  }
-  void OnListItemMoved(size_t from_index,
-                       size_t to_index,
-                       AppListItem* item) override {
-    [parent_ listItemMovedFromIndex:from_index
-                       toModelIndex:to_index];
-  }
-  void OnAppListItemHighlight(size_t index, bool highlight) override {
-    // NSCollectionView (or -[AppsGridController scrollToPage]) ensures only one
-    // item is highlighted, so clearing a highlight isn't necessary.
-    if (!highlight)
-      return;
-
-    [parent_ selectItemAtIndex:index];
-    [parent_ scrollToPage:index / ItemsPerPage()];
-  }
-
-  AppsGridController* parent_;  // Weak, owns us.
-
-  DISALLOW_COPY_AND_ASSIGN(AppsGridDelegateBridge);
-};
-
-}  // namespace app_list
-
-@interface PageContainerView : NSView;
-@end
-
-// The container view needs to flip coordinates so that it is laid out
-// correctly whether or not there is a horizontal scrollbar.
-@implementation PageContainerView
-
-- (BOOL)isFlipped {
-  return YES;
-}
-
-@end
-
-@implementation AppsGridController
-
-+ (void)setScrollAnimationDuration:(NSTimeInterval)duration {
-  g_scroll_duration = duration;
-}
-
-+ (CGFloat)scrollerPadding {
-  return kScrollerPadding;
-}
-
-+ (BOOL)hasFewerRows {
-  return !base::CommandLine::ForCurrentProcess()->HasSwitch(kTestType);
-}
-
-@synthesize paginationObserver = paginationObserver_;
-
-- (id)init {
-  if ((self = [super init])) {
-    bridge_.reset(new app_list::AppsGridDelegateBridge(self));
-    NSSize cellSize = NSMakeSize(kPreferredTileWidth, kPreferredTileHeight);
-    dragManager_.reset([[AppsCollectionViewDragManager alloc]
-        initWithCellSize:cellSize
-                    rows:RowCount()
-                 columns:kFixedColumns
-          gridController:self]);
-    pages_.reset([[NSMutableArray alloc] init]);
-    items_.reset([[NSMutableArray alloc] init]);
-    [self loadAndSetView];
-    [self updatePages:0];
-  }
-  return self;
-}
-
-- (void)dealloc {
-  [[NSNotificationCenter defaultCenter] removeObserver:self];
-  [super dealloc];
-}
-
-- (NSCollectionView*)collectionViewAtPageIndex:(size_t)pageIndex {
-  return [pages_ objectAtIndex:pageIndex];
-}
-
-- (size_t)pageIndexForCollectionView:(NSCollectionView*)page {
-  for (size_t pageIndex = 0; pageIndex < [pages_ count]; ++pageIndex) {
-    if (page == [self collectionViewAtPageIndex:pageIndex])
-      return pageIndex;
-  }
-  return NSNotFound;
-}
-
-- (app_list::AppListModel*)model {
-  return delegate_ ? delegate_->GetModel() : NULL;
-}
-
-- (void)setDelegate:(app_list::AppListViewDelegate*)newDelegate {
-  if (delegate_) {
-    app_list::AppListModel* oldModel = delegate_->GetModel();
-    if (oldModel)
-      oldModel->top_level_item_list()->RemoveObserver(bridge_.get());
-  }
-
-  // Since the old model may be getting deleted, and the AppKit objects might
-  // be sitting in an NSAutoreleasePool, ensure there are no references to
-  // the model.
-  for (size_t i = 0; i < [items_ count]; ++i)
-    [[self itemAtIndex:i] setModel:NULL];
-
-  [items_ removeAllObjects];
-  [self updatePages:0];
-  [self scrollToPage:0];
-
-  delegate_ = newDelegate;
-  if (!delegate_)
-    return;
-
-  app_list::AppListModel* newModel = delegate_->GetModel();
-  if (!newModel)
-    return;
-
-  newModel->top_level_item_list()->AddObserver(bridge_.get());
-  for (size_t i = 0; i < newModel->top_level_item_list()->item_count(); ++i) {
-    app_list::AppListItem* itemModel =
-        newModel->top_level_item_list()->item_at(i);
-    [items_ insertObject:[NSValue valueWithPointer:itemModel]
-                 atIndex:i];
-  }
-  [self updatePages:0];
-}
-
-- (size_t)visiblePage {
-  return visiblePage_;
-}
-
-- (void)activateSelection {
-  [[self selectedButton] performClick:self];
-}
-
-- (size_t)pageCount {
-  return [pages_ count];
-}
-
-- (size_t)itemCount {
-  return [items_ count];
-}
-
-- (void)scrollToPage:(size_t)pageIndex {
-  NSClipView* clipView = [[self gridScrollView] contentView];
-  NSPoint newOrigin = [clipView bounds].origin;
-
-  // Scrolling outside of this range is edge elasticity, which animates
-  // automatically.
-  if ((pageIndex == 0 && (newOrigin.x <= 0)) ||
-      (pageIndex + 1 == [self pageCount] &&
-          newOrigin.x >= pageIndex * kViewWidth)) {
-    return;
-  }
-
-  // Clear any selection on the current page (unless it has been removed).
-  if (visiblePage_ < [pages_ count]) {
-    [[self collectionViewAtPageIndex:visiblePage_]
-        setSelectionIndexes:[NSIndexSet indexSet]];
-  }
-
-  newOrigin.x = pageIndex * kViewWidth;
-  [NSAnimationContext beginGrouping];
-  [[NSAnimationContext currentContext] setDuration:g_scroll_duration];
-  [[clipView animator] setBoundsOrigin:newOrigin];
-  [NSAnimationContext endGrouping];
-  animatingScroll_ = YES;
-  targetScrollPage_ = pageIndex;
-  [self cancelScrollTimer];
-}
-
-- (void)maybeChangePageForPoint:(NSPoint)locationInWindow {
-  NSPoint pointInView = [[self view] convertPoint:locationInWindow
-                                         fromView:nil];
-  // Check if the point is outside the view on the left or right.
-  if (pointInView.x <= 0 || pointInView.x >= NSWidth([[self view] bounds])) {
-    size_t targetPage = visiblePage_;
-    if (pointInView.x <= 0)
-      targetPage -= targetPage != 0 ? 1 : 0;
-    else
-      targetPage += targetPage < [pages_ count] - 1 ? 1 : 0;
-    [self scrollToPageWithTimer:targetPage];
-    return;
-  }
-
-  if (paginationObserver_) {
-    NSInteger segment =
-        [paginationObserver_ pagerSegmentAtLocation:locationInWindow];
-    if (segment >= 0 && static_cast<size_t>(segment) != targetScrollPage_) {
-      [self scrollToPageWithTimer:segment];
-      return;
-    }
-  }
-
-  // Otherwise the point may have moved back into the view.
-  [self cancelScrollTimer];
-}
-
-- (void)cancelScrollTimer {
-  scheduledScrollPage_ = targetScrollPage_;
-  [scrollWhileDraggingTimer_ invalidate];
-}
-
-- (void)scrollToPageWithTimer:(size_t)targetPage {
-  if (targetPage == targetScrollPage_) {
-    [self cancelScrollTimer];
-    return;
-  }
-
-  if (targetPage == scheduledScrollPage_)
-    return;
-
-  scheduledScrollPage_ = targetPage;
-  [scrollWhileDraggingTimer_ invalidate];
-  scrollWhileDraggingTimer_.reset(
-      [[NSTimer scheduledTimerWithTimeInterval:kScrollWhileDraggingDelay
-                                        target:self
-                                      selector:@selector(onTimer:)
-                                      userInfo:nil
-                                       repeats:NO] retain]);
-}
-
-- (void)onTimer:(NSTimer*)theTimer {
-  if (scheduledScrollPage_ == targetScrollPage_)
-    return;  // Already animating scroll.
-
-  [self scrollToPage:scheduledScrollPage_];
-}
-
-- (void)cancelScrollAnimation {
-  NSClipView* clipView = [[self gridScrollView] contentView];
-  [NSAnimationContext beginGrouping];
-  [[NSAnimationContext currentContext] setDuration:0];
-  [[clipView animator] setBoundsOrigin:[clipView bounds].origin];
-  [NSAnimationContext endGrouping];
-  animatingScroll_ = NO;
-}
-
-- (size_t)nearestPageIndex {
-  return lround(
-      NSMinX([[[self gridScrollView] contentView] bounds]) / kViewWidth);
-}
-
-- (void)userScrolling:(BOOL)isScrolling {
-  if (isScrolling) {
-    if (animatingScroll_)
-      [self cancelScrollAnimation];
-  } else {
-    [self scrollToPage:[self nearestPageIndex]];
-  }
-}
-
-- (void)loadAndSetView {
-  base::scoped_nsobject<PageContainerView> pagesContainer(
-      [[PageContainerView alloc] initWithFrame:NSZeroRect]);
-
-  NSRect scrollFrame = NSMakeRect(0, kGridTopPadding, kViewWidth,
-                                  ViewHeight() + kScrollerPadding);
-  base::scoped_nsobject<ScrollViewWithNoScrollbars> scrollView(
-      [[ScrollViewWithNoScrollbars alloc] initWithFrame:scrollFrame]);
-  [scrollView setBorderType:NSNoBorder];
-  [scrollView setLineScroll:kViewWidth];
-  [scrollView setPageScroll:kViewWidth];
-  [scrollView setDelegate:self];
-  [scrollView setDocumentView:pagesContainer];
-  [scrollView setDrawsBackground:NO];
-
-  [[NSNotificationCenter defaultCenter]
-      addObserver:self
-         selector:@selector(boundsDidChange:)
-             name:NSViewBoundsDidChangeNotification
-           object:[scrollView contentView]];
-
-  [self setView:scrollView];
-}
-
-- (void)boundsDidChange:(NSNotification*)notification {
-  size_t newPage = [self nearestPageIndex];
-  if (newPage == visiblePage_) {
-    [paginationObserver_ pageVisibilityChanged];
-    return;
-  }
-
-  visiblePage_ = newPage;
-  [paginationObserver_ selectedPageChanged:newPage];
-  [paginationObserver_ pageVisibilityChanged];
-}
-
-- (void)onItemClicked:(id)sender {
-  for (size_t i = 0; i < [items_ count]; ++i) {
-    AppsGridViewItem* gridItem = [self itemAtIndex:i];
-    if ([[gridItem button] isEqual:sender])
-      [gridItem model]->Activate(0);
-  }
-}
-
-- (AppsGridViewItem*)itemAtPageIndex:(size_t)pageIndex
-                         indexInPage:(size_t)indexInPage {
-  return base::mac::ObjCCastStrict<AppsGridViewItem>(
-      [[self collectionViewAtPageIndex:pageIndex] itemAtIndex:indexInPage]);
-}
-
-- (AppsGridViewItem*)itemAtIndex:(size_t)itemIndex {
-  const size_t pageIndex = itemIndex / ItemsPerPage();
-  return [self itemAtPageIndex:pageIndex
-                   indexInPage:itemIndex - pageIndex * ItemsPerPage()];
-}
-
-- (NSUInteger)selectedItemIndex {
-  NSCollectionView* page = [self collectionViewAtPageIndex:visiblePage_];
-  NSUInteger indexOnPage = [[page selectionIndexes] firstIndex];
-  if (indexOnPage == NSNotFound)
-    return NSNotFound;
-
-  return indexOnPage + visiblePage_ * ItemsPerPage();
-}
-
-- (NSButton*)selectedButton {
-  NSUInteger index = [self selectedItemIndex];
-  if (index == NSNotFound)
-    return nil;
-
-  return [[self itemAtIndex:index] button];
-}
-
-- (NSScrollView*)gridScrollView {
-  return base::mac::ObjCCastStrict<NSScrollView>([self view]);
-}
-
-- (NSView*)pagesContainerView {
-  return [[self gridScrollView] documentView];
-}
-
-- (void)updatePages:(size_t)startItemIndex {
-  // Note there is always at least one page.
-  size_t targetPages = 1;
-  if ([items_ count] != 0)
-    targetPages = ([items_ count] - 1) / ItemsPerPage() + 1;
-
-  const size_t currentPages = [self pageCount];
-  // First see if the number of pages have changed.
-  if (targetPages != currentPages) {
-    if (targetPages < currentPages) {
-      // Pages need to be removed.
-      [pages_ removeObjectsInRange:NSMakeRange(targetPages,
-                                               currentPages - targetPages)];
-    } else {
-      // Pages need to be added.
-      for (size_t i = currentPages; i < targetPages; ++i) {
-        NSRect pageFrame = NSMakeRect(kLeftRightPadding + kViewWidth * i, 0,
-                                      kViewWidth, ViewHeight());
-        [pages_ addObject:[dragManager_ makePageWithFrame:pageFrame]];
-      }
-    }
-
-    [[self pagesContainerView] setSubviews:pages_];
-    NSSize pagesSize = NSMakeSize(kViewWidth * targetPages, ViewHeight());
-    [[self pagesContainerView] setFrameSize:pagesSize];
-    [paginationObserver_ totalPagesChanged];
-  }
-
-  const size_t startPage = startItemIndex / ItemsPerPage();
-  // All pages on or after |startPage| may need items added or removed.
-  for (size_t pageIndex = startPage; pageIndex < targetPages; ++pageIndex) {
-    [self updatePageContent:pageIndex
-                 resetModel:YES];
-  }
-}
-
-- (void)updatePageContent:(size_t)pageIndex
-               resetModel:(BOOL)resetModel {
-  NSCollectionView* pageView = [self collectionViewAtPageIndex:pageIndex];
-  if (resetModel) {
-    // Clear the models first, otherwise removed items could be autoreleased at
-    // an unknown point in the future, when the model owner may have gone away.
-    for (size_t i = 0; i < [[pageView content] count]; ++i) {
-      AppsGridViewItem* gridItem = base::mac::ObjCCastStrict<AppsGridViewItem>(
-          [pageView itemAtIndex:i]);
-      [gridItem setModel:NULL];
-    }
-  }
-
-  NSRange inPageRange = NSIntersectionRange(
-      NSMakeRange(pageIndex * ItemsPerPage(), ItemsPerPage()),
-      NSMakeRange(0, [items_ count]));
-  NSArray* pageContent = [items_ subarrayWithRange:inPageRange];
-  [pageView setContent:pageContent];
-  if (!resetModel)
-    return;
-
-  for (size_t i = 0; i < [pageContent count]; ++i) {
-    AppsGridViewItem* gridItem = base::mac::ObjCCastStrict<AppsGridViewItem>(
-        [pageView itemAtIndex:i]);
-    [gridItem setModel:static_cast<app_list::AppListItem*>(
-        [[pageContent objectAtIndex:i] pointerValue])];
-  }
-}
-
-- (void)moveItemInView:(size_t)fromIndex
-           toItemIndex:(size_t)toIndex {
-  base::scoped_nsobject<NSValue> item(
-      [[items_ objectAtIndex:fromIndex] retain]);
-  [items_ removeObjectAtIndex:fromIndex];
-  [items_ insertObject:item
-               atIndex:toIndex];
-
-  size_t fromPageIndex = fromIndex / ItemsPerPage();
-  size_t toPageIndex = toIndex / ItemsPerPage();
-  if (fromPageIndex == toPageIndex) {
-    [self updatePageContent:fromPageIndex
-                 resetModel:NO];  // Just reorder items.
-    return;
-  }
-
-  if (fromPageIndex > toPageIndex)
-    std::swap(fromPageIndex, toPageIndex);
-
-  for (size_t i = fromPageIndex; i <= toPageIndex; ++i) {
-    [self updatePageContent:i
-                 resetModel:YES];
-  }
-}
-
-// Compare with views implementation in AppsGridView::MoveItemInModel().
-- (void)moveItemWithIndex:(size_t)itemIndex
-             toModelIndex:(size_t)modelIndex {
-  // Ingore no-op moves. Note that this is always the case when canceled.
-  if (itemIndex == modelIndex)
-    return;
-
-  app_list::AppListItemList* itemList = [self model]->top_level_item_list();
-  itemList->RemoveObserver(bridge_.get());
-  itemList->MoveItem(itemIndex, modelIndex);
-  itemList->AddObserver(bridge_.get());
-}
-
-- (AppsCollectionViewDragManager*)dragManager {
-  return dragManager_;
-}
-
-- (size_t)scheduledScrollPage {
-  return scheduledScrollPage_;
-}
-
-- (void)listItemAdded:(size_t)index
-                 item:(app_list::AppListItem*)itemModel {
-  // Cancel any drag, to ensure the model stays consistent.
-  [dragManager_ cancelDrag];
-
-  [items_ insertObject:[NSValue valueWithPointer:itemModel]
-              atIndex:index];
-
-  [self updatePages:index];
-}
-
-- (void)listItemRemoved:(size_t)index {
-  [dragManager_ cancelDrag];
-
-  // Clear the models explicitly to avoid surprises from autorelease.
-  [[self itemAtIndex:index] setModel:NULL];
-
-  [items_ removeObjectsInRange:NSMakeRange(index, 1)];
-  [self updatePages:index];
-}
-
-- (void)listItemMovedFromIndex:(size_t)fromIndex
-                  toModelIndex:(size_t)toIndex {
-  [dragManager_ cancelDrag];
-  [self moveItemInView:fromIndex
-           toItemIndex:toIndex];
-}
-
-- (CGFloat)visiblePortionOfPage:(int)page {
-  CGFloat scrollOffsetOfPage =
-      NSMinX([[[self gridScrollView] contentView] bounds]) / kViewWidth - page;
-  if (scrollOffsetOfPage <= -1.0 || scrollOffsetOfPage >= 1.0)
-    return 0.0;
-
-  if (scrollOffsetOfPage <= 0.0)
-    return scrollOffsetOfPage + 1.0;
-
-  return -1.0 + scrollOffsetOfPage;
-}
-
-- (void)onPagerClicked:(AppListPagerView*)sender {
-  int selectedSegment = [sender selectedSegment];
-  if (selectedSegment < 0)
-    return;  // No selection.
-
-  int pageIndex = [[sender cell] tagForSegment:selectedSegment];
-  if (pageIndex >= 0)
-    [self scrollToPage:pageIndex];
-}
-
-- (BOOL)moveSelectionByDelta:(int)indexDelta {
-  if (indexDelta == 0)
-    return NO;
-
-  NSUInteger oldIndex = [self selectedItemIndex];
-
-  // If nothing is currently selected, select the first item on the page.
-  if (oldIndex == NSNotFound) {
-    [self selectItemAtIndex:visiblePage_ * ItemsPerPage()];
-    return YES;
-  }
-
-  // Can't select a negative index.
-  if (indexDelta < 0 && static_cast<NSUInteger>(-indexDelta) > oldIndex)
-    return NO;
-
-  // Can't select an index greater or equal to the number of items.
-  if (oldIndex + indexDelta >= [items_ count]) {
-    if (visiblePage_ == [pages_ count] - 1)
-      return NO;
-
-    // If we're not on the last page, then select the last item.
-    [self selectItemAtIndex:[items_ count] - 1];
-    return YES;
-  }
-
-  [self selectItemAtIndex:oldIndex + indexDelta];
-  return YES;
-}
-
-- (void)selectItemAtIndex:(NSUInteger)index {
-  if (index >= [items_ count])
-    return;
-
-  if (index / ItemsPerPage() != visiblePage_)
-    [self scrollToPage:index / ItemsPerPage()];
-
-  [[self itemAtIndex:index] setSelected:YES];
-}
-
-- (BOOL)handleCommandBySelector:(SEL)command {
-  if (command == @selector(insertNewline:) ||
-      command == @selector(insertLineBreak:)) {
-    [self activateSelection];
-    return YES;
-  }
-
-  NSUInteger oldIndex = [self selectedItemIndex];
-  // If nothing is currently selected, select the first item on the page.
-  if (oldIndex == NSNotFound) {
-    [self selectItemAtIndex:visiblePage_ * ItemsPerPage()];
-    return YES;
-  }
-
-  if (command == @selector(moveLeft:)) {
-    return oldIndex % kFixedColumns == 0
-               ? [self moveSelectionByDelta:-ItemsPerPage() + kFixedColumns - 1]
-               : [self moveSelectionByDelta:-1];
-  }
-
-  if (command == @selector(moveRight:)) {
-    return oldIndex % kFixedColumns == kFixedColumns - 1
-               ? [self moveSelectionByDelta:+ItemsPerPage() - kFixedColumns + 1]
-               : [self moveSelectionByDelta:1];
-  }
-
-  if (command == @selector(moveUp:)) {
-    return oldIndex / kFixedColumns % RowCount() == 0
-               ? NO
-               : [self moveSelectionByDelta:-kFixedColumns];
-  }
-
-  if (command == @selector(moveDown:)) {
-    return oldIndex / kFixedColumns % RowCount() == RowCount() - 1
-               ? NO
-               : [self moveSelectionByDelta:kFixedColumns];
-  }
-
-  if (command == @selector(pageUp:) ||
-      command == @selector(scrollPageUp:))
-    return [self moveSelectionByDelta:-ItemsPerPage()];
-
-  if (command == @selector(pageDown:) ||
-      command == @selector(scrollPageDown:))
-    return [self moveSelectionByDelta:ItemsPerPage()];
-
-  return NO;
-}
-
-@end
diff --git a/ui/app_list/cocoa/apps_grid_controller_unittest.mm b/ui/app_list/cocoa/apps_grid_controller_unittest.mm
deleted file mode 100644
index 357eb465..0000000
--- a/ui/app_list/cocoa/apps_grid_controller_unittest.mm
+++ /dev/null
@@ -1,979 +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 <stddef.h>
-
-#include "base/mac/foundation_util.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#include "base/strings/utf_string_conversions.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "testing/gtest_mac.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_item.h"
-#import "ui/app_list/cocoa/apps_collection_view_drag_manager.h"
-#import "ui/app_list/cocoa/apps_grid_controller.h"
-#import "ui/app_list/cocoa/apps_grid_view_item.h"
-#import "ui/app_list/cocoa/apps_pagination_model_observer.h"
-#import "ui/app_list/cocoa/test/apps_grid_controller_test_helper.h"
-#include "ui/app_list/test/app_list_test_model.h"
-#include "ui/app_list/test/app_list_test_view_delegate.h"
-#include "ui/base/models/simple_menu_model.h"
-#import "ui/events/test/cocoa_test_event_utils.h"
-
-@interface TestPaginationObserver : NSObject<AppsPaginationModelObserver> {
- @private
-  NSInteger hoveredSegmentForTest_;
-  int totalPagesChangedCount_;
-  int selectedPageChangedCount_;
-  int lastNewSelectedPage_;
-  bool visibilityDidChange_;
-}
-
-@property(assign, nonatomic) NSInteger hoveredSegmentForTest;
-@property(assign, nonatomic) int totalPagesChangedCount;
-@property(assign, nonatomic) int selectedPageChangedCount;
-@property(assign, nonatomic) int lastNewSelectedPage;
-
-- (bool)readVisibilityDidChange;
-
-@end
-
-@implementation TestPaginationObserver
-
-@synthesize hoveredSegmentForTest = hoveredSegmentForTest_;
-@synthesize totalPagesChangedCount = totalPagesChangedCount_;
-@synthesize selectedPageChangedCount = selectedPageChangedCount_;
-@synthesize lastNewSelectedPage = lastNewSelectedPage_;
-
-- (id)init {
-  if ((self = [super init]))
-    hoveredSegmentForTest_ = -1;
-
-  return self;
-}
-
-- (bool)readVisibilityDidChange {
-  bool truth = visibilityDidChange_;
-  visibilityDidChange_ = false;
-  return truth;
-}
-
-- (void)totalPagesChanged {
-  ++totalPagesChangedCount_;
-}
-
-- (void)selectedPageChanged:(int)newSelected {
-  ++selectedPageChangedCount_;
-  lastNewSelectedPage_ = newSelected;
-}
-
-- (void)pageVisibilityChanged {
-  visibilityDidChange_ = true;
-}
-
-- (NSInteger)pagerSegmentAtLocation:(NSPoint)locationInWindow {
-  return hoveredSegmentForTest_;
-}
-
-@end
-
-namespace app_list {
-namespace test {
-
-namespace {
-
-class AppsGridControllerTest : public AppsGridControllerTestHelper {
- public:
-  AppsGridControllerTest() {}
-
-  AppListTestViewDelegate* delegate() {
-    return owned_delegate_.get();
-  }
-
-  NSColor* ButtonTitleColorAt(size_t index) {
-    NSDictionary* attributes =
-        [[[GetItemViewAt(index) cell] attributedTitle] attributesAtIndex:0
-                                                          effectiveRange:NULL];
-    return [attributes objectForKey:NSForegroundColorAttributeName];
-  }
-
-  void SetUp() override {
-    owned_apps_grid_controller_.reset([[AppsGridController alloc] init]);
-    owned_delegate_.reset(new AppListTestViewDelegate);
-    [owned_apps_grid_controller_ setDelegate:owned_delegate_.get()];
-    AppsGridControllerTestHelper::SetUpWithGridController(
-        owned_apps_grid_controller_.get());
-
-    [[test_window() contentView] addSubview:[apps_grid_controller_ view]];
-    [test_window() makePretendKeyWindowAndSetFirstResponder:
-        [apps_grid_controller_ collectionViewAtPageIndex:0]];
-  }
-
-  void TearDown() override {
-    [owned_apps_grid_controller_ setDelegate:NULL];
-    owned_apps_grid_controller_.reset();
-    AppsGridControllerTestHelper::TearDown();
-  }
-
-  void ReplaceTestModel(int item_count) {
-    // Clear the delegate before reseting and destroying the model.
-    [owned_apps_grid_controller_ setDelegate:NULL];
-
-    owned_delegate_->ReplaceTestModel(item_count);
-    [owned_apps_grid_controller_ setDelegate:owned_delegate_.get()];
-  }
-
-  AppListTestModel* model() { return owned_delegate_->GetTestModel(); }
-
- private:
-  base::scoped_nsobject<AppsGridController> owned_apps_grid_controller_;
-  std::unique_ptr<AppListTestViewDelegate> owned_delegate_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppsGridControllerTest);
-};
-
-class AppListItemWithMenu : public AppListItem {
- public:
-  explicit AppListItemWithMenu(const std::string& id)
-      : AppListItem(id),
-        menu_model_(NULL),
-        menu_ready_(true) {
-    SetName(id);
-    menu_model_.AddItem(0, base::UTF8ToUTF16("Menu For: " + id));
-  }
-
-  void SetMenuReadyForTesting(bool ready) {
-    menu_ready_ = ready;
-  }
-
-  ui::MenuModel* GetContextMenuModel() override {
-    if (!menu_ready_)
-      return NULL;
-
-    return &menu_model_;
-  }
-
- private:
-  ui::SimpleMenuModel menu_model_;
-  bool menu_ready_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppListItemWithMenu);
-};
-
-// Generate a mouse event at the centre of the view in |page| with the given
-// |index_in_page| that can be used to initiate, update and complete drag
-// operations.
-NSEvent* MouseEventInCell(NSCollectionView* page, size_t index_in_page) {
-  NSRect cell_rect = [page frameForItemAtIndex:index_in_page];
-  NSPoint point_in_view = NSMakePoint(NSMidX(cell_rect), NSMidY(cell_rect));
-  NSPoint point_in_window = [page convertPoint:point_in_view
-                                        toView:nil];
-  return cocoa_test_event_utils::LeftMouseDownAtPoint(point_in_window);
-}
-
-NSEvent* MouseEventForScroll(NSView* view, CGFloat relative_x) {
-  NSRect view_rect = [view frame];
-  NSPoint point_in_view = NSMakePoint(NSMidX(view_rect), NSMidY(view_rect));
-  point_in_view.x += point_in_view.x * relative_x;
-  NSPoint point_in_window = [view convertPoint:point_in_view
-                                        toView:nil];
-  return cocoa_test_event_utils::LeftMouseDownAtPoint(point_in_window);
-}
-
-}  // namespace
-
-TEST_VIEW(AppsGridControllerTest, [apps_grid_controller_ view]);
-
-// Test showing with an empty model.
-TEST_F(AppsGridControllerTest, EmptyModelAndShow) {
-  EXPECT_TRUE([[apps_grid_controller_ view] superview]);
-
-  // First page should always exist, even if empty.
-  EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
-  EXPECT_EQ(0u, [[GetPageAt(0) content] count]);
-  EXPECT_TRUE([GetPageAt(0) superview]);  // The pages container.
-  EXPECT_TRUE([[GetPageAt(0) superview] superview]);
-}
-
-// Test with a single item.
-// This test is disabled in builders until the delay to wait for the collection
-// view to load subviews can be removed, or some other solution is found.
-TEST_F(AppsGridControllerTest, DISABLED_SingleEntryModel) {
-  // We need to "wake up" the NSCollectionView, otherwise it does not
-  // immediately update its subviews later in this function.
-  // When this test is run by itself, it's enough just to send a keypress (and
-  // this delay is not needed).
-  DelayForCollectionView();
-  EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
-  EXPECT_EQ(0u, [[GetPageAt(0) content] count]);
-
-  model()->PopulateApps(1);
-  SinkEvents();
-  EXPECT_FALSE([GetPageAt(0) animations]);
-
-  EXPECT_EQ(1u, [[GetPageAt(0) content] count]);
-  NSArray* subviews = [GetPageAt(0) subviews];
-  EXPECT_EQ(1u, [subviews count]);
-
-  // Note that using GetItemViewAt(0) here also works, and returns non-nil even
-  // without the delay, but a "click" on it does not register without the delay.
-  NSView* subview = [subviews objectAtIndex:0];
-
-  // Launch the item.
-  SimulateClick(subview);
-  SinkEvents();
-  EXPECT_EQ(1, model()->activate_count());
-  ASSERT_TRUE(model()->last_activated());
-  EXPECT_EQ(std::string("Item 0"), model()->last_activated()->name());
-}
-
-// Test activating an item on the second page (the 17th item).
-TEST_F(AppsGridControllerTest, DISABLED_TwoPageModel) {
-  DelayForCollectionView();
-  ReplaceTestModel(kItemsPerPage * 2);
-  [apps_grid_controller_ scrollToPage:1];
-
-  // The NSScrollView animator ignores the duration configured on the
-  // NSAnimationContext (set by CocoaTest::Init), so we need to delay here.
-  DelayForCollectionView();
-  NSArray* subviews = [GetPageAt(1) subviews];
-  NSView* subview = [subviews objectAtIndex:0];
-  // Launch the item.
-  SimulateClick(subview);
-  SinkEvents();
-  EXPECT_EQ(1, model()->activate_count());
-  ASSERT_TRUE(model()->last_activated());
-  EXPECT_EQ(std::string("Item 16"), model()->last_activated()->name());
-}
-
-// Test setModel.
-TEST_F(AppsGridControllerTest, ReplaceModel) {
-  const size_t kOrigItems = 1;
-  const size_t kNewItems = 2;
-
-  model()->PopulateApps(kOrigItems);
-  EXPECT_EQ(kOrigItems, [[GetPageAt(0) content] count]);
-
-  ReplaceTestModel(kNewItems);
-  EXPECT_EQ(kNewItems, [[GetPageAt(0) content] count]);
-}
-
-// Test pagination.
-TEST_F(AppsGridControllerTest, Pagination) {
-  model()->PopulateApps(1);
-  EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
-  EXPECT_EQ(1u, [[GetPageAt(0) content] count]);
-
-  ReplaceTestModel(kItemsPerPage);
-  EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
-  EXPECT_EQ(kItemsPerPage, [[GetPageAt(0) content] count]);
-
-  // Test adding an item onto the next page.
-  model()->PopulateApps(1);  // Now 17 items.
-  EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
-  EXPECT_EQ(kItemsPerPage, [[GetPageAt(0) content] count]);
-  EXPECT_EQ(1u, [[GetPageAt(1) content] count]);
-
-  // Test N pages with the last page having one empty spot.
-  const size_t kPagesToTest = 3;
-  ReplaceTestModel(kPagesToTest * kItemsPerPage - 1);
-  EXPECT_EQ(kPagesToTest, [apps_grid_controller_ pageCount]);
-  for (size_t page_index = 0; page_index < kPagesToTest - 1; ++page_index) {
-    EXPECT_EQ(kItemsPerPage, [[GetPageAt(page_index) content] count]);
-  }
-  EXPECT_EQ(kItemsPerPage - 1, [[GetPageAt(kPagesToTest - 1) content] count]);
-
-  // Test removing pages.
-  ReplaceTestModel(1);
-  EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
-  EXPECT_EQ(1u, [[GetPageAt(0) content] count]);
-}
-
-// Tests basic keyboard navigation on the first page.
-TEST_F(AppsGridControllerTest, FirstPageKeyboardNavigation) {
-  model()->PopulateApps(kItemsPerPage - 2);
-  EXPECT_EQ(kItemsPerPage - 2, [[GetPageAt(0) content] count]);
-
-  SimulateKeyAction(@selector(moveRight:));
-  EXPECT_EQ(0u, [apps_grid_controller_ selectedItemIndex]);
-
-  SimulateKeyAction(@selector(moveRight:));
-  EXPECT_EQ(1u, [apps_grid_controller_ selectedItemIndex]);
-
-  SimulateKeyAction(@selector(moveDown:));
-  EXPECT_EQ(5u, [apps_grid_controller_ selectedItemIndex]);
-
-  SimulateKeyAction(@selector(moveLeft:));
-  EXPECT_EQ(4u, [apps_grid_controller_ selectedItemIndex]);
-
-  SimulateKeyAction(@selector(moveUp:));
-  EXPECT_EQ(0u, [apps_grid_controller_ selectedItemIndex]);
-
-  // Go to the third item, and launch it.
-  SimulateKeyAction(@selector(moveRight:));
-  SimulateKeyAction(@selector(moveRight:));
-  EXPECT_EQ(2u, [apps_grid_controller_ selectedItemIndex]);
-  SimulateKeyAction(@selector(insertNewline:));
-  EXPECT_EQ(1, model()->activate_count());
-  ASSERT_TRUE(model()->last_activated());
-  EXPECT_EQ(std::string("Item 2"), model()->last_activated()->name());
-}
-
-// Tests keyboard navigation across pages.
-TEST_F(AppsGridControllerTest, CrossPageKeyboardNavigation) {
-  model()->PopulateApps(kItemsPerPage + 10);
-  EXPECT_EQ(kItemsPerPage, [[GetPageAt(0) content] count]);
-  EXPECT_EQ(10u, [[GetPageAt(1) content] count]);
-
-  // Moving Left, Up, or PageUp from the top-left corner of the first page does
-  // nothing.
-  [apps_grid_controller_ selectItemAtIndex:0];
-  SimulateKeyAction(@selector(moveLeft:));
-  EXPECT_EQ(0u, [apps_grid_controller_ selectedItemIndex]);
-  SimulateKeyAction(@selector(moveUp:));
-  EXPECT_EQ(0u, [apps_grid_controller_ selectedItemIndex]);
-  SimulateKeyAction(@selector(scrollPageUp:));
-  EXPECT_EQ(0u, [apps_grid_controller_ selectedItemIndex]);
-
-  // Moving Right from the right side goes to the next page. Moving Left goes
-  // back to the first page.
-  [apps_grid_controller_ selectItemAtIndex:3];
-  SimulateKeyAction(@selector(moveRight:));
-  EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(kItemsPerPage, [apps_grid_controller_ selectedItemIndex]);
-  SimulateKeyAction(@selector(moveLeft:));
-  EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(3u, [apps_grid_controller_ selectedItemIndex]);
-
-  // Moving Down from the bottom does nothing.
-  [apps_grid_controller_ selectItemAtIndex:13];
-  EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-  SimulateKeyAction(@selector(moveDown:));
-  EXPECT_EQ(13u, [apps_grid_controller_ selectedItemIndex]);
-
-  // Moving Right into a non-existent square on the next page will select the
-  // last item.
-  [apps_grid_controller_ selectItemAtIndex:15];
-  EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-  SimulateKeyAction(@selector(moveRight:));
-  EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(kItemsPerPage + 9, [apps_grid_controller_ selectedItemIndex]);
-
-  // PageDown and PageUp switches pages while maintaining the same selection
-  // position.
-  [apps_grid_controller_ selectItemAtIndex:6];
-  EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-  SimulateKeyAction(@selector(scrollPageDown:));
-  EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(kItemsPerPage + 6, [apps_grid_controller_ selectedItemIndex]);
-  SimulateKeyAction(@selector(scrollPageUp:));
-  EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(6u, [apps_grid_controller_ selectedItemIndex]);
-
-  // PageDown into a non-existent square on the next page will select the last
-  // item.
-  [apps_grid_controller_ selectItemAtIndex:11];
-  EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-  SimulateKeyAction(@selector(scrollPageDown:));
-  EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(kItemsPerPage + 9, [apps_grid_controller_ selectedItemIndex]);
-
-  // Moving Right, Down, or PageDown from the bottom-right corner of the last
-  // page (not the last item) does nothing.
-  [apps_grid_controller_ selectItemAtIndex:kItemsPerPage + 9];
-  EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-  SimulateKeyAction(@selector(moveRight:));
-  EXPECT_EQ(kItemsPerPage + 9, [apps_grid_controller_ selectedItemIndex]);
-  SimulateKeyAction(@selector(moveDown:));
-  EXPECT_EQ(kItemsPerPage + 9, [apps_grid_controller_ selectedItemIndex]);
-  SimulateKeyAction(@selector(scrollPageDown:));
-  EXPECT_EQ(kItemsPerPage + 9, [apps_grid_controller_ selectedItemIndex]);
-
-  // After page switch, arrow keys select first item on current page.
-  [apps_grid_controller_ scrollToPage:0];
-  [apps_grid_controller_ scrollToPage:1];
-  EXPECT_EQ(static_cast<NSUInteger>(NSNotFound),
-            [apps_grid_controller_ selectedItemIndex]);
-  SimulateKeyAction(@selector(moveUp:));
-  EXPECT_EQ(kItemsPerPage, [apps_grid_controller_ selectedItemIndex]);
-}
-
-// Highlighting an item should cause the page it's on to be visible.
-TEST_F(AppsGridControllerTest, EnsureHighlightedVisible) {
-  model()->PopulateApps(3 * kItemsPerPage);
-  EXPECT_EQ(kItemsPerPage, [[GetPageAt(2) content] count]);
-
-  // First and last items of first page.
-  [apps_grid_controller_ selectItemAtIndex:0];
-  EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-  [apps_grid_controller_ selectItemAtIndex:kItemsPerPage - 1];
-  EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-
-  // First item of second page.
-  [apps_grid_controller_ selectItemAtIndex:kItemsPerPage + 1];
-  EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-
-  // Last item in model.
-  [apps_grid_controller_ selectItemAtIndex:3 * kItemsPerPage - 1];
-  EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
-}
-
-// Test runtime updates: adding items, removing items, and moving items (e.g. in
-// response to app install, uninstall, and chrome sync changes. Also test
-// changing titles and icons.
-TEST_F(AppsGridControllerTest, ModelUpdate) {
-  model()->PopulateApps(2);
-  EXPECT_EQ(2u, [[GetPageAt(0) content] count]);
-  EXPECT_EQ(std::string("|Item 0,Item 1|"), GetViewContent());
-
-  // Add an item (PopulateApps will create a new "Item 2").
-  model()->PopulateApps(1);
-  EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
-  NSButton* button = GetItemViewAt(2);
-  EXPECT_NSEQ(@"Item 2", [button title]);
-  EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
-
-  // Update the title via the ItemModelObserver.
-  app_list::AppListItem* item_model =
-      model()->top_level_item_list()->item_at(2);
-  model()->SetItemName(item_model, "UpdatedItem");
-  EXPECT_NSEQ(@"UpdatedItem", [button title]);
-
-  // Test icon updates through the model observer by ensuring the icon changes.
-  item_model->SetIcon(gfx::ImageSkia());
-  NSSize icon_size = [[button image] size];
-  EXPECT_EQ(0, icon_size.width);
-  EXPECT_EQ(0, icon_size.height);
-
-  SkBitmap bitmap;
-  const int kTestImageSize = 10;
-  const int kTargetImageSize = 48;
-  bitmap.setInfo(SkImageInfo::MakeN32Premul(kTestImageSize, kTestImageSize));
-  item_model->SetIcon(gfx::ImageSkia::CreateFrom1xBitmap(bitmap));
-  icon_size = [[button image] size];
-  // Icon should always be resized to 48x48.
-  EXPECT_EQ(kTargetImageSize, icon_size.width);
-  EXPECT_EQ(kTargetImageSize, icon_size.height);
-}
-
-TEST_F(AppsGridControllerTest, ModelAdd) {
-  model()->PopulateApps(2);
-  EXPECT_EQ(2u, [[GetPageAt(0) content] count]);
-  EXPECT_EQ(std::string("|Item 0,Item 1|"), GetViewContent());
-
-  app_list::AppListItemList* item_list = model()->top_level_item_list();
-
-  model()->CreateAndAddItem("Item 2");
-  ASSERT_EQ(3u, item_list->item_count());
-  EXPECT_EQ(3u, [apps_grid_controller_ itemCount]);
-  EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
-
-  // Test adding an item whose position is in the middle.
-  app_list::AppListItem* item0 = item_list->item_at(0);
-  app_list::AppListItem* item1 = item_list->item_at(1);
-  app_list::AppListItem* item3 = model()->CreateItem("Item Three");
-  model()->AddItem(item3);
-  item_list->SetItemPosition(
-      item3, item0->position().CreateBetween(item1->position()));
-  EXPECT_EQ(4u, [apps_grid_controller_ itemCount]);
-  EXPECT_EQ(std::string("|Item 0,Item Three,Item 1,Item 2|"), GetViewContent());
-}
-
-TEST_F(AppsGridControllerTest, ModelMove) {
-  model()->PopulateApps(3);
-  EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
-  EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
-
-  // Test swapping items (e.g. rearranging via sync).
-  model()->top_level_item_list()->MoveItem(1, 2);
-  EXPECT_EQ(std::string("|Item 0,Item 2,Item 1|"), GetViewContent());
-}
-
-TEST_F(AppsGridControllerTest, ModelRemove) {
-  model()->PopulateApps(3);
-  EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
-  EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
-
-  // Test removing an item at the end.
-  model()->DeleteItem("Item 2");
-  EXPECT_EQ(2u, [apps_grid_controller_ itemCount]);
-  EXPECT_EQ(std::string("|Item 0,Item 1|"), GetViewContent());
-
-  // Test removing in the middle.
-  model()->CreateAndAddItem("Item 2");
-  EXPECT_EQ(3u, [apps_grid_controller_ itemCount]);
-  EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
-  model()->DeleteItem("Item 1");
-  EXPECT_EQ(2u, [apps_grid_controller_ itemCount]);
-  EXPECT_EQ(std::string("|Item 0,Item 2|"), GetViewContent());
-}
-
-TEST_F(AppsGridControllerTest, ModelRemoveSeveral) {
-  model()->PopulateApps(3);
-  EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
-  EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
-
-  // Test removing multiple items via the model.
-  model()->DeleteItem("Item 0");
-  model()->DeleteItem("Item 1");
-  model()->DeleteItem("Item 2");
-  EXPECT_EQ(0u, [apps_grid_controller_ itemCount]);
-  EXPECT_EQ(std::string("||"), GetViewContent());
-}
-
-TEST_F(AppsGridControllerTest, ModelRemovePage) {
-  app_list::AppListItemList* item_list = model()->top_level_item_list();
-
-  model()->PopulateApps(kItemsPerPage + 1);
-  ASSERT_EQ(kItemsPerPage + 1, item_list->item_count());
-  EXPECT_EQ(kItemsPerPage + 1, [apps_grid_controller_ itemCount]);
-  EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
-
-  // Test removing the last item when there is one item on the second page.
-  app_list::AppListItem* last_item = item_list->item_at(kItemsPerPage);
-  model()->DeleteItem(last_item->id());
-  EXPECT_EQ(kItemsPerPage, item_list->item_count());
-  EXPECT_EQ(kItemsPerPage, [apps_grid_controller_ itemCount]);
-  EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
-}
-
-// Test install progress bars, and install flow with item highlighting.
-TEST_F(AppsGridControllerTest, ItemInstallProgress) {
-  ReplaceTestModel(kItemsPerPage + 1);
-  EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
-  EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-  // The single item on the second page.
-  int kTestItemIndex = kItemsPerPage;
-  app_list::AppListItem* item_model =
-      model()->top_level_item_list()->item_at(kTestItemIndex);
-
-  // Highlighting an item should activate the page it is on.
-  model()->HighlightItemAt(kTestItemIndex);
-  EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-
-  // Starting install should add a progress bar, and temporarily clear the
-  // button title.
-  NSButton* button = GetItemViewAt(kTestItemIndex);
-  NSView* containerView = [button superview];
-  EXPECT_EQ(1u, [[containerView subviews] count]);
-  EXPECT_NSEQ(@"Item 16", [button title]);
-  model()->HighlightItemAt(kTestItemIndex);
-  item_model->SetIsInstalling(true);
-  EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-
-  EXPECT_EQ(2u, [[containerView subviews] count]);
-  EXPECT_NSEQ(@"", [button title]);
-  NSProgressIndicator* progressIndicator =
-      [[containerView subviews] objectAtIndex:1];
-  EXPECT_FALSE([progressIndicator isIndeterminate]);
-  EXPECT_EQ(0.0, [progressIndicator doubleValue]);
-
-  // Updating the progress in the model should update the progress bar.
-  item_model->SetPercentDownloaded(50);
-  EXPECT_EQ(50.0, [progressIndicator doubleValue]);
-
-  // Two things can be installing simultaneously. When one starts or completes
-  // the model builder will ask for the item to be highlighted.
-  const int kAlternateTestItemIndex = 0;
-  model()->HighlightItemAt(kAlternateTestItemIndex);
-  EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-
-  // Update the first item (page doesn't change on updates).
-  item_model->SetPercentDownloaded(100);
-  EXPECT_EQ(100.0, [progressIndicator doubleValue]);
-  EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-
-  // A percent of -1 indicates the download is complete and the unpack/install
-  // process has started.
-  item_model->SetPercentDownloaded(-1);
-  EXPECT_TRUE([progressIndicator isIndeterminate]);
-
-  // Completing install removes the progress bar, and restores the title.
-  // ExtensionAppModelBuilder will reload the ExtensionAppItem, which also
-  // highlights. Do the same here.
-  model()->HighlightItemAt(kTestItemIndex);
-  item_model->SetIsInstalling(false);
-  EXPECT_EQ(1u, [[containerView subviews] count]);
-  EXPECT_NSEQ(@"Item 16", [button title]);
-  EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-
-  // Things should cleanup OK with |alternate_item_model| left installing.
-}
-
-// Test mouseover selection.
-TEST_F(AppsGridControllerTest, MouseoverSelects) {
-  model()->PopulateApps(2);
-  EXPECT_EQ(nil, GetSelectedView());
-
-  // Test entering and exiting the first item.
-  SimulateMouseEnterItemAt(0);
-  EXPECT_EQ(GetItemViewAt(0), GetSelectedView());
-  SimulateMouseExitItemAt(0);
-  EXPECT_EQ(nil, GetSelectedView());
-
-  // AppKit doesn't guarantee the order, so test moving between items.
-  SimulateMouseEnterItemAt(0);
-  EXPECT_EQ(GetItemViewAt(0), GetSelectedView());
-  SimulateMouseEnterItemAt(1);
-  EXPECT_EQ(GetItemViewAt(1), GetSelectedView());
-  SimulateMouseExitItemAt(0);
-  EXPECT_EQ(GetItemViewAt(1), GetSelectedView());
-  SimulateMouseExitItemAt(1);
-  EXPECT_EQ(nil, GetSelectedView());
-}
-
-// Test AppsGridPaginationObserver totalPagesChanged().
-TEST_F(AppsGridControllerTest, PaginationObserverPagesChanged) {
-  base::scoped_nsobject<TestPaginationObserver> observer(
-      [[TestPaginationObserver alloc] init]);
-  [apps_grid_controller_ setPaginationObserver:observer];
-
-  // Test totalPagesChanged.
-  model()->PopulateApps(kItemsPerPage);
-  EXPECT_EQ(0, [observer totalPagesChangedCount]);
-  EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
-  model()->PopulateApps(1);
-  EXPECT_EQ(1, [observer totalPagesChangedCount]);
-  EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
-  ReplaceTestModel(0);
-  EXPECT_EQ(2, [observer totalPagesChangedCount]);
-  EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
-  ReplaceTestModel(kItemsPerPage * 3 + 1);
-  EXPECT_EQ(3, [observer totalPagesChangedCount]);
-  EXPECT_EQ(4u, [apps_grid_controller_ pageCount]);
-
-  EXPECT_FALSE([observer readVisibilityDidChange]);
-  EXPECT_EQ(0, [observer selectedPageChangedCount]);
-
-  [apps_grid_controller_ setPaginationObserver:nil];
-}
-
-// Test AppsGridPaginationObserver selectedPageChanged().
-TEST_F(AppsGridControllerTest, PaginationObserverSelectedPageChanged) {
-  base::scoped_nsobject<TestPaginationObserver> observer(
-      [[TestPaginationObserver alloc] init]);
-  [apps_grid_controller_ setPaginationObserver:observer];
-  EXPECT_EQ(0, [[NSAnimationContext currentContext] duration]);
-
-  ReplaceTestModel(kItemsPerPage * 3 + 1);
-  EXPECT_EQ(1, [observer totalPagesChangedCount]);
-  EXPECT_EQ(4u, [apps_grid_controller_ pageCount]);
-
-  EXPECT_FALSE([observer readVisibilityDidChange]);
-  EXPECT_EQ(0, [observer selectedPageChangedCount]);
-
-  [apps_grid_controller_ scrollToPage:1];
-  EXPECT_EQ(1, [observer selectedPageChangedCount]);
-  EXPECT_EQ(1, [observer lastNewSelectedPage]);
-  EXPECT_TRUE([observer readVisibilityDidChange]);
-  EXPECT_FALSE([observer readVisibilityDidChange]);  // Testing test behaviour.
-  EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:0]);
-  EXPECT_EQ(1.0, [apps_grid_controller_ visiblePortionOfPage:1]);
-  EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:2]);
-  EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:3]);
-
-  [apps_grid_controller_ scrollToPage:0];
-  EXPECT_EQ(2, [observer selectedPageChangedCount]);
-  EXPECT_EQ(0, [observer lastNewSelectedPage]);
-  EXPECT_TRUE([observer readVisibilityDidChange]);
-  EXPECT_EQ(1.0, [apps_grid_controller_ visiblePortionOfPage:0]);
-  EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:1]);
-
-  [apps_grid_controller_ scrollToPage:3];
-  // Note: with no animations, there is only a single page change. However, with
-  // animations we expect multiple updates depending on the rate that the scroll
-  // view updates and sends out NSViewBoundsDidChangeNotification.
-  EXPECT_EQ(3, [observer selectedPageChangedCount]);
-  EXPECT_EQ(3, [observer lastNewSelectedPage]);
-  EXPECT_TRUE([observer readVisibilityDidChange]);
-  EXPECT_EQ(0.0, [apps_grid_controller_ visiblePortionOfPage:0]);
-  EXPECT_EQ(1.0, [apps_grid_controller_ visiblePortionOfPage:3]);
-
-  [apps_grid_controller_ setPaginationObserver:nil];
-}
-
-// Test basic item moves with two items; swapping them around, dragging outside
-// of the view bounds, and dragging on the background.
-TEST_F(AppsGridControllerTest, DragAndDropSimple) {
-  model()->PopulateApps(2);
-  NSCollectionView* page = [apps_grid_controller_ collectionViewAtPageIndex:0];
-  NSEvent* mouse_at_cell_0 = MouseEventInCell(page, 0);
-  NSEvent* mouse_at_cell_1 = MouseEventInCell(page, 1);
-  NSEvent* mouse_at_page_centre = MouseEventInCell(page, 6);
-  NSEvent* mouse_off_page = MouseEventInCell(page, kItemsPerPage * 2);
-
-  const std::string kOrdered = "Item 0,Item 1";
-  const std::string kSwapped = "Item 1,Item 0";
-  const std::string kOrderedView = "|Item 0,Item 1|";
-  const std::string kSwappedView = "|Item 1,Item 0|";
-
-  EXPECT_EQ(kOrdered, model()->GetModelContent());
-  EXPECT_EQ(kOrderedView, GetViewContent());
-  AppsCollectionViewDragManager* drag_manager =
-      [apps_grid_controller_ dragManager];
-
-  // Drag first item over the second item and release.
-  [drag_manager onMouseDownInPage:page
-                        withEvent:mouse_at_cell_0];
-  [drag_manager onMouseDragged:mouse_at_cell_1];
-  EXPECT_EQ(kOrdered, model()->GetModelContent());
-  EXPECT_EQ(kSwappedView, GetViewContent());  // View swaps first.
-  [drag_manager onMouseUp:mouse_at_cell_1];
-  EXPECT_EQ(kSwapped, model()->GetModelContent());
-  EXPECT_EQ(kSwappedView, GetViewContent());
-
-  // Drag item back.
-  [drag_manager onMouseDownInPage:page
-                        withEvent:mouse_at_cell_1];
-  [drag_manager onMouseDragged:mouse_at_cell_0];
-  EXPECT_EQ(kSwapped, model()->GetModelContent());
-  EXPECT_EQ(kOrderedView, GetViewContent());
-  [drag_manager onMouseUp:mouse_at_cell_0];
-  EXPECT_EQ(kOrdered, model()->GetModelContent());
-  EXPECT_EQ(kOrderedView, GetViewContent());
-
-  // Drag first item to centre of view (should put in last place).
-  [drag_manager onMouseDownInPage:page
-                        withEvent:mouse_at_cell_0];
-  [drag_manager onMouseDragged:mouse_at_page_centre];
-  EXPECT_EQ(kOrdered, model()->GetModelContent());
-  EXPECT_EQ(kSwappedView, GetViewContent());
-  [drag_manager onMouseUp:mouse_at_page_centre];
-  EXPECT_EQ(kSwapped, model()->GetModelContent());
-  EXPECT_EQ(kSwappedView, GetViewContent());
-
-  // Drag item to centre again (should leave it in the last place).
-  [drag_manager onMouseDownInPage:page
-                        withEvent:mouse_at_cell_1];
-  [drag_manager onMouseDragged:mouse_at_page_centre];
-  EXPECT_EQ(kSwapped, model()->GetModelContent());
-  EXPECT_EQ(kSwappedView, GetViewContent());
-  [drag_manager onMouseUp:mouse_at_page_centre];
-  EXPECT_EQ(kSwapped, model()->GetModelContent());
-  EXPECT_EQ(kSwappedView, GetViewContent());
-
-  // Drag starting in the centre of the view, should do nothing.
-  [drag_manager onMouseDownInPage:page
-                        withEvent:mouse_at_page_centre];
-  [drag_manager onMouseDragged:mouse_at_cell_0];
-  EXPECT_EQ(kSwapped, model()->GetModelContent());
-  EXPECT_EQ(kSwappedView, GetViewContent());
-  [drag_manager onMouseUp:mouse_at_cell_0];
-  EXPECT_EQ(kSwapped, model()->GetModelContent());
-  EXPECT_EQ(kSwappedView, GetViewContent());
-
-  // Click off page.
-  [drag_manager onMouseDownInPage:page
-                        withEvent:mouse_off_page];
-  [drag_manager onMouseDragged:mouse_at_cell_0];
-  EXPECT_EQ(kSwapped, model()->GetModelContent());
-  EXPECT_EQ(kSwappedView, GetViewContent());
-  [drag_manager onMouseUp:mouse_at_cell_0];
-  EXPECT_EQ(kSwapped, model()->GetModelContent());
-  EXPECT_EQ(kSwappedView, GetViewContent());
-
-  // Drag to first over second item, then off page.
-  [drag_manager onMouseDownInPage:page
-                        withEvent:mouse_at_cell_0];
-  [drag_manager onMouseDragged:mouse_at_cell_1];
-  EXPECT_EQ(kSwapped, model()->GetModelContent());
-  EXPECT_EQ(kOrderedView, GetViewContent());
-  [drag_manager onMouseDragged:mouse_off_page];
-  EXPECT_EQ(kSwapped, model()->GetModelContent());
-  EXPECT_EQ(kOrderedView, GetViewContent());
-  [drag_manager onMouseUp:mouse_off_page];
-  EXPECT_EQ(kOrdered, model()->GetModelContent());
-  EXPECT_EQ(kOrderedView, GetViewContent());
-
-  // Replace with an empty model, and ensure we do not break.
-  ReplaceTestModel(0);
-  EXPECT_EQ(std::string(), model()->GetModelContent());
-  EXPECT_EQ(std::string("||"), GetViewContent());
-  [drag_manager onMouseDownInPage:page
-                        withEvent:mouse_at_cell_0];
-  [drag_manager onMouseDragged:mouse_at_cell_1];
-  [drag_manager onMouseUp:mouse_at_cell_1];
-  EXPECT_EQ(std::string(), model()->GetModelContent());
-  EXPECT_EQ(std::string("||"), GetViewContent());
-}
-
-// Test item moves between pages.
-TEST_F(AppsGridControllerTest, DragAndDropMultiPage) {
-  const size_t kPagesToTest = 3;
-  // Put one item on the last page to hit more edge cases.
-  ReplaceTestModel(kItemsPerPage * (kPagesToTest - 1) + 1);
-  NSCollectionView* page[kPagesToTest];
-  for (size_t i = 0; i < kPagesToTest; ++i)
-    page[i] = [apps_grid_controller_ collectionViewAtPageIndex:i];
-
-  const std::string kSecondItemMovedToSecondPage =
-      "|Item 0,Item 2,Item 3,Item 4,Item 5,Item 6,Item 7,Item 8,"
-      "Item 9,Item 10,Item 11,Item 12,Item 13,Item 14,Item 15,Item 16|"
-      "|Item 17,Item 1,Item 18,Item 19,Item 20,Item 21,Item 22,Item 23,"
-      "Item 24,Item 25,Item 26,Item 27,Item 28,Item 29,Item 30,Item 31|"
-      "|Item 32|";
-
-  NSEvent* mouse_at_cell_0 = MouseEventInCell(page[0], 0);
-  NSEvent* mouse_at_cell_1 = MouseEventInCell(page[0], 1);
-  AppsCollectionViewDragManager* drag_manager =
-      [apps_grid_controller_ dragManager];
-  [drag_manager onMouseDownInPage:page[0]
-                        withEvent:mouse_at_cell_1];
-
-  // Initiate dragging before changing pages.
-  [drag_manager onMouseDragged:mouse_at_cell_0];
-
-  // Scroll to the second page.
-  [apps_grid_controller_ scrollToPage:1];
-  [drag_manager onMouseDragged:mouse_at_cell_1];
-
-  // Do one exhaustive check, and then spot-check corner cases.
-  EXPECT_EQ(kSecondItemMovedToSecondPage, GetViewContent());
-  EXPECT_EQ(0u, GetPageIndexForItem(0));
-  EXPECT_EQ(1u, GetPageIndexForItem(1));
-  EXPECT_EQ(0u, GetPageIndexForItem(2));
-  EXPECT_EQ(0u, GetPageIndexForItem(16));
-  EXPECT_EQ(1u, GetPageIndexForItem(17));
-  EXPECT_EQ(1u, GetPageIndexForItem(31));
-  EXPECT_EQ(2u, GetPageIndexForItem(32));
-
-  // Scroll to the third page and drag some more.
-  [apps_grid_controller_ scrollToPage:2];
-  [drag_manager onMouseDragged:mouse_at_cell_1];
-  EXPECT_EQ(2u, GetPageIndexForItem(1));
-  EXPECT_EQ(1u, GetPageIndexForItem(31));
-  EXPECT_EQ(1u, GetPageIndexForItem(32));
-
-  // Scroll backwards.
-  [apps_grid_controller_ scrollToPage:1];
-  [drag_manager onMouseDragged:mouse_at_cell_1];
-  EXPECT_EQ(kSecondItemMovedToSecondPage, GetViewContent());
-  EXPECT_EQ(1u, GetPageIndexForItem(1));
-  EXPECT_EQ(1u, GetPageIndexForItem(31));
-  EXPECT_EQ(2u, GetPageIndexForItem(32));
-
-  // Simulate installing an item while dragging (or have it appear during sync).
-  model()->PopulateAppWithId(33);
-  // Item should go back to its position before the drag.
-  EXPECT_EQ(0u, GetPageIndexForItem(1));
-  EXPECT_EQ(1u, GetPageIndexForItem(31));
-  EXPECT_EQ(2u, GetPageIndexForItem(32));
-  // New item should appear at end.
-  EXPECT_EQ(2u, GetPageIndexForItem(33));
-
-  // Scroll to end again, and keep dragging (should be ignored).
-  [apps_grid_controller_ scrollToPage:2];
-  [drag_manager onMouseDragged:mouse_at_cell_0];
-  EXPECT_EQ(0u, GetPageIndexForItem(1));
-  [drag_manager onMouseUp:mouse_at_cell_0];
-  EXPECT_EQ(0u, GetPageIndexForItem(1));
-}
-
-// Test scrolling when dragging past edge or over the pager.
-TEST_F(AppsGridControllerTest, ScrollingWhileDragging) {
-  base::scoped_nsobject<TestPaginationObserver> observer(
-      [[TestPaginationObserver alloc] init]);
-  [apps_grid_controller_ setPaginationObserver:observer];
-
-  ReplaceTestModel(kItemsPerPage * 3);
-  // Start on the middle page.
-  [apps_grid_controller_ scrollToPage:1];
-  NSCollectionView* page = [apps_grid_controller_ collectionViewAtPageIndex:1];
-  NSEvent* mouse_at_cell_0 = MouseEventInCell(page, 0);
-
-  NSEvent* at_center = MouseEventForScroll([apps_grid_controller_ view], 0.0);
-  NSEvent* at_left = MouseEventForScroll([apps_grid_controller_ view], -1.1);
-  NSEvent* at_right = MouseEventForScroll([apps_grid_controller_ view], 1.1);
-
-  AppsCollectionViewDragManager* drag_manager =
-      [apps_grid_controller_ dragManager];
-  [drag_manager onMouseDownInPage:page
-                        withEvent:mouse_at_cell_0];
-  [drag_manager onMouseDragged:at_center];
-
-  // Nothing should be scheduled: target page is visible page.
-  EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(1u, [apps_grid_controller_ scheduledScrollPage]);
-
-  // Drag to the left, should go to first page and no further.
-  [drag_manager onMouseDragged:at_left];
-  EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(0u, [apps_grid_controller_ scheduledScrollPage]);
-  [apps_grid_controller_ scrollToPage:0];  // Commit without timer for testing.
-  [drag_manager onMouseDragged:at_left];
-  EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(0u, [apps_grid_controller_ scheduledScrollPage]);
-
-  // Drag to the right, should go to last page and no futher.
-  [drag_manager onMouseDragged:at_right];
-  EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(1u, [apps_grid_controller_ scheduledScrollPage]);
-  [apps_grid_controller_ scrollToPage:1];
-  [drag_manager onMouseDragged:at_right];
-  EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(2u, [apps_grid_controller_ scheduledScrollPage]);
-  [apps_grid_controller_ scrollToPage:2];
-  [drag_manager onMouseDragged:at_right];
-  EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(2u, [apps_grid_controller_ scheduledScrollPage]);
-
-  // Simulate a hover over the first pager segment.
-  [observer setHoveredSegmentForTest:0];
-  [drag_manager onMouseDragged:at_center];
-  EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(0u, [apps_grid_controller_ scheduledScrollPage]);
-
-  // Drag it back, should cancel schedule.
-  [observer setHoveredSegmentForTest:-1];
-  [drag_manager onMouseDragged:at_center];
-  EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(2u, [apps_grid_controller_ scheduledScrollPage]);
-
-  // Hover again, now over middle segment, and ensure a release also cancels.
-  [observer setHoveredSegmentForTest:1];
-  [drag_manager onMouseDragged:at_center];
-  EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(1u, [apps_grid_controller_ scheduledScrollPage]);
-  [drag_manager onMouseUp:at_center];
-  EXPECT_EQ(2u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(2u, [apps_grid_controller_ scheduledScrollPage]);
-
-  [apps_grid_controller_ setPaginationObserver:nil];
-}
-
-TEST_F(AppsGridControllerTest, ContextMenus) {
-  AppListItemWithMenu* item_two_model = new AppListItemWithMenu("Item Two");
-  model()->AddItem(new AppListItemWithMenu("Item One"));
-  model()->AddItem(item_two_model);
-  EXPECT_EQ(2u, [apps_grid_controller_ itemCount]);
-
-  NSCollectionView* page = [apps_grid_controller_ collectionViewAtPageIndex:0];
-  NSEvent* mouse_at_cell_0 = MouseEventInCell(page, 0);
-  NSEvent* mouse_at_cell_1 = MouseEventInCell(page, 1);
-
-  NSMenu* menu = [page menuForEvent:mouse_at_cell_0];
-  EXPECT_EQ(1, [menu numberOfItems]);
-  EXPECT_NSEQ(@"Menu For: Item One", [[menu itemAtIndex:0] title]);
-
-  // Test a context menu request while the item is still installing.
-  item_two_model->SetMenuReadyForTesting(false);
-  menu = [page menuForEvent:mouse_at_cell_1];
-  EXPECT_EQ(nil, menu);
-
-  item_two_model->SetMenuReadyForTesting(true);
-  menu = [page menuForEvent:mouse_at_cell_1];
-  EXPECT_EQ(1, [menu numberOfItems]);
-  EXPECT_NSEQ(@"Menu For: Item Two", [[menu itemAtIndex:0] title]);
-
-  // Test that a button being held down with the left button does not also show
-  // a context menu.
-  [GetItemViewAt(0) highlight:YES];
-  EXPECT_FALSE([page menuForEvent:mouse_at_cell_0]);
-  [GetItemViewAt(0) highlight:NO];
-  EXPECT_TRUE([page menuForEvent:mouse_at_cell_0]);
-}
-
-}  // namespace test
-}  // namespace app_list
diff --git a/ui/app_list/cocoa/apps_grid_view_item.h b/ui/app_list/cocoa/apps_grid_view_item.h
deleted file mode 100644
index 8eae04b..0000000
--- a/ui/app_list/cocoa/apps_grid_view_item.h
+++ /dev/null
@@ -1,56 +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.
-
-#ifndef UI_APP_LIST_COCOA_APPS_GRID_VIEW_ITEM_H_
-#define UI_APP_LIST_COCOA_APPS_GRID_VIEW_ITEM_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include <memory>
-
-#include "ui/app_list/app_list_export.h"
-#import "ui/base/cocoa/tracking_area.h"
-
-namespace app_list {
-class AppListItem;
-class ItemModelObserverBridge;
-}
-
-// AppsGridViewItem is the controller for an NSButton representing an app item
-// on an NSCollectionView controlled by an AppsGridController.
-APP_LIST_EXPORT
-@interface AppsGridViewItem : NSCollectionViewItem {
- @private
-  std::unique_ptr<app_list::ItemModelObserverBridge> observerBridge_;
-  base::scoped_nsobject<NSProgressIndicator> progressIndicator_;
-
-  // Used to highlight the background on hover.
-  ui::ScopedCrTrackingArea trackingArea_;
-}
-
-@property(readonly, nonatomic) NSProgressIndicator* progressIndicator;
-
-// Designated initializer. |tileSize| is the size of tiles in the grid.
-- (id)initWithSize:(NSSize)tileSize;
-
-// Set the represented model, updating views. Clears if |itemModel| is NULL.
-- (void)setModel:(app_list::AppListItem*)itemModel;
-
-// Model accessor, via the |observerBridge_|.
-- (app_list::AppListItem*)model;
-
-// Return the button portion of the item, showing the icon and title.
-- (NSButton*)button;
-
-// Generate and return a context menu, populated using the represented model.
-- (NSMenu*)contextMenu;
-
-// Take a snapshot of the grid cell with correct layout, then hide the button.
-// If |isRestore| is true, the snapshot includes the label and items hidden for
-// the initial snapshot are restored.
-- (NSBitmapImageRep*)dragRepresentationForRestore:(BOOL)isRestore;
-
-@end
-
-#endif  // UI_APP_LIST_COCOA_APPS_GRID_VIEW_ITEM_H_
diff --git a/ui/app_list/cocoa/apps_grid_view_item.mm b/ui/app_list/cocoa/apps_grid_view_item.mm
deleted file mode 100644
index 9a4198a..0000000
--- a/ui/app_list/cocoa/apps_grid_view_item.mm
+++ /dev/null
@@ -1,455 +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.
-
-#import "ui/app_list/cocoa/apps_grid_view_item.h"
-
-#include "base/mac/foundation_util.h"
-#include "base/mac/mac_util.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#include "base/strings/sys_string_conversions.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_item.h"
-#include "ui/app_list/app_list_item_observer.h"
-#import "ui/app_list/cocoa/apps_grid_controller.h"
-#import "ui/base/cocoa/menu_controller.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/font_list.h"
-#include "ui/gfx/image/image_skia_operations.h"
-#include "ui/gfx/image/image_skia_util_mac.h"
-#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
-
-namespace {
-
-// Padding from the top of the tile to the top of the app icon.
-const CGFloat kTileTopPadding = 10;
-
-const CGFloat kIconSize = 48;
-
-const CGFloat kProgressBarHorizontalPadding = 8;
-const CGFloat kProgressBarVerticalPadding = 13;
-
-// On Mac, fonts of the same enum from ResourceBundle are larger. The smallest
-// enum is already used, so it needs to be reduced further to match Windows.
-const int kMacFontSizeDelta = -1;
-
-}  // namespace
-
-@class AppsGridItemBackgroundView;
-
-@interface AppsGridViewItem ()
-
-// Typed accessor for the root view.
-- (AppsGridItemBackgroundView*)itemBackgroundView;
-
-// Bridged methods from app_list::AppListItemObserver:
-// Update the title, correctly setting the color if the button is highlighted.
-- (void)updateButtonTitle;
-
-// Update the button image after ensuring its dimensions are |kIconSize|.
-- (void)updateButtonImage;
-
-// Add or remove a progress bar from the view.
-- (void)setItemIsInstalling:(BOOL)isInstalling;
-
-// Update the progress bar to represent |percent|, or make it indeterminate if
-// |percent| is -1, when unpacking begins.
-- (void)setPercentDownloaded:(int)percent;
-
-@end
-
-namespace app_list {
-
-class ItemModelObserverBridge : public app_list::AppListItemObserver {
- public:
-  ItemModelObserverBridge(AppsGridViewItem* parent, AppListItem* model);
-  ~ItemModelObserverBridge() override;
-
-  AppListItem* model() { return model_; }
-  NSMenu* GetContextMenu();
-
-  void ItemIconChanged() override;
-  void ItemNameChanged() override;
-  void ItemIsInstallingChanged() override;
-  void ItemPercentDownloadedChanged() override;
-
- private:
-  AppsGridViewItem* parent_;  // Weak. Owns us.
-  AppListItem* model_;  // Weak. Owned by AppListModel.
-  base::scoped_nsobject<MenuController> context_menu_controller_;
-
-  DISALLOW_COPY_AND_ASSIGN(ItemModelObserverBridge);
-};
-
-ItemModelObserverBridge::ItemModelObserverBridge(AppsGridViewItem* parent,
-                                       AppListItem* model)
-    : parent_(parent),
-      model_(model) {
-  model_->AddObserver(this);
-}
-
-ItemModelObserverBridge::~ItemModelObserverBridge() {
-  model_->RemoveObserver(this);
-}
-
-NSMenu* ItemModelObserverBridge::GetContextMenu() {
-  if (!context_menu_controller_) {
-    ui::MenuModel* menu_model = model_->GetContextMenuModel();
-    if (!menu_model)
-      return nil;
-
-    context_menu_controller_.reset(
-        [[MenuController alloc] initWithModel:menu_model
-                       useWithPopUpButtonCell:NO]);
-  }
-  return [context_menu_controller_ menu];
-}
-
-void ItemModelObserverBridge::ItemIconChanged() {
-  [parent_ updateButtonImage];
-}
-
-void ItemModelObserverBridge::ItemNameChanged() {
-  [parent_ updateButtonTitle];
-}
-
-void ItemModelObserverBridge::ItemIsInstallingChanged() {
-  [parent_ setItemIsInstalling:model_->is_installing()];
-}
-
-void ItemModelObserverBridge::ItemPercentDownloadedChanged() {
-  [parent_ setPercentDownloaded:model_->percent_downloaded()];
-}
-
-}  // namespace app_list
-
-// Container for an NSButton to allow proper alignment of the icon in the apps
-// grid, and to draw with a highlight when selected.
-@interface AppsGridItemBackgroundView : NSView {
- @private
-  BOOL selected_;
-}
-
-- (NSButton*)button;
-
-- (void)setSelected:(BOOL)flag;
-
-@end
-
-@interface AppsGridItemButtonCell : NSButtonCell {
- @private
-  BOOL hasShadow_;
-}
-
-@property(assign, nonatomic) BOOL hasShadow;
-
-@end
-
-@interface AppsGridItemButton : NSButton;
-@end
-
-@implementation AppsGridItemBackgroundView
-
-- (NSButton*)button {
-  // These views are part of a prototype NSCollectionViewItem, copied with an
-  // NSCoder. Rather than encoding additional members, the following relies on
-  // the button always being the first item added to AppsGridItemBackgroundView.
-  return base::mac::ObjCCastStrict<NSButton>([[self subviews] objectAtIndex:0]);
-}
-
-- (void)setSelected:(BOOL)flag {
-  DCHECK(selected_ != flag);
-  selected_ = flag;
-  [self setNeedsDisplay:YES];
-}
-
-// Ignore all hit tests. The grid controller needs to be the owner of any drags.
-- (NSView*)hitTest:(NSPoint)aPoint {
-  return nil;
-}
-
-- (void)drawRect:(NSRect)dirtyRect {
-  if (!selected_)
-    return;
-
-  [skia::SkColorToSRGBNSColor(app_list::kSelectedColor) set];
-  NSRectFillUsingOperation(dirtyRect, NSCompositeSourceOver);
-}
-
-- (void)mouseDown:(NSEvent*)theEvent {
-  [[[self button] cell] setHighlighted:YES];
-}
-
-- (void)mouseDragged:(NSEvent*)theEvent {
-  NSPoint pointInView = [self convertPoint:[theEvent locationInWindow]
-                                  fromView:nil];
-  BOOL isInView = [self mouse:pointInView inRect:[self bounds]];
-  [[[self button] cell] setHighlighted:isInView];
-}
-
-- (void)mouseUp:(NSEvent*)theEvent {
-  NSPoint pointInView = [self convertPoint:[theEvent locationInWindow]
-                                  fromView:nil];
-  if (![self mouse:pointInView inRect:[self bounds]])
-    return;
-
-  [[self button] performClick:self];
-}
-
-@end
-
-@implementation AppsGridViewItem
-
-- (id)initWithSize:(NSSize)tileSize {
-  if ((self = [super init])) {
-    base::scoped_nsobject<AppsGridItemButton> prototypeButton(
-        [[AppsGridItemButton alloc] initWithFrame:NSMakeRect(
-            0, 0, tileSize.width, tileSize.height - kTileTopPadding)]);
-
-    // This NSButton style always positions the icon at the very top of the
-    // button frame. AppsGridViewItem uses an enclosing view so that it is
-    // visually correct.
-    [prototypeButton setImagePosition:NSImageAbove];
-    [prototypeButton setButtonType:NSMomentaryChangeButton];
-    [prototypeButton setBordered:NO];
-
-    base::scoped_nsobject<AppsGridItemBackgroundView> prototypeButtonBackground(
-        [[AppsGridItemBackgroundView alloc]
-            initWithFrame:NSMakeRect(0, 0, tileSize.width, tileSize.height)]);
-    [prototypeButtonBackground addSubview:prototypeButton];
-    [self setView:prototypeButtonBackground];
-  }
-  return self;
-}
-
-- (NSProgressIndicator*)progressIndicator {
-  return progressIndicator_;
-}
-
-- (void)updateButtonTitle {
-  if (progressIndicator_)
-    return;
-
-  base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
-      [[NSMutableParagraphStyle alloc] init]);
-  [paragraphStyle setLineBreakMode:NSLineBreakByTruncatingTail];
-  [paragraphStyle setAlignment:NSCenterTextAlignment];
-  NSDictionary* titleAttributes = @{
-    NSParagraphStyleAttributeName : paragraphStyle,
-    NSFontAttributeName : ui::ResourceBundle::GetSharedInstance()
-                              .GetFontList(app_list::kItemTextFontStyle)
-                              .DeriveWithSizeDelta(kMacFontSizeDelta)
-                              .GetPrimaryFont()
-                              .GetNativeFont(),
-    NSForegroundColorAttributeName :
-        skia::SkColorToSRGBNSColor(app_list::kGridTitleColor)
-  };
-  NSString* buttonTitle =
-      base::SysUTF8ToNSString([self model]->GetDisplayName());
-  base::scoped_nsobject<NSAttributedString> attributedTitle(
-      [[NSAttributedString alloc] initWithString:buttonTitle
-                                      attributes:titleAttributes]);
-  [[self button] setAttributedTitle:attributedTitle];
-
-  // If the display name would be truncated in the NSButton, or if the display
-  // name differs from the full name, add a tooltip showing the full name.
-  NSRect titleRect =
-      [[[self button] cell] titleRectForBounds:[[self button] bounds]];
-  if ([self model]->name() == [self model]->GetDisplayName() &&
-      [attributedTitle size].width < NSWidth(titleRect)) {
-    [[self view] removeAllToolTips];
-  } else {
-    [[self view] setToolTip:base::SysUTF8ToNSString([self model]->name())];
-  }
-}
-
-- (void)updateButtonImage {
-  const gfx::Size iconSize = gfx::Size(kIconSize, kIconSize);
-  gfx::ImageSkia icon = [self model]->icon();
-  if (icon.size() != iconSize) {
-    icon = gfx::ImageSkiaOperations::CreateResizedImage(
-        icon, skia::ImageOperations::RESIZE_BEST, iconSize);
-  }
-  NSImage* buttonImage = gfx::NSImageFromImageSkiaWithColorSpace(
-      icon, base::mac::GetSRGBColorSpace());
-  [[self button] setImage:buttonImage];
-  [[[self button] cell] setHasShadow:true];
-}
-
-- (void)setModel:(app_list::AppListItem*)itemModel {
-  [trackingArea_.get() clearOwner];
-  if (!itemModel) {
-    observerBridge_.reset();
-    return;
-  }
-
-  observerBridge_.reset(new app_list::ItemModelObserverBridge(self, itemModel));
-  [self updateButtonTitle];
-  [self updateButtonImage];
-
-  if (trackingArea_.get())
-    [[self view] removeTrackingArea:trackingArea_.get()];
-
-  trackingArea_.reset(
-      [[CrTrackingArea alloc] initWithRect:NSZeroRect
-                                   options:NSTrackingInVisibleRect |
-                                           NSTrackingMouseEnteredAndExited |
-                                           NSTrackingActiveInKeyWindow
-                                     owner:self
-                                  userInfo:nil]);
-  [[self view] addTrackingArea:trackingArea_.get()];
-}
-
-- (app_list::AppListItem*)model {
-  return observerBridge_->model();
-}
-
-- (NSButton*)button {
-  return [[self itemBackgroundView] button];
-}
-
-- (NSMenu*)contextMenu {
-  // Don't show the menu if button is already held down, e.g. with a left-click.
-  if ([[[self button] cell] isHighlighted])
-    return nil;
-
-  [self setSelected:YES];
-  return observerBridge_->GetContextMenu();
-}
-
-- (NSBitmapImageRep*)dragRepresentationForRestore:(BOOL)isRestore {
-  NSButton* button = [self button];
-  NSView* itemView = [self view];
-
-  // The snapshot is never drawn as if it was selected. Also remove the cell
-  // highlight on the button image, added when it was clicked.
-  [button setHidden:NO];
-  [[button cell] setHighlighted:NO];
-  [self setSelected:NO];
-  [progressIndicator_ setHidden:YES];
-  if (isRestore)
-    [self updateButtonTitle];
-  else
-    [button setTitle:@""];
-
-  NSBitmapImageRep* imageRep =
-      [itemView bitmapImageRepForCachingDisplayInRect:[itemView visibleRect]];
-  [itemView cacheDisplayInRect:[itemView visibleRect]
-              toBitmapImageRep:imageRep];
-
-  if (isRestore) {
-    [progressIndicator_ setHidden:NO];
-    [self setSelected:YES];
-  }
-  // Button is always hidden until the drag animation completes.
-  [button setHidden:YES];
-  return imageRep;
-}
-
-- (void)setItemIsInstalling:(BOOL)isInstalling {
-  if (!isInstalling == !progressIndicator_)
-    return;
-
-  if (!isInstalling) {
-    [progressIndicator_ removeFromSuperview];
-    progressIndicator_.reset();
-    [self updateButtonTitle];
-    [self setSelected:YES];
-    return;
-  }
-
-  NSRect rect = NSMakeRect(
-      kProgressBarHorizontalPadding,
-      kProgressBarVerticalPadding,
-      NSWidth([[self view] bounds]) - 2 * kProgressBarHorizontalPadding,
-      NSProgressIndicatorPreferredAquaThickness);
-  [[self button] setTitle:@""];
-  progressIndicator_.reset([[NSProgressIndicator alloc] initWithFrame:rect]);
-  [progressIndicator_ setIndeterminate:NO];
-  [progressIndicator_ setControlSize:NSSmallControlSize];
-  [[self view] addSubview:progressIndicator_];
-}
-
-- (void)setPercentDownloaded:(int)percent {
-  // In a corner case, items can be installing when they are first added. For
-  // those, the icon will start desaturated. Wait for a progress update before
-  // showing the progress bar.
-  [self setItemIsInstalling:YES];
-  if (percent != -1) {
-    [progressIndicator_ setDoubleValue:percent];
-    return;
-  }
-
-  // Otherwise, fully downloaded and waiting for install to complete.
-  [progressIndicator_ setIndeterminate:YES];
-  [progressIndicator_ startAnimation:self];
-}
-
-- (AppsGridItemBackgroundView*)itemBackgroundView {
-  return base::mac::ObjCCastStrict<AppsGridItemBackgroundView>([self view]);
-}
-
-- (void)mouseEntered:(NSEvent*)theEvent {
-  [self setSelected:YES];
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
-  [self setSelected:NO];
-}
-
-- (void)setSelected:(BOOL)flag {
-  if ([self isSelected] == flag)
-    return;
-
-  [[self itemBackgroundView] setSelected:flag];
-  [super setSelected:flag];
-  [self updateButtonTitle];
-}
-
-@end
-
-@implementation AppsGridItemButton
-
-+ (Class)cellClass {
-  return [AppsGridItemButtonCell class];
-}
-
-@end
-
-@implementation AppsGridItemButtonCell
-
-@synthesize hasShadow = hasShadow_;
-
-- (void)drawImage:(NSImage*)image
-        withFrame:(NSRect)frame
-           inView:(NSView*)controlView {
-  if (!hasShadow_) {
-    [super drawImage:image
-           withFrame:frame
-              inView:controlView];
-    return;
-  }
-
-  base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
-  gfx::ScopedNSGraphicsContextSaveGState context;
-  [shadow setShadowOffset:NSMakeSize(0, -2)];
-  [shadow setShadowBlurRadius:2.0];
-  [shadow setShadowColor:[NSColor colorWithCalibratedWhite:0
-                                                     alpha:0.14]];
-  [shadow set];
-
-  [super drawImage:image
-         withFrame:frame
-            inView:controlView];
-}
-
-// Workaround for http://crbug.com/324365: AppKit in Mavericks tries to call
-// - [NSButtonCell item] when inspecting accessibility. Without this, an
-// unrecognized selector exception is thrown inside AppKit, crashing Chrome.
-- (id)item {
-  return nil;
-}
-
-@end
diff --git a/ui/app_list/cocoa/apps_pagination_model_observer.h b/ui/app_list/cocoa/apps_pagination_model_observer.h
deleted file mode 100644
index a2f463f..0000000
--- a/ui/app_list/cocoa/apps_pagination_model_observer.h
+++ /dev/null
@@ -1,26 +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.
-
-#ifndef UI_APP_LIST_COCOA_APPS_PAGINATION_MODEL_OBSERVER_H_
-#define UI_APP_LIST_COCOA_APPS_PAGINATION_MODEL_OBSERVER_H_
-
-// Observer protocol for page changes. Compare with
-// app_list::PaginationModelObserver.
-@protocol AppsPaginationModelObserver
-
-// Invoked when the total number of pages has changed.
-- (void)totalPagesChanged;
-
-// Invoked when the selected page index is changed.
-- (void)selectedPageChanged:(int)newSelected;
-
-// Invoked when the portion of pages that are visible have changed.
-- (void)pageVisibilityChanged;
-
-// Return a pager segment at |locationInWindow| or -1 if there is none.
-- (NSInteger)pagerSegmentAtLocation:(NSPoint)locationInWindow;
-
-@end
-
-#endif  // UI_APP_LIST_COCOA_APPS_PAGINATION_MODEL_OBSERVER_H_
diff --git a/ui/app_list/cocoa/apps_search_box_controller.h b/ui/app_list/cocoa/apps_search_box_controller.h
deleted file mode 100644
index 553ba98..0000000
--- a/ui/app_list/cocoa/apps_search_box_controller.h
+++ /dev/null
@@ -1,68 +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.
-
-#ifndef UI_APP_LIST_COCOA_APPS_SEARCH_BOX_CONTROLLER_H_
-#define UI_APP_LIST_COCOA_APPS_SEARCH_BOX_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include <memory>
-
-#include "base/mac/scoped_nsobject.h"
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-class AppListMenu;
-class AppListModel;
-class AppListViewDelegate;
-class SearchBoxModel;
-class SearchBoxModelObserverBridge;
-}
-
-@class AppListMenuController;
-@class HoverImageMenuButton;
-@class SearchTextField;
-
-@protocol AppsSearchBoxDelegate<NSTextFieldDelegate>
-
-- (app_list::AppListViewDelegate*)appListDelegate;
-- (app_list::SearchBoxModel*)searchBoxModel;
-- (app_list::AppListModel*)appListModel;
-- (void)modelTextDidChange;
-
-@end
-
-// Controller for the search box in the topmost portion of the app list.
-APP_LIST_EXPORT
-@interface AppsSearchBoxController : NSViewController<NSTextFieldDelegate> {
- @private
-  base::scoped_nsobject<SearchTextField> searchTextField_;
-  base::scoped_nsobject<NSImageView> searchImageView_;
-  base::scoped_nsobject<HoverImageMenuButton> menuButton_;
-  base::scoped_nsobject<AppListMenuController> menuController_;
-  std::unique_ptr<app_list::SearchBoxModelObserverBridge> bridge_;
-  std::unique_ptr<app_list::AppListMenu> appListMenu_;
-
-  id<AppsSearchBoxDelegate> delegate_;  // Weak. Owns us.
-}
-
-@property(assign, nonatomic) id<AppsSearchBoxDelegate> delegate;
-
-- (id)initWithFrame:(NSRect)frame;
-- (void)clearSearch;
-
-// Rebuild the menu due to changes from the AppListViewDelegate.
-- (void)rebuildMenu;
-
-@end
-
-@interface AppsSearchBoxController (TestingAPI)
-
-- (NSTextField*)searchTextField;
-- (NSPopUpButton*)menuControl;
-- (app_list::AppListMenu*)appListMenu;
-
-@end
-
-#endif  // UI_APP_LIST_COCOA_APPS_SEARCH_BOX_CONTROLLER_H_
diff --git a/ui/app_list/cocoa/apps_search_box_controller.mm b/ui/app_list/cocoa/apps_search_box_controller.mm
deleted file mode 100644
index 19ef300..0000000
--- a/ui/app_list/cocoa/apps_search_box_controller.mm
+++ /dev/null
@@ -1,403 +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.
-
-#import "ui/app_list/cocoa/apps_search_box_controller.h"
-
-#include "base/mac/foundation_util.h"
-#include "base/mac/mac_util.h"
-#include "base/macros.h"
-#include "base/strings/sys_string_conversions.h"
-#include "ui/app_list/app_list_menu.h"
-#include "ui/app_list/app_list_model.h"
-#include "ui/app_list/resources/grit/app_list_resources.h"
-#include "ui/app_list/search_box_model.h"
-#include "ui/app_list/search_box_model_observer.h"
-#include "ui/base/cocoa/cocoa_base_utils.h"
-#import "ui/base/cocoa/controls/hover_image_menu_button.h"
-#import "ui/base/cocoa/controls/hover_image_menu_button_cell.h"
-#import "ui/base/cocoa/menu_controller.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/image/image_skia_util_mac.h"
-
-namespace {
-
-// Padding either side of the search icon and menu button.
-const CGFloat kPadding = 14;
-
-// Size of the search icon.
-const CGFloat kSearchIconDimension = 32;
-
-// Size of the menu button on the right.
-const CGFloat kMenuButtonDimension = 29;
-
-// Menu offset relative to the bottom-right corner of the menu button.
-const CGFloat kMenuYOffsetFromButton = -4;
-const CGFloat kMenuXOffsetFromButton = -7;
-
-}
-
-@interface AppsSearchBoxController ()
-
-- (NSImageView*)searchImageView;
-- (void)addSubviews;
-
-@end
-
-namespace app_list {
-
-class SearchBoxModelObserverBridge : public SearchBoxModelObserver {
- public:
-  SearchBoxModelObserverBridge(AppsSearchBoxController* parent);
-  ~SearchBoxModelObserverBridge() override;
-
-  void SetSearchText(const base::string16& text);
-
-  void IconChanged() override;
-  void SpeechRecognitionButtonPropChanged() override;
-  void HintTextChanged() override;
-  void SelectionModelChanged() override;
-  void TextChanged() override;
-
- private:
-  SearchBoxModel* GetModel();
-
-  AppsSearchBoxController* parent_;  // Weak. Owns us.
-
-  DISALLOW_COPY_AND_ASSIGN(SearchBoxModelObserverBridge);
-};
-
-SearchBoxModelObserverBridge::SearchBoxModelObserverBridge(
-    AppsSearchBoxController* parent)
-    : parent_(parent) {
-  IconChanged();
-  HintTextChanged();
-  GetModel()->AddObserver(this);
-}
-
-SearchBoxModelObserverBridge::~SearchBoxModelObserverBridge() {
-  GetModel()->RemoveObserver(this);
-}
-
-SearchBoxModel* SearchBoxModelObserverBridge::GetModel() {
-  SearchBoxModel* searchBoxModel = [[parent_ delegate] searchBoxModel];
-  DCHECK(searchBoxModel);
-  return searchBoxModel;
-}
-
-void SearchBoxModelObserverBridge::SetSearchText(const base::string16& text) {
-  SearchBoxModel* model = GetModel();
-  model->RemoveObserver(this);
-  model->SetText(text);
-  // TODO(tapted): See if this should call SetSelectionModel here.
-  model->AddObserver(this);
-}
-
-void SearchBoxModelObserverBridge::IconChanged() {
-  [[parent_ searchImageView] setImage:gfx::NSImageFromImageSkiaWithColorSpace(
-      GetModel()->icon(), base::mac::GetSRGBColorSpace())];
-}
-
-void SearchBoxModelObserverBridge::SpeechRecognitionButtonPropChanged() {
-  // TODO(mukai): implement.
-  NOTIMPLEMENTED();
-}
-
-void SearchBoxModelObserverBridge::HintTextChanged() {
-  [[[parent_ searchTextField] cell] setPlaceholderString:
-      base::SysUTF16ToNSString(GetModel()->hint_text())];
-}
-
-void SearchBoxModelObserverBridge::SelectionModelChanged() {
-  // TODO(tapted): See if anything needs to be done here for RTL.
-}
-
-void SearchBoxModelObserverBridge::TextChanged() {
-  // Currently the model text is only changed when we are not observing it, or
-  // it is changed in tests to establish a particular state.
-  [[parent_ searchTextField]
-      setStringValue:base::SysUTF16ToNSString(GetModel()->text())];
-  [[parent_ delegate] modelTextDidChange];
-}
-
-}  // namespace app_list
-
-@interface SearchTextField : NSTextField {
- @private
-  NSRect textFrameInset_;
-}
-
-@property(readonly, nonatomic) NSRect textFrameInset;
-
-- (void)setMarginsWithLeftMargin:(CGFloat)leftMargin
-                     rightMargin:(CGFloat)rightMargin;
-
-@end
-
-@interface AppListMenuController : MenuController {
- @private
-  AppsSearchBoxController* searchBoxController_;  // Weak. Owns us.
-}
-
-- (id)initWithSearchBoxController:(AppsSearchBoxController*)parent;
-
-@end
-
-@implementation AppsSearchBoxController
-
-@synthesize delegate = delegate_;
-
-- (id)initWithFrame:(NSRect)frame {
-  if ((self = [super init])) {
-    base::scoped_nsobject<NSView> containerView(
-        [[NSView alloc] initWithFrame:frame]);
-    [self setView:containerView];
-    [self addSubviews];
-  }
-  return self;
-}
-
-- (void)clearSearch {
-  [searchTextField_ setStringValue:@""];
-  // -controlTextDidChange:'s parameter is marked nonnull in the 10.11 SDK,
-  // so pass a dummy object even though we know that this class's implementation
-  // never looks at the parameter.
-  [self controlTextDidChange:[NSNotification notificationWithName:@""
-                                                           object:self]];
-}
-
-- (void)rebuildMenu {
-  if (![delegate_ appListDelegate])
-    return;
-
-  menuController_.reset();
-  appListMenu_.reset(
-      new app_list::AppListMenu([delegate_ appListDelegate]));
-  menuController_.reset([[AppListMenuController alloc]
-      initWithSearchBoxController:self]);
-  [menuButton_ setMenu:[menuController_ menu]];  // Menu will populate here.
-}
-
-- (void)setDelegate:(id<AppsSearchBoxDelegate>)delegate {
-  [[menuButton_ menu] removeAllItems];
-  menuController_.reset();
-  appListMenu_.reset();
-  bridge_.reset();  // Ensure observers are cleared before updating |delegate_|.
-  delegate_ = delegate;
-  if (!delegate_)
-    return;
-
-  bridge_.reset(new app_list::SearchBoxModelObserverBridge(self));
-  [self rebuildMenu];
-}
-
-- (NSTextField*)searchTextField {
-  return searchTextField_;
-}
-
-- (NSPopUpButton*)menuControl {
-  return menuButton_;
-}
-
-- (app_list::AppListMenu*)appListMenu {
-  return appListMenu_.get();
-}
-
-- (NSImageView*)searchImageView {
-  return searchImageView_;
-}
-
-- (void)addSubviews {
-  NSRect viewBounds = [[self view] bounds];
-  searchImageView_.reset([[NSImageView alloc] initWithFrame:NSMakeRect(
-      kPadding, 0, kSearchIconDimension, NSHeight(viewBounds))]);
-
-  searchTextField_.reset([[SearchTextField alloc] initWithFrame:viewBounds]);
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  [searchTextField_ setDelegate:self];
-  [searchTextField_ setFont:rb.GetFont(
-      ui::ResourceBundle::MediumFont).GetNativeFont()];
-  [searchTextField_
-      setMarginsWithLeftMargin:NSMaxX([searchImageView_ frame]) + kPadding
-                   rightMargin:kMenuButtonDimension + 2 * kPadding];
-
-  // Add the drop-down menu, with a custom button.
-  NSRect buttonFrame = NSMakeRect(
-      NSWidth(viewBounds) - kMenuButtonDimension - kPadding,
-      floor(NSMidY(viewBounds) - kMenuButtonDimension / 2),
-      kMenuButtonDimension,
-      kMenuButtonDimension);
-  menuButton_.reset([[HoverImageMenuButton alloc] initWithFrame:buttonFrame
-                                                      pullsDown:YES]);
-  [[menuButton_ hoverImageMenuButtonCell] setDefaultImage:
-      rb.GetNativeImageNamed(IDR_APP_LIST_TOOLS_NORMAL).AsNSImage()];
-  [[menuButton_ hoverImageMenuButtonCell] setAlternateImage:
-      rb.GetNativeImageNamed(IDR_APP_LIST_TOOLS_PRESSED).AsNSImage()];
-  [[menuButton_ hoverImageMenuButtonCell] setHoverImage:
-      rb.GetNativeImageNamed(IDR_APP_LIST_TOOLS_HOVER).AsNSImage()];
-
-  [[self view] addSubview:searchImageView_];
-  [[self view] addSubview:searchTextField_];
-  [[self view] addSubview:menuButton_];
-}
-
-- (BOOL)control:(NSControl*)control
-               textView:(NSTextView*)textView
-    doCommandBySelector:(SEL)command {
-  // Forward the message first, to handle grid or search results navigation.
-  BOOL handled = [delegate_ control:control
-                           textView:textView
-                doCommandBySelector:command];
-  if (handled)
-    return YES;
-
-  // If the delegate did not handle the escape key, it means the window was not
-  // dismissed because there were search results. Clear them.
-  if (command == @selector(complete:)) {
-    [self clearSearch];
-    return YES;
-  }
-
-  return NO;
-}
-
-- (void)controlTextDidChange:(NSNotification*)notification {
-  if (bridge_) {
-    bridge_->SetSearchText(
-        base::SysNSStringToUTF16([searchTextField_ stringValue]));
-  }
-
-  [delegate_ modelTextDidChange];
-}
-
-@end
-
-@interface SearchTextFieldCell : NSTextFieldCell;
-
-- (NSRect)textFrameForFrameInternal:(NSRect)cellFrame;
-
-@end
-
-@implementation SearchTextField
-
-@synthesize textFrameInset = textFrameInset_;
-
-+ (Class)cellClass {
-  return [SearchTextFieldCell class];
-}
-
-- (id)initWithFrame:(NSRect)theFrame {
-  if ((self = [super initWithFrame:theFrame])) {
-    [self setFocusRingType:NSFocusRingTypeNone];
-    [self setDrawsBackground:NO];
-    [self setBordered:NO];
-  }
-  return self;
-}
-
-- (void)setMarginsWithLeftMargin:(CGFloat)leftMargin
-                     rightMargin:(CGFloat)rightMargin {
-  // Find the preferred height for the current text properties, and center.
-  NSRect viewBounds = [self bounds];
-  [self sizeToFit];
-  NSRect textBounds = [self bounds];
-  textFrameInset_.origin.x = leftMargin;
-  textFrameInset_.origin.y = floor(NSMidY(viewBounds) - NSMidY(textBounds));
-  textFrameInset_.size.width = leftMargin + rightMargin;
-  textFrameInset_.size.height = NSHeight(viewBounds) - NSHeight(textBounds);
-  [self setFrame:viewBounds];
-}
-
-@end
-
-@implementation SearchTextFieldCell
-
-- (NSRect)textFrameForFrameInternal:(NSRect)cellFrame {
-  SearchTextField* searchTextField =
-      base::mac::ObjCCastStrict<SearchTextField>([self controlView]);
-  NSRect insetRect = [searchTextField textFrameInset];
-  cellFrame.origin.x += insetRect.origin.x;
-  cellFrame.origin.y += insetRect.origin.y;
-  cellFrame.size.width -= insetRect.size.width;
-  cellFrame.size.height -= insetRect.size.height;
-  return cellFrame;
-}
-
-- (NSRect)textFrameForFrame:(NSRect)cellFrame {
-  return [self textFrameForFrameInternal:cellFrame];
-}
-
-- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame {
-  return [self textFrameForFrameInternal:cellFrame];
-}
-
-- (void)resetCursorRect:(NSRect)cellFrame
-                 inView:(NSView*)controlView {
-  [super resetCursorRect:[self textCursorFrameForFrame:cellFrame]
-                  inView:controlView];
-}
-
-- (NSRect)drawingRectForBounds:(NSRect)theRect {
-  return [super drawingRectForBounds:[self textFrameForFrame:theRect]];
-}
-
-- (void)editWithFrame:(NSRect)cellFrame
-               inView:(NSView*)controlView
-               editor:(NSText*)editor
-             delegate:(id)delegate
-                event:(NSEvent*)event {
-  [super editWithFrame:[self textFrameForFrame:cellFrame]
-                inView:controlView
-                editor:editor
-              delegate:delegate
-                 event:event];
-}
-
-- (void)selectWithFrame:(NSRect)cellFrame
-                 inView:(NSView*)controlView
-                 editor:(NSText*)editor
-               delegate:(id)delegate
-                  start:(NSInteger)start
-                 length:(NSInteger)length {
-  [super selectWithFrame:[self textFrameForFrame:cellFrame]
-                  inView:controlView
-                  editor:editor
-                delegate:delegate
-                   start:start
-                  length:length];
-}
-
-@end
-
-@implementation AppListMenuController
-
-- (id)initWithSearchBoxController:(AppsSearchBoxController*)parent {
-  // Need to initialze super with a NULL model, otherwise it will immediately
-  // try to populate, which can't be done until setting the parent.
-  if ((self = [super initWithModel:NULL
-            useWithPopUpButtonCell:YES])) {
-    searchBoxController_ = parent;
-    [super setModel:[parent appListMenu]->menu_model()];
-  }
-  return self;
-}
-
-- (NSRect)confinementRectForMenu:(NSMenu*)menu
-                        onScreen:(NSScreen*)screen {
-  NSPopUpButton* menuButton = [searchBoxController_ menuControl];
-  // Ensure the menu comes up below the menu button by trimming the window frame
-  // to a point anchored below the bottom right of the button.
-  NSRect anchorRect = [menuButton convertRect:[menuButton bounds]
-                                       toView:nil];
-  NSPoint anchorPoint = ui::ConvertPointFromWindowToScreen(
-      [menuButton window],
-      NSMakePoint(NSMaxX(anchorRect) + kMenuXOffsetFromButton,
-                  NSMinY(anchorRect) - kMenuYOffsetFromButton));
-
-  NSRect confinementRect = [[menuButton window] frame];
-  confinementRect.size = NSMakeSize(anchorPoint.x - NSMinX(confinementRect),
-                                    anchorPoint.y - NSMinY(confinementRect));
-  return confinementRect;
-}
-
-@end
diff --git a/ui/app_list/cocoa/apps_search_box_controller_unittest.mm b/ui/app_list/cocoa/apps_search_box_controller_unittest.mm
deleted file mode 100644
index 75ba7cd..0000000
--- a/ui/app_list/cocoa/apps_search_box_controller_unittest.mm
+++ /dev/null
@@ -1,270 +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.
-
-#import "ui/app_list/cocoa/apps_search_box_controller.h"
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#import "testing/gtest_mac.h"
-#include "ui/app_list/app_list_menu.h"
-#include "ui/app_list/app_list_model_observer.h"
-#include "ui/app_list/search_box_model.h"
-#include "ui/app_list/test/app_list_test_model.h"
-#include "ui/app_list/test/app_list_test_view_delegate.h"
-#import "ui/base/cocoa/menu_controller.h"
-#import "ui/gfx/test/ui_cocoa_test_helper.h"
-
-using base::ASCIIToUTF16;
-
-@interface TestAppsSearchBoxDelegate : NSObject<AppsSearchBoxDelegate> {
- @private
-  app_list::SearchBoxModel searchBoxModel_;
-  app_list::test::AppListTestViewDelegate appListDelegate_;
-  app_list::test::AppListTestModel appListModel_;
-  int textChangeCount_;
-}
-
-@property(assign, nonatomic) int textChangeCount;
-
-@end
-
-@implementation TestAppsSearchBoxDelegate
-
-@synthesize textChangeCount = textChangeCount_;
-
-- (id)init {
-  if ((self = [super init])) {
-    app_list::AppListViewDelegate::Users users(2);
-    users[0].name = ASCIIToUTF16("user1");
-    users[1].name = ASCIIToUTF16("user2");
-    users[1].email = ASCIIToUTF16("user2@chromium.org");
-    users[1].active = true;
-    appListDelegate_.SetUsers(users);
-  }
-  return self;
-}
-
-- (app_list::SearchBoxModel*)searchBoxModel {
-  return &searchBoxModel_;
-}
-
-- (app_list::AppListViewDelegate*)appListDelegate {
-  return &appListDelegate_;
-}
-
-- (app_list::test::AppListTestViewDelegate*)appListTestViewDelegate {
-  return &appListDelegate_;
-}
-
-
-- (BOOL)control:(NSControl*)control
-               textView:(NSTextView*)textView
-    doCommandBySelector:(SEL)command {
-  return NO;
-}
-
-- (void)modelTextDidChange {
-  ++textChangeCount_;
-}
-
-- (CGFloat)bubbleCornerRadius {
-  return 3;
-}
-
-- (app_list::AppListModel*)appListModel {
-  return &appListModel_;
-}
-
-@end
-
-namespace app_list {
-namespace test {
-
-class AppsSearchBoxControllerTest : public ui::CocoaTest {
- public:
-  AppsSearchBoxControllerTest() {
-    Init();
-  }
-
-  void SetUp() override {
-    apps_search_box_controller_.reset(
-        [[AppsSearchBoxController alloc] initWithFrame:
-            NSMakeRect(0, 0, 400, 100)]);
-    delegate_.reset([[TestAppsSearchBoxDelegate alloc] init]);
-    [apps_search_box_controller_ setDelegate:delegate_];
-
-    ui::CocoaTest::SetUp();
-    [[test_window() contentView] addSubview:[apps_search_box_controller_ view]];
-  }
-
-  void TearDown() override {
-    [apps_search_box_controller_ setDelegate:nil];
-    ui::CocoaTest::TearDown();
-  }
-
-  void SimulateKeyAction(SEL c) {
-    base::scoped_nsobject<NSTextView> stub_field_editor(
-        [[NSTextView alloc] initWithFrame:NSZeroRect]);
-    NSControl* control = [apps_search_box_controller_ searchTextField];
-    [apps_search_box_controller_ control:control
-                                textView:stub_field_editor.get()
-                     doCommandBySelector:c];
-  }
-
- protected:
-  base::scoped_nsobject<TestAppsSearchBoxDelegate> delegate_;
-  base::scoped_nsobject<AppsSearchBoxController> apps_search_box_controller_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AppsSearchBoxControllerTest);
-};
-
-TEST_VIEW(AppsSearchBoxControllerTest, [apps_search_box_controller_ view]);
-
-// Test the search box initialization, and search input and clearing.
-TEST_F(AppsSearchBoxControllerTest, SearchBoxModel) {
-  app_list::SearchBoxModel* model = [delegate_ searchBoxModel];
-  // Usually localized "Search".
-  const base::string16 hit_text(ASCIIToUTF16("hint"));
-  model->SetHintText(hit_text);
-  EXPECT_NSEQ(base::SysUTF16ToNSString(hit_text),
-      [[[apps_search_box_controller_ searchTextField] cell] placeholderString]);
-
-  const base::string16 search_text(ASCIIToUTF16("test"));
-  model->SetText(search_text);
-  EXPECT_NSEQ(base::SysUTF16ToNSString(search_text),
-              [[apps_search_box_controller_ searchTextField] stringValue]);
-  // Updates coming via the model should notify the delegate.
-  EXPECT_EQ(1, [delegate_ textChangeCount]);
-
-  // Updates from the view should update the model and notify the delegate.
-  [apps_search_box_controller_ clearSearch];
-  EXPECT_EQ(base::string16(), model->text());
-  EXPECT_NSEQ([NSString string],
-              [[apps_search_box_controller_ searchTextField] stringValue]);
-  EXPECT_EQ(2, [delegate_ textChangeCount]);
-
-  // Test pressing escape clears the search. First add some text.
-  model->SetText(search_text);
-  EXPECT_EQ(3, [delegate_ textChangeCount]);
-
-  EXPECT_NSEQ(base::SysUTF16ToNSString(search_text),
-              [[apps_search_box_controller_ searchTextField] stringValue]);
-  SimulateKeyAction(@selector(complete:));
-  EXPECT_NSEQ([NSString string],
-              [[apps_search_box_controller_ searchTextField] stringValue]);
-  EXPECT_EQ(4, [delegate_ textChangeCount]);
-}
-
-// Test the popup menu items when there is only one user..
-TEST_F(AppsSearchBoxControllerTest, SearchBoxMenuSingleUser) {
-  // Set a single user. We need to set the delegate again because the
-  // AppListModel observer isn't hooked up in these tests.
-  [delegate_ appListTestViewDelegate]->SetUsers(
-      app_list::AppListViewDelegate::Users(1));
-  [apps_search_box_controller_ setDelegate:delegate_];
-
-  NSPopUpButton* menu_control = [apps_search_box_controller_ menuControl];
-  EXPECT_TRUE([apps_search_box_controller_ appListMenu]);
-  ui::MenuModel* menu_model
-      = [apps_search_box_controller_ appListMenu]->menu_model();
-  // Add one to the item count to account for the blank, first item that Cocoa
-  // has in its popup menus.
-  EXPECT_EQ(menu_model->GetItemCount() + 1,
-            [[menu_control menu] numberOfItems]);
-
-  // All command ids should be less than |SELECT_PROFILE| as no user menu items
-  // are being shown.
-  for (int i = 0; i < menu_model->GetItemCount(); ++i)
-    EXPECT_LT(menu_model->GetCommandIdAt(i), AppListMenu::SELECT_PROFILE);
-
-  // The number of items should match the index that starts profile items.
-  EXPECT_EQ(AppListMenu::SELECT_PROFILE, menu_model->GetItemCount());
-}
-
-// Test the popup menu items for the multi-profile case.
-TEST_F(AppsSearchBoxControllerTest, SearchBoxMenu) {
-  const app_list::AppListViewDelegate::Users& users =
-      [delegate_ appListDelegate]->GetUsers();
-  NSPopUpButton* menu_control = [apps_search_box_controller_ menuControl];
-  EXPECT_TRUE([apps_search_box_controller_ appListMenu]);
-  ui::MenuModel* menu_model
-      = [apps_search_box_controller_ appListMenu]->menu_model();
-  // Add one to the item count to account for the blank, first item that Cocoa
-  // has in its popup menus.
-  EXPECT_EQ(menu_model->GetItemCount() + 1,
-            [[menu_control menu] numberOfItems]);
-
-  ui::MenuModel* found_menu_model = menu_model;
-  int index;
-  MenuController* controller = [[menu_control menu] delegate];
-
-  // The first user item is an unchecked label.
-  EXPECT_TRUE(ui::MenuModel::GetModelAndIndexForCommandId(
-      AppListMenu::SELECT_PROFILE, &menu_model, &index));
-  EXPECT_EQ(found_menu_model, menu_model);
-  NSMenuItem* unchecked_user_item = [[menu_control menu] itemAtIndex:index + 1];
-  [controller validateUserInterfaceItem:unchecked_user_item];
-  // The profile name should be shown if there is no email available.
-  EXPECT_NSEQ(base::SysUTF16ToNSString(users[0].name),
-              [unchecked_user_item title]);
-  EXPECT_EQ(NSOffState, [unchecked_user_item state]);
-
-  // The second user item is a checked label because it is the active profile.
-  EXPECT_TRUE(ui::MenuModel::GetModelAndIndexForCommandId(
-      AppListMenu::SELECT_PROFILE + 1, &menu_model, &index));
-  EXPECT_EQ(found_menu_model, menu_model);
-  NSMenuItem* checked_user_item = [[menu_control menu] itemAtIndex:index + 1];
-  [controller validateUserInterfaceItem:checked_user_item];
-  // The email is shown when available.
-  EXPECT_NSEQ(base::SysUTF16ToNSString(users[1].email),
-              [checked_user_item title]);
-  EXPECT_EQ(NSOnState, [checked_user_item state]);
-
-  // A regular item should have just the label.
-  EXPECT_TRUE(ui::MenuModel::GetModelAndIndexForCommandId(
-      AppListMenu::SHOW_SETTINGS, &menu_model, &index));
-  EXPECT_EQ(found_menu_model, menu_model);
-  NSMenuItem* settings_item = [[menu_control menu] itemAtIndex:index + 1];
-  EXPECT_FALSE([settings_item view]);
-  EXPECT_NSEQ(base::SysUTF16ToNSString(menu_model->GetLabelAt(index)),
-              [settings_item title]);
-}
-
-// Test adding another user, and changing an existing one.
-TEST_F(AppsSearchBoxControllerTest, SearchBoxMenuChangingUsers) {
-  app_list::AppListViewDelegate::Users users =
-      [delegate_ appListDelegate]->GetUsers();
-  EXPECT_EQ(2u, users.size());
-  ui::MenuModel* menu_model
-      = [apps_search_box_controller_ appListMenu]->menu_model();
-  // Adding one to account for the empty item at index 0 in Cocoa popup menus.
-  int non_user_items = menu_model->GetItemCount() - users.size() + 1;
-
-  NSPopUpButton* menu_control = [apps_search_box_controller_ menuControl];
-  EXPECT_EQ(2, [[menu_control menu] numberOfItems] - non_user_items);
-  EXPECT_NSEQ(base::SysUTF16ToNSString(users[0].name),
-              [[[menu_control menu] itemAtIndex:1] title]);
-
-  users[0].name = ASCIIToUTF16("renamed user");
-  app_list::AppListViewDelegate::User new_user;
-  new_user.name = ASCIIToUTF16("user3");
-  users.push_back(new_user);
-  [delegate_ appListTestViewDelegate]->SetUsers(users);
-  // Note: menu does not automatically get rebuilt. Force a rebuild (which
-  // would normally occur when the UI is closed / re-opend).
-  [apps_search_box_controller_ rebuildMenu];
-
-  // Should now be an extra item, and it should have correct titles.
-  EXPECT_EQ(3, [[menu_control menu] numberOfItems] - non_user_items);
-  EXPECT_NSEQ(base::SysUTF16ToNSString(users[0].name),
-              [[[menu_control menu] itemAtIndex:1] title]);
-  EXPECT_NSEQ(base::SysUTF16ToNSString(new_user.name),
-              [[[menu_control menu] itemAtIndex:3] title]);
-}
-
-}  // namespace test
-}  // namespace app_list
diff --git a/ui/app_list/cocoa/apps_search_results_controller.h b/ui/app_list/cocoa/apps_search_results_controller.h
deleted file mode 100644
index 18684eb..0000000
--- a/ui/app_list/cocoa/apps_search_results_controller.h
+++ /dev/null
@@ -1,59 +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.
-
-#ifndef UI_APP_LIST_COCOA_APPS_SEARCH_RESULTS_CONTROLLER_H_
-#define UI_APP_LIST_COCOA_APPS_SEARCH_RESULTS_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include <memory>
-
-#include "base/mac/scoped_nsobject.h"
-#include "ui/app_list/app_list_export.h"
-#include "ui/app_list/app_list_model.h"
-#import "ui/base/cocoa/tracking_area.h"
-
-namespace app_list {
-class AppsSearchResultsModelBridge;
-class SearchResult;
-}
-
-@class AppsSearchResultsCell;
-
-@protocol AppsSearchResultsDelegate<NSObject>
-
-- (app_list::AppListModel*)appListModel;
-- (void)openResult:(app_list::SearchResult*)result;
-
-@end
-
-// Controller for the search results displayed when a user types in the app list
-// search box. Results display in an NSTableView with a single column. Each row
-// has an icon on the left, and one or two lines of formatted text describing
-// the result.
-APP_LIST_EXPORT
-@interface AppsSearchResultsController
-    : NSViewController<NSTableViewDelegate, NSTableViewDataSource> {
- @private
-  base::scoped_nsobject<NSTableView> tableView_;
-  ui::ScopedCrTrackingArea trackingArea_;
-  NSPoint lastMouseDownInView_;
-  NSInteger hoveredRowIndex_;
-  std::unique_ptr<app_list::AppsSearchResultsModelBridge> bridge_;
-  NSObject<AppsSearchResultsDelegate>* delegate_;  // Weak. Owns us.
-}
-
-@property(assign, nonatomic) NSObject<AppsSearchResultsDelegate>* delegate;
-@property(readonly, nonatomic) app_list::AppListModel::SearchResults* results;
-@property(readonly, nonatomic) NSTableView* tableView;
-
-- (id)initWithAppsSearchResultsFrameSize:(NSSize)size;
-
-// Returns true when handling Enter, to activate the highlighted search result,
-// or up/down to navigate results.
-- (BOOL)handleCommandBySelector:(SEL)command;
-
-@end
-
-#endif  // UI_APP_LIST_COCOA_APPS_SEARCH_RESULTS_CONTROLLER_H_
diff --git a/ui/app_list/cocoa/apps_search_results_controller.mm b/ui/app_list/cocoa/apps_search_results_controller.mm
deleted file mode 100644
index 41155f22..0000000
--- a/ui/app_list/cocoa/apps_search_results_controller.mm
+++ /dev/null
@@ -1,469 +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.
-
-#import "ui/app_list/cocoa/apps_search_results_controller.h"
-
-#include "base/mac/foundation_util.h"
-#include "base/mac/mac_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/sys_string_conversions.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "ui/app_list/app_list_constants.h"
-#include "ui/app_list/app_list_model.h"
-#import "ui/app_list/cocoa/apps_search_results_model_bridge.h"
-#include "ui/app_list/search_result.h"
-#import "ui/base/cocoa/flipped_view.h"
-#include "ui/gfx/image/image_skia_util_mac.h"
-
-namespace {
-
-const CGFloat kPreferredRowHeight = 52;
-const CGFloat kIconDimension = 32;
-const CGFloat kIconPadding = 14;
-const CGFloat kIconViewWidth = kIconDimension + 2 * kIconPadding;
-const CGFloat kTextTrailPadding = kIconPadding;
-
-// Map background styles to represent selection and hover in the results list.
-const NSBackgroundStyle kBackgroundNormal = NSBackgroundStyleLight;
-const NSBackgroundStyle kBackgroundSelected = NSBackgroundStyleDark;
-const NSBackgroundStyle kBackgroundHovered = NSBackgroundStyleRaised;
-
-// The mouse hover colour (3% black over kContentsBackgroundColor).
-const SkColor kHighlightedRowColor = SkColorSetRGB(0xEE, 0xEE, 0xEE);
-// The keyboard select colour (6% black over kContentsBackgroundColor).
-const SkColor kSelectedRowColor = SkColorSetRGB(0xE6, 0xE6, 0xE6);
-
-}  // namespace
-
-@interface AppsSearchResultsController ()
-
-- (void)loadAndSetViewWithResultsFrameSize:(NSSize)size;
-- (void)mouseDown:(NSEvent*)theEvent;
-- (void)tableViewClicked:(id)sender;
-- (app_list::AppListModel::SearchResults*)searchResults;
-- (void)activateSelection;
-- (BOOL)moveSelectionByDelta:(NSInteger)delta;
-- (NSMenu*)contextMenuForRow:(NSInteger)rowIndex;
-
-@end
-
-@interface AppsSearchResultsCell : NSTextFieldCell
-@end
-
-// Immutable class representing a search result in the NSTableView.
-@interface AppsSearchResultRep : NSObject<NSCopying> {
- @private
-  base::scoped_nsobject<NSAttributedString> attributedStringValue_;
-  base::scoped_nsobject<NSImage> resultIcon_;
-}
-
-@property(readonly, nonatomic) NSAttributedString* attributedStringValue;
-@property(readonly, nonatomic) NSImage* resultIcon;
-
-- (id)initWithSearchResult:(app_list::SearchResult*)result;
-
-- (NSMutableAttributedString*)createRenderText:(const base::string16&)content
-    tags:(const app_list::SearchResult::Tags&)tags;
-
-- (NSAttributedString*)createResultsAttributedStringWithModel
-    :(app_list::SearchResult*)result;
-
-@end
-
-// Simple extension to NSTableView that passes mouseDown events to the
-// delegate so that drag events can be detected, and forwards requests for
-// context menus.
-@interface AppsSearchResultsTableView : NSTableView
-
-- (AppsSearchResultsController*)controller;
-
-@end
-
-@implementation AppsSearchResultsController
-
-@synthesize delegate = delegate_;
-
-- (id)initWithAppsSearchResultsFrameSize:(NSSize)size {
-  if ((self = [super init])) {
-    hoveredRowIndex_ = -1;
-    [self loadAndSetViewWithResultsFrameSize:size];
-  }
-  return self;
-}
-
-- (app_list::AppListModel::SearchResults*)results {
-  DCHECK([delegate_ appListModel]);
-  return [delegate_ appListModel]->results();
-}
-
-- (NSTableView*)tableView {
-  return tableView_;
-}
-
-- (void)setDelegate:(id<AppsSearchResultsDelegate>)newDelegate {
-  bridge_.reset();
-  delegate_ = newDelegate;
-  app_list::AppListModel* appListModel = [delegate_ appListModel];
-  if (!appListModel || !appListModel->results()) {
-    [tableView_ reloadData];
-    return;
-  }
-
-  bridge_.reset(new app_list::AppsSearchResultsModelBridge(self));
-  [tableView_ reloadData];
-}
-
-- (BOOL)handleCommandBySelector:(SEL)command {
-  if (command == @selector(insertNewline:) ||
-      command == @selector(insertLineBreak:)) {
-    [self activateSelection];
-    return YES;
-  }
-
-  if (command == @selector(moveUp:))
-    return [self moveSelectionByDelta:-1];
-
-  if (command == @selector(moveDown:))
-    return [self moveSelectionByDelta:1];
-
-  return NO;
-}
-
-- (void)loadAndSetViewWithResultsFrameSize:(NSSize)size {
-  tableView_.reset(
-      [[AppsSearchResultsTableView alloc] initWithFrame:NSZeroRect]);
-  // Refuse first responder so that focus stays with the search text field.
-  [tableView_ setRefusesFirstResponder:YES];
-  [tableView_ setRowHeight:kPreferredRowHeight];
-  [tableView_ setGridStyleMask:NSTableViewSolidHorizontalGridLineMask];
-  [tableView_
-      setGridColor:skia::SkColorToSRGBNSColor(app_list::kResultBorderColor)];
-  [tableView_ setBackgroundColor:[NSColor clearColor]];
-  [tableView_ setAction:@selector(tableViewClicked:)];
-  [tableView_ setDelegate:self];
-  [tableView_ setDataSource:self];
-  [tableView_ setTarget:self];
-
-  // Tracking to highlight an individual row on mouseover.
-  trackingArea_.reset(
-    [[CrTrackingArea alloc] initWithRect:NSZeroRect
-                                 options:NSTrackingInVisibleRect |
-                                         NSTrackingMouseEnteredAndExited |
-                                         NSTrackingMouseMoved |
-                                         NSTrackingActiveInKeyWindow
-                                   owner:self
-                                userInfo:nil]);
-  [tableView_ addTrackingArea:trackingArea_.get()];
-
-  base::scoped_nsobject<NSTableColumn> resultsColumn(
-      [[NSTableColumn alloc] initWithIdentifier:@""]);
-  base::scoped_nsobject<NSCell> resultsDataCell(
-      [[AppsSearchResultsCell alloc] initTextCell:@""]);
-  [resultsColumn setDataCell:resultsDataCell];
-  [resultsColumn setWidth:size.width];
-  [tableView_ addTableColumn:resultsColumn];
-
-  // An NSTableView is normally put in a NSScrollView, but scrolling is not
-  // used for the app list. Instead, place it in a container with the desired
-  // size; flipped so the table is anchored to the top-left.
-  base::scoped_nsobject<FlippedView> containerView([[FlippedView alloc]
-      initWithFrame:NSMakeRect(0, 0, size.width, size.height)]);
-
-  // The container is then anchored in an un-flipped view, initially hidden,
-  // so that |containerView| slides in from the top when showing results.
-  base::scoped_nsobject<NSView> clipView(
-      [[NSView alloc] initWithFrame:NSMakeRect(0, 0, size.width, 0)]);
-
-  [containerView addSubview:tableView_];
-  [clipView addSubview:containerView];
-  [self setView:clipView];
-}
-
-- (void)mouseDown:(NSEvent*)theEvent {
-  lastMouseDownInView_ = [tableView_ convertPoint:[theEvent locationInWindow]
-                                         fromView:nil];
-}
-
-- (void)tableViewClicked:(id)sender {
-  const CGFloat kDragThreshold = 5;
-  // If the user clicked and then dragged elsewhere, ignore the click.
-  NSEvent* event = [[tableView_ window] currentEvent];
-  NSPoint pointInView = [tableView_ convertPoint:[event locationInWindow]
-                                        fromView:nil];
-  CGFloat deltaX = pointInView.x - lastMouseDownInView_.x;
-  CGFloat deltaY = pointInView.y - lastMouseDownInView_.y;
-  if (deltaX * deltaX + deltaY * deltaY <= kDragThreshold * kDragThreshold)
-    [self activateSelection];
-
-  // Mouse tracking is suppressed by the NSTableView during a drag, so ensure
-  // any hover state is cleaned up.
-  [self mouseMoved:event];
-}
-
-- (app_list::AppListModel::SearchResults*)searchResults {
-  app_list::AppListModel* appListModel = [delegate_ appListModel];
-  DCHECK(bridge_);
-  DCHECK(appListModel);
-  DCHECK(appListModel->results());
-  return appListModel->results();
-}
-
-- (void)activateSelection {
-  NSInteger selectedRow = [tableView_ selectedRow];
-  if (!bridge_ || selectedRow < 0)
-    return;
-
-  [delegate_ openResult:[self searchResults]->GetItemAt(selectedRow)];
-}
-
-- (BOOL)moveSelectionByDelta:(NSInteger)delta {
-  NSInteger rowCount = [tableView_ numberOfRows];
-  if (rowCount <= 0)
-    return NO;
-
-  NSInteger selectedRow = [tableView_ selectedRow];
-  NSInteger targetRow;
-  if (selectedRow == -1) {
-    // No selection. Select first or last, based on direction.
-    targetRow = delta > 0 ? 0 : rowCount - 1;
-  } else {
-    targetRow = (selectedRow + delta) % rowCount;
-    if (targetRow < 0)
-      targetRow += rowCount;
-  }
-
-  [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:targetRow]
-          byExtendingSelection:NO];
-  return YES;
-}
-
-- (NSMenu*)contextMenuForRow:(NSInteger)rowIndex {
-  DCHECK(bridge_);
-  if (rowIndex < 0)
-    return nil;
-
-  [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:rowIndex]
-          byExtendingSelection:NO];
-  return bridge_->MenuForItem(rowIndex);
-}
-
-- (NSInteger)numberOfRowsInTableView:(NSTableView*)aTableView {
-  return bridge_ ? [self searchResults]->item_count() : 0;
-}
-
-- (id)tableView:(NSTableView*)aTableView
-    objectValueForTableColumn:(NSTableColumn*)aTableColumn
-                          row:(NSInteger)rowIndex {
-  // When the results were previously cleared, nothing will be selected. For
-  // that case, select the first row when it appears.
-  if (rowIndex == 0 && [tableView_ selectedRow] == -1) {
-    [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:0]
-            byExtendingSelection:NO];
-  }
-
-  base::scoped_nsobject<AppsSearchResultRep> resultRep(
-      [[AppsSearchResultRep alloc]
-          initWithSearchResult:[self searchResults]->GetItemAt(rowIndex)]);
-  return resultRep.autorelease();
-}
-
-- (void)tableView:(NSTableView*)tableView
-    willDisplayCell:(id)cell
-     forTableColumn:(NSTableColumn*)tableColumn
-                row:(NSInteger)rowIndex {
-  if (rowIndex == [tableView selectedRow])
-    [cell setBackgroundStyle:kBackgroundSelected];
-  else if (rowIndex == hoveredRowIndex_)
-    [cell setBackgroundStyle:kBackgroundHovered];
-  else
-    [cell setBackgroundStyle:kBackgroundNormal];
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
-  if (hoveredRowIndex_ == -1)
-    return;
-
-  [tableView_ setNeedsDisplayInRect:[tableView_ rectOfRow:hoveredRowIndex_]];
-  hoveredRowIndex_ = -1;
-}
-
-- (void)mouseMoved:(NSEvent*)theEvent {
-  NSPoint pointInView = [tableView_ convertPoint:[theEvent locationInWindow]
-                                        fromView:nil];
-  NSInteger newIndex = [tableView_ rowAtPoint:pointInView];
-  if (newIndex == hoveredRowIndex_)
-    return;
-
-  if (newIndex != -1)
-    [tableView_ setNeedsDisplayInRect:[tableView_ rectOfRow:newIndex]];
-  if (hoveredRowIndex_ != -1)
-    [tableView_ setNeedsDisplayInRect:[tableView_ rectOfRow:hoveredRowIndex_]];
-  hoveredRowIndex_ = newIndex;
-}
-
-@end
-
-@implementation AppsSearchResultRep
-
-- (NSAttributedString*)attributedStringValue {
-  return attributedStringValue_;
-}
-
-- (NSImage*)resultIcon {
-  return resultIcon_;
-}
-
-- (id)initWithSearchResult:(app_list::SearchResult*)result {
-  if ((self = [super init])) {
-    attributedStringValue_.reset(
-        [[self createResultsAttributedStringWithModel:result] retain]);
-    if (!result->icon().isNull()) {
-      resultIcon_.reset([gfx::NSImageFromImageSkiaWithColorSpace(
-          result->icon(), base::mac::GetSRGBColorSpace()) retain]);
-    }
-  }
-  return self;
-}
-
-- (NSMutableAttributedString*)createRenderText:(const base::string16&)content
-    tags:(const app_list::SearchResult::Tags&)tags {
-  NSFont* boldFont = nil;
-  base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
-      [[NSMutableParagraphStyle alloc] init]);
-  [paragraphStyle setLineBreakMode:NSLineBreakByTruncatingTail];
-  NSDictionary* defaultAttributes = @{
-    NSForegroundColorAttributeName :
-        skia::SkColorToSRGBNSColor(app_list::kResultDefaultTextColor),
-    NSParagraphStyleAttributeName : paragraphStyle
-  };
-
-  base::scoped_nsobject<NSMutableAttributedString> text(
-      [[NSMutableAttributedString alloc]
-          initWithString:base::SysUTF16ToNSString(content)
-              attributes:defaultAttributes]);
-
-  for (app_list::SearchResult::Tags::const_iterator it = tags.begin();
-       it != tags.end(); ++it) {
-    if (it->styles == app_list::SearchResult::Tag::NONE)
-      continue;
-
-    if (it->styles & app_list::SearchResult::Tag::MATCH) {
-      if (!boldFont) {
-        NSFontManager* fontManager = [NSFontManager sharedFontManager];
-        boldFont = [fontManager convertFont:[NSFont controlContentFontOfSize:0]
-                                toHaveTrait:NSBoldFontMask];
-      }
-      [text addAttribute:NSFontAttributeName
-                   value:boldFont
-                   range:it->range.ToNSRange()];
-    }
-
-    if (it->styles & app_list::SearchResult::Tag::DIM) {
-      NSColor* dimmedColor =
-          skia::SkColorToSRGBNSColor(app_list::kResultDimmedTextColor);
-      [text addAttribute:NSForegroundColorAttributeName
-                   value:dimmedColor
-                   range:it->range.ToNSRange()];
-    } else if (it->styles & app_list::SearchResult::Tag::URL) {
-      NSColor* urlColor =
-          skia::SkColorToSRGBNSColor(app_list::kResultURLTextColor);
-      [text addAttribute:NSForegroundColorAttributeName
-                   value:urlColor
-                   range:it->range.ToNSRange()];
-    }
-  }
-
-  return text.autorelease();
-}
-
-- (NSAttributedString*)createResultsAttributedStringWithModel
-    :(app_list::SearchResult*)result {
-  NSMutableAttributedString* titleText =
-      [self createRenderText:result->title()
-                        tags:result->title_tags()];
-  if (!result->details().empty()) {
-    NSMutableAttributedString* detailText =
-        [self createRenderText:result->details()
-                          tags:result->details_tags()];
-    base::scoped_nsobject<NSAttributedString> lineBreak(
-        [[NSAttributedString alloc] initWithString:@"\n"]);
-    [titleText appendAttributedString:lineBreak];
-    [titleText appendAttributedString:detailText];
-  }
-  return titleText;
-}
-
-- (id)copyWithZone:(NSZone*)zone {
-  return [self retain];
-}
-
-@end
-
-@implementation AppsSearchResultsTableView
-
-- (AppsSearchResultsController*)controller {
-  return base::mac::ObjCCastStrict<AppsSearchResultsController>(
-      [self delegate]);
-}
-
-- (void)mouseDown:(NSEvent*)theEvent {
-  [[self controller] mouseDown:theEvent];
-  [super mouseDown:theEvent];
-}
-
-- (NSMenu*)menuForEvent:(NSEvent*)theEvent {
-  NSPoint pointInView = [self convertPoint:[theEvent locationInWindow]
-                                  fromView:nil];
-  return [[self controller] contextMenuForRow:[self rowAtPoint:pointInView]];
-}
-
-@end
-
-@implementation AppsSearchResultsCell
-
-- (void)drawWithFrame:(NSRect)cellFrame
-               inView:(NSView*)controlView {
-  if ([self backgroundStyle] != kBackgroundNormal) {
-    if ([self backgroundStyle] == kBackgroundSelected)
-      [skia::SkColorToSRGBNSColor(kSelectedRowColor) set];
-    else
-      [skia::SkColorToSRGBNSColor(kHighlightedRowColor) set];
-
-    // Extend up by one pixel to draw over cell border.
-    NSRect backgroundRect = cellFrame;
-    backgroundRect.origin.y -= 1;
-    backgroundRect.size.height += 1;
-    NSRectFill(backgroundRect);
-  }
-
-  NSAttributedString* titleText = [self attributedStringValue];
-  NSRect titleRect = cellFrame;
-  titleRect.size.width -= kTextTrailPadding + kIconViewWidth;
-  titleRect.origin.x += kIconViewWidth;
-  titleRect.origin.y +=
-      floor(NSHeight(cellFrame) / 2 - [titleText size].height / 2);
-  // Ensure no drawing occurs outside of the cell.
-  titleRect = NSIntersectionRect(titleRect, cellFrame);
-
-  [titleText drawInRect:titleRect];
-
-  NSImage* resultIcon = [[self objectValue] resultIcon];
-  if (!resultIcon)
-    return;
-
-  NSSize iconSize = [resultIcon size];
-  NSRect iconRect = NSMakeRect(
-      floor(NSMinX(cellFrame) + kIconViewWidth / 2 - iconSize.width / 2),
-      floor(NSMinY(cellFrame) + kPreferredRowHeight / 2 - iconSize.height / 2),
-      std::min(iconSize.width, kIconDimension),
-      std::min(iconSize.height, kIconDimension));
-  [resultIcon drawInRect:iconRect
-                fromRect:NSZeroRect
-               operation:NSCompositeSourceOver
-                fraction:1.0
-          respectFlipped:YES
-                   hints:nil];
-}
-
-@end
diff --git a/ui/app_list/cocoa/apps_search_results_controller_unittest.mm b/ui/app_list/cocoa/apps_search_results_controller_unittest.mm
deleted file mode 100644
index 78d0730b..0000000
--- a/ui/app_list/cocoa/apps_search_results_controller_unittest.mm
+++ /dev/null
@@ -1,301 +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.
-
-#import "ui/app_list/cocoa/apps_search_results_controller.h"
-
-#include <stddef.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#import "testing/gtest_mac.h"
-#include "ui/app_list/test/app_list_test_model.h"
-#include "ui/app_list/test/test_search_result.h"
-#include "ui/base/models/simple_menu_model.h"
-#import "ui/events/test/cocoa_test_event_utils.h"
-#include "ui/gfx/image/image_skia_util_mac.h"
-#import "ui/gfx/test/ui_cocoa_test_helper.h"
-
-@interface TestAppsSearchResultsDelegate : NSObject<AppsSearchResultsDelegate> {
- @private
-  app_list::test::AppListTestModel appListModel_;
-  app_list::SearchResult* lastOpenedResult_;
-}
-
-@property(readonly, nonatomic) app_list::SearchResult* lastOpenedResult;
-
-- (void)quitMessageLoop;
-
-@end
-
-@implementation TestAppsSearchResultsDelegate
-
-@synthesize lastOpenedResult = lastOpenedResult_;
-
-- (app_list::AppListModel*)appListModel {
-  return &appListModel_;
-}
-
-- (void)openResult:(app_list::SearchResult*)result {
-  lastOpenedResult_ = result;
-}
-
-- (void)quitMessageLoop {
-  base::MessageLoop::current()->QuitNow();
-}
-
-@end
-
-namespace app_list {
-namespace test {
-namespace {
-
-const int kDefaultResultsCount = 3;
-
-class SearchResultWithMenu : public TestSearchResult {
- public:
-  SearchResultWithMenu(const std::string& title, const std::string& details)
-      : menu_model_(NULL),
-        menu_ready_(true) {
-    set_title(base::ASCIIToUTF16(title));
-    set_details(base::ASCIIToUTF16(details));
-    menu_model_.AddItem(0, base::UTF8ToUTF16("Menu For: " + title));
-  }
-
-  void SetMenuReadyForTesting(bool ready) {
-    menu_ready_ = ready;
-  }
-
-  ui::MenuModel* GetContextMenuModel() override {
-    if (!menu_ready_)
-      return NULL;
-
-    return &menu_model_;
-  }
-
- private:
-  ui::SimpleMenuModel menu_model_;
-  bool menu_ready_;
-
-  DISALLOW_COPY_AND_ASSIGN(SearchResultWithMenu);
-};
-
-class AppsSearchResultsControllerTest : public ui::CocoaTest {
- public:
-  AppsSearchResultsControllerTest() {}
-
-  void AddTestResultAtIndex(size_t index,
-                            const std::string& title,
-                            const std::string& details) {
-    std::unique_ptr<SearchResult> result(
-        new SearchResultWithMenu(title, details));
-    AppListModel::SearchResults* results = [delegate_ appListModel]->results();
-    results->AddAt(index, result.release());
-  }
-
-  SearchResult* ModelResultAt(size_t index) {
-    return [delegate_ appListModel]->results()->GetItemAt(index);
-  }
-
-  NSCell* ViewResultAt(NSInteger index) {
-    NSTableView* table_view = [apps_search_results_controller_ tableView];
-    return [table_view preparedCellAtColumn:0
-                                        row:index];
-  }
-
-  void SetMenuReadyAt(size_t index, bool ready) {
-    SearchResultWithMenu* result =
-        static_cast<SearchResultWithMenu*>(ModelResultAt(index));
-    result->SetMenuReadyForTesting(ready);
-  }
-
-  BOOL SimulateKeyAction(SEL c) {
-    return [apps_search_results_controller_ handleCommandBySelector:c];
-  }
-
-  void ExpectConsistent();
-
-  // ui::CocoaTest overrides:
-  void SetUp() override;
-  void TearDown() override;
-
- protected:
-  base::scoped_nsobject<TestAppsSearchResultsDelegate> delegate_;
-  base::scoped_nsobject<AppsSearchResultsController>
-      apps_search_results_controller_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AppsSearchResultsControllerTest);
-};
-
-void AppsSearchResultsControllerTest::ExpectConsistent() {
-  NSInteger item_count = [delegate_ appListModel]->results()->item_count();
-  ASSERT_EQ(item_count,
-            [[apps_search_results_controller_ tableView] numberOfRows]);
-
-  // Compare content strings to ensure the order of items is consistent, and any
-  // model data that should have been reloaded has been reloaded in the view.
-  for (NSInteger i = 0; i < item_count; ++i) {
-    SearchResult* result = ModelResultAt(i);
-    base::string16 string_in_model = result->title();
-    if (!result->details().empty())
-      string_in_model += base::ASCIIToUTF16("\n") + result->details();
-    EXPECT_NSEQ(base::SysUTF16ToNSString(string_in_model),
-                [[ViewResultAt(i) attributedStringValue] string]);
-  }
-}
-
-void AppsSearchResultsControllerTest::SetUp() {
-  apps_search_results_controller_.reset(
-      [[AppsSearchResultsController alloc] initWithAppsSearchResultsFrameSize:
-          NSMakeSize(400, 400)]);
-  // The view is initially hidden. Give it a non-zero height so it draws.
-  [[apps_search_results_controller_ view] setFrameSize:NSMakeSize(400, 400)];
-
-  delegate_.reset([[TestAppsSearchResultsDelegate alloc] init]);
-
-  // Populate with some results so that TEST_VIEW does something non-trivial.
-  for (int i = 0; i < kDefaultResultsCount; ++i)
-    AddTestResultAtIndex(i, base::StringPrintf("Result %d", i), "ItemDetail");
-
-  SearchResult::Tags test_tags;
-  // Apply markup to the substring "Result" in the first item.
-  test_tags.push_back(SearchResult::Tag(SearchResult::Tag::NONE, 0, 1));
-  test_tags.push_back(SearchResult::Tag(SearchResult::Tag::URL, 1, 2));
-  test_tags.push_back(SearchResult::Tag(SearchResult::Tag::MATCH, 2, 3));
-  test_tags.push_back(SearchResult::Tag(SearchResult::Tag::DIM, 3, 4));
-  test_tags.push_back(SearchResult::Tag(SearchResult::Tag::MATCH |
-                                        SearchResult::Tag::URL, 4, 5));
-  test_tags.push_back(SearchResult::Tag(SearchResult::Tag::MATCH |
-                                        SearchResult::Tag::DIM, 5, 6));
-
-  SearchResult* result = ModelResultAt(0);
-  result->SetIcon(gfx::ImageSkiaFromNSImage(
-      [NSImage imageNamed:NSImageNameStatusAvailable]));
-  result->set_title_tags(test_tags);
-
-  [apps_search_results_controller_ setDelegate:delegate_];
-
-  ui::CocoaTest::SetUp();
-  [[test_window() contentView] addSubview:
-      [apps_search_results_controller_ view]];
-}
-
-void AppsSearchResultsControllerTest::TearDown() {
-  [apps_search_results_controller_ setDelegate:nil];
-  ui::CocoaTest::TearDown();
-}
-
-NSEvent* MouseEventInRow(NSTableView* table_view, NSInteger row_index) {
-  NSRect row_rect = [table_view rectOfRow:row_index];
-  NSPoint point_in_view = NSMakePoint(NSMidX(row_rect), NSMidY(row_rect));
-  NSPoint point_in_window = [table_view convertPoint:point_in_view
-                                              toView:nil];
-  return cocoa_test_event_utils::LeftMouseDownAtPoint(point_in_window);
-}
-
-}  // namespace
-
-TEST_VIEW(AppsSearchResultsControllerTest,
-          [apps_search_results_controller_ view]);
-
-TEST_F(AppsSearchResultsControllerTest, ModelObservers) {
-  NSTableView* table_view = [apps_search_results_controller_ tableView];
-  ExpectConsistent();
-
-  EXPECT_EQ(1, [table_view numberOfColumns]);
-  EXPECT_EQ(kDefaultResultsCount, [table_view numberOfRows]);
-
-  // Insert at start.
-  AddTestResultAtIndex(0, "One", std::string());
-  EXPECT_EQ(kDefaultResultsCount + 1, [table_view numberOfRows]);
-  ExpectConsistent();
-
-  // Remove from end.
-  [delegate_ appListModel]->results()->DeleteAt(kDefaultResultsCount);
-  EXPECT_EQ(kDefaultResultsCount, [table_view numberOfRows]);
-  ExpectConsistent();
-
-  // Insert at end.
-  AddTestResultAtIndex(kDefaultResultsCount, "Four", std::string());
-  EXPECT_EQ(kDefaultResultsCount + 1, [table_view numberOfRows]);
-  ExpectConsistent();
-
-  // Delete from start.
-  [delegate_ appListModel]->results()->DeleteAt(0);
-  EXPECT_EQ(kDefaultResultsCount, [table_view numberOfRows]);
-  ExpectConsistent();
-
-  // Test clearing results.
-  [delegate_ appListModel]->results()->DeleteAll();
-  EXPECT_EQ(0, [table_view numberOfRows]);
-  ExpectConsistent();
-}
-
-TEST_F(AppsSearchResultsControllerTest, KeyboardSelectAndActivate) {
-  NSTableView* table_view = [apps_search_results_controller_ tableView];
-  EXPECT_EQ(-1, [table_view selectedRow]);
-
-  // Pressing up when nothing is selected should select the last item.
-  EXPECT_TRUE(SimulateKeyAction(@selector(moveUp:)));
-  EXPECT_EQ(kDefaultResultsCount - 1, [table_view selectedRow]);
-  [table_view deselectAll:nil];
-  EXPECT_EQ(-1, [table_view selectedRow]);
-
-  // Pressing down when nothing is selected should select the first item.
-  EXPECT_TRUE(SimulateKeyAction(@selector(moveDown:)));
-  EXPECT_EQ(0, [table_view selectedRow]);
-
-  // Pressing up should wrap around.
-  EXPECT_TRUE(SimulateKeyAction(@selector(moveUp:)));
-  EXPECT_EQ(kDefaultResultsCount - 1, [table_view selectedRow]);
-
-  // Down should now also wrap, since the selection is at the end.
-  EXPECT_TRUE(SimulateKeyAction(@selector(moveDown:)));
-  EXPECT_EQ(0, [table_view selectedRow]);
-
-  // Regular down and up movement, ensuring the cells have correct backgrounds.
-  EXPECT_TRUE(SimulateKeyAction(@selector(moveDown:)));
-  EXPECT_EQ(1, [table_view selectedRow]);
-  EXPECT_EQ(NSBackgroundStyleDark, [ViewResultAt(1) backgroundStyle]);
-  EXPECT_EQ(NSBackgroundStyleLight, [ViewResultAt(0) backgroundStyle]);
-
-  EXPECT_TRUE(SimulateKeyAction(@selector(moveUp:)));
-  EXPECT_EQ(0, [table_view selectedRow]);
-  EXPECT_EQ(NSBackgroundStyleDark, [ViewResultAt(0) backgroundStyle]);
-  EXPECT_EQ(NSBackgroundStyleLight, [ViewResultAt(1) backgroundStyle]);
-
-  // Test activating items.
-  EXPECT_TRUE(SimulateKeyAction(@selector(insertNewline:)));
-  EXPECT_EQ(ModelResultAt(0), [delegate_ lastOpenedResult]);
-  EXPECT_TRUE(SimulateKeyAction(@selector(moveDown:)));
-  EXPECT_TRUE(SimulateKeyAction(@selector(insertNewline:)));
-  EXPECT_EQ(ModelResultAt(1), [delegate_ lastOpenedResult]);
-}
-
-TEST_F(AppsSearchResultsControllerTest, ContextMenus) {
-  NSTableView* table_view = [apps_search_results_controller_ tableView];
-  NSEvent* mouse_in_row_0 = MouseEventInRow(table_view, 0);
-  NSEvent* mouse_in_row_1 = MouseEventInRow(table_view, 1);
-
-  NSMenu* menu = [table_view menuForEvent:mouse_in_row_0];
-  EXPECT_EQ(1, [menu numberOfItems]);
-  EXPECT_NSEQ(@"Menu For: Result 0", [[menu itemAtIndex:0] title]);
-
-  // Test a context menu request while the item is still installing.
-  SetMenuReadyAt(1, false);
-  menu = [table_view menuForEvent:mouse_in_row_1];
-  EXPECT_EQ(nil, menu);
-
-  SetMenuReadyAt(1, true);
-  menu = [table_view menuForEvent:mouse_in_row_1];
-  EXPECT_EQ(1, [menu numberOfItems]);
-  EXPECT_NSEQ(@"Menu For: Result 1", [[menu itemAtIndex:0] title]);
-}
-
-}  // namespace test
-}  // namespace app_list
diff --git a/ui/app_list/cocoa/apps_search_results_model_bridge.h b/ui/app_list/cocoa/apps_search_results_model_bridge.h
deleted file mode 100644
index c29487b..0000000
--- a/ui/app_list/cocoa/apps_search_results_model_bridge.h
+++ /dev/null
@@ -1,53 +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.
-
-#ifndef UI_APP_LIST_COCOA_APPS_SEARCH_RESULTS_MODEL_BRIDGE_H_
-#define UI_APP_LIST_COCOA_APPS_SEARCH_RESULTS_MODEL_BRIDGE_H_
-
-#include <stddef.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#include "base/memory/scoped_vector.h"
-#include "ui/base/models/list_model_observer.h"
-
-@class NSMenu;
-@class AppsSearchResultsController;
-
-namespace app_list {
-
-// Bridge observing the ListModel representing search results in the app list,
-// and updating the NSTableView where they are displayed.
-class AppsSearchResultsModelBridge : public ui::ListModelObserver {
- public:
-  explicit AppsSearchResultsModelBridge(
-      AppsSearchResultsController* results_controller);
-  ~AppsSearchResultsModelBridge() override;
-
-  // Returns the context menu for the item at |index| in the search results
-  // model. A menu will be generated if it hasn't been previously requested.
-  NSMenu* MenuForItem(size_t index);
-
- private:
-  // Lightweight observer to react to icon updates on individual results.
-  class ItemObserver;
-
-  void UpdateItemObservers();
-  void ReloadDataForItems(size_t start, size_t count) const;
-
-  // Overridden from ui::ListModelObserver:
-  void ListItemsAdded(size_t start, size_t count) override;
-  void ListItemsRemoved(size_t start, size_t count) override;
-  void ListItemMoved(size_t index, size_t target_index) override;
-  void ListItemsChanged(size_t start, size_t count) override;
-
-  AppsSearchResultsController* parent_;  // Weak. Owns us.
-  ScopedVector<ItemObserver> item_observers_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppsSearchResultsModelBridge);
-};
-
-}  // namespace app_list
-
-#endif  // UI_APP_LIST_COCOA_APPS_SEARCH_RESULTS_MODEL_BRIDGE_H_
diff --git a/ui/app_list/cocoa/apps_search_results_model_bridge.mm b/ui/app_list/cocoa/apps_search_results_model_bridge.mm
deleted file mode 100644
index bbe09ae..0000000
--- a/ui/app_list/cocoa/apps_search_results_model_bridge.mm
+++ /dev/null
@@ -1,126 +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.
-
-#import "ui/app_list/cocoa/apps_search_results_model_bridge.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/macros.h"
-#include "base/strings/sys_string_conversions.h"
-#include "ui/app_list/app_list_model.h"
-#import "ui/app_list/cocoa/apps_search_results_controller.h"
-#include "ui/app_list/search_result.h"
-#include "ui/app_list/search_result_observer.h"
-#import "ui/base/cocoa/menu_controller.h"
-
-namespace app_list {
-
-class AppsSearchResultsModelBridge::ItemObserver : public SearchResultObserver {
- public:
-  ItemObserver(AppsSearchResultsModelBridge* bridge, size_t index)
-      : bridge_(bridge), row_in_view_(index) {
-    // Cache the result, because the results array is updated before notifying
-    // observers (which happens before deleting the SearchResult).
-    result_ = [bridge_->parent_ results]->GetItemAt(index);
-    result_->AddObserver(this);
-  }
-
-  ~ItemObserver() override { result_->RemoveObserver(this); }
-
-  NSMenu* GetContextMenu() {
-    if (!context_menu_controller_) {
-      ui::MenuModel* menu_model = result_->GetContextMenuModel();
-      if (!menu_model)
-        return nil;
-
-      context_menu_controller_.reset(
-          [[MenuController alloc] initWithModel:menu_model
-                         useWithPopUpButtonCell:NO]);
-    }
-    return [context_menu_controller_ menu];
-  }
-
-  // SearchResultObserver overrides:
-  void OnIconChanged() override {
-    bridge_->ReloadDataForItems(row_in_view_, 1);
-  }
-  void OnActionsChanged() override {}
-  void OnIsInstallingChanged() override {}
-  void OnPercentDownloadedChanged() override {}
-  void OnItemInstalled() override {}
-
- private:
-  AppsSearchResultsModelBridge* bridge_;  // Weak. Owns us.
-  SearchResult* result_;  // Weak. Owned by AppListModel::SearchResults.
-  size_t row_in_view_;
-  base::scoped_nsobject<MenuController> context_menu_controller_;
-
-  DISALLOW_COPY_AND_ASSIGN(ItemObserver);
-};
-
-AppsSearchResultsModelBridge::AppsSearchResultsModelBridge(
-    AppsSearchResultsController* results_controller)
-    : parent_(results_controller) {
-  UpdateItemObservers();
-  [parent_ results]->AddObserver(this);
-}
-
-AppsSearchResultsModelBridge::~AppsSearchResultsModelBridge() {
-  [parent_ results]->RemoveObserver(this);
-}
-
-NSMenu* AppsSearchResultsModelBridge::MenuForItem(size_t index) {
-  DCHECK_LT(index, item_observers_.size());
-  return item_observers_[index]->GetContextMenu();
-}
-
-void AppsSearchResultsModelBridge::UpdateItemObservers() {
-  DCHECK(item_observers_.empty());
-  const size_t itemCount = [parent_ results]->item_count();
-  for (size_t i = 0 ; i < itemCount; ++i)
-    item_observers_.push_back(new ItemObserver(this, i));
-}
-
-void AppsSearchResultsModelBridge::ReloadDataForItems(
-    size_t start, size_t count) const {
-  NSIndexSet* column = [NSIndexSet indexSetWithIndex:0];
-  NSIndexSet* rows =
-      [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(start, count)];
-  [[parent_ tableView] reloadDataForRowIndexes:rows
-                                 columnIndexes:column];
-}
-
-void AppsSearchResultsModelBridge::ListItemsAdded(
-    size_t start, size_t count) {
-  item_observers_.clear();
-  if (start == static_cast<size_t>([[parent_ tableView] numberOfRows]))
-    [[parent_ tableView] noteNumberOfRowsChanged];
-  else
-    [[parent_ tableView] reloadData];
-  UpdateItemObservers();
-}
-
-void AppsSearchResultsModelBridge::ListItemsRemoved(
-    size_t start, size_t count) {
-  item_observers_.clear();
-  if (start == [parent_ results]->item_count())
-    [[parent_ tableView] noteNumberOfRowsChanged];
-  else
-    [[parent_ tableView] reloadData];
-  UpdateItemObservers();
-}
-
-void AppsSearchResultsModelBridge::ListItemMoved(
-    size_t index, size_t target_index) {
-  NOTREACHED();
-}
-
-void AppsSearchResultsModelBridge::ListItemsChanged(
-    size_t start, size_t count) {
-  item_observers_.clear();
-  ReloadDataForItems(start, count);
-  UpdateItemObservers();
-}
-
-}  // namespace app_list
diff --git a/ui/app_list/cocoa/item_drag_controller.h b/ui/app_list/cocoa/item_drag_controller.h
deleted file mode 100644
index 3e5b045b..0000000
--- a/ui/app_list/cocoa/item_drag_controller.h
+++ /dev/null
@@ -1,44 +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.
-
-#ifndef UI_APP_LIST_COCOA_ITEM_DRAG_CONTROLLER_H_
-#define UI_APP_LIST_COCOA_ITEM_DRAG_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-#import <QuartzCore/QuartzCore.h>
-
-#include "base/mac/scoped_nsobject.h"
-
-@class AppsGridViewItem;
-
-// Controller to manage the animations and transient views that are used when
-// dragging an app list item around the app list grid. When initiated, the item
-// image (only) is grown in an animation, and sticks to the mouse cursor. When
-// released, the label is added to the image and it shrinks and moves to the
-// item location in the grid.
-@interface ItemDragController : NSViewController {
- @private
-  base::scoped_nsobject<CALayer> dragLayer_;
-  base::scoped_nsobject<NSButton> buttonToRestore_;
-  NSPoint mouseOffset_;
-  NSTimeInterval growStart_;
-  BOOL shrinking_;
-}
-
-- (id)initWithGridCellSize:(NSSize)size;
-
-- (void)initiate:(AppsGridViewItem*)item
-    mouseDownLocation:(NSPoint)mouseDownLocation
-      currentLocation:(NSPoint)currentLocation
-            timestamp:(NSTimeInterval)eventTimestamp;
-
-- (void)update:(NSPoint)currentLocation
-     timestamp:(NSTimeInterval)eventTimestamp;
-
-- (void)complete:(AppsGridViewItem*)item
-    targetOrigin:(NSPoint)targetOrigin;
-
-@end
-
-#endif  // UI_APP_LIST_COCOA_ITEM_DRAG_CONTROLLER_H_
diff --git a/ui/app_list/cocoa/item_drag_controller.mm b/ui/app_list/cocoa/item_drag_controller.mm
deleted file mode 100644
index 1de425b..0000000
--- a/ui/app_list/cocoa/item_drag_controller.mm
+++ /dev/null
@@ -1,184 +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.
-
-#import "ui/app_list/cocoa/item_drag_controller.h"
-
-#include "base/logging.h"
-#import "ui/app_list/cocoa/apps_grid_view_item.h"
-#include "ui/base/cocoa/window_size_constants.h"
-
-// Scale to transform the grid cell when a drag starts. Note that 1.5 ensures
-// that integers are used for the layer bounds when the grid cell dimensions
-// are even.
-const CGFloat kDraggingIconScale = 1.5;
-
-const NSTimeInterval kAnimationDuration = 0.2;
-
-
-@interface ItemDragController ()
-
-- (void)animateTransformFrom:(CATransform3D)fromValue
-                 useDelegate:(BOOL)useDelegate;
-
-- (void)clearAnimations;
-
-@end
-
-@implementation ItemDragController
-
-- (id)initWithGridCellSize:(NSSize)size {
-  if ((self = [super init])) {
-    NSRect frameRect = NSMakeRect(0,
-                                  0,
-                                  size.width * kDraggingIconScale,
-                                  size.height * kDraggingIconScale);
-    base::scoped_nsobject<NSView> dragView(
-        [[NSView alloc] initWithFrame:frameRect]);
-    [dragView setWantsLayer:YES];
-    [dragView setHidden:YES];
-
-    dragLayer_.reset([[CALayer layer] retain]);
-    [dragLayer_ setFrame:NSRectToCGRect(frameRect)];
-    [[dragView layer] addSublayer:dragLayer_];
-
-    [self setView:dragView];
-  }
-  return self;
-}
-
-- (void)initiate:(AppsGridViewItem*)item
-    mouseDownLocation:(NSPoint)mouseDownLocation
-      currentLocation:(NSPoint)currentLocation
-            timestamp:(NSTimeInterval)eventTimestamp {
-  [self clearAnimations];
-  NSView* itemView = [item view];
-  NSPoint pointInGridCell = [itemView convertPoint:mouseDownLocation
-                                          fromView:nil];
-  mouseOffset_ = NSMakePoint(pointInGridCell.x - NSMidX([itemView bounds]),
-                             NSMidY([itemView bounds]) - pointInGridCell.y);
-
-  NSBitmapImageRep* imageRep = [item dragRepresentationForRestore:NO];
-  [dragLayer_ setContents:reinterpret_cast<id>([imageRep CGImage])];
-  [dragLayer_ setTransform:CATransform3DIdentity];
-
-  // Add a grow animation to the layer.
-  CATransform3D growFrom = CATransform3DScale(CATransform3DIdentity,
-                                              1.0 / kDraggingIconScale,
-                                              1.0 / kDraggingIconScale,
-                                              1.0);
-  [self animateTransformFrom:growFrom
-                 useDelegate:NO];
-
-  growStart_ = eventTimestamp;
-  [[self view] setHidden:NO];
-}
-
-- (void)update:(NSPoint)currentLocation
-     timestamp:(NSTimeInterval)eventTimestamp {
-  NSPoint pointInSuperview = [[[self view] superview]
-      convertPoint:currentLocation
-          fromView:nil];
-  NSRect rect = [[self view] bounds];
-  NSPoint anchor = NSMakePoint(NSMidX(rect), NSMidY(rect));
-
-  // If the grow animation is still in progress, make the point of the image
-  // that was clicked appear stuck to the mouse cursor.
-  CGFloat progress = (eventTimestamp - growStart_) / kAnimationDuration;
-  CGFloat currentIconScale = progress < 1.0 ?
-      1.0 + (kDraggingIconScale - 1.0) * progress :
-      kDraggingIconScale;
-
-  pointInSuperview.x -= (mouseOffset_.x * currentIconScale + anchor.x);
-  pointInSuperview.y -= (mouseOffset_.y * currentIconScale + anchor.y);
-  [[self view] setFrameOrigin:pointInSuperview];
-}
-
-- (void)complete:(AppsGridViewItem*)item
-    targetOrigin:(NSPoint)targetOrigin {
-  [self clearAnimations];
-
-  NSView* itemView = [item view];
-  NSBitmapImageRep* imageRep = [item dragRepresentationForRestore:YES];
-
-  [dragLayer_ setContents:reinterpret_cast<id>([imageRep CGImage])];
-  [dragLayer_ setTransform:CATransform3DScale(CATransform3DIdentity,
-                                              1.0 / kDraggingIconScale,
-                                              1.0 / kDraggingIconScale,
-                                              1.0)];
-
-  // Retain the button so it can be unhidden when the animation completes. Note
-  // that the |item| and corresponding button can differ from the |item| passed
-  // to initiate(), if it moved to a new page during the drag. At this point the
-  // destination page is known, so retain the button.
-  buttonToRestore_.reset([[item button] retain]);
-
-  // Add the shrink animation for the layer.
-  [self animateTransformFrom:CATransform3DIdentity
-                 useDelegate:YES];
-  shrinking_ = YES;
-
-  // Also animate the translation, on the view.
-  // TODO(tapted): This should be merged into the scale transform, instead of
-  // using a separate NSViewAnimation.
-  NSRect startRect = [[self view] frame];
-
-  // The final position needs to be adjusted since it shrinks from each side.
-  NSRect targetRect = NSMakeRect(
-      targetOrigin.x - NSMidX([itemView bounds]) * (kDraggingIconScale - 1),
-      targetOrigin.y - NSMidY([itemView bounds]) * (kDraggingIconScale - 1),
-      startRect.size.width,
-      startRect.size.height);
-
-  NSDictionary* animationDict = @{
-      NSViewAnimationTargetKey:     [self view],
-      NSViewAnimationStartFrameKey: [NSValue valueWithRect:startRect],
-      NSViewAnimationEndFrameKey:   [NSValue valueWithRect:targetRect]
-  };
-
-  base::scoped_nsobject<NSViewAnimation> translate([[NSViewAnimation alloc]
-      initWithViewAnimations:[NSArray arrayWithObject:animationDict]]);
-  [translate setDuration:kAnimationDuration];
-  [translate startAnimation];
-}
-
-- (void)animateTransformFrom:(CATransform3D)fromValue
-                 useDelegate:(BOOL)useDelegate {
-  CABasicAnimation* animation =
-      [CABasicAnimation animationWithKeyPath:@"transform"];
-  [animation setFromValue:[NSValue valueWithCATransform3D:fromValue]];
-  if (useDelegate)
-    [animation setDelegate:self];
-
-  [animation setDuration:kAnimationDuration];
-  [CATransaction begin];
-  [CATransaction setValue:[NSNumber numberWithFloat:kAnimationDuration]
-                   forKey:kCATransactionAnimationDuration];
-  [dragLayer_ addAnimation:animation
-                    forKey:@"transform"];
-  [CATransaction commit];
-}
-
-- (void)clearAnimations {
-  [dragLayer_ removeAllAnimations];
-  if (!shrinking_)
-    return;
-
-  DCHECK(buttonToRestore_);
-  [buttonToRestore_ setHidden:NO];
-  buttonToRestore_.reset();
-  shrinking_ = NO;
-}
-
-- (void)animationDidStop:(CAAnimation*)anim
-                finished:(BOOL)finished {
-  if (!finished)
-    return;
-
-  DCHECK(shrinking_);
-  [self clearAnimations];
-  [dragLayer_ setContents:nil];
-  [[self view] setHidden:YES];
-}
-
-@end
diff --git a/ui/app_list/cocoa/scroll_view_with_no_scrollbars.h b/ui/app_list/cocoa/scroll_view_with_no_scrollbars.h
deleted file mode 100644
index 0697e240..0000000
--- a/ui/app_list/cocoa/scroll_view_with_no_scrollbars.h
+++ /dev/null
@@ -1,30 +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.
-
-#ifndef UI_APP_LIST_COCOA_SCROLL_VIEW_WITH_NO_SCROLLBARS_H_
-#define UI_APP_LIST_COCOA_SCROLL_VIEW_WITH_NO_SCROLLBARS_H_
-
-#include <Cocoa/Cocoa.h>
-
-// Delegate to notify when a user interaction to scroll completes.
-@protocol GestureScrollDelegate
-
-// Called when a scroll gesture is observed, or when it completes.
-- (void)userScrolling:(BOOL)isScrolling;
-
-@end
-
-// NSScrollView has a quirk when created programatically that causes gesture
-// scrolling to fail if it does not have a scroll bar. This provides a scroll
-// view using custom scrollers that are not visible.
-@interface ScrollViewWithNoScrollbars : NSScrollView {
- @private
-  id<GestureScrollDelegate> delegate_;
-}
-
-@property(assign, nonatomic) id<GestureScrollDelegate> delegate;
-
-@end
-
-#endif  // UI_APP_LIST_COCOA_SCROLL_VIEW_WITH_NO_SCROLLBARS_H_
diff --git a/ui/app_list/cocoa/scroll_view_with_no_scrollbars.mm b/ui/app_list/cocoa/scroll_view_with_no_scrollbars.mm
deleted file mode 100644
index d4cff30..0000000
--- a/ui/app_list/cocoa/scroll_view_with_no_scrollbars.mm
+++ /dev/null
@@ -1,71 +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 "ui/app_list/cocoa/scroll_view_with_no_scrollbars.h"
-
-#include "base/mac/scoped_cftyperef.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/mac/sdk_forward_declarations.h"
-
-@interface InvisibleScroller : NSScroller;
-@end
-
-@implementation InvisibleScroller
-
-// Makes it non-interactive (and invisible) on Lion with both 10.6 and 10.7
-// SDKs. TODO(tapted): Find a way to make it non-interactive on Snow Leopard.
-// TODO(tapted): Find a way to make it take up no space on Lion with a 10.6 SDK.
-- (NSRect)rectForPart:(NSScrollerPart)aPart {
-  return NSZeroRect;
-}
-
-@end
-
-@implementation ScrollViewWithNoScrollbars
-
-@synthesize delegate = delegate_;
-
-- (id)initWithFrame:(NSRect)frame {
-  if ((self = [super initWithFrame:frame])) {
-    [self setHasHorizontalScroller:YES];
-    NSRect horizontalScrollerRect = [self bounds];
-    horizontalScrollerRect.size.height = 0;
-    base::scoped_nsobject<InvisibleScroller> horizontalScroller(
-        [[InvisibleScroller alloc] initWithFrame:horizontalScrollerRect]);
-    [self setHorizontalScroller:horizontalScroller];
-  }
-  return self;
-}
-
-- (void)scrollWheel:(NSEvent*)event {
-  if ([event subtype] == NSMouseEventSubtype) {
-    // Since the scroll view has no vertical scroller, regular up and down mouse
-    // wheel events would be ignored. This maps mouse wheel events to a
-    // horizontal scroll event of one line, to turn pages.
-    BOOL downOrRight;
-    if ([event deltaX] != 0)
-      downOrRight = [event deltaX] > 0;
-    else if ([event deltaY] != 0)
-      downOrRight = [event deltaY] > 0;
-    else
-      return;
-
-    base::ScopedCFTypeRef<CGEventRef> cgEvent(CGEventCreateScrollWheelEvent(
-        NULL, kCGScrollEventUnitLine, 2, 0, downOrRight ? 1 : -1));
-    [super scrollWheel:[NSEvent eventWithCGEvent:cgEvent]];
-    return;
-  }
-
-  [super scrollWheel:event];
-  if (![event respondsToSelector:@selector(momentumPhase)])
-    return;
-
-  BOOL scrollComplete = [event momentumPhase] == NSEventPhaseEnded ||
-      ([event momentumPhase] == NSEventPhaseNone &&
-          [event phase] == NSEventPhaseEnded);
-
-  [delegate_ userScrolling:!scrollComplete];
-}
-
-@end
diff --git a/ui/app_list/cocoa/test/apps_grid_controller_test_helper.h b/ui/app_list/cocoa/test/apps_grid_controller_test_helper.h
deleted file mode 100644
index 3411638..0000000
--- a/ui/app_list/cocoa/test/apps_grid_controller_test_helper.h
+++ /dev/null
@@ -1,69 +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.
-
-#ifndef UI_APP_LIST_COCOA_TEST_APPS_GRID_CONTROLLER_TEST_HELPER_H_
-#define UI_APP_LIST_COCOA_TEST_APPS_GRID_CONTROLLER_TEST_HELPER_H_
-
-#include <stddef.h>
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#import "ui/gfx/test/ui_cocoa_test_helper.h"
-
-@class AppsGridController;
-
-namespace app_list {
-
-namespace test {
-
-class AppsGridControllerTestHelper : public ui::CocoaTest {
- public:
-  static const size_t kItemsPerPage;
-
-  AppsGridControllerTestHelper();
-  ~AppsGridControllerTestHelper() override;
-
-  void SetUpWithGridController(AppsGridController* grid_controller);
-
- protected:
-  // Send a click to the test window in the centre of |view|.
-  void SimulateClick(NSView* view);
-
-  // Send a key action using handleCommandBySelector.
-  void SimulateKeyAction(SEL c);
-
-  void SimulateMouseEnterItemAt(size_t index);
-  void SimulateMouseExitItemAt(size_t index);
-
-  // Get a string representation of the items as they are currently ordered in
-  // the view. Each page will start and end with a | character.
-  std::string GetViewContent() const;
-
-  // Find the page containing |item_id|, and return the index of that page.
-  // Return NSNotFound if the item is not found, or if the item appears more
-  // than once.
-  size_t GetPageIndexForItem(int item_id) const;
-
-  void DelayForCollectionView();
-  void SinkEvents();
-
-  NSButton* GetItemViewAt(size_t index);
-  NSCollectionView* GetPageAt(size_t index);
-  NSView* GetSelectedView();
-
-  AppsGridController* apps_grid_controller_;
-
- private:
-  base::MessageLoopForUI message_loop_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppsGridControllerTestHelper);
-};
-
-}  // namespace test
-}  // namespace app_list
-
-#endif  // UI_APP_LIST_COCOA_TEST_APPS_GRID_CONTROLLER_TEST_HELPER_H_
diff --git a/ui/app_list/cocoa/test/apps_grid_controller_test_helper.mm b/ui/app_list/cocoa/test/apps_grid_controller_test_helper.mm
deleted file mode 100644
index df6a139e..0000000
--- a/ui/app_list/cocoa/test/apps_grid_controller_test_helper.mm
+++ /dev/null
@@ -1,120 +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.
-
-#import "ui/app_list/cocoa/test/apps_grid_controller_test_helper.h"
-
-#include "base/mac/foundation_util.h"
-#include "base/strings/stringprintf.h"
-#include "ui/app_list/app_list_item.h"
-#import "ui/app_list/cocoa/apps_grid_controller.h"
-#import "ui/app_list/cocoa/apps_grid_view_item.h"
-#import "ui/events/test/cocoa_test_event_utils.h"
-
-namespace app_list {
-namespace test {
-
-const size_t AppsGridControllerTestHelper::kItemsPerPage = 16;
-
-AppsGridControllerTestHelper::AppsGridControllerTestHelper() {
-  Init();
-  [AppsGridController setScrollAnimationDuration:0.0];
-}
-
-AppsGridControllerTestHelper::~AppsGridControllerTestHelper() {}
-
-void AppsGridControllerTestHelper::SetUpWithGridController(
-    AppsGridController* grid_controller) {
-  ui::CocoaTest::SetUp();
-  apps_grid_controller_ = grid_controller;
-}
-
-void AppsGridControllerTestHelper::SimulateClick(NSView* view) {
-  std::pair<NSEvent*, NSEvent*> events(
-      cocoa_test_event_utils::MouseClickInView(view, 1));
-  [NSApp postEvent:events.first atStart:NO];
-  [NSApp postEvent:events.second atStart:NO];
-}
-
-void AppsGridControllerTestHelper::SimulateKeyAction(SEL c) {
-  [apps_grid_controller_ handleCommandBySelector:c];
-}
-
-void AppsGridControllerTestHelper::SimulateMouseEnterItemAt(size_t index) {
-  [[apps_grid_controller_ itemAtIndex:index]
-      mouseEntered:cocoa_test_event_utils::EnterEvent()];
-}
-
-void AppsGridControllerTestHelper::SimulateMouseExitItemAt(size_t index) {
-  [[apps_grid_controller_ itemAtIndex:index]
-      mouseExited:cocoa_test_event_utils::ExitEvent()];
-}
-
-std::string AppsGridControllerTestHelper::GetViewContent() const {
-  std::string s;
-  for (size_t page_index = 0; page_index < [apps_grid_controller_ pageCount];
-       ++page_index) {
-    s += '|';
-    NSCollectionView* page_view =
-        [apps_grid_controller_ collectionViewAtPageIndex:page_index];
-    for (size_t i = 0; i < [[page_view content] count]; ++i) {
-      AppsGridViewItem* item = base::mac::ObjCCastStrict<AppsGridViewItem>(
-          [page_view itemAtIndex:i]);
-      if (i != 0)
-        s += ',';
-      s += [item model]->id();
-    }
-    s += '|';
-  }
-  return s;
-}
-
-size_t AppsGridControllerTestHelper::GetPageIndexForItem(int item_id) const {
-  const std::string search = base::StringPrintf("Item %d", item_id);
-  size_t page_index = 0;
-  NSUInteger found_at_page_index = NSNotFound;
-  for (; page_index < [apps_grid_controller_ pageCount]; ++page_index) {
-    NSCollectionView* page_view =
-        [apps_grid_controller_ collectionViewAtPageIndex:page_index];
-    for (NSUInteger i = 0; i < [[page_view content] count]; ++i) {
-      AppsGridViewItem* item = base::mac::ObjCCastStrict<AppsGridViewItem>(
-          [page_view itemAtIndex:i]);
-      if ([item model]->id() == search) {
-        if (found_at_page_index != NSNotFound)
-          return NSNotFound;  // Duplicate.
-        found_at_page_index = page_index;
-      }
-    }
-  }
-  return found_at_page_index;
-}
-
-void AppsGridControllerTestHelper::DelayForCollectionView() {
-  message_loop_.PostDelayedTask(FROM_HERE,
-                                base::MessageLoop::QuitWhenIdleClosure(),
-                                base::TimeDelta::FromMilliseconds(100));
-  message_loop_.Run();
-}
-
-void AppsGridControllerTestHelper::SinkEvents() {
-  message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
-  message_loop_.Run();
-}
-
-NSButton* AppsGridControllerTestHelper::GetItemViewAt(size_t index) {
-  if (index == NSNotFound)
-    return nil;
-
-  return [[apps_grid_controller_ itemAtIndex:index] button];
-}
-
-NSCollectionView* AppsGridControllerTestHelper::GetPageAt(size_t index) {
-  return [apps_grid_controller_ collectionViewAtPageIndex:index];
-}
-
-NSView* AppsGridControllerTestHelper::GetSelectedView() {
-  return GetItemViewAt([apps_grid_controller_ selectedItemIndex]);
-}
-
-}  // namespace test
-}  // namespace app_list
diff --git a/ui/gfx/mac/io_surface.cc b/ui/gfx/mac/io_surface.cc
index 80e855a..c2d4ea0d 100644
--- a/ui/gfx/mac/io_surface.cc
+++ b/ui/gfx/mac/io_surface.cc
@@ -21,7 +21,7 @@
 namespace {
 
 const base::Feature kIOSurfaceClearYosemite{"IOSurfaceClearYosemite",
-                                            base::FEATURE_ENABLED_BY_DEFAULT};
+                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
 void AddIntegerValue(CFMutableDictionaryRef dictionary,
                      const CFStringRef key,
diff --git a/ui/gfx/transform.h b/ui/gfx/transform.h
index c7a4684..b580a671 100644
--- a/ui/gfx/transform.h
+++ b/ui/gfx/transform.h
@@ -68,7 +68,6 @@
             SkMScalar col2row2,
             SkMScalar x_translation,
             SkMScalar y_translation);
-  ~Transform() {}
 
   bool operator==(const Transform& rhs) const { return matrix_ == rhs.matrix_; }
   bool operator!=(const Transform& rhs) const { return matrix_ != rhs.matrix_; }
diff --git a/ui/gl/test/gl_image_test_template.h b/ui/gl/test/gl_image_test_template.h
index f8122dc5..3cf1178 100644
--- a/ui/gl/test/gl_image_test_template.h
+++ b/ui/gl/test/gl_image_test_template.h
@@ -211,6 +211,11 @@
   // rendering. https://crbug.com/594343.
   if (base::mac::IsOSMavericks())
     return;
+
+  // This functionality is disabled on Yosemite because it is suspected of
+  // causing performance regressions on old hardware. https://crbug.com/606850.
+  if (base::mac::IsOSYosemite())
+    return;
 #endif
 
   const gfx::Size image_size(256, 256);
diff --git a/ui/login/account_picker/user_pod_row.css b/ui/login/account_picker/user_pod_row.css
index fd9b1ff..6f29c15 100644
--- a/ui/login/account_picker/user_pod_row.css
+++ b/ui/login/account_picker/user_pod_row.css
@@ -185,8 +185,7 @@
 
 .auth-container.pin-disabled {
   opacity: 1;
-  transition: opacity 200ms ease-in-out 180ms,
-              visibility 200ms ease-in-out 180ms;
+  transition: opacity 200ms ease-in-out 180ms;
   visibility: visible;
 }
 
diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js
index c258be18..ab4f576 100644
--- a/ui/login/account_picker/user_pod_row.js
+++ b/ui/login/account_picker/user_pod_row.js
@@ -1137,6 +1137,12 @@
         currentElement.classList.toggle('pin-enabled', visible);
         currentElement.classList.toggle('pin-disabled', !visible);
       }
+
+      // Set the focus to the input element after showing/hiding pin keyboard.
+      if (visible)
+        this.pinKeyboard.focus();
+      else
+        this.mainInput.focus();
     },
 
     setUserPodIconType: function(userTypeClass) {
diff --git a/ui/login/screen_container.css b/ui/login/screen_container.css
index 9b3e13d..3825817 100644
--- a/ui/login/screen_container.css
+++ b/ui/login/screen_container.css
@@ -23,8 +23,7 @@
 
 .pin-container.pin-enabled {
   opacity: 1;
-  transition: opacity 200ms ease-in-out 180ms,
-              visibility 200ms ease-in-out 180ms;
+  transition: opacity 200ms ease-in-out 180ms;
   visibility: visible;
 }
 
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc
index 69954dd..b683cdf 100644
--- a/ui/native_theme/native_theme_win.cc
+++ b/ui/native_theme/native_theme_win.cc
@@ -21,8 +21,6 @@
 #include "skia/ext/skia_utils_win.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkColorPriv.h"
-#include "third_party/skia/include/core/SkRefCnt.h"
 #include "third_party/skia/include/core/SkShader.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/display/win/dpi.h"
@@ -251,43 +249,77 @@
       CommonThemePaintMenuItemBackground(this, canvas, state, rect,
                                          extra.menu_item);
       return;
+    case kScrollbarCorner:
+      canvas->drawColor(SK_ColorWHITE, SkXfermode::kSrc_Mode);
+      return;
     default:
       break;
   }
 
-  bool needs_paint_indirect = false;
-  if (!skia::SupportsPlatformPaint(canvas)) {
-    // This block will only get hit with --enable-accelerated-drawing flag.
-    needs_paint_indirect = true;
-  } else {
-    // Scrollbar components on Windows Classic theme (on all Windows versions)
-    // have particularly problematic alpha values, so always draw them
-    // indirectly. In addition, scrollbar thumbs and grippers for the Windows XP
-    // theme (available only on Windows XP) also need their alpha values
-    // fixed.
-    switch (part) {
-      case kScrollbarDownArrow:
-      case kScrollbarUpArrow:
-      case kScrollbarLeftArrow:
-      case kScrollbarRightArrow:
-        needs_paint_indirect = !GetThemeHandle(SCROLLBAR);
-        break;
-      case kScrollbarHorizontalThumb:
-      case kScrollbarVerticalThumb:
-      case kScrollbarHorizontalGripper:
-      case kScrollbarVerticalGripper:
-        needs_paint_indirect = !GetThemeHandle(SCROLLBAR) ||
-            base::win::GetVersion() == base::win::VERSION_XP;
-        break;
-      default:
-        break;
-    }
-  }
+  skia::ScopedPlatformPaint scoped_platform_paint(canvas);
+  HDC hdc = scoped_platform_paint.GetPlatformSurface();
 
-  if (needs_paint_indirect)
-    PaintIndirect(canvas, part, state, rect, extra);
-  else
-    PaintDirect(canvas, part, state, rect, extra);
+  switch (part) {
+    case kCheckbox:
+      PaintCheckbox(hdc, part, state, rect, extra.button);
+      return;
+    case kInnerSpinButton:
+      PaintSpinButton(hdc, part, state, rect, extra.inner_spin);
+      return;
+    case kMenuList:
+      PaintMenuList(hdc, state, rect, extra.menu_list);
+      return;
+    case kMenuCheck:
+      PaintMenuCheck(hdc, state, rect, extra.menu_check);
+      return;
+    case kMenuCheckBackground:
+      PaintMenuCheckBackground(hdc, state, rect);
+      return;
+    case kMenuPopupArrow:
+      PaintMenuArrow(hdc, state, rect, extra.menu_arrow);
+      return;
+    case kProgressBar:
+      PaintProgressBar(hdc, rect, extra.progress_bar);
+      return;
+    case kPushButton:
+      PaintPushButton(hdc, part, state, rect, extra.button);
+      return;
+    case kRadio:
+      PaintRadioButton(hdc, part, state, rect, extra.button);
+      return;
+    case kScrollbarDownArrow:
+    case kScrollbarUpArrow:
+    case kScrollbarLeftArrow:
+    case kScrollbarRightArrow:
+      PaintScrollbarArrow(hdc, part, state, rect, extra.scrollbar_arrow);
+      return;
+    case kScrollbarHorizontalThumb:
+    case kScrollbarVerticalThumb:
+    case kScrollbarHorizontalGripper:
+    case kScrollbarVerticalGripper:
+      PaintScrollbarThumb(hdc, part, state, rect, extra.scrollbar_thumb);
+      return;
+    case kScrollbarHorizontalTrack:
+    case kScrollbarVerticalTrack:
+      PaintScrollbarTrack(canvas, hdc, part, state, rect,
+                          extra.scrollbar_track);
+      return;
+    case kTabPanelBackground:
+      PaintTabPanelBackground(hdc, rect);
+      return;
+    case kTextField:
+      PaintTextField(hdc, part, state, rect, extra.text_field);
+      return;
+    case kTrackbarThumb:
+    case kTrackbarTrack:
+      PaintTrackbar(canvas, hdc, part, state, rect, extra.trackbar);
+      return;
+    case kWindowResizeGripper:
+      PaintWindowResizeGripper(hdc, rect);
+      return;
+    default:
+      NOTREACHED();
+  }
 }
 
 NativeThemeWin::NativeThemeWin()
@@ -376,94 +408,6 @@
   canvas->drawRect(gfx::RectToSkRect(rect), paint);
 }
 
-void NativeThemeWin::PaintDirect(SkCanvas* canvas,
-                                 Part part,
-                                 State state,
-                                 const gfx::Rect& rect,
-                                 const ExtraParams& extra) const {
-  skia::ScopedPlatformPaint scoped_platform_paint(canvas);
-  HDC hdc = scoped_platform_paint.GetPlatformSurface();
-
-  switch (part) {
-    case kCheckbox:
-      PaintCheckbox(hdc, part, state, rect, extra.button);
-      return;
-    case kInnerSpinButton:
-      PaintSpinButton(hdc, part, state, rect, extra.inner_spin);
-      return;
-    case kMenuList:
-      PaintMenuList(hdc, state, rect, extra.menu_list);
-      return;
-    case kMenuCheck:
-      PaintMenuCheck(hdc, state, rect, extra.menu_check);
-      return;
-    case kMenuCheckBackground:
-      PaintMenuCheckBackground(hdc, state, rect);
-      return;
-    case kMenuPopupArrow:
-      PaintMenuArrow(hdc, state, rect, extra.menu_arrow);
-      return;
-    case kMenuPopupBackground:
-      PaintMenuBackground(hdc, rect);
-      return;
-    case kMenuPopupGutter:
-      PaintMenuGutter(hdc, rect);
-      return;
-    case kMenuPopupSeparator:
-      PaintMenuSeparator(hdc, rect);
-      return;
-    case kMenuItemBackground:
-      PaintMenuItemBackground(hdc, state, rect, extra.menu_item);
-      return;
-    case kProgressBar:
-      PaintProgressBar(hdc, rect, extra.progress_bar);
-      return;
-    case kPushButton:
-      PaintPushButton(hdc, part, state, rect, extra.button);
-      return;
-    case kRadio:
-      PaintRadioButton(hdc, part, state, rect, extra.button);
-      return;
-    case kScrollbarDownArrow:
-    case kScrollbarUpArrow:
-    case kScrollbarLeftArrow:
-    case kScrollbarRightArrow:
-      PaintScrollbarArrow(hdc, part, state, rect, extra.scrollbar_arrow);
-      return;
-    case kScrollbarHorizontalThumb:
-    case kScrollbarVerticalThumb:
-    case kScrollbarHorizontalGripper:
-    case kScrollbarVerticalGripper:
-      PaintScrollbarThumb(hdc, part, state, rect, extra.scrollbar_thumb);
-      return;
-    case kScrollbarHorizontalTrack:
-    case kScrollbarVerticalTrack:
-      PaintScrollbarTrack(canvas, hdc, part, state, rect,
-                          extra.scrollbar_track);
-      return;
-    case kScrollbarCorner:
-      canvas->drawColor(SK_ColorWHITE, SkXfermode::kSrc_Mode);
-      return;
-    case kTabPanelBackground:
-      PaintTabPanelBackground(hdc, rect);
-      return;
-    case kTextField:
-      PaintTextField(hdc, part, state, rect, extra.text_field);
-      return;
-    case kTrackbarThumb:
-    case kTrackbarTrack:
-      PaintTrackbar(canvas, hdc, part, state, rect, extra.trackbar);
-      return;
-    case kWindowResizeGripper:
-      PaintWindowResizeGripper(hdc, rect);
-      return;
-    case kSliderTrack:
-    case kSliderThumb:
-    case kMaxPart:
-      NOTREACHED();
-  }
-}
-
 SkColor NativeThemeWin::GetSystemColor(ColorId color_id) const {
   const bool md = ui::MaterialDesignController::IsModeMaterial();
   if (!md) {
@@ -672,76 +616,6 @@
   return GetAuraColor(color_id, this);
 }
 
-void NativeThemeWin::PaintIndirect(SkCanvas* canvas,
-                                   Part part,
-                                   State state,
-                                   const gfx::Rect& rect,
-                                   const ExtraParams& extra) const {
-  // TODO(asvitkine): This path is pretty inefficient - for each paint operation
-  //                  it creates a new offscreen bitmap Skia canvas. This can
-  //                  be sped up by doing it only once per part/state and
-  //                  keeping a cache of the resulting bitmaps.
-
-  // Create an offscreen canvas that is backed by an HDC.
-  sk_sp<skia::BitmapPlatformDevice> device(
-      skia::BitmapPlatformDevice::Create(
-          rect.width(), rect.height(), false, NULL));
-  DCHECK(device);
-  SkCanvas offscreen_canvas(device.get());
-  DCHECK(skia::SupportsPlatformPaint(&offscreen_canvas));
-
-  // Some of the Windows theme drawing operations do not write correct alpha
-  // values for fully-opaque pixels; instead the pixels get alpha 0. This is
-  // especially a problem on Windows XP or when using the Classic theme.
-  //
-  // To work-around this, mark all pixels with a placeholder value, to detect
-  // which pixels get touched by the paint operation. After paint, set any
-  // pixels that have alpha 0 to opaque and placeholders to fully-transparent.
-  const SkColor placeholder = SkColorSetARGB(1, 0, 0, 0);
-  offscreen_canvas.clear(placeholder);
-
-  // Offset destination rects to have origin (0,0).
-  gfx::Rect adjusted_rect(rect.size());
-  ExtraParams adjusted_extra(extra);
-  switch (part) {
-    case kProgressBar:
-      adjusted_extra.progress_bar.value_rect_x = 0;
-      adjusted_extra.progress_bar.value_rect_y = 0;
-      break;
-    case kScrollbarHorizontalTrack:
-    case kScrollbarVerticalTrack:
-      adjusted_extra.scrollbar_track.track_x = 0;
-      adjusted_extra.scrollbar_track.track_y = 0;
-      break;
-    default:
-      break;
-  }
-  // Draw the theme controls using existing HDC-drawing code.
-  PaintDirect(&offscreen_canvas, part, state, adjusted_rect, adjusted_extra);
-
-  SkBitmap bitmap = skia::ReadPixels(&offscreen_canvas);
-
-  // Post-process the pixels to fix up the alpha values (see big comment above).
-  const SkPMColor placeholder_value = SkPreMultiplyColor(placeholder);
-  const int pixel_count = rect.width() * rect.height();
-  SkPMColor* pixels = bitmap.getAddr32(0, 0);
-  for (int i = 0; i < pixel_count; i++) {
-    if (pixels[i] == placeholder_value) {
-      // Pixel wasn't touched - make it fully transparent.
-      pixels[i] = SkPackARGB32(0, 0, 0, 0);
-    } else if (SkGetPackedA32(pixels[i]) == 0) {
-      // Pixel was touched but has incorrect alpha of 0, make it fully opaque.
-      pixels[i] = SkPackARGB32(0xFF,
-                               SkGetPackedR32(pixels[i]),
-                               SkGetPackedG32(pixels[i]),
-                               SkGetPackedB32(pixels[i]));
-    }
-  }
-
-  // Draw the offscreen bitmap to the destination canvas.
-  canvas->drawBitmap(bitmap, rect.x(), rect.y());
-}
-
 HRESULT NativeThemeWin::GetThemePartSize(ThemeName theme_name,
                                          HDC hdc,
                                          int part_id,
@@ -843,33 +717,6 @@
   return S_OK;
 }
 
-HRESULT NativeThemeWin::PaintMenuSeparator(
-    HDC hdc,
-    const gfx::Rect& rect) const {
-  RECT rect_win = rect.ToRECT();
-
-  HANDLE handle = GetThemeHandle(MENU);
-  if (handle && draw_theme_) {
-    // Delta is needed for non-classic to move separator up slightly.
-    --rect_win.top;
-    --rect_win.bottom;
-    return draw_theme_(handle, hdc, MENU_POPUPSEPARATOR, MPI_NORMAL, &rect_win,
-                       NULL);
-  }
-
-  DrawEdge(hdc, &rect_win, EDGE_ETCHED, BF_TOP);
-  return S_OK;
-}
-
-HRESULT NativeThemeWin::PaintMenuGutter(HDC hdc,
-                                        const gfx::Rect& rect) const {
-  RECT rect_win = rect.ToRECT();
-  HANDLE handle = GetThemeHandle(MENU);
-  return (handle && draw_theme_) ?
-      draw_theme_(handle, hdc, MENU_POPUPGUTTER, MPI_NORMAL, &rect_win, NULL) :
-      E_NOTIMPL;
-}
-
 HRESULT NativeThemeWin::PaintMenuArrow(
     HDC hdc,
     State state,
@@ -916,22 +763,6 @@
                            state);
 }
 
-HRESULT NativeThemeWin::PaintMenuBackground(HDC hdc,
-                                            const gfx::Rect& rect) const {
-  HANDLE handle = GetThemeHandle(MENU);
-  RECT rect_win = rect.ToRECT();
-  if (handle && draw_theme_) {
-    HRESULT result = draw_theme_(handle, hdc, MENU_POPUPBACKGROUND, 0,
-                                 &rect_win, NULL);
-    FrameRect(hdc, &rect_win, GetSysColorBrush(COLOR_3DSHADOW));
-    return result;
-  }
-
-  FillRect(hdc, &rect_win, GetSysColorBrush(COLOR_MENU));
-  DrawEdge(hdc, &rect_win, EDGE_RAISED, BF_RECT);
-  return S_OK;
-}
-
 HRESULT NativeThemeWin::PaintMenuCheck(
     HDC hdc,
     State state,
@@ -964,37 +795,6 @@
                      &rect_win, NULL);
 }
 
-HRESULT NativeThemeWin::PaintMenuItemBackground(
-    HDC hdc,
-    State state,
-    const gfx::Rect& rect,
-    const MenuItemExtraParams& extra) const {
-  HANDLE handle = GetThemeHandle(MENU);
-  RECT rect_win = rect.ToRECT();
-  int state_id = MPI_NORMAL;
-  switch (state) {
-    case kDisabled:
-      state_id = extra.is_selected ? MPI_DISABLEDHOT : MPI_DISABLED;
-      break;
-    case kHovered:
-      state_id = MPI_HOT;
-      break;
-    case kNormal:
-      break;
-    case kPressed:
-    case kNumStates:
-      NOTREACHED();
-      break;
-  }
-
-  if (handle && draw_theme_)
-    return draw_theme_(handle, hdc, MENU_POPUPITEM, state_id, &rect_win, NULL);
-
-  if (extra.is_selected)
-    FillRect(hdc, &rect_win, GetSysColorBrush(COLOR_HIGHLIGHT));
-  return S_OK;
-}
-
 HRESULT NativeThemeWin::PaintPushButton(HDC hdc,
                                         Part part,
                                         State state,
diff --git a/ui/native_theme/native_theme_win.h b/ui/native_theme/native_theme_win.h
index 03483650..8f8597b 100644
--- a/ui/native_theme/native_theme_win.h
+++ b/ui/native_theme/native_theme_win.h
@@ -130,22 +130,6 @@
   void PaintMenuGutter(SkCanvas* canvas, const gfx::Rect& rect) const;
   void PaintMenuBackground(SkCanvas* canvas, const gfx::Rect& rect) const;
 
-  // Paint directly to canvas' HDC.
-  void PaintDirect(SkCanvas* canvas,
-                   Part part,
-                   State state,
-                   const gfx::Rect& rect,
-                   const ExtraParams& extra) const;
-
-  // Create a temporary HDC, paint to that, clean up the alpha values in the
-  // temporary HDC, and then blit the result to canvas.  This is to work around
-  // the fact that Windows XP and some classic themes give bogus alpha values.
-  void PaintIndirect(SkCanvas* canvas,
-                     Part part,
-                     State state,
-                     const gfx::Rect& rect,
-                     const ExtraParams& extra) const;
-
   HRESULT GetThemePartSize(ThemeName themeName,
                            HDC hdc,
                            int part_id,
@@ -161,11 +145,6 @@
                       int state_id,
                       RECT* rect) const;
 
-  HRESULT PaintMenuSeparator(HDC hdc,
-                             const gfx::Rect& rect) const;
-
-  HRESULT PaintMenuGutter(HDC hdc, const gfx::Rect& rect) const;
-
   // |arrow_direction| determines whether the arrow is pointing to the left or
   // to the right. In RTL locales, sub-menus open from right to left and
   // therefore the menu arrow should point to the left and not to the right.
@@ -174,8 +153,6 @@
                          const gfx::Rect& rect,
                          const MenuArrowExtraParams& extra) const;
 
-  HRESULT PaintMenuBackground(HDC hdc, const gfx::Rect& rect) const;
-
   HRESULT PaintMenuCheck(HDC hdc,
                          State state,
                          const gfx::Rect& rect,
@@ -185,11 +162,6 @@
                                    State state,
                                    const gfx::Rect& rect) const;
 
-  HRESULT PaintMenuItemBackground(HDC hdc,
-                                  State state,
-                                  const gfx::Rect& rect,
-                                  const MenuItemExtraParams& extra) const;
-
   HRESULT PaintPushButton(HDC hdc,
                           Part part,
                           State state,
diff --git a/ui/views/animation/ink_drop_host_view.cc b/ui/views/animation/ink_drop_host_view.cc
index ab14900..b7ae651 100644
--- a/ui/views/animation/ink_drop_host_view.cc
+++ b/ui/views/animation/ink_drop_host_view.cc
@@ -44,18 +44,16 @@
 // TODO(bruthig): Consider getting rid of this class.
 class InkDropHostView::InkDropGestureHandler : public ui::EventHandler {
  public:
-  InkDropGestureHandler(InkDropHostView* host_view, InkDrop* ink_drop)
+  explicit InkDropGestureHandler(InkDropHostView* host_view)
       : target_handler_(new ui::ScopedTargetHandler(host_view, this)),
-        host_view_(host_view),
-        ink_drop_(ink_drop) {}
+        host_view_(host_view) {}
 
   ~InkDropGestureHandler() override {}
 
-  void SetInkDrop(InkDrop* ink_drop) { ink_drop_ = ink_drop; }
-
   // ui::EventHandler:
   void OnGestureEvent(ui::GestureEvent* event) override {
-    InkDropState current_ink_drop_state = ink_drop_->GetTargetInkDropState();
+    InkDropState current_ink_drop_state =
+        host_view_->ink_drop()->GetTargetInkDropState();
 
     InkDropState ink_drop_state = InkDropState::HIDDEN;
     switch (event->type()) {
@@ -102,9 +100,6 @@
   // The host view to cache ui::Events to when animating the ink drop.
   InkDropHostView* host_view_;
 
-  // Animation controller for the ink drop ripple effect.
-  InkDrop* ink_drop_;
-
   DISALLOW_COPY_AND_ASSIGN(InkDropGestureHandler);
 };
 
@@ -241,14 +236,10 @@
   else
     ink_drop_.reset(new InkDropImpl(this));
 
-  if (ink_drop_mode == InkDropMode::ON) {
-    if (gesture_handler_)
-      gesture_handler_->SetInkDrop(ink_drop_.get());
-    else
-      gesture_handler_.reset(new InkDropGestureHandler(this, ink_drop_.get()));
-  } else {
+  if (ink_drop_mode != InkDropMode::ON)
     gesture_handler_.reset();
-  }
+  else if (!gesture_handler_)
+    gesture_handler_.reset(new InkDropGestureHandler(this));
 }
 
 }  // namespace views
diff --git a/ui/views/mus/views_mus_test_suite.cc b/ui/views/mus/views_mus_test_suite.cc
index 5446606e..72ed1412 100644
--- a/ui/views/mus/views_mus_test_suite.cc
+++ b/ui/views/mus/views_mus_test_suite.cc
@@ -15,8 +15,7 @@
 #include "services/shell/background/background_shell.h"
 #include "services/shell/public/cpp/connector.h"
 #include "services/shell/public/cpp/service.h"
-#include "services/shell/public/cpp/shell_connection.h"
-#include "services/ui/common/gpu_service.h"
+#include "services/shell/public/cpp/service_context.h"
 #include "services/ui/common/switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/views/mus/window_manager_connection.h"
@@ -45,12 +44,11 @@
  public:
   PlatformTestHelperMus(shell::Connector* connector,
                         const shell::Identity& identity) {
-    ui::GpuService::Initialize(connector);
     // It is necessary to recreate the WindowManagerConnection for each test,
     // since a new MessageLoop is created for each test.
     connection_ = WindowManagerConnection::Create(connector, identity);
   }
-  ~PlatformTestHelperMus() override { ui::GpuService::Terminate(); }
+  ~PlatformTestHelperMus() override {}
 
  private:
   std::unique_ptr<WindowManagerConnection> connection_;
@@ -119,7 +117,7 @@
     background_shell_.reset(new shell::BackgroundShell);
     background_shell_->Init(nullptr);
     service_.reset(new DefaultService);
-    shell_connection_.reset(new shell::ShellConnection(
+    shell_connection_.reset(new shell::ServiceContext(
         service_.get(),
         background_shell_->CreateServiceRequest(GetTestName())));
 
@@ -147,7 +145,7 @@
 
   base::Thread thread_;
   std::unique_ptr<shell::BackgroundShell> background_shell_;
-  std::unique_ptr<shell::ShellConnection> shell_connection_;
+  std::unique_ptr<shell::ServiceContext> shell_connection_;
   std::unique_ptr<DefaultService> service_;
   std::unique_ptr<shell::Connector> shell_connector_;
   shell::Identity shell_identity_;
diff --git a/ui/views/mus/window_manager_connection.cc b/ui/views/mus/window_manager_connection.cc
index d5f3670..c9ac178 100644
--- a/ui/views/mus/window_manager_connection.cc
+++ b/ui/views/mus/window_manager_connection.cc
@@ -10,6 +10,7 @@
 #include "base/threading/thread_local.h"
 #include "services/shell/public/cpp/connection.h"
 #include "services/shell/public/cpp/connector.h"
+#include "services/ui/common/gpu_service.h"
 #include "services/ui/public/cpp/property_type_converters.h"
 #include "services/ui/public/cpp/window.h"
 #include "services/ui/public/cpp/window_property.h"
@@ -105,6 +106,9 @@
     const shell::Identity& identity)
     : connector_(connector), identity_(identity) {
   lazy_tls_ptr.Pointer()->Set(this);
+
+  ui::GpuService::Initialize(connector);
+
   client_.reset(new ui::WindowTreeClient(this, nullptr, nullptr));
   client_->ConnectViaWindowTreeFactory(connector_);
 
@@ -126,6 +130,7 @@
   // we are still valid.
   client_.reset();
   ui::Clipboard::DestroyClipboardForCurrentThread();
+  ui::GpuService::Terminate();
   lazy_tls_ptr.Pointer()->Set(nullptr);
 
   if (ViewsDelegate::GetInstance()) {