diff --git a/DEPS b/DEPS
index 32f03b7..48446782 100644
--- a/DEPS
+++ b/DEPS
@@ -79,11 +79,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': '945ac788d85dad4c298fb482a8e53c730e90c752',
+  'skia_revision': '8402542dac9e90dcaf2712d187ac96ee191ab187',
   # 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': '1acdfd58f7117ad962240cbaa94704244fd06797',
+  'v8_revision': 'f585291b281440934e8c74d0abbc719d9b9a1e51',
   # 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.
@@ -91,7 +91,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': '41918387cc52553defbfc10ed30b504e628b6fe4',
+  'angle_revision': '44a73fcfbe2d20db7f9bafada736368e3312520d',
   # 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.
@@ -103,7 +103,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': 'd1ffda2acaee90a7b8a6dd36e0605dce826058e9',
+  'pdfium_revision': '7d75650672a848428aaadb603b2814d33dfb479f',
   # 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.
@@ -135,7 +135,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': '1446cf3fe8a3b827432365c3fdaf902d6bd033a7',
+  'catapult_revision': '36d08eec1a0703adada45bc1474e59e45c1cd376',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -365,7 +365,7 @@
   },
 
   'src/third_party/ffmpeg':
-    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '4468d4967f5dd6a733860af355ef61095b5cd5b1',
+    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '02ec9ce5a9bc14a5e245fdfce30770d2e878bb24',
 
   'src/third_party/flac':
     Var('chromium_git') + '/chromium/deps/flac.git' + '@' + '7d0f5b3a173ffe98db08057d1f52b7787569e0a6',
@@ -657,7 +657,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '3c1cb0203b6cfc10389e85a350b2ea6ca29d01ce',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '853715c9a90611486aa191219a103a4acd7a664f', # commit position 21742
+    Var('webrtc_git') + '/src.git' + '@' + '24c220c178f9f1375e190d770425f5c83fc223cf', # commit position 21742
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -680,7 +680,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@5d11b541fc9e0bc0549401ab1fbdfef4f03626fe',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ceb1b20c43132851bb4cd489b9c772e10e85e355',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 256993f..b43328e 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1389,7 +1389,7 @@
     "//content/public/browser",
     "//content/test:test_support",
     "//device/bluetooth",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//net",
     "//skia",
     "//testing/gtest",
@@ -1695,7 +1695,7 @@
     "//components/user_manager",
     "//components/user_manager:test_support",
     "//device/bluetooth",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//net:net",
     "//services/ui/public/cpp/input_devices:test_support",
     "//services/ui/public/interfaces",
@@ -1769,7 +1769,7 @@
     "//ash/public/cpp",
     "//base/test:test_support",
     "//cc/base",
-    "//mojo/edk/embedder:headers",
+    "//mojo/edk",
     "//testing/gtest",
     "//testing/perf",
     "//ui/aura",
diff --git a/ash/accessibility/accessibility_focus_ring_controller.cc b/ash/accessibility/accessibility_focus_ring_controller.cc
index cb586df..6e4a8e7 100644
--- a/ash/accessibility/accessibility_focus_ring_controller.cc
+++ b/ash/accessibility/accessibility_focus_ring_controller.cc
@@ -12,6 +12,8 @@
 #include <utility>
 #include <vector>
 
+#include "ash/accessibility/accessibility_cursor_ring_layer.h"
+#include "ash/accessibility/accessibility_focus_ring_layer.h"
 #include "ash/accessibility/accessibility_highlight_layer.h"
 #include "ash/accessibility/focus_ring_layer.h"
 #include "base/logging.h"
@@ -23,31 +25,31 @@
 // The number of pixels the focus ring is outset from the object it outlines,
 // which also determines the border radius of the rounded corners.
 // TODO(dmazzoni): take display resolution into account.
-const int kAccessibilityFocusRingMargin = 7;
+constexpr int kAccessibilityFocusRingMargin = 7;
 
 // Time to transition between one location and the next.
-const int kTransitionTimeMilliseconds = 300;
+constexpr int kTransitionTimeMilliseconds = 300;
 
 // Focus constants.
-const int kFocusFadeInTimeMilliseconds = 100;
-const int kFocusFadeOutTimeMilliseconds = 1600;
+constexpr int kFocusFadeInTimeMilliseconds = 100;
+constexpr int kFocusFadeOutTimeMilliseconds = 1600;
 
 // Cursor constants.
-const int kCursorFadeInTimeMilliseconds = 400;
-const int kCursorFadeOutTimeMilliseconds = 1200;
-const int kCursorRingColorRed = 255;
-const int kCursorRingColorGreen = 51;
-const int kCursorRingColorBlue = 51;
+constexpr int kCursorFadeInTimeMilliseconds = 400;
+constexpr int kCursorFadeOutTimeMilliseconds = 1200;
+constexpr int kCursorRingColorRed = 255;
+constexpr int kCursorRingColorGreen = 51;
+constexpr int kCursorRingColorBlue = 51;
 
 // Caret constants.
-const int kCaretFadeInTimeMilliseconds = 100;
-const int kCaretFadeOutTimeMilliseconds = 1600;
-const int kCaretRingColorRed = 51;
-const int kCaretRingColorGreen = 51;
-const int kCaretRingColorBlue = 255;
+constexpr int kCaretFadeInTimeMilliseconds = 100;
+constexpr int kCaretFadeOutTimeMilliseconds = 1600;
+constexpr int kCaretRingColorRed = 51;
+constexpr int kCaretRingColorGreen = 51;
+constexpr int kCaretRingColorBlue = 255;
 
 // Highlight constants.
-const float kHighlightOpacity = 0.3f;
+constexpr float kHighlightOpacity = 0.3f;
 
 // A Region is an unordered collection of Rects that maintains its
 // bounding box. Used in the middle of an algorithm that groups
@@ -63,12 +65,6 @@
 
 }  // namespace
 
-// static
-AccessibilityFocusRingController*
-AccessibilityFocusRingController::GetInstance() {
-  return base::Singleton<AccessibilityFocusRingController>::get();
-}
-
 AccessibilityFocusRingController::AccessibilityFocusRingController()
     : binding_(this) {
   focus_animation_info_.fade_in_time =
diff --git a/ash/accessibility/accessibility_focus_ring_controller.h b/ash/accessibility/accessibility_focus_ring_controller.h
index 1e809912..05f7e4e 100644
--- a/ash/accessibility/accessibility_focus_ring_controller.h
+++ b/ash/accessibility/accessibility_focus_ring_controller.h
@@ -8,14 +8,12 @@
 #include <memory>
 #include <vector>
 
-#include "ash/accessibility/accessibility_cursor_ring_layer.h"
-#include "ash/accessibility/accessibility_focus_ring_layer.h"
-#include "ash/accessibility/accessibility_highlight_layer.h"
+#include "ash/accessibility/accessibility_focus_ring.h"
+#include "ash/accessibility/accessibility_layer.h"
 #include "ash/ash_export.h"
 #include "ash/public/interfaces/accessibility_focus_ring_controller.mojom.h"
 #include "base/bind.h"
 #include "base/macros.h"
-#include "base/memory/singleton.h"
 #include "base/optional.h"
 #include "base/time/time.h"
 #include "mojo/public/cpp/bindings/binding.h"
@@ -24,14 +22,18 @@
 
 namespace ash {
 
+class AccessibilityCursorRingLayer;
+class AccessibilityFocusRingLayer;
+class AccessibilityHighlightLayer;
+
 // AccessibilityFocusRingController handles drawing custom rings around
 // the focused object, cursor, and/or caret for accessibility.
 class ASH_EXPORT AccessibilityFocusRingController
     : public AccessibilityLayerDelegate,
       public mojom::AccessibilityFocusRingController {
  public:
-  // Get the single instance of this class.
-  static AccessibilityFocusRingController* GetInstance();
+  AccessibilityFocusRingController();
+  ~AccessibilityFocusRingController() override;
 
   // Binds the mojom::AccessibilityFocusRingController interface to this object.
   void BindRequest(mojom::AccessibilityFocusRingControllerRequest request);
@@ -68,14 +70,8 @@
   focus_ring_layers_for_testing() {
     return focus_layers_;
   }
-  AccessibilityHighlightLayer* highlight_layer_for_testing() {
-    return highlight_layer_.get();
-  }
 
  protected:
-  AccessibilityFocusRingController();
-  ~AccessibilityFocusRingController() override;
-
   // Given an unordered vector of bounding rectangles that cover everything
   // that currently has focus, populate a vector of one or more
   // AccessibilityFocusRings that surround the rectangles. Adjacent or
@@ -151,8 +147,6 @@
   SkColor highlight_color_ = SK_ColorBLACK;
   float highlight_opacity_ = 0.f;
 
-  friend struct base::DefaultSingletonTraits<AccessibilityFocusRingController>;
-
   DISALLOW_COPY_AND_ASSIGN(AccessibilityFocusRingController);
 };
 
diff --git a/ash/accessibility/accessibility_focus_ring_controller_unittest.cc b/ash/accessibility/accessibility_focus_ring_controller_unittest.cc
index d5c9320..4ee954d 100644
--- a/ash/accessibility/accessibility_focus_ring_controller_unittest.cc
+++ b/ash/accessibility/accessibility_focus_ring_controller_unittest.cc
@@ -148,7 +148,7 @@
 
   // Simulate a mouse event on the primary display.
   AccessibilityFocusRingController* controller =
-      AccessibilityFocusRingController::GetInstance();
+      Shell::Get()->accessibility_focus_ring_controller();
   gfx::Point location(90, 90);
   controller->SetCursorRing(location);
   AccessibilityCursorRingLayer* cursor_layer =
diff --git a/ash/accessibility/accessibility_highlight_controller.cc b/ash/accessibility/accessibility_highlight_controller.cc
index 217cf88..13dd54bd 100644
--- a/ash/accessibility/accessibility_highlight_controller.cc
+++ b/ash/accessibility/accessibility_highlight_controller.cc
@@ -42,10 +42,12 @@
 }
 
 AccessibilityHighlightController::~AccessibilityHighlightController() {
-  AccessibilityFocusRingController::GetInstance()->SetFocusRing(
-      std::vector<gfx::Rect>(), mojom::FocusRingBehavior::FADE_OUT_FOCUS_RING);
-  AccessibilityFocusRingController::GetInstance()->HideCaretRing();
-  AccessibilityFocusRingController::GetInstance()->HideCursorRing();
+  AccessibilityFocusRingController* controller =
+      Shell::Get()->accessibility_focus_ring_controller();
+  controller->SetFocusRing(std::vector<gfx::Rect>(),
+                           mojom::FocusRingBehavior::FADE_OUT_FOCUS_RING);
+  controller->HideCaretRing();
+  controller->HideCursorRing();
 
   aura::Window* root_window = Shell::GetPrimaryRootWindow();
   ui::InputMethod* input_method = GetInputMethod(root_window);
@@ -141,7 +143,8 @@
 }
 
 void AccessibilityHighlightController::UpdateFocusAndCaretHighlights() {
-  auto* controller = AccessibilityFocusRingController::GetInstance();
+  AccessibilityFocusRingController* controller =
+      Shell::Get()->accessibility_focus_ring_controller();
 
   // The caret highlight takes precedence over the focus highlight if
   // both are visible.
@@ -164,12 +167,12 @@
 }
 
 void AccessibilityHighlightController::UpdateCursorHighlight() {
-  if (cursor_ && IsCursorVisible()) {
-    AccessibilityFocusRingController::GetInstance()->SetCursorRing(
-        cursor_point_);
-  } else {
-    AccessibilityFocusRingController::GetInstance()->HideCursorRing();
-  }
+  AccessibilityFocusRingController* controller =
+      Shell::Get()->accessibility_focus_ring_controller();
+  if (cursor_ && IsCursorVisible())
+    controller->SetCursorRing(cursor_point_);
+  else
+    controller->HideCursorRing();
 }
 
 }  // namespace ash
diff --git a/ash/accessibility/accessibility_highlight_controller_unittest.cc b/ash/accessibility/accessibility_highlight_controller_unittest.cc
index 8969c803..d7ae502 100644
--- a/ash/accessibility/accessibility_highlight_controller_unittest.cc
+++ b/ash/accessibility/accessibility_highlight_controller_unittest.cc
@@ -5,6 +5,7 @@
 #include "ash/accessibility/accessibility_highlight_controller.h"
 
 #include <cmath>
+#include <memory>
 
 #include "ash/accessibility/accessibility_cursor_ring_layer.h"
 #include "ash/accessibility/accessibility_focus_ring_controller.h"
@@ -72,7 +73,7 @@
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         ::switches::kEnablePixelOutputInTests);
     AshTestBase::SetUp();
-    AccessibilityFocusRingController::GetInstance()->SetNoFadeForTesting();
+    Shell::Get()->accessibility_focus_ring_controller()->SetNoFadeForTesting();
   }
 
   void CaptureBeforeImage(const gfx::Rect& bounds) {
@@ -226,7 +227,8 @@
   event_mod.set_target(root_windows[0]);
   highlight_controller.OnMouseEvent(&event0);
 
-  auto* focus_ring_controller = AccessibilityFocusRingController::GetInstance();
+  AccessibilityFocusRingController* focus_ring_controller =
+      Shell::Get()->accessibility_focus_ring_controller();
   auto* cursor_layer = focus_ring_controller->cursor_layer_for_testing();
   EXPECT_EQ(root_windows[0], cursor_layer->root_window());
   EXPECT_LT(
@@ -267,7 +269,8 @@
   text_input_client.SetCaretBounds(caret_bounds);
   highlight_controller.OnCaretBoundsChanged(&text_input_client);
 
-  auto* focus_ring_controller = AccessibilityFocusRingController::GetInstance();
+  AccessibilityFocusRingController* focus_ring_controller =
+      Shell::Get()->accessibility_focus_ring_controller();
   auto* caret_layer = focus_ring_controller->caret_layer_for_testing();
   EXPECT_EQ(
       std::abs(caret_layer->layer()->GetTargetBounds().x() - caret_bounds.x()),
diff --git a/ash/accessibility/touch_exploration_manager.cc b/ash/accessibility/touch_exploration_manager.cc
index e6ce3b1..0b1e8ad9 100644
--- a/ash/accessibility/touch_exploration_manager.cc
+++ b/ash/accessibility/touch_exploration_manager.cc
@@ -212,7 +212,7 @@
       touch_exploration_controller_->SetExcludeBounds(work_area);
       SilenceSpokenFeedback();
       // Clear the focus highlight.
-      AccessibilityFocusRingController::GetInstance()->SetFocusRing(
+      Shell::Get()->accessibility_focus_ring_controller()->SetFocusRing(
           std::vector<gfx::Rect>(),
           mojom::FocusRingBehavior::PERSIST_FOCUS_RING);
     } else {
diff --git a/ash/app_list/presenter/BUILD.gn b/ash/app_list/presenter/BUILD.gn
index cca7d97..911e7e5 100644
--- a/ash/app_list/presenter/BUILD.gn
+++ b/ash/app_list/presenter/BUILD.gn
@@ -72,7 +72,7 @@
     "//ash:ash",
     "//base",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//testing/gtest",
     "//ui/app_list:test_support",
     "//ui/aura:aura",
diff --git a/ash/display/display_color_manager_chromeos.cc b/ash/display/display_color_manager_chromeos.cc
index efce478..b76d014 100644
--- a/ash/display/display_color_manager_chromeos.cc
+++ b/ash/display/display_color_manager_chromeos.cc
@@ -186,14 +186,16 @@
 
     UMA_HISTOGRAM_BOOLEAN("Ash.DisplayColorManager.HasColorCorrectionMatrix",
                           state->has_color_correction_matrix());
-    if (calibration_map_[state->product_id()]) {
-      ApplyDisplayColorCalibration(state->display_id(), state->product_id());
+    if (calibration_map_[state->product_code()]) {
+      ApplyDisplayColorCalibration(state->display_id(), state->product_code());
     } else {
-      const bool valid_product_id =
-          state->product_id() != display::DisplaySnapshot::kInvalidProductID;
+      const bool valid_product_code =
+          state->product_code() !=
+          display::DisplaySnapshot::kInvalidProductCode;
+      // TODO(mcasas): correct UMA s/Id/Code/, https://crbug.com/821393.
       UMA_HISTOGRAM_BOOLEAN("Ash.DisplayColorManager.ValidProductId",
-                            valid_product_id);
-      if (valid_product_id)
+                            valid_product_code);
+      if (valid_product_code)
         LoadCalibrationForDisplay(state);
     }
   }
@@ -225,11 +227,11 @@
     return;
 
   quirks::QuirksManager::Get()->RequestIccProfilePath(
-      display->product_id(), display->display_name(),
+      display->product_code(), display->display_name(),
       base::Bind(&DisplayColorManager::FinishLoadCalibrationForDisplay,
                  weak_ptr_factory_.GetWeakPtr(), display->display_id(),
-                 display->product_id(), display->has_color_correction_matrix(),
-                 display->type()));
+                 display->product_code(),
+                 display->has_color_correction_matrix(), display->type()));
 }
 
 void DisplayColorManager::FinishLoadCalibrationForDisplay(
diff --git a/ash/display/display_error_observer_chromeos_unittest.cc b/ash/display/display_error_observer_chromeos_unittest.cc
index 0b8a3ba..48168b8 100644
--- a/ash/display/display_error_observer_chromeos_unittest.cc
+++ b/ash/display/display_error_observer_chromeos_unittest.cc
@@ -35,6 +35,7 @@
       display::DisplaySnapshot::DisplayModeList() /* modes */,
       std::vector<uint8_t>() /* edid */, nullptr /* current_mode */,
       nullptr /* native_mode */, 0 /* product_id */,
+      display::kInvalidYearOfManufacture,
       gfx::Size() /* maximum_cursor_size */);
 }
 
diff --git a/ash/mojo_interface_factory.cc b/ash/mojo_interface_factory.cc
index 767864ec..33cafbc 100644
--- a/ash/mojo_interface_factory.cc
+++ b/ash/mojo_interface_factory.cc
@@ -60,7 +60,7 @@
 
 void BindAccessibilityFocusRingControllerRequestOnMainThread(
     mojom::AccessibilityFocusRingControllerRequest request) {
-  AccessibilityFocusRingController::GetInstance()->BindRequest(
+  Shell::Get()->accessibility_focus_ring_controller()->BindRequest(
       std::move(request));
 }
 
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index e5e82698b..868db6e 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -2228,6 +2228,15 @@
     requested_states_.push_back(ink_drop_state);
     ink_drop_->AnimateToState(ink_drop_state);
   }
+
+  void SetHoverHighlightFadeDurationMs(int duration_ms) override {
+    ink_drop_->SetHoverHighlightFadeDurationMs(duration_ms);
+  }
+
+  void UseDefaultHoverHighlightFadeDuration() override {
+    ink_drop_->UseDefaultHoverHighlightFadeDuration();
+  }
+
   void SnapToActivated() override { ink_drop_->SnapToActivated(); }
   void SnapToHidden() override { ink_drop_->SnapToHidden(); }
   void SetHovered(bool is_hovered) override {
diff --git a/ash/shell.cc b/ash/shell.cc
index 0e3be269..5ebe7ff 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -16,6 +16,7 @@
 #include "ash/accelerators/spoken_feedback_toggler.h"
 #include "ash/accessibility/accessibility_controller.h"
 #include "ash/accessibility/accessibility_delegate.h"
+#include "ash/accessibility/accessibility_focus_ring_controller.h"
 #include "ash/app_list/app_list_controller_impl.h"
 #include "ash/ash_constants.h"
 #include "ash/autoclick/autoclick_controller.h"
@@ -808,6 +809,7 @@
   wallpaper_controller_.reset();
   accessibility_controller_.reset();
   accessibility_delegate_.reset();
+  accessibility_focus_ring_controller_.reset();
 
   // Balances the Install() in Initialize().
   views::FocusManagerFactory::Install(nullptr);
@@ -914,6 +916,8 @@
 
   // Some delegates access ShellPort during their construction. Create them here
   // instead of the ShellPort constructor.
+  accessibility_focus_ring_controller_ =
+      std::make_unique<AccessibilityFocusRingController>();
   accessibility_delegate_.reset(shell_delegate_->CreateAccessibilityDelegate());
   accessibility_controller_ = std::make_unique<AccessibilityController>(
       shell_delegate_->GetShellConnector());
diff --git a/ash/shell.h b/ash/shell.h
index 0fd274897..160bc36 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -77,6 +77,7 @@
 class AcceleratorController;
 class AccessibilityController;
 class AccessibilityDelegate;
+class AccessibilityFocusRingController;
 class AshDisplayController;
 class AppListControllerImpl;
 class NativeCursorManagerAsh;
@@ -307,6 +308,9 @@
   AccessibilityDelegate* accessibility_delegate() {
     return accessibility_delegate_.get();
   }
+  AccessibilityFocusRingController* accessibility_focus_ring_controller() {
+    return accessibility_focus_ring_controller_.get();
+  }
   ::wm::ActivationClient* activation_client();
   AppListControllerImpl* app_list_controller() {
     return app_list_controller_.get();
@@ -659,6 +663,8 @@
   std::unique_ptr<AcceleratorController> accelerator_controller_;
   std::unique_ptr<AccessibilityController> accessibility_controller_;
   std::unique_ptr<AccessibilityDelegate> accessibility_delegate_;
+  std::unique_ptr<AccessibilityFocusRingController>
+      accessibility_focus_ring_controller_;
   std::unique_ptr<AppListControllerImpl> app_list_controller_;
   std::unique_ptr<AshDisplayController> ash_display_controller_;
   std::unique_ptr<BacklightsForcedOffSetter> backlights_forced_off_setter_;
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc
index 226b381..fe7ff5b 100644
--- a/ash/wm/overview/window_selector_item.cc
+++ b/ash/wm/overview/window_selector_item.cc
@@ -448,11 +448,8 @@
     // during the initial animation. Once the initial fade-in completes and the
     // overview header is fully exposed update stacking to keep the label above
     // the item which prevents input events from reaching the window.
-    aura::Window* widget_window = GetWidget()->GetNativeWindow();
-    aura::Window* stacking_window =
-        item_ ? item_->GetWindowForStacking() : nullptr;
-    if (widget_window && stacking_window)
-      widget_window->parent()->StackChildAbove(widget_window, stacking_window);
+    if (item_)
+      item_->RestackItemWidget();
   }
 
   void AnimationProgressed(const gfx::Animation* animation) override {
@@ -753,6 +750,14 @@
 
 void WindowSelectorItem::PrepareForOverview() {
   transform_window_.PrepareForOverview();
+  RestackItemWidget();
+  // The minimized widget was unavailable up to this point, but if a window
+  // is minimized, |item_widget_| should stack on top of it, unless the
+  // animation is in progress and will take care of that.
+  if (!background_view_->should_animate() &&
+      wm::GetWindowState(GetWindow())->IsMinimized()) {
+    RestackItemWidget();
+  }
   UpdateHeaderLayout(HeaderFadeInMode::kEnter,
                      OverviewAnimationType::OVERVIEW_ANIMATION_NONE);
 }
@@ -898,6 +903,12 @@
   SetOpacity(dimmed ? kDimmedItemOpacity : 1.0f);
 }
 
+void WindowSelectorItem::RestackItemWidget() {
+  aura::Window* widget_window = item_widget_->GetNativeWindow();
+  widget_window->parent()->StackChildAbove(widget_window,
+                                           GetWindowForStacking());
+}
+
 void WindowSelectorItem::ButtonPressed(views::Button* sender,
                                        const ui::Event& event) {
   if (sender == close_button_) {
@@ -1128,12 +1139,14 @@
                                              transform_window_.window());
   }
 
-  // Create an image view for and scale down the windows window icon, if it
-  // exists.
+  // Create an image view the header icon. Tries to use the app icon, as it is
+  // higher resolution. If it does not exist, use the window icon. If neither
+  // exist, display nothing.
   views::ImageView* image_view = nullptr;
   if (IsNewOverviewUi()) {
-    gfx::ImageSkia* icon =
-        transform_window_.window()->GetProperty(aura::client::kWindowIconKey);
+    gfx::ImageSkia* icon = GetWindow()->GetProperty(aura::client::kAppIconKey);
+    if (!icon || icon->size().IsEmpty())
+      icon = GetWindow()->GetProperty(aura::client::kWindowIconKey);
     if (icon && !icon->size().IsEmpty()) {
       image_view = new views::ImageView();
       image_view->SetImage(gfx::ImageSkiaOperations::CreateResizedImage(
diff --git a/ash/wm/overview/window_selector_item.h b/ash/wm/overview/window_selector_item.h
index 744ad74..68b9a45c 100644
--- a/ash/wm/overview/window_selector_item.h
+++ b/ash/wm/overview/window_selector_item.h
@@ -165,6 +165,12 @@
 
   const gfx::Rect& target_bounds() const { return target_bounds_; }
 
+  // Stacks the |item_widget_| in the correct place. |item_widget_| may be
+  // initially stacked in the wrong place due to animation or if it is a
+  // minimized window, the overview minimized widget is not available on
+  // |item_widget_|'s creation.
+  void RestackItemWidget();
+
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index 6efce9c..dad6836 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -2591,9 +2591,11 @@
   EXPECT_EQ(1.f, item2->GetCloseButtonOpacityForTesting());
 }
 
-// http://crbug.com/822049
 // Tests that overview widgets are stacked in the correct order.
-TEST_F(WindowSelectorTest, DISABLED_OverviewWidgetStackingOrder) {
+TEST_F(WindowSelectorTest, OverviewWidgetStackingOrder) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kAshEnableNewOverviewUi);
+
   // Helper function to get the index of |child|, give its parent window
   // |parent|. Given the same |parent|, the children with higher index will be
   // stacked above (but not neccessarily directly) the children with lower
@@ -2663,6 +2665,8 @@
             index_of(window.get(), parent));
   EXPECT_GT(index_of(widget2->GetNativeWindow(), parent),
             index_of(min_widget2->GetNativeWindow(), parent));
+  EXPECT_GT(index_of(widget3->GetNativeWindow(), parent),
+            index_of(window3.get(), parent));
 
   // Drag the first window. Verify that it's item widget is not stacked above
   // the other two.
diff --git a/ash/wm/splitview/OWNERS b/ash/wm/splitview/OWNERS
new file mode 100644
index 0000000..302bdd9
--- /dev/null
+++ b/ash/wm/splitview/OWNERS
@@ -0,0 +1,3 @@
+xdai@chromium.org
+
+# COMPONENT: UI>Shell>WindowManager>Splitscreen
diff --git a/ash/wm/splitview/split_view_drag_indicators.cc b/ash/wm/splitview/split_view_drag_indicators.cc
index 4c0cd625..d6a241c06 100644
--- a/ash/wm/splitview/split_view_drag_indicators.cc
+++ b/ash/wm/splitview/split_view_drag_indicators.cc
@@ -374,10 +374,8 @@
 
     // Calculate the bounds of the views which contain the guidance text and
     // icon. Rotate the two views in landscape mode.
-    const gfx::Size size(
-        left_rotated_view_->GetPreferredSize().width(),
-        std::max(kSplitviewLabelPreferredHeightDp,
-                 left_rotated_view_->GetPreferredSize().height()));
+    const gfx::Size size(left_rotated_view_->GetPreferredSize().width(),
+                         kSplitviewLabelPreferredHeightDp);
     gfx::Rect left_rotated_bounds(highlight_width / 2 - size.width() / 2,
                                   highlight_height / 2 - size.height() / 2,
                                   size.width(), size.height());
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index c403990..71f4ce4 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -385,18 +385,15 @@
   if (dumper_registrations_ignored_for_testing_)
     return;
 
-  // A handful of MDPs are required to compute the summary struct these are
-  // 'whitelisted for summary mode'. These MDPs are a subset of those which
+  // Only a handful of MDPs are required to compute the memory metrics. These
   // have small enough performance overhead that it is resonable to run them
   // in the background while the user is doing other things. Those MDPs are
   // 'whitelisted for background mode'.
   bool whitelisted_for_background_mode = IsMemoryDumpProviderWhitelisted(name);
-  bool whitelisted_for_summary_mode =
-      IsMemoryDumpProviderWhitelistedForSummary(name);
 
-  scoped_refptr<MemoryDumpProviderInfo> mdpinfo = new MemoryDumpProviderInfo(
-      mdp, name, std::move(task_runner), options,
-      whitelisted_for_background_mode, whitelisted_for_summary_mode);
+  scoped_refptr<MemoryDumpProviderInfo> mdpinfo =
+      new MemoryDumpProviderInfo(mdp, name, std::move(task_runner), options,
+                                 whitelisted_for_background_mode);
 
   if (options.is_fast_polling_supported) {
     DCHECK(!mdpinfo->task_runner) << "MemoryDumpProviders capable of fast "
@@ -597,7 +594,11 @@
     MemoryDumpProviderInfo* mdpinfo =
         pmd_async_state->pending_dump_providers.back().get();
 
-    if (!IsDumpProviderAllowedToDump(pmd_async_state->req_args, *mdpinfo)) {
+    // If we are in background mode, we should invoke only the whitelisted
+    // providers. Ignore other providers and continue.
+    if (pmd_async_state->req_args.level_of_detail ==
+            MemoryDumpLevelOfDetail::BACKGROUND &&
+        !mdpinfo->whitelisted_for_background_mode) {
       pmd_async_state->pending_dump_providers.pop_back();
       continue;
     }
@@ -647,26 +648,6 @@
   FinishAsyncProcessDump(std::move(pmd_async_state));
 }
 
-bool MemoryDumpManager::IsDumpProviderAllowedToDump(
-    const MemoryDumpRequestArgs& req_args,
-    const MemoryDumpProviderInfo& mdpinfo) const {
-  // If we are in background tracing, we should invoke only the whitelisted
-  // providers. Ignore other providers and continue.
-  if (req_args.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND &&
-      !mdpinfo.whitelisted_for_background_mode) {
-    return false;
-  }
-
-  // If we are in summary mode, we only need to invoke the providers
-  // whitelisted for summary mode.
-  if (req_args.dump_type == MemoryDumpType::SUMMARY_ONLY &&
-      !mdpinfo.whitelisted_for_summary_mode) {
-    return false;
-  }
-
-  return true;
-}
-
 // This function is called on the right task runner for current MDP. It is
 // either the task runner specified by MDP or |dump_thread_task_runner| if the
 // MDP did not specify task runner. Invokes the dump provider's OnMemoryDump()
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
index 593bfe0..331f931 100644
--- a/base/trace_event/memory_dump_manager.h
+++ b/base/trace_event/memory_dump_manager.h
@@ -252,10 +252,6 @@
   void ContinueAsyncProcessDump(
       ProcessMemoryDumpAsyncState* owned_pmd_async_state);
 
-  // Returns true if the given dump type and mode allows the given MDP to dump.
-  bool IsDumpProviderAllowedToDump(const MemoryDumpRequestArgs& req_args,
-                                   const MemoryDumpProviderInfo& mdpinfo) const;
-
   // Invokes OnMemoryDump() of the given MDP. Should be called on the MDP task
   // runner.
   void InvokeOnMemoryDump(MemoryDumpProviderInfo* mdpinfo,
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index 025bd736..de98f1d 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -59,12 +59,7 @@
 
 const char* kMDPName = "TestDumpProvider";
 const char* kWhitelistedMDPName = "WhitelistedTestDumpProvider";
-const char* kBackgroundButNotSummaryWhitelistedMDPName =
-    "BackgroundButNotSummaryWhitelistedTestDumpProvider";
-const char* const kTestMDPWhitelist[] = {
-    kWhitelistedMDPName, kBackgroundButNotSummaryWhitelistedMDPName, nullptr};
-const char* const kTestMDPWhitelistForSummary[] = {kWhitelistedMDPName,
-                                                   nullptr};
+const char* const kTestMDPWhitelist[] = {kWhitelistedMDPName, nullptr};
 
 void RegisterDumpProvider(
     MemoryDumpProvider* mdp,
@@ -752,23 +747,17 @@
                                         MemoryDumpLevelOfDetail::DETAILED));
 }
 
-TEST_F(MemoryDumpManagerTest, SummaryOnlyWhitelisting) {
-  // Summary only MDPs are a subset of background MDPs.
+TEST_F(MemoryDumpManagerTest, BackgroundWhitelisting) {
   SetDumpProviderWhitelistForTesting(kTestMDPWhitelist);
-  SetDumpProviderSummaryWhitelistForTesting(kTestMDPWhitelistForSummary);
 
   // Standard provider with default options (create dump for current process).
-  MockMemoryDumpProvider summaryMdp;
-  RegisterDumpProvider(&summaryMdp, nullptr, kDefaultOptions,
-                       kWhitelistedMDPName);
   MockMemoryDumpProvider backgroundMdp;
   RegisterDumpProvider(&backgroundMdp, nullptr, kDefaultOptions,
-                       kBackgroundButNotSummaryWhitelistedMDPName);
+                       kWhitelistedMDPName);
 
   EnableForTracing();
 
-  EXPECT_CALL(backgroundMdp, OnMemoryDump(_, _)).Times(0);
-  EXPECT_CALL(summaryMdp, OnMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(backgroundMdp, OnMemoryDump(_, _)).Times(1);
   EXPECT_TRUE(RequestProcessDumpAndWait(MemoryDumpType::SUMMARY_ONLY,
                                         MemoryDumpLevelOfDetail::BACKGROUND));
   DisableTracing();
@@ -1046,7 +1035,6 @@
 
 TEST_F(MemoryDumpManagerTest, NoStackOverflowWithTooManyMDPs) {
   SetDumpProviderWhitelistForTesting(kTestMDPWhitelist);
-  SetDumpProviderSummaryWhitelistForTesting(kTestMDPWhitelistForSummary);
 
   int kMDPCount = 1000;
   std::vector<std::unique_ptr<SimpleMockMemoryDumpProvider>> mdps;
@@ -1055,11 +1043,6 @@
     RegisterDumpProvider(mdps.back().get(), nullptr);
   }
   for (int i = 0; i < kMDPCount; ++i) {
-    mdps.push_back(std::make_unique<SimpleMockMemoryDumpProvider>(2));
-    RegisterDumpProvider(mdps.back().get(), nullptr, kDefaultOptions,
-                         kBackgroundButNotSummaryWhitelistedMDPName);
-  }
-  for (int i = 0; i < kMDPCount; ++i) {
     mdps.push_back(std::make_unique<SimpleMockMemoryDumpProvider>(3));
     RegisterDumpProvider(mdps.back().get(), nullptr, kDefaultOptions,
                          kWhitelistedMDPName);
diff --git a/base/trace_event/memory_dump_provider_info.cc b/base/trace_event/memory_dump_provider_info.cc
index 65eeadf..3220476c 100644
--- a/base/trace_event/memory_dump_provider_info.cc
+++ b/base/trace_event/memory_dump_provider_info.cc
@@ -16,14 +16,12 @@
     const char* name,
     scoped_refptr<SequencedTaskRunner> task_runner,
     const MemoryDumpProvider::Options& options,
-    bool whitelisted_for_background_mode,
-    bool whitelisted_for_summary_mode)
+    bool whitelisted_for_background_mode)
     : dump_provider(dump_provider),
       options(options),
       name(name),
       task_runner(std::move(task_runner)),
       whitelisted_for_background_mode(whitelisted_for_background_mode),
-      whitelisted_for_summary_mode(whitelisted_for_summary_mode),
       consecutive_failures(0),
       disabled(false) {}
 
diff --git a/base/trace_event/memory_dump_provider_info.h b/base/trace_event/memory_dump_provider_info.h
index 9d18b82..f0ea1e6b 100644
--- a/base/trace_event/memory_dump_provider_info.h
+++ b/base/trace_event/memory_dump_provider_info.h
@@ -58,8 +58,7 @@
                          const char* name,
                          scoped_refptr<SequencedTaskRunner> task_runner,
                          const MemoryDumpProvider::Options& options,
-                         bool whitelisted_for_background_mode,
-                         bool whitelisted_for_summary_mode);
+                         bool whitelisted_for_background_mode);
 
   // It is safe to access the const fields below from any thread as they are
   // never mutated.
@@ -81,9 +80,6 @@
   // True if the dump provider is whitelisted for background mode.
   const bool whitelisted_for_background_mode;
 
-  // True if the dump provider is whitelisted for summary mode.
-  const bool whitelisted_for_summary_mode;
-
   // These fields below, instead, are not thread safe and can be mutated only:
   // - On the |task_runner|, when not null (i.e. for thread-bound MDPS).
   // - By the MDM's background thread (or in any other way that guarantees
diff --git a/base/trace_event/memory_infra_background_whitelist.cc b/base/trace_event/memory_infra_background_whitelist.cc
index 4e07d58d..d6998ac 100644
--- a/base/trace_event/memory_infra_background_whitelist.cc
+++ b/base/trace_event/memory_infra_background_whitelist.cc
@@ -18,6 +18,8 @@
 // The names of dump providers whitelisted for background tracing. Dump
 // providers can be added here only if the background mode dump has very
 // little processor and memory overhead.
+// TODO(ssid): Some dump providers do not create ownership edges on background
+// dump. So, the effective size will not be correct.
 const char* const kDumpProviderWhitelist[] = {
     "android::ResourceManagerImpl",
     "AutocompleteController",
@@ -45,41 +47,6 @@
     "MojoLevelDB",
     "PartitionAlloc",
     "ProcessMemoryMetrics",
-    "Skia",
-    "SharedMemoryTracker",
-    "Sql",
-    "URLRequestContext",
-    "V8Isolate",
-    "WinHeap",
-    "SyncDirectory",
-    "TabRestoreServiceHelper",
-    nullptr  // End of list marker.
-};
-
-// The names of dump providers whitelisted for summary tracing.
-// TODO(ssid): Some dump providers do not create ownership edges on background
-// dump. So, the effective size will not be correct.
-const char* const kDumpProviderSummaryWhitelist[] = {
-    "android::ResourceManagerImpl",
-    "BlinkGC",
-    "BlinkObjectCounters",
-    "ClientDiscardableSharedMemoryManager",
-    "DiscardableSharedMemoryManager",
-    "gpu::BufferManager",
-    "gpu::RenderbufferManager",
-    "gpu::TextureManager",
-    "HistoryReport",
-    "IndexedDBBackingStore",
-    "JavaHeap",
-    "LevelDB",
-    "LeveldbValueStore",
-    "LocalStorage",
-    "Malloc",
-    "MemoryCache",
-    "MojoHandleTable",
-    "MojoLevelDB",
-    "PartitionAlloc",
-    "ProcessMemoryMetrics",
     "SharedMemoryTracker",
     "Skia",
     "Sql",
@@ -237,8 +204,6 @@
     "v8/isolate_0x?/heap_spaces/other_spaces",
     "v8/isolate_0x?/malloc",
     "v8/isolate_0x?/zapped_for_debug",
-    "winheap",
-    "winheap/allocated_objects",
     "site_storage/blob_storage/0x?",
     "site_storage/index_db/0x?",
     "site_storage/localstorage/0x?/cache_size",
@@ -294,8 +259,6 @@
 };
 
 const char* const* g_dump_provider_whitelist = kDumpProviderWhitelist;
-const char* const* g_dump_provider_whitelist_for_summary =
-    kDumpProviderSummaryWhitelist;
 const char* const* g_allocator_dump_name_whitelist =
     kAllocatorDumpNameWhitelist;
 
@@ -313,11 +276,6 @@
   return IsMemoryDumpProviderInList(mdp_name, g_dump_provider_whitelist);
 }
 
-bool IsMemoryDumpProviderWhitelistedForSummary(const char* mdp_name) {
-  return IsMemoryDumpProviderInList(mdp_name,
-                                    g_dump_provider_whitelist_for_summary);
-}
-
 bool IsMemoryAllocatorDumpNameWhitelisted(const std::string& name) {
   // Global dumps are explicitly whitelisted for background use.
   if (base::StartsWith(name, "global/", CompareCase::SENSITIVE)) {
@@ -365,10 +323,6 @@
   g_dump_provider_whitelist = list;
 }
 
-void SetDumpProviderSummaryWhitelistForTesting(const char* const* list) {
-  g_dump_provider_whitelist_for_summary = list;
-}
-
 void SetAllocatorDumpNameWhitelistForTesting(const char* const* list) {
   g_allocator_dump_name_whitelist = list;
 }
diff --git a/base/trace_event/memory_infra_background_whitelist.h b/base/trace_event/memory_infra_background_whitelist.h
index 11900109..b8d704ae 100644
--- a/base/trace_event/memory_infra_background_whitelist.h
+++ b/base/trace_event/memory_infra_background_whitelist.h
@@ -18,10 +18,6 @@
 // Checks if the given |mdp_name| is in the whitelist.
 bool BASE_EXPORT IsMemoryDumpProviderWhitelisted(const char* mdp_name);
 
-// Checks if the given |mdp_name| is required for summary dumps.
-bool BASE_EXPORT
-IsMemoryDumpProviderWhitelistedForSummary(const char* mdp_name);
-
 // Checks if the given |name| matches any of the whitelisted patterns.
 bool BASE_EXPORT IsMemoryAllocatorDumpNameWhitelisted(const std::string& name);
 
@@ -29,8 +25,6 @@
 // the list must be nullptr.
 void BASE_EXPORT SetDumpProviderWhitelistForTesting(const char* const* list);
 void BASE_EXPORT
-SetDumpProviderSummaryWhitelistForTesting(const char* const* list);
-void BASE_EXPORT
 SetAllocatorDumpNameWhitelistForTesting(const char* const* list);
 
 }  // namespace trace_event
diff --git a/base/trace_event/memory_peak_detector_unittest.cc b/base/trace_event/memory_peak_detector_unittest.cc
index bd70e3e9..bc10c80 100644
--- a/base/trace_event/memory_peak_detector_unittest.cc
+++ b/base/trace_event/memory_peak_detector_unittest.cc
@@ -176,10 +176,9 @@
     std::unique_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider());
     MemoryDumpProvider::Options opt;
     opt.is_fast_polling_supported = true;
-    scoped_refptr<MemoryDumpProviderInfo> mdp_info(
-        new MemoryDumpProviderInfo(mdp.get(), "Mock MDP", nullptr, opt,
-                                   false /* whitelisted_for_background_mode */,
-                                   false /* whitelisted_for_summary_mode */));
+    scoped_refptr<MemoryDumpProviderInfo> mdp_info(new MemoryDumpProviderInfo(
+        mdp.get(), "Mock MDP", nullptr, opt,
+        false /* whitelisted_for_background_mode */));
 
     // The |mdp| instance will be destroyed together with the |mdp_info|.
     mdp_info->owned_dump_provider = std::move(mdp);
diff --git a/build/android/gyp/util/proguard_util.py b/build/android/gyp/util/proguard_util.py
index 171c35bf..ec3409b 100644
--- a/build/android/gyp/util/proguard_util.py
+++ b/build/android/gyp/util/proguard_util.py
@@ -16,7 +16,7 @@
 
   IGNORE_RE = re.compile(
       r'Pro.*version|Note:|Reading|Preparing|Printing|ProgramClass:|Searching|'
-      r'jar \[|\d+ class path entries checked|.*:.*(?:MANIFEST\.MF|\.empty)')
+      r'jar \[|\d+ class path entries checked')
 
   def __init__(self):
     self._last_line_ignored = False
@@ -128,8 +128,11 @@
     for optimization in self._disabled_optimizations:
       cmd += [ '-optimizations', '!' + optimization ]
 
+    # Filter out META-INF files to avoid warnings about multiple inputs having
+    # the same files.
     cmd += [
-      '-injars', ':'.join(self._injars)
+        '-injars',
+        ':'.join('{}(!META-INF/**,!.empty)'.format(x) for x in self._injars)
     ]
 
     for config_file in self._configs:
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
index da74494f..b3517ba 100644
--- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py
+++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -39,7 +39,6 @@
 from py_utils import tempfile_ext
 import tombstones
 
-
 with host_paths.SysPath(
     os.path.join(host_paths.DIR_SOURCE_ROOT, 'third_party'), 0):
   import jinja2  # pylint: disable=import-error
@@ -76,6 +75,8 @@
 _EXTRA_TEST_LIST = (
     'org.chromium.base.test.BaseChromiumAndroidJUnitRunner.TestList')
 
+UI_CAPTURE_DIRS = ['chromium_tests_root', 'UiCapture']
+
 FEATURE_ANNOTATION = 'Feature'
 RENDER_TEST_FEATURE_ANNOTATION = 'RenderTest'
 
@@ -125,6 +126,7 @@
     super(LocalDeviceInstrumentationTestRun, self).__init__(
         env, test_instance)
     self._flag_changers = {}
+    self._ui_capture_dir = dict()
     self._replace_package_contextmanager = None
 
   #override
@@ -251,8 +253,21 @@
         valgrind_tools.SetChromeTimeoutScale(
             dev, self._test_instance.timeout_scale)
 
+      @trace_event.traced
+      def setup_ui_capture_dir(dev):
+        # Make sure the UI capture directory exists and is empty by deleting
+        # and recreating it.
+        # TODO (aberent) once DeviceTempDir exists use it here.
+        self._ui_capture_dir[dev] = posixpath.join(
+            dev.GetExternalStoragePath(),
+            *UI_CAPTURE_DIRS)
+
+        if dev.PathExists(self._ui_capture_dir[dev]):
+          dev.RunShellCommand(['rm', '-rf', self._ui_capture_dir[dev]])
+        dev.RunShellCommand(['mkdir', self._ui_capture_dir[dev]])
+
       steps += [set_debug_app, edit_shared_prefs, push_test_data,
-                create_flag_changer]
+                create_flag_changer, setup_ui_capture_dir]
 
       def bind_crash_handler(step, dev):
         return lambda: crash_handler.RetryOnSystemCrash(step, dev)
@@ -357,11 +372,7 @@
         device.adb, suffix='.png', dir=device.GetExternalStoragePath())
     extras[EXTRA_SCREENSHOT_FILE] = screenshot_device_file.name
 
-    # Set up the screenshot directory. This needs to be done for each test so
-    # that we only get screenshots created by that test.
-    ui_capture_dir = device_temp_file.NamedDeviceTemporaryDirectory(
-        device.adb)
-    extras[EXTRA_UI_CAPTURE_DIR] = ui_capture_dir.name
+    extras[EXTRA_UI_CAPTURE_DIR] = self._ui_capture_dir[device]
 
     if self._env.trace_output:
       trace_device_file = device_temp_file.DeviceTempFile(
@@ -439,116 +450,114 @@
         time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()),
         device.serial)
 
-    with ui_capture_dir:
-      with self._env.output_manager.ArchivedTempfile(
-          stream_name, 'logcat') as logcat_file:
+    with self._env.output_manager.ArchivedTempfile(
+        stream_name, 'logcat') as logcat_file:
+      try:
+        with logcat_monitor.LogcatMonitor(
+            device.adb,
+            filter_specs=local_device_environment.LOGCAT_FILTERS,
+            output_file=logcat_file.name,
+            transform_func=self._test_instance.MaybeDeobfuscateLines) as logmon:
+          with _LogTestEndpoints(device, test_name):
+            with contextlib_ext.Optional(
+                trace_event.trace(test_name),
+                self._env.trace_output):
+              output = device.StartInstrumentation(
+                  target, raw=True, extras=extras, timeout=timeout, retries=0)
+      finally:
+        logmon.Close()
+
+    if logcat_file.Link():
+      logging.info('Logcat saved to %s', logcat_file.Link())
+
+    duration_ms = time_ms() - start_ms
+
+    with contextlib_ext.Optional(
+        trace_event.trace('ProcessResults'),
+        self._env.trace_output):
+      output = self._test_instance.MaybeDeobfuscateLines(output)
+      # TODO(jbudorick): Make instrumentation tests output a JSON so this
+      # doesn't have to parse the output.
+      result_code, result_bundle, statuses = (
+          self._test_instance.ParseAmInstrumentRawOutput(output))
+      results = self._test_instance.GenerateTestResults(
+          result_code, result_bundle, statuses, start_ms, duration_ms,
+          device.product_cpu_abi, self._test_instance.symbolizer)
+
+    if self._env.trace_output:
+      self._SaveTraceData(trace_device_file, device, test['class'])
+
+    def restore_flags():
+      if flags_to_add:
+        self._flag_changers[str(device)].Restore()
+
+    def restore_timeout_scale():
+      if test_timeout_scale:
+        valgrind_tools.SetChromeTimeoutScale(
+            device, self._test_instance.timeout_scale)
+
+    def handle_coverage_data():
+      if self._test_instance.coverage_directory:
+        device.PullFile(coverage_directory,
+            self._test_instance.coverage_directory)
+        device.RunShellCommand(
+            'rm -f %s' % posixpath.join(coverage_directory, '*'),
+            check_return=True, shell=True)
+
+    def handle_render_test_data():
+      if _IsRenderTest(test):
+        # Render tests do not cause test failure by default. So we have to check
+        # to see if any failure images were generated even if the test does not
+        # fail.
         try:
-          with logcat_monitor.LogcatMonitor(
-              device.adb,
-              filter_specs=local_device_environment.LOGCAT_FILTERS,
-              output_file=logcat_file.name,
-              transform_func=self._test_instance.MaybeDeobfuscateLines
-              ) as logmon:
-            with _LogTestEndpoints(device, test_name):
-              with contextlib_ext.Optional(
-                  trace_event.trace(test_name),
-                  self._env.trace_output):
-                output = device.StartInstrumentation(
-                    target, raw=True, extras=extras, timeout=timeout, retries=0)
+          self._ProcessRenderTestResults(
+              device, render_tests_device_output_dir, results)
         finally:
-          logmon.Close()
+          device.RemovePath(render_tests_device_output_dir,
+                            recursive=True, force=True)
 
-      if logcat_file.Link():
-        logging.info('Logcat saved to %s', logcat_file.Link())
-
-      duration_ms = time_ms() - start_ms
-
-      with contextlib_ext.Optional(
-          trace_event.trace('ProcessResults'),
-          self._env.trace_output):
-        output = self._test_instance.MaybeDeobfuscateLines(output)
-        # TODO(jbudorick): Make instrumentation tests output a JSON so this
-        # doesn't have to parse the output.
-        result_code, result_bundle, statuses = (
-            self._test_instance.ParseAmInstrumentRawOutput(output))
-        results = self._test_instance.GenerateTestResults(
-            result_code, result_bundle, statuses, start_ms, duration_ms,
-            device.product_cpu_abi, self._test_instance.symbolizer)
-
-      if self._env.trace_output:
-        self._SaveTraceData(trace_device_file, device, test['class'])
-
-      def restore_flags():
-        if flags_to_add:
-          self._flag_changers[str(device)].Restore()
-
-      def restore_timeout_scale():
-        if test_timeout_scale:
-          valgrind_tools.SetChromeTimeoutScale(
-              device, self._test_instance.timeout_scale)
-
-      def handle_coverage_data():
-        if self._test_instance.coverage_directory:
-          device.PullFile(coverage_directory,
-              self._test_instance.coverage_directory)
-          device.RunShellCommand(
-              'rm -f %s' % posixpath.join(coverage_directory, '*'),
-              check_return=True, shell=True)
-
-      def handle_render_test_data():
-        if _IsRenderTest(test):
-          # Render tests do not cause test failure by default. So we have to
-          # check to see if any failure images were generated even if the test
-          # does not fail.
-          try:
-            self._ProcessRenderTestResults(
-                device, render_tests_device_output_dir, results)
-          finally:
-            device.RemovePath(render_tests_device_output_dir,
-                              recursive=True, force=True)
-
-      def pull_ui_screen_captures():
-        screenshots = []
-        for filename in device.ListDirectory(ui_capture_dir.name):
-          if filename.endswith('.json'):
-            screenshots.append(pull_ui_screenshot(filename))
-        if screenshots:
-          json_archive_name = 'ui_capture_%s_%s.json' % (
-              test_name.replace('#', '.'),
-              time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()))
-          with self._env.output_manager.ArchivedTempfile(
-              json_archive_name, 'ui_capture', output_manager.Datatype.JSON
-              ) as json_archive:
-            json.dump(screenshots, json_archive)
-          for result in results:
-            result.SetLink('ui screenshot', json_archive.Link())
-
-      def pull_ui_screenshot(filename):
-        source_dir = ui_capture_dir.name
-        json_path = posixpath.join(source_dir, filename)
-        json_data = json.loads(device.ReadFile(json_path))
-        image_file_path = posixpath.join(source_dir, json_data['location'])
+    def pull_ui_screen_captures():
+      screenshots = []
+      for filename in device.ListDirectory(self._ui_capture_dir[device]):
+        if filename.endswith('.json'):
+          screenshots.append(pull_ui_screenshot(filename))
+      if screenshots:
+        json_archive_name = 'ui_capture_%s_%s.json' % (
+            test_name.replace('#', '.'),
+            time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()))
         with self._env.output_manager.ArchivedTempfile(
-            json_data['location'], 'ui_capture', output_manager.Datatype.IMAGE
-            ) as image_archive:
-          device.PullFile(image_file_path, image_archive.name)
-        json_data['image_link'] = image_archive.Link()
-        return json_data
+            json_archive_name, 'ui_capture', output_manager.Datatype.JSON
+            ) as json_archive:
+          json.dump(screenshots, json_archive)
+        for result in results:
+          result.SetLink('ui screenshot', json_archive.Link())
 
-      # While constructing the TestResult objects, we can parallelize several
-      # steps that involve ADB. These steps should NOT depend on any info in
-      # the results! Things such as whether the test CRASHED have not yet been
-      # determined.
-      post_test_steps = [restore_flags, restore_timeout_scale,
-                         handle_coverage_data, handle_render_test_data,
-                         pull_ui_screen_captures]
-      if self._env.concurrent_adb:
-        post_test_step_thread_group = reraiser_thread.ReraiserThreadGroup(
-            reraiser_thread.ReraiserThread(f) for f in post_test_steps)
-        post_test_step_thread_group.StartAll(will_block=True)
-      else:
-        for step in post_test_steps:
-          step()
+    def pull_ui_screenshot(filename):
+      source_dir = self._ui_capture_dir[device]
+      json_path = posixpath.join(source_dir, filename)
+      json_data = json.loads(device.ReadFile(json_path))
+      image_file_path = posixpath.join(source_dir, json_data['location'])
+      with self._env.output_manager.ArchivedTempfile(
+          json_data['location'], 'ui_capture', output_manager.Datatype.IMAGE
+          ) as image_archive:
+        device.PullFile(image_file_path, image_archive.name)
+      json_data['image_link'] = image_archive.Link()
+      return json_data
+
+    # While constructing the TestResult objects, we can parallelize several
+    # steps that involve ADB. These steps should NOT depend on any info in
+    # the results! Things such as whether the test CRASHED have not yet been
+    # determined.
+    post_test_steps = [restore_flags, restore_timeout_scale,
+                       handle_coverage_data, handle_render_test_data,
+                       pull_ui_screen_captures]
+    if self._env.concurrent_adb:
+      post_test_step_thread_group = reraiser_thread.ReraiserThreadGroup(
+          reraiser_thread.ReraiserThread(f) for f in post_test_steps)
+      post_test_step_thread_group.StartAll(will_block=True)
+    else:
+      for step in post_test_steps:
+        step()
 
     for result in results:
       if logcat_file:
diff --git a/build/android/pylib/results/presentation/test_results_presentation.py b/build/android/pylib/results/presentation/test_results_presentation.py
index e218dac..21137fe 100755
--- a/build/android/pylib/results/presentation/test_results_presentation.py
+++ b/build/android/pylib/results/presentation/test_results_presentation.py
@@ -6,9 +6,7 @@
 
 import argparse
 import collections
-import contextlib
 import json
-import logging
 import tempfile
 import os
 import sys
@@ -363,56 +361,6 @@
         authenticated_link=True)
 
 
-def ui_screenshot_set(json_path):
-  with open(json_path) as json_file:
-    json_object = json.loads(json_file.read())
-  if not 'per_iteration_data' in json_object:
-    # This will be reported as an error by result_details, no need to duplicate.
-    return None
-  ui_screenshots = []
-  for testsuite_run in json_object['per_iteration_data']:
-    for _, test_runs in testsuite_run.iteritems():
-      for test_run in test_runs:
-        if 'ui screenshot' in test_run['links']:
-          screenshot_link = test_run['links']['ui screenshot']
-          if screenshot_link.startswith('file:'):
-            with contextlib.closing(urllib.urlopen(screenshot_link)) as f:
-              test_screenshots = json.load(f)
-          else:
-            # Assume anything that isn't a file link is a google storage link
-            screenshot_string = google_storage_helper.read_from_link(
-                screenshot_link)
-            if not screenshot_string:
-              logging.error('Bad screenshot link %s', screenshot_link)
-              continue
-            test_screenshots = json.loads(
-                screenshot_string)
-          ui_screenshots.extend(test_screenshots)
-
-  if ui_screenshots:
-    return json.dumps(ui_screenshots)
-  return None
-
-
-def upload_screenshot_set(json_path, test_name, bucket, builder_name,
-                          build_number):
-  screenshot_set = ui_screenshot_set(json_path)
-  if not screenshot_set:
-    return None
-  dest = google_storage_helper.unique_name(
-    'screenshots_%s_%s_%s' % (test_name, builder_name, build_number),
-    suffix='.json')
-  with tempfile.NamedTemporaryFile(suffix='.json') as temp_file:
-    temp_file.write(screenshot_set)
-    temp_file.flush()
-    return google_storage_helper.upload(
-        name=dest,
-        filepath=temp_file.name,
-        bucket='%s/json' % bucket,
-        content_type='application/json',
-        authenticated_link=True)
-
-
 def main():
   parser = argparse.ArgumentParser()
   parser.add_argument('--json-file', help='Path of json file.')
@@ -507,28 +455,16 @@
       'Result details link do not match. The link returned by get_url_link'
       ' should be the same as that returned by upload.')
 
-  ui_screenshot_link = upload_screenshot_set(json_file, args.test_name,
-      args.bucket, builder_name, build_number)
-
-
   if args.output_json:
     with open(json_file) as original_json_file:
       json_object = json.load(original_json_file)
       json_object['links'] = {
           'result_details (logcats, flakiness links)': result_details_link
       }
-
-      if ui_screenshot_link:
-        json_object['links']['ui screenshots'] = ui_screenshot_link
-
       with open(args.output_json, 'w') as f:
         json.dump(json_object, f)
   else:
-    print 'Result Details: %s' % result_details_link
-
-    if ui_screenshot_link:
-      print 'UI Screenshots %s' % ui_screenshot_link
-
+    print result_details_link
 
 if __name__ == '__main__':
   sys.exit(main())
diff --git a/build/android/pylib/utils/google_storage_helper.py b/build/android/pylib/utils/google_storage_helper.py
index 3101d71..55e4882 100644
--- a/build/android/pylib/utils/google_storage_helper.py
+++ b/build/android/pylib/utils/google_storage_helper.py
@@ -13,7 +13,6 @@
 import os
 import sys
 import time
-import urlparse
 
 from pylib.constants import host_paths
 from pylib.utils import decorators
@@ -63,15 +62,6 @@
   return get_url_link(name, bucket, authenticated_link)
 
 
-@decorators.NoRaiseException(default_return_value='')
-def read_from_link(link):
-  # Note that urlparse returns the path with an initial '/', so we only need to
-  # add one more after the 'gs;'
-  gs_path = 'gs:/%s' % urlparse.urlparse(link).path
-  cmd = [_GSUTIL_PATH, '-q', 'cat', gs_path]
-  return cmd_helper.GetCmdOutput(cmd)
-
-
 @decorators.NoRaiseException(default_return_value=False)
 def exists(name, bucket):
   bucket = _format_bucket_name(bucket)
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index 1a8bf0f..97c31b8 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -937,16 +937,6 @@
         results_detail_file.flush()
       logging.critical('TEST RESULTS: %s', results_detail_file.Link())
 
-      ui_screenshots = test_results_presentation.ui_screenshot_set(
-          json_file.name)
-      if ui_screenshots:
-        with out_manager.ArchivedTempfile(
-            'ui_screenshots.json',
-            'ui_capture',
-            output_manager.Datatype.JSON) as ui_screenshot_file:
-          ui_screenshot_file.write(ui_screenshots)
-        logging.critical('UI Screenshots: %s', ui_screenshot_file.Link())
-
   if args.command == 'perf' and (args.steps or args.single_step):
     return 0
 
diff --git a/build/config/linux/BUILD.gn b/build/config/linux/BUILD.gn
index 45fee9a0..bee0538e 100644
--- a/build/config/linux/BUILD.gn
+++ b/build/config/linux/BUILD.gn
@@ -25,6 +25,10 @@
   if (is_chromeos) {
     defines = [ "OS_CHROMEOS" ]
   }
+
+  if (current_cpu == "mipsel") {
+    libs = [ "atomic" ]
+  }
 }
 
 config("x11") {
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index a1d67f8..6cc7ef6c 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -186,7 +186,6 @@
     "resources/resource_pool.h",
     "resources/resource_provider.cc",
     "resources/resource_provider.h",
-    "resources/resource_util.h",
     "resources/scoped_ui_resource.cc",
     "resources/scoped_ui_resource.h",
     "resources/ui_resource_bitmap.cc",
@@ -739,7 +738,7 @@
     "//gpu/ipc:gl_in_process_context",
     "//gpu/skia_bindings",
     "//media",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/bindings",
     "//testing/gmock",
     "//testing/gtest",
@@ -791,7 +790,7 @@
     "//gpu/command_buffer/client:raster",
     "//gpu/ipc/common:struct_traits",
     "//media",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/bindings",
     "//services/viz/public/interfaces",
     "//skia",
diff --git a/cc/raster/one_copy_raster_buffer_provider.cc b/cc/raster/one_copy_raster_buffer_provider.cc
index 6388dc7..afdb591 100644
--- a/cc/raster/one_copy_raster_buffer_provider.cc
+++ b/cc/raster/one_copy_raster_buffer_provider.cc
@@ -16,12 +16,12 @@
 #include "base/trace_event/trace_event.h"
 #include "cc/base/histograms.h"
 #include "cc/base/math_util.h"
-#include "cc/resources/resource_util.h"
 #include "components/viz/common/gpu/context_provider.h"
 #include "components/viz/common/gpu/raster_context_provider.h"
 #include "components/viz/common/gpu/texture_allocation.h"
 #include "components/viz/common/resources/platform_color.h"
 #include "components/viz/common/resources/resource_format.h"
+#include "components/viz/common/resources/resource_sizes.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/context_support.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
@@ -465,7 +465,7 @@
     ri->CompressedCopyTextureCHROMIUM(staging_buffer->texture_id,
                                       mailbox_texture_id);
   } else {
-    int bytes_per_row = ResourceUtil::UncheckedWidthInBytes<int>(
+    int bytes_per_row = viz::ResourceSizes::UncheckedWidthInBytes<int>(
         rect_to_copy.width(), staging_buffer->format);
     int chunk_size_in_rows =
         std::max(1, max_bytes_per_copy_operation_ / bytes_per_row);
diff --git a/cc/raster/staging_buffer_pool.cc b/cc/raster/staging_buffer_pool.cc
index 84ee9a3..8ef7dd3e 100644
--- a/cc/raster/staging_buffer_pool.cc
+++ b/cc/raster/staging_buffer_pool.cc
@@ -12,8 +12,8 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "cc/base/container_util.h"
-#include "cc/resources/resource_util.h"
 #include "components/viz/common/gpu/raster_context_provider.h"
+#include "components/viz/common/resources/resource_sizes.h"
 #include "gpu/command_buffer/client/raster_interface.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 
@@ -103,7 +103,7 @@
   MemoryAllocatorDump* buffer_dump = pmd->CreateAllocatorDump(buffer_dump_name);
 
   uint64_t buffer_size_in_bytes =
-      ResourceUtil::UncheckedSizeInBytes<uint64_t>(size, format);
+      viz::ResourceSizes::UncheckedSizeInBytes<uint64_t>(size, format);
   buffer_dump->AddScalar(MemoryAllocatorDump::kNameSize,
                          MemoryAllocatorDump::kUnitsBytes,
                          buffer_size_in_bytes);
@@ -210,8 +210,8 @@
 
   DCHECK(buffers_.find(staging_buffer) == buffers_.end());
   buffers_.insert(staging_buffer);
-  int buffer_usage_in_bytes =
-      ResourceUtil::UncheckedSizeInBytes<int>(staging_buffer->size, format);
+  int buffer_usage_in_bytes = viz::ResourceSizes::UncheckedSizeInBytes<int>(
+      staging_buffer->size, format);
   staging_buffer_usage_in_bytes_ += buffer_usage_in_bytes;
 }
 
@@ -221,7 +221,7 @@
 
   DCHECK(buffers_.find(staging_buffer) != buffers_.end());
   buffers_.erase(staging_buffer);
-  int buffer_usage_in_bytes = ResourceUtil::UncheckedSizeInBytes<int>(
+  int buffer_usage_in_bytes = viz::ResourceSizes::UncheckedSizeInBytes<int>(
       staging_buffer->size, staging_buffer->format);
   DCHECK_GE(staging_buffer_usage_in_bytes_, buffer_usage_in_bytes);
   staging_buffer_usage_in_bytes_ -= buffer_usage_in_bytes;
@@ -231,7 +231,7 @@
     const StagingBuffer* staging_buffer) {
   lock_.AssertAcquired();
 
-  int buffer_usage_in_bytes = ResourceUtil::UncheckedSizeInBytes<int>(
+  int buffer_usage_in_bytes = viz::ResourceSizes::UncheckedSizeInBytes<int>(
       staging_buffer->size, staging_buffer->format);
   free_staging_buffer_usage_in_bytes_ += buffer_usage_in_bytes;
 }
@@ -240,7 +240,7 @@
     const StagingBuffer* staging_buffer) {
   lock_.AssertAcquired();
 
-  int buffer_usage_in_bytes = ResourceUtil::UncheckedSizeInBytes<int>(
+  int buffer_usage_in_bytes = viz::ResourceSizes::UncheckedSizeInBytes<int>(
       staging_buffer->size, staging_buffer->format);
   DCHECK_GE(free_staging_buffer_usage_in_bytes_, buffer_usage_in_bytes);
   free_staging_buffer_usage_in_bytes_ -= buffer_usage_in_bytes;
diff --git a/cc/resources/layer_tree_resource_provider.cc b/cc/resources/layer_tree_resource_provider.cc
index 9fb642c..3adf492 100644
--- a/cc/resources/layer_tree_resource_provider.cc
+++ b/cc/resources/layer_tree_resource_provider.cc
@@ -7,10 +7,10 @@
 #include "base/bits.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "cc/resources/resource_util.h"
 #include "components/viz/common/gpu/context_provider.h"
 #include "components/viz/common/resources/platform_color.h"
 #include "components/viz/common/resources/resource_format_utils.h"
+#include "components/viz/common/resources/resource_sizes.h"
 #include "components/viz/common/resources/shared_bitmap_manager.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/context_support.h"
@@ -504,7 +504,7 @@
     if (resource->format == viz::ETC1) {
       DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
       int image_bytes =
-          ResourceUtil::CheckedSizeInBytes<int>(image_size, viz::ETC1);
+          viz::ResourceSizes::CheckedSizeInBytes<int>(image_size, viz::ETC1);
       gl->CompressedTexImage2D(resource->target, 0, GLInternalFormat(viz::ETC1),
                                image_size.width(), image_size.height(), 0,
                                image_bytes, image);
diff --git a/cc/resources/resource_pool.cc b/cc/resources/resource_pool.cc
index 5e9d24a..659d5743 100644
--- a/cc/resources/resource_pool.cc
+++ b/cc/resources/resource_pool.cc
@@ -20,7 +20,7 @@
 #include "build/build_config.h"
 #include "cc/base/container_util.h"
 #include "cc/resources/layer_tree_resource_provider.h"
-#include "cc/resources/resource_util.h"
+#include "components/viz/common/resources/resource_sizes.h"
 
 using base::trace_event::MemoryAllocatorDump;
 using base::trace_event::MemoryDumpLevelOfDetail;
@@ -124,8 +124,9 @@
     // Transfer resource to |in_use_resources_|.
     in_use_resources_[resource->unique_id()] = std::move(*it);
     unused_resources_.erase(it);
-    in_use_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>(
-        resource->size(), resource->format());
+    in_use_memory_usage_bytes_ +=
+        viz::ResourceSizes::UncheckedSizeInBytes<size_t>(resource->size(),
+                                                         resource->format());
     return resource;
   }
   return nullptr;
@@ -135,19 +136,19 @@
     const gfx::Size& size,
     viz::ResourceFormat format,
     const gfx::ColorSpace& color_space) {
-  DCHECK(ResourceUtil::VerifySizeInBytes<size_t>(size, format));
+  DCHECK(viz::ResourceSizes::VerifySizeInBytes<size_t>(size, format));
 
   auto pool_resource = std::make_unique<PoolResource>(
       next_resource_unique_id_++, size, format, color_space);
 
   total_memory_usage_bytes_ +=
-      ResourceUtil::UncheckedSizeInBytes<size_t>(size, format);
+      viz::ResourceSizes::UncheckedSizeInBytes<size_t>(size, format);
   ++total_resource_count_;
 
   PoolResource* resource = pool_resource.get();
   in_use_resources_[resource->unique_id()] = std::move(pool_resource);
   in_use_memory_usage_bytes_ +=
-      ResourceUtil::UncheckedSizeInBytes<size_t>(size, format);
+      viz::ResourceSizes::UncheckedSizeInBytes<size_t>(size, format);
 
   return resource;
 }
@@ -231,8 +232,9 @@
     in_use_resources_[resource->unique_id()] =
         std::move(*iter_resource_to_return);
     unused_resources_.erase(iter_resource_to_return);
-    in_use_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>(
-        resource->size(), resource->format());
+    in_use_memory_usage_bytes_ +=
+        viz::ResourceSizes::UncheckedSizeInBytes<size_t>(resource->size(),
+                                                         resource->format());
     *total_invalidated_rect = resource->invalidated_rect();
 
     // Clear the invalidated rect and content ID on the resource being retunred.
@@ -364,8 +366,9 @@
   CHECK(it->second.get());
 
   pool_resource->set_last_usage(base::TimeTicks::Now());
-  in_use_memory_usage_bytes_ -= ResourceUtil::UncheckedSizeInBytes<size_t>(
-      pool_resource->size(), pool_resource->format());
+  in_use_memory_usage_bytes_ -=
+      viz::ResourceSizes::UncheckedSizeInBytes<size_t>(pool_resource->size(),
+                                                       pool_resource->format());
 
   // Save the ResourceId since the |pool_resource| can be deleted in the next
   // step.
@@ -436,7 +439,7 @@
 }
 
 void ResourcePool::DeleteResource(std::unique_ptr<PoolResource> resource) {
-  size_t resource_bytes = ResourceUtil::UncheckedSizeInBytes<size_t>(
+  size_t resource_bytes = viz::ResourceSizes::UncheckedSizeInBytes<size_t>(
       resource->size(), resource->format());
   total_memory_usage_bytes_ -= resource_bytes;
   --total_resource_count_;
@@ -611,7 +614,7 @@
   }
 
   uint64_t total_bytes =
-      ResourceUtil::UncheckedSizeInBytesAligned<size_t>(size_, format_);
+      viz::ResourceSizes::UncheckedSizeInBytesAligned<size_t>(size_, format_);
   dump->AddScalar(MemoryAllocatorDump::kNameSize,
                   MemoryAllocatorDump::kUnitsBytes, total_bytes);
 
diff --git a/cc/resources/resource_pool_unittest.cc b/cc/resources/resource_pool_unittest.cc
index 0aa7a5c..cf233dc 100644
--- a/cc/resources/resource_pool_unittest.cc
+++ b/cc/resources/resource_pool_unittest.cc
@@ -9,8 +9,8 @@
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "cc/resources/resource_util.h"
 #include "cc/test/fake_resource_provider.h"
+#include "components/viz/common/resources/resource_sizes.h"
 #include "components/viz/test/test_context_provider.h"
 #include "components/viz/test/test_shared_bitmap_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -82,7 +82,7 @@
   viz::ResourceFormat format = viz::RGBA_8888;
   gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
   size_t resource_bytes =
-      ResourceUtil::UncheckedSizeInBytes<size_t>(size, format);
+      viz::ResourceSizes::UncheckedSizeInBytes<size_t>(size, format);
   ResourcePool::InUsePoolResource resource =
       resource_pool_->AcquireResource(size, format, color_space);
 
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 3e63b71b..ab6c358 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -23,8 +23,8 @@
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
-#include "cc/resources/resource_util.h"
 #include "components/viz/common/gpu/context_provider.h"
+#include "components/viz/common/resources/resource_sizes.h"
 #include "components/viz/common/resources/returned_resource.h"
 #include "components/viz/common/resources/transferable_resource.h"
 #include "gpu/command_buffer/client/context_support.h"
@@ -226,11 +226,16 @@
     base::trace_event::MemoryAllocatorDump* dump =
         pmd->CreateAllocatorDump(dump_name);
 
-    uint64_t total_bytes = ResourceUtil::UncheckedSizeInBytesAligned<size_t>(
-        resource.size, resource.format);
-    dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
-                    base::trace_event::MemoryAllocatorDump::kUnitsBytes,
-                    static_cast<uint64_t>(total_bytes));
+    // Texture resources may not come with a size, in which case don't report
+    // one.
+    if (!resource.size.IsEmpty()) {
+      uint64_t total_bytes =
+          viz::ResourceSizes::UncheckedSizeInBytesAligned<size_t>(
+              resource.size, resource.format);
+      dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
+                      base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+                      static_cast<uint64_t>(total_bytes));
+    }
 
     // Resources may be shared across processes and require a shared GUID to
     // prevent double counting the memory.
diff --git a/cc/resources/resource_util.h b/cc/resources/resource_util.h
deleted file mode 100644
index e263aa6..0000000
--- a/cc/resources/resource_util.h
+++ /dev/null
@@ -1,218 +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 CC_RESOURCES_RESOURCE_UTIL_H_
-#define CC_RESOURCES_RESOURCE_UTIL_H_
-
-#include <stddef.h>
-
-#include <limits>
-
-#include "base/macros.h"
-#include "base/numerics/safe_math.h"
-#include "cc/base/math_util.h"
-#include "cc/cc_export.h"
-#include "components/viz/common/resources/resource_format.h"
-#include "components/viz/common/resources/resource_format_utils.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace cc {
-
-class CC_EXPORT ResourceUtil {
- public:
-  // Returns true if the width is valid and fits in bytes, false otherwise.
-  template <typename T>
-  static bool VerifyWidthInBytes(int width, viz::ResourceFormat format);
-  // Returns true if the size is valid and fits in bytes, false otherwise.
-  template <typename T>
-  static bool VerifySizeInBytes(const gfx::Size& size,
-                                viz::ResourceFormat format);
-
-  // Dies with a CRASH() if the width can not be represented as a positive
-  // number of bytes.
-  template <typename T>
-  static T CheckedWidthInBytes(int width, viz::ResourceFormat format);
-  // Dies with a CRASH() if the size can not be represented as a positive
-  // number of bytes.
-  template <typename T>
-  static T CheckedSizeInBytes(const gfx::Size& size,
-                              viz::ResourceFormat format);
-
-  // Returns the width in bytes but may overflow or return 0. Only do this for
-  // computing widths for sizes that have already been checked.
-  template <typename T>
-  static T UncheckedWidthInBytes(int width, viz::ResourceFormat format);
-  // Returns the size in bytes but may overflow or return 0. Only do this for
-  // sizes that have already been checked.
-  template <typename T>
-  static T UncheckedSizeInBytes(const gfx::Size& size,
-                                viz::ResourceFormat format);
-  // Returns the width in bytes aligned but may overflow or return 0. Only do
-  // this for computing widths for sizes that have already been checked.
-  template <typename T>
-  static T UncheckedWidthInBytesAligned(int width, viz::ResourceFormat format);
-  // Returns the size in bytes aligned but may overflow or return 0. Only do
-  // this for sizes that have already been checked.
-  template <typename T>
-  static T UncheckedSizeInBytesAligned(const gfx::Size& size,
-                                       viz::ResourceFormat format);
-
- private:
-  template <typename T>
-  static inline void VerifyType();
-
-  template <typename T>
-  static bool VerifyFitsInBytesInternal(int width,
-                                        int height,
-                                        viz::ResourceFormat format,
-                                        bool verify_size,
-                                        bool aligned);
-
-  template <typename T>
-  static T BytesInternal(int width,
-                         int height,
-                         viz::ResourceFormat format,
-                         bool verify_size,
-                         bool aligned);
-
-  DISALLOW_COPY_AND_ASSIGN(ResourceUtil);
-};
-
-template <typename T>
-bool ResourceUtil::VerifyWidthInBytes(int width, viz::ResourceFormat format) {
-  VerifyType<T>();
-  return VerifyFitsInBytesInternal<T>(width, 0, format, false, false);
-}
-
-template <typename T>
-bool ResourceUtil::VerifySizeInBytes(const gfx::Size& size,
-                                     viz::ResourceFormat format) {
-  VerifyType<T>();
-  return VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true,
-                                      false);
-}
-
-template <typename T>
-T ResourceUtil::CheckedWidthInBytes(int width, viz::ResourceFormat format) {
-  VerifyType<T>();
-  DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, false));
-  base::CheckedNumeric<T> checked_value = BitsPerPixel(format);
-  checked_value *= width;
-  checked_value = MathUtil::CheckedRoundUp<T>(checked_value.ValueOrDie(), 8);
-  checked_value /= 8;
-  return checked_value.ValueOrDie();
-}
-
-template <typename T>
-T ResourceUtil::CheckedSizeInBytes(const gfx::Size& size,
-                                   viz::ResourceFormat format) {
-  VerifyType<T>();
-  DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true,
-                                      false));
-  base::CheckedNumeric<T> checked_value = BitsPerPixel(format);
-  checked_value *= size.width();
-  checked_value = MathUtil::CheckedRoundUp<T>(checked_value.ValueOrDie(), 8);
-  checked_value /= 8;
-  checked_value *= size.height();
-  return checked_value.ValueOrDie();
-}
-
-template <typename T>
-T ResourceUtil::UncheckedWidthInBytes(int width, viz::ResourceFormat format) {
-  VerifyType<T>();
-  DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, false));
-  return BytesInternal<T>(width, 0, format, false, false);
-}
-
-template <typename T>
-T ResourceUtil::UncheckedSizeInBytes(const gfx::Size& size,
-                                     viz::ResourceFormat format) {
-  VerifyType<T>();
-  DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true,
-                                      false));
-  return BytesInternal<T>(size.width(), size.height(), format, true, false);
-}
-
-template <typename T>
-T ResourceUtil::UncheckedWidthInBytesAligned(int width,
-                                             viz::ResourceFormat format) {
-  VerifyType<T>();
-  DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, true));
-  return BytesInternal<T>(width, 0, format, false, true);
-}
-
-template <typename T>
-T ResourceUtil::UncheckedSizeInBytesAligned(const gfx::Size& size,
-                                            viz::ResourceFormat format) {
-  VerifyType<T>();
-  DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true,
-                                      true));
-  return BytesInternal<T>(size.width(), size.height(), format, true, true);
-}
-
-template <typename T>
-void ResourceUtil::VerifyType() {
-  static_assert(
-      std::numeric_limits<T>::is_integer && !std::is_same<T, bool>::value,
-      "T must be non-bool integer type. Preferred type is size_t.");
-}
-
-template <typename T>
-bool ResourceUtil::VerifyFitsInBytesInternal(int width,
-                                             int height,
-                                             viz::ResourceFormat format,
-                                             bool verify_size,
-                                             bool aligned) {
-  base::CheckedNumeric<T> checked_value = BitsPerPixel(format);
-  checked_value *= width;
-  if (!checked_value.IsValid())
-    return false;
-
-  // Roundup bits to byte (8 bits) boundary. If width is 3 and BitsPerPixel is
-  // 4, then it should return 16, so that row pixels do not get truncated.
-  checked_value = MathUtil::UncheckedRoundUp<T>(checked_value.ValueOrDie(), 8);
-
-  // If aligned is true, bytes are aligned on 4-bytes boundaries for upload
-  // performance, assuming that GL_PACK_ALIGNMENT or GL_UNPACK_ALIGNMENT have
-  // not changed from default.
-  if (aligned) {
-    checked_value /= 8;
-    if (!checked_value.IsValid())
-      return false;
-    checked_value =
-        MathUtil::UncheckedRoundUp<T>(checked_value.ValueOrDie(), 4);
-    checked_value *= 8;
-  }
-
-  if (verify_size)
-    checked_value *= height;
-  if (!checked_value.IsValid())
-    return false;
-  T value = checked_value.ValueOrDie();
-  if ((value % 8) != 0)
-    return false;
-  return true;
-}
-
-template <typename T>
-T ResourceUtil::BytesInternal(int width,
-                              int height,
-                              viz::ResourceFormat format,
-                              bool verify_size,
-                              bool aligned) {
-  T bytes = BitsPerPixel(format);
-  bytes *= width;
-  bytes = MathUtil::UncheckedRoundUp<T>(bytes, 8);
-  bytes /= 8;
-  if (aligned)
-    bytes = MathUtil::UncheckedRoundUp<T>(bytes, 4);
-  if (verify_size)
-    bytes *= height;
-
-  return bytes;
-}
-
-}  // namespace cc
-
-#endif  // CC_RESOURCES_RESOURCE_UTIL_H_
diff --git a/cc/resources/resource_util_unittest.cc b/cc/resources/resource_util_unittest.cc
index 8bffa6b..4680c0c 100644
--- a/cc/resources/resource_util_unittest.cc
+++ b/cc/resources/resource_util_unittest.cc
@@ -5,7 +5,7 @@
 #include <stddef.h>
 
 #include "base/logging.h"
-#include "cc/resources/resource_util.h"
+#include "components/viz/common/resources/resource_sizes.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cc {
@@ -24,14 +24,14 @@
  public:
   void TestVerifyWidthInBytes(int width, const TestFormat* test_formats) {
     for (int i = 0; i < kTestFormats; ++i) {
-      EXPECT_TRUE(ResourceUtil::VerifyWidthInBytes<size_t>(
+      EXPECT_TRUE(viz::ResourceSizes::VerifyWidthInBytes<size_t>(
           width, test_formats[i].format));
     }
   }
 
   void TestCheckedWidthInBytes(int width, const TestFormat* test_formats) {
     for (int i = 0; i < kTestFormats; ++i) {
-      size_t bytes = ResourceUtil::CheckedWidthInBytes<size_t>(
+      size_t bytes = viz::ResourceSizes::CheckedWidthInBytes<size_t>(
           width, test_formats[i].format);
       EXPECT_EQ(bytes, test_formats[i].expected_bytes);
     }
@@ -39,7 +39,7 @@
 
   void TestUncheckedWidthInBytes(int width, const TestFormat* test_formats) {
     for (int i = 0; i < kTestFormats; ++i) {
-      size_t bytes = ResourceUtil::UncheckedWidthInBytes<size_t>(
+      size_t bytes = viz::ResourceSizes::UncheckedWidthInBytes<size_t>(
           width, test_formats[i].format);
       EXPECT_EQ(bytes, test_formats[i].expected_bytes);
     }
@@ -48,7 +48,7 @@
   void TestUncheckedWidthInBytesAligned(int width,
                                         const TestFormat* test_formats) {
     for (int i = 0; i < kTestFormats; ++i) {
-      size_t bytes = ResourceUtil::UncheckedWidthInBytesAligned<size_t>(
+      size_t bytes = viz::ResourceSizes::UncheckedWidthInBytesAligned<size_t>(
           width, test_formats[i].format);
       EXPECT_EQ(bytes, test_formats[i].expected_bytes_aligned);
     }
@@ -57,7 +57,7 @@
   void TestVerifySizeInBytes(const gfx::Size& size,
                              const TestFormat* test_formats) {
     for (int i = 0; i < kTestFormats; ++i) {
-      EXPECT_TRUE(ResourceUtil::VerifySizeInBytes<size_t>(
+      EXPECT_TRUE(viz::ResourceSizes::VerifySizeInBytes<size_t>(
           size, test_formats[i].format));
     }
   }
@@ -65,7 +65,7 @@
   void TestCheckedSizeInBytes(const gfx::Size& size,
                               const TestFormat* test_formats) {
     for (int i = 0; i < kTestFormats; ++i) {
-      size_t bytes = ResourceUtil::CheckedSizeInBytes<size_t>(
+      size_t bytes = viz::ResourceSizes::CheckedSizeInBytes<size_t>(
           size, test_formats[i].format);
       EXPECT_EQ(bytes, test_formats[i].expected_bytes);
     }
@@ -74,7 +74,7 @@
   void TestUncheckedSizeInBytes(const gfx::Size& size,
                                 const TestFormat* test_formats) {
     for (int i = 0; i < kTestFormats; ++i) {
-      size_t bytes = ResourceUtil::UncheckedSizeInBytes<size_t>(
+      size_t bytes = viz::ResourceSizes::UncheckedSizeInBytes<size_t>(
           size, test_formats[i].format);
       EXPECT_EQ(bytes, test_formats[i].expected_bytes);
     }
@@ -83,7 +83,7 @@
   void TestUncheckedSizeInBytesAligned(const gfx::Size& size,
                                        const TestFormat* test_formats) {
     for (int i = 0; i < kTestFormats; ++i) {
-      size_t bytes = ResourceUtil::UncheckedSizeInBytesAligned<size_t>(
+      size_t bytes = viz::ResourceSizes::UncheckedSizeInBytesAligned<size_t>(
           size, test_formats[i].format);
       EXPECT_EQ(bytes, test_formats[i].expected_bytes_aligned);
     }
@@ -153,18 +153,18 @@
 TEST_F(ResourceUtilTest, WidthInBytesOverflow) {
   int width = 10;
   // 10 * 16 = 160 bits, overflows in char, but fits in unsigned char.
-  EXPECT_FALSE(
-      ResourceUtil::VerifyWidthInBytes<signed char>(width, viz::RGBA_4444));
-  EXPECT_TRUE(
-      ResourceUtil::VerifyWidthInBytes<unsigned char>(width, viz::RGBA_4444));
+  EXPECT_FALSE(viz::ResourceSizes::VerifyWidthInBytes<signed char>(
+      width, viz::RGBA_4444));
+  EXPECT_TRUE(viz::ResourceSizes::VerifyWidthInBytes<unsigned char>(
+      width, viz::RGBA_4444));
 }
 
 TEST_F(ResourceUtilTest, SizeInBytesOverflow) {
   gfx::Size size(10, 10);
   // 10 * 16 * 10 = 1600 bits, overflows in char, but fits in int.
   EXPECT_FALSE(
-      ResourceUtil::VerifySizeInBytes<signed char>(size, viz::RGBA_4444));
-  EXPECT_TRUE(ResourceUtil::VerifySizeInBytes<int>(size, viz::RGBA_4444));
+      viz::ResourceSizes::VerifySizeInBytes<signed char>(size, viz::RGBA_4444));
+  EXPECT_TRUE(viz::ResourceSizes::VerifySizeInBytes<int>(size, viz::RGBA_4444));
 }
 
 }  // namespace
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index c24bd0d..4da5ac1 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -15,12 +15,12 @@
 #include "cc/base/math_util.h"
 #include "cc/paint/skia_paint_canvas.h"
 #include "cc/resources/layer_tree_resource_provider.h"
-#include "cc/resources/resource_util.h"
 #include "components/viz/common/gpu/context_provider.h"
 #include "components/viz/common/quads/render_pass.h"
 #include "components/viz/common/quads/stream_video_draw_quad.h"
 #include "components/viz/common/quads/texture_draw_quad.h"
 #include "components/viz/common/quads/yuv_video_draw_quad.h"
+#include "components/viz/common/resources/resource_sizes.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "media/base/video_frame.h"
@@ -738,7 +738,7 @@
         // by software.
         video_renderer_->Copy(video_frame, &canvas, media::Context3D());
       } else {
-        size_t bytes_per_row = ResourceUtil::CheckedWidthInBytes<size_t>(
+        size_t bytes_per_row = viz::ResourceSizes::CheckedWidthInBytes<size_t>(
             video_frame->coded_size().width(), viz::ResourceFormat::RGBA_8888);
         size_t needed_size = bytes_per_row * video_frame->coded_size().height();
         if (upload_pixels_.size() < needed_size)
@@ -819,8 +819,9 @@
     // |resource_size_pixels| is the size of the destination resource.
     const gfx::Size resource_size_pixels = plane_resource.resource_size();
 
-    const size_t bytes_per_row = ResourceUtil::CheckedWidthInBytes<size_t>(
-        resource_size_pixels.width(), plane_resource_format);
+    const size_t bytes_per_row =
+        viz::ResourceSizes::CheckedWidthInBytes<size_t>(
+            resource_size_pixels.width(), plane_resource_format);
     // Use 4-byte row alignment (OpenGL default) for upload performance.
     // Assuming that GL_UNPACK_ALIGNMENT has not changed from default.
     const size_t upload_image_stride =
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc
index 7d7d3f6..0354cfcc 100644
--- a/cc/tiles/gpu_image_decode_cache.cc
+++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -211,12 +211,16 @@
 
   GrSurfaceOrigin origin;
   image->getTextureHandle(false /* flushPendingGrContextIO */, &origin);
+  SkColorType color_type = image->colorType();
+  if (color_type == kUnknown_SkColorType) {
+    return nullptr;
+  }
   sk_sp<SkColorSpace> color_space = image->refColorSpace();
   GrBackendTexture backend_texture;
   SkImage::BackendTextureReleaseProc release_proc;
   SkImage::MakeBackendTextureFromSkImage(context, std::move(image),
                                          &backend_texture, &release_proc);
-  return SkImage::MakeFromTexture(context, backend_texture, origin,
+  return SkImage::MakeFromTexture(context, backend_texture, origin, color_type,
                                   kPremul_SkAlphaType, std::move(color_space));
 }
 
diff --git a/cc/tiles/tile.cc b/cc/tiles/tile.cc
index 1dd6367..db0ba9f 100644
--- a/cc/tiles/tile.cc
+++ b/cc/tiles/tile.cc
@@ -12,8 +12,8 @@
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "cc/base/math_util.h"
-#include "cc/resources/resource_util.h"
 #include "cc/tiles/tile_manager.h"
+#include "components/viz/common/resources/resource_sizes.h"
 #include "components/viz/common/traced_value.h"
 
 namespace cc {
@@ -81,7 +81,7 @@
   if (draw_info_.resource_) {
     // We can use UncheckedSizeInBytes, since the tile size is determined by the
     // compositor.
-    return ResourceUtil::UncheckedSizeInBytes<size_t>(
+    return viz::ResourceSizes::UncheckedSizeInBytes<size_t>(
         draw_info_.resource_size(), draw_info_.resource_format());
   }
   return 0;
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index e5ed9cd..c2e98e8 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -28,9 +28,9 @@
 #include "cc/raster/playback_image_provider.h"
 #include "cc/raster/raster_buffer.h"
 #include "cc/raster/task_category.h"
-#include "cc/resources/resource_util.h"
 #include "cc/tiles/frame_viewer_instrumentation.h"
 #include "cc/tiles/tile.h"
+#include "components/viz/common/resources/resource_sizes.h"
 #include "ui/gfx/geometry/axis_transform2d.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 
@@ -1715,8 +1715,8 @@
   // We can use UncheckedSizeInBytes here since this is used with a tile
   // size which is determined by the compositor (it's at most max texture
   // size).
-  return MemoryUsage(ResourceUtil::UncheckedSizeInBytes<size_t>(size, format),
-                     1);
+  return MemoryUsage(
+      viz::ResourceSizes::UncheckedSizeInBytes<size_t>(size, format), 1);
 }
 
 // static
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc
index c284688..dcfffbd 100644
--- a/cc/tiles/tile_manager_unittest.cc
+++ b/cc/tiles/tile_manager_unittest.cc
@@ -18,7 +18,6 @@
 #include "cc/raster/raster_source.h"
 #include "cc/raster/synchronous_task_graph_runner.h"
 #include "cc/resources/resource_pool.h"
-#include "cc/resources/resource_util.h"
 #include "cc/test/fake_impl_task_runner_provider.h"
 #include "cc/test/fake_layer_tree_frame_sink.h"
 #include "cc/test/fake_layer_tree_frame_sink_client.h"
@@ -40,6 +39,7 @@
 #include "cc/tiles/tile_priority.h"
 #include "cc/tiles/tiling_set_raster_queue_all.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "components/viz/common/resources/resource_sizes.h"
 #include "components/viz/test/begin_frame_args_test.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -1370,8 +1370,9 @@
             host_impl()->resource_provider()->best_texture_format());
 
   ManagedMemoryPolicy policy = host_impl()->ActualManagedMemoryPolicy();
-  policy.bytes_limit_when_visible = ResourceUtil::UncheckedSizeInBytes<size_t>(
-      gfx::Size(256, 256), viz::RGBA_8888);
+  policy.bytes_limit_when_visible =
+      viz::ResourceSizes::UncheckedSizeInBytes<size_t>(gfx::Size(256, 256),
+                                                       viz::RGBA_8888);
   host_impl()->SetMemoryPolicy(policy);
 
   EXPECT_FALSE(host_impl()->is_likely_to_require_a_draw());
@@ -1543,9 +1544,9 @@
     if (!resource.software_backing()) {
       auto backing = std::make_unique<TestSoftwareBacking>();
       backing->shared_bitmap_id = viz::SharedBitmap::GenerateId();
-      backing->pixels =
-          std::make_unique<uint32_t[]>(viz::SharedBitmap::CheckedSizeInBytes(
-              resource.size(), viz::RGBA_8888));
+      backing->pixels = std::make_unique<uint32_t[]>(
+          viz::ResourceSizes::CheckedSizeInBytes<size_t>(resource.size(),
+                                                         viz::RGBA_8888));
       resource.set_software_backing(std::move(backing));
     }
     auto* backing =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index d380ef9..646684ab 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -1248,6 +1248,7 @@
             getLayoutInflater().inflate(R.layout.bottom_sheet, coordinator);
             mBottomSheet = coordinator.findViewById(R.id.bottom_sheet);
             mBottomSheet.init(coordinator, this);
+            mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_PEEK, true);
 
             mFadingBackgroundView = (FadingBackgroundView) findViewById(R.id.fading_focus_target);
             mBottomSheet.addObserver(new EmptyBottomSheetObserver() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InstallableAmbientBadgeInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InstallableAmbientBadgeInfoBar.java
index 2f505e8..5a81ca8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InstallableAmbientBadgeInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InstallableAmbientBadgeInfoBar.java
@@ -32,15 +32,17 @@
  * An ambient infobar to tell the user that the current site they are visiting is a PWA.
  */
 public class InstallableAmbientBadgeInfoBar extends InfoBar implements View.OnClickListener {
+    private String mMessageText;
     private String mUrl;
     private boolean mIsInstalled;
     private boolean mIsHiding;
 
     @CalledByNative
-    private static InfoBar show(
-            int enumeratedIconId, Bitmap iconBitmap, String url, boolean isInstalled) {
+    private static InfoBar show(int enumeratedIconId, Bitmap iconBitmap, String messageText,
+            String url, boolean isInstalled) {
         int drawableId = ResourceId.mapToDrawableId(enumeratedIconId);
-        return new InstallableAmbientBadgeInfoBar(drawableId, iconBitmap, url, isInstalled);
+        return new InstallableAmbientBadgeInfoBar(
+                drawableId, iconBitmap, messageText, url, isInstalled);
     }
 
     @Override
@@ -58,7 +60,7 @@
         TextView prompt = new AccessibleTextView(getContext());
 
         Resources res = layout.getResources();
-        prompt.setText(mIsInstalled ? R.string.ambient_badge_open : R.string.ambient_badge_install);
+        prompt.setText(mMessageText);
         prompt.setTextSize(TypedValue.COMPLEX_UNIT_PX, res.getDimension(R.dimen.infobar_text_size));
         prompt.setTextColor(ApiCompatibilityUtils.getColor(res, R.color.google_blue_700));
         prompt.setGravity(Gravity.CENTER_VERTICAL);
@@ -104,11 +106,13 @@
      * Creates the infobar.
      * @param iconDrawableId    Drawable ID corresponding to the icon that the infobar will show.
      * @param iconBitmap        Bitmap of the icon to display in the infobar.
+     * @param messageText       String to display
      * @param isInstalled       Whether the associated app is installed.
      */
-    private InstallableAmbientBadgeInfoBar(
-            int iconDrawableId, Bitmap iconBitmap, String url, boolean isInstalled) {
+    private InstallableAmbientBadgeInfoBar(int iconDrawableId, Bitmap iconBitmap,
+            String messageText, String url, boolean isInstalled) {
         super(iconDrawableId, iconBitmap, null);
+        mMessageText = messageText;
         mUrl = url;
         mIsInstalled = isInstalled;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
index b5d2f40..0dc81e71 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
@@ -48,7 +48,7 @@
     // entries must not be overwritten.
     private static final int PASSWORD_ENTRY_ACTION_VIEWED = 0;
     private static final int PASSWORD_ENTRY_ACTION_DELETED = 1;
-    private static final int PASSWORD_ENTRY_ACTION_CANCELLED = 2;
+    // Value 2 used to mean 'cancel' and is now obsolete. See https://crbug.com/807577 for details.
     private static final int PASSWORD_ENTRY_ACTION_VIEWED_AFTER_SEARCH = 3;
     private static final int PASSWORD_ENTRY_ACTION_BOUNDARY = 4;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index fef748f..953eaea5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -73,8 +73,8 @@
         extends FrameLayout implements BottomSheetSwipeDetector.SwipeableBottomSheet,
                                        FadingBackgroundView.FadingViewObserver, NativePageHost {
     /** The different states that the bottom sheet can have. */
-    @IntDef({SHEET_STATE_NONE, SHEET_STATE_PEEK, SHEET_STATE_HALF, SHEET_STATE_FULL,
-            SHEET_STATE_SCROLLING})
+    @IntDef({SHEET_STATE_NONE, SHEET_STATE_HIDDEN, SHEET_STATE_PEEK, SHEET_STATE_HALF,
+            SHEET_STATE_FULL, SHEET_STATE_SCROLLING})
     @Retention(RetentionPolicy.SOURCE)
     public @interface SheetState {}
     /**
@@ -82,10 +82,11 @@
      * transitioning between states.
      */
     private static final int SHEET_STATE_NONE = -1;
-    public static final int SHEET_STATE_PEEK = 0;
-    public static final int SHEET_STATE_HALF = 1;
-    public static final int SHEET_STATE_FULL = 2;
-    public static final int SHEET_STATE_SCROLLING = 3;
+    public static final int SHEET_STATE_HIDDEN = 0;
+    public static final int SHEET_STATE_PEEK = 1;
+    public static final int SHEET_STATE_HALF = 2;
+    public static final int SHEET_STATE_FULL = 3;
+    public static final int SHEET_STATE_SCROLLING = 4;
 
     /** The different reasons that the sheet's state can change. */
     @IntDef({StateChangeReason.NONE, StateChangeReason.OMNIBOX_FOCUS, StateChangeReason.SWIPE,
@@ -181,8 +182,8 @@
      * they go from smallest to largest.
      */
     private static final int[] sStates =
-            new int[] {SHEET_STATE_PEEK, SHEET_STATE_HALF, SHEET_STATE_FULL};
-    private final float[] mStateRatios = new float[3];
+            new int[] {SHEET_STATE_HIDDEN, SHEET_STATE_PEEK, SHEET_STATE_HALF, SHEET_STATE_FULL};
+    private final float[] mStateRatios = new float[4];
 
     /** The interpolator that the height animator uses. */
     private final Interpolator mInterpolator = new DecelerateInterpolator(1.0f);
@@ -222,7 +223,7 @@
 
     /** The current state that the sheet is in. */
     @SheetState
-    private int mCurrentState = SHEET_STATE_PEEK;
+    private int mCurrentState = SHEET_STATE_HIDDEN;
 
     /** The target sheet state. This is the state that the sheet is currently moving to. */
     @SheetState
@@ -250,6 +251,12 @@
      */
     private float mLastPeekToHalfRatioSent;
 
+    /**
+     * The last offset ratio sent to observers of onSheetOffsetChanged(). This is used to ensure the
+     * min and max values are provided at least once (0 and 1).
+     */
+    private float mLastOffsetRatioSent;
+
     /** The FrameLayout used to hold the bottom sheet toolbar. */
     private TouchRestrictingFrameLayout mToolbarHolder;
 
@@ -352,6 +359,7 @@
      */
     public static boolean isStateStable(@SheetState int sheetState) {
         switch (sheetState) {
+            case SHEET_STATE_HIDDEN:
             case SHEET_STATE_PEEK:
             case SHEET_STATE_HALF:
             case SHEET_STATE_FULL:
@@ -367,6 +375,10 @@
 
     @Override
     public boolean shouldGestureMoveSheet(MotionEvent initialEvent, MotionEvent currentEvent) {
+        // If the sheet is scrolling off-screen or in the process of hiding, gestures should not
+        // affect it.
+        if (getCurrentOffsetPx() < getSheetHeightForState(SHEET_STATE_PEEK)) return false;
+
         // If the sheet is already open, the experiment is not enabled, or accessibility is enabled
         // there is no need to restrict the swipe area.
         if (mActivity == null || isSheetOpen() || AccessibilityUtil.isAccessibilityEnabled()) {
@@ -770,7 +782,15 @@
 
             @Override
             public void onControlsOffsetChanged(
-                    float topOffset, float bottomOffset, boolean needsAnimate) {}
+                    float topOffset, float bottomOffset, boolean needsAnimate) {
+                if (getSheetState() == SHEET_STATE_HIDDEN) return;
+                if (getCurrentOffsetPx() > getSheetHeightForState(SHEET_STATE_PEEK)) return;
+
+                float hiddenRatio = -topOffset / mFullscreenManager.getTopControlsHeight();
+                float peekHeight = getPeekRatio() * mContainerHeight;
+
+                setSheetOffsetFromBottom(peekHeight - hiddenRatio * peekHeight);
+            }
 
             @Override
             public void onContentOffsetChanged(float offset) {}
@@ -844,7 +864,22 @@
 
     @Override
     public float getMinOffsetPx() {
-        return getPeekRatio() * mContainerHeight;
+        return (flingToHideEnabled() ? getHiddenRatio() : getPeekRatio()) * mContainerHeight;
+    }
+
+    /**
+     * @return Whether flinging down hard enough will close the sheet.
+     */
+    private boolean flingToHideEnabled() {
+        return true;
+    }
+
+    /**
+     * @return The minimum sheet state that the user can swipe to. i.e. flinging down will either
+     *         close the sheet or peek it.
+     */
+    private @SheetState int getMinSwipableSheetState() {
+        return flingToHideEnabled() ? SHEET_STATE_HIDDEN : SHEET_STATE_PEEK;
     }
 
     @Override
@@ -1090,6 +1125,7 @@
         // the correct toolbar height and container height are not know until those views are
         // inflated. The other views are a specific DP distance from the top and bottom and are
         // also updated.
+        mStateRatios[SHEET_STATE_HIDDEN] = 0;
         mStateRatios[SHEET_STATE_PEEK] = (mToolbarHeight + mToolbarShadowHeight) / mContainerHeight;
         mStateRatios[SHEET_STATE_HALF] = HALF_HEIGHT_RATIO;
         // The max height ratio will be greater than 1 to account for the toolbar shadow.
@@ -1199,6 +1235,13 @@
     }
 
     /**
+     * @return The ratio of the height of the screen that the hidden state is.
+     */
+    private float getHiddenRatio() {
+        return mStateRatios[SHEET_STATE_HIDDEN];
+    }
+
+    /**
      * @return The ratio of the height of the screen that the peeking state is.
      */
     @VisibleForTesting
@@ -1233,19 +1276,30 @@
     /**
      * Sends notifications if the sheet is transitioning from the peeking to half expanded state and
      * from the peeking to fully expanded state. The peek to half events are only sent when the
-     * sheet is between the peeking and half states.
+     * sheet is between the peeking and half states. Events are not sent for states less than
+     * peeking (i.e. hidden).
      */
     private void sendOffsetChangeEvents() {
+        // Do not send events for states less than the peeking state unless 0 has not been sent.
+        if (getCurrentOffsetPx() < getSheetHeightForState(SHEET_STATE_PEEK)
+                && mLastOffsetRatioSent <= 0) {
+            return;
+        }
+
         float screenRatio = mContainerHeight > 0 ? getCurrentOffsetPx() / mContainerHeight : 0;
 
         // This ratio is relative to the peek and full positions of the sheet.
         float peekFullRatio = MathUtils.clamp(
                 (screenRatio - getPeekRatio()) / (getFullRatio() - getPeekRatio()), 0, 1);
 
-        for (BottomSheetObserver o : mObservers) {
-            o.onSheetOffsetChanged(MathUtils.areFloatsEqual(peekFullRatio, 0) ? 0 : peekFullRatio);
+        if (getCurrentOffsetPx() < getSheetHeightForState(SHEET_STATE_PEEK)) {
+            mLastOffsetRatioSent = 0;
+        } else {
+            mLastOffsetRatioSent = MathUtils.areFloatsEqual(peekFullRatio, 0) ? 0 : peekFullRatio;
         }
 
+        for (BottomSheetObserver o : mObservers) o.onSheetOffsetChanged(mLastOffsetRatioSent);
+
         // This ratio is relative to the peek and half positions of the sheet.
         float peekHalfRatio = MathUtils.clamp(
                 (screenRatio - getPeekRatio()) / (getHalfRatio() - getPeekRatio()), 0, 1);
@@ -1355,11 +1409,13 @@
             if (getFocusedChild() == null) requestFocus();
         }
 
+        setVisibility(mCurrentState == SHEET_STATE_HIDDEN ? GONE : VISIBLE);
+
         for (BottomSheetObserver o : mObservers) {
             o.onSheetStateChanged(mCurrentState);
         }
 
-        if (state == SHEET_STATE_PEEK) {
+        if (state <= SHEET_STATE_PEEK) {
             onSheetClosed(reason);
         } else {
             onSheetOpened(reason);
@@ -1431,7 +1487,7 @@
      */
     @SheetState
     private int getTargetSheetState(float sheetHeight, float yVelocity) {
-        if (sheetHeight <= getMinOffsetPx()) return SHEET_STATE_PEEK;
+        if (sheetHeight <= getMinOffsetPx()) return sStates[getMinSwipableSheetState()];
         if (sheetHeight >= getMaxOffsetPx()) return SHEET_STATE_FULL;
 
         boolean isMovingDownward = yVelocity < 0;
@@ -1439,11 +1495,11 @@
 
         // First, find the two states that the sheet height is between.
         @SheetState
-        int nextState = sStates[0];
+        int nextState = sStates[getMinSwipableSheetState()];
 
         @SheetState
         int prevState = nextState;
-        for (int i = 0; i < sStates.length; i++) {
+        for (int i = getMinSwipableSheetState(); i < sStates.length; i++) {
             if (sStates[i] == SHEET_STATE_HALF && shouldSkipHalfState) continue;
             prevState = nextState;
             nextState = sStates[i];
@@ -1478,6 +1534,7 @@
 
     @Override
     public void onFadingViewClick() {
+        if (!mIsSheetOpen) return;
         setSheetState(SHEET_STATE_PEEK, true, StateChangeReason.TAP_SCRIM);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/test/ScreenShooter.java b/chrome/android/javatests/src/org/chromium/chrome/browser/test/ScreenShooter.java
index 878de8b..4382b7c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/test/ScreenShooter.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/test/ScreenShooter.java
@@ -10,7 +10,6 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.annotation.SuppressLint;
 import android.app.Instrumentation;
 import android.content.res.Configuration;
 import android.graphics.Point;
@@ -94,7 +93,6 @@
  * }
  * </pre>
  */
-@SuppressLint("SetWorldReadable")
 public class ScreenShooter extends TestWatcher {
     private static final String SCREENSHOT_DIR =
             "org.chromium.base.test.util.Screenshooter.ScreenshotDir";
@@ -206,9 +204,6 @@
             File shotFile = File.createTempFile(shotName, IMAGE_SUFFIX, new File(mBaseDir));
             assertTrue("Screenshot " + shotName, mDevice.takeScreenshot(shotFile));
             writeImageDescription(shotFile, filters, tags, metadata);
-            // Set as world readable so that the test runner can read it from /data/local/tmp
-            // without having to run as root
-            shotFile.setReadable(true, false);
         } catch (IOException e) {
             fail("Cannot create shot files " + e.toString());
         }
@@ -236,12 +231,8 @@
         String jsonFileName =
                 shotFileName.substring(0, shotFileName.length() - IMAGE_SUFFIX.length())
                 + JSON_SUFFIX;
-        File descriptionFile = new File(mBaseDir, jsonFileName);
-        try (FileWriter fileWriter = new FileWriter(descriptionFile)) {
+        try (FileWriter fileWriter = new FileWriter(new File(mBaseDir, jsonFileName));) {
             fileWriter.write(imageDescription.toString());
         }
-        // Set as world readable so that the test runner can read it from /data/local/tmp without
-        // having to run as root
-        descriptionFile.setReadable(true, false);
     }
 }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 56f139a8..0682848 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -1908,11 +1908,11 @@
 
       <!-- Ambient badge -->
       <if expr="is_android">
-        <message name="IDS_AMBIENT_BADGE_INSTALL" desc="String for the ambient badge promoting an app installation" formatter_data="android_java">
-          Add to Home screen
+        <message name="IDS_AMBIENT_BADGE_INSTALL" desc="String for the ambient badge promoting an app installation">
+          Add <ph name="APP_NAME">$1<ex>Google Maps</ex></ph> to Home screen
         </message>
-        <message name="IDS_AMBIENT_BADGE_OPEN" desc="String for the ambient badge promoting opening an installed app" formatter_data="android_java">
-          Open in app
+        <message name="IDS_AMBIENT_BADGE_OPEN" desc="String for the ambient badge promoting opening an installed app">
+          Open <ph name="APP_NAME">$1<ex>Google Maps</ex></ph>
         </message>
       </if>
       <!-- Bookmark app bubble -->
diff --git a/chrome/app_shim/BUILD.gn b/chrome/app_shim/BUILD.gn
index 40b3086..9981be0 100644
--- a/chrome/app_shim/BUILD.gn
+++ b/chrome/app_shim/BUILD.gn
@@ -18,7 +18,7 @@
     "//chrome:strings",
     "//chrome/common",
     "//ipc",
-    "//mojo/edk/embedder:headers",
+    "//mojo/edk",
     "//ui/base",
   ]
 }
@@ -36,7 +36,9 @@
   extra_configs = [ "//build/config/compiler:wexit_time_destructors" ]
 
   info_plist_target = ":app_mode_loader_plist"
-  extra_substitutions = [ "APP_MODE_APP_BUNDLE_ID=$chrome_mac_bundle_id.app.@APP_MODE_SHORTCUT_ID@" ]
+  extra_substitutions = [
+    "APP_MODE_APP_BUNDLE_ID=$chrome_mac_bundle_id.app.@APP_MODE_SHORTCUT_ID@",
+  ]
 
   sources = [
     "app_mode_loader_mac.mm",
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 36b91761..cf12590b 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1763,7 +1763,7 @@
     "//media/mojo/interfaces:remoting",
     "//media/mojo/services",
     "//mojo/common",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/bindings",
     "//net:extras",
     "//net:net_browser_services",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 84750b5..a2e57d4 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1491,12 +1491,6 @@
      flag_descriptions::kAshEnableUnifiedDesktopName,
      flag_descriptions::kAshEnableUnifiedDesktopDescription, kOsCrOS,
      SINGLE_VALUE_TYPE(switches::kEnableUnifiedDesktop)},
-    {"disable-easy-unlock-bluetooth-low-energy-detection",
-     flag_descriptions::kEasyUnlockBluetoothLowEnergyDiscoveryName,
-     flag_descriptions::kEasyUnlockBluetoothLowEnergyDiscoveryDescription,
-     kOsCrOS,
-     SINGLE_DISABLE_VALUE_TYPE(
-         proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery)},
     {
         "disable-office-editing-component-app",
         flag_descriptions::kOfficeEditingComponentAppName,
diff --git a/chrome/browser/banners/app_banner_manager_android.cc b/chrome/browser/banners/app_banner_manager_android.cc
index b813463..ccb3690 100644
--- a/chrome/browser/banners/app_banner_manager_android.cc
+++ b/chrome/browser/banners/app_banner_manager_android.cc
@@ -360,13 +360,26 @@
   return NO_ERROR_DETECTED;
 }
 
+const base::string16 AppBannerManagerAndroid::GetAppNameForAmbientBadge()
+    const {
+  if (native_app_data_.is_null()) {
+    // Prefer the short name if it's available. It's guaranteed that at least
+    // one of these is non-empty.
+    return manifest_.short_name.string().empty()
+               ? manifest_.name.string()
+               : manifest_.short_name.string();
+  }
+
+  return native_app_title_;
+}
+
 void AppBannerManagerAndroid::ShowAmbientBadge(bool is_installed) {
   InfoBarService* infobar_service =
       InfoBarService::FromWebContents(web_contents());
   if (GetVisibleAmbientBadgeInfoBar(infobar_service) == nullptr) {
     InstallableAmbientBadgeInfoBarDelegate::Create(
-        web_contents(), GetWeakPtr(), primary_icon_, manifest_.start_url,
-        is_installed);
+        web_contents(), GetWeakPtr(), GetAppNameForAmbientBadge(),
+        primary_icon_, manifest_.start_url, is_installed);
   }
 }
 
diff --git a/chrome/browser/banners/app_banner_manager_android.h b/chrome/browser/banners/app_banner_manager_android.h
index 718cb41..58a281e 100644
--- a/chrome/browser/banners/app_banner_manager_android.h
+++ b/chrome/browser/banners/app_banner_manager_android.h
@@ -123,6 +123,9 @@
                                        const GURL& url,
                                        const std::string& id);
 
+  // Returns the appropriate app name based on whether we have a native/web app.
+  const base::string16 GetAppNameForAmbientBadge() const;
+
   // Shows the ambient badge if the current page advertises a native app or is
   // a PWA.
   void ShowAmbientBadge(bool is_installed);
diff --git a/chrome/browser/chrome_notification_types.h b/chrome/browser/chrome_notification_types.h
index b47d21cb..3c553a6 100644
--- a/chrome/browser/chrome_notification_types.h
+++ b/chrome/browser/chrome_notification_types.h
@@ -20,11 +20,19 @@
 #define PREVIOUS_END content::NOTIFICATION_CONTENT_END
 #endif
 
+// **
+// ** NOTICE
+// **
+// ** The notification system is deprecated, obsolete, and is slowly being
+// ** removed. See https://crbug.com/268984.
+// **
+// ** Please don't add any new notification types, and please help migrate
+// ** existing uses of the notification types below to use the Observer and
+// ** Callback patterns.
+// **
+
 namespace chrome {
 
-// NotificationService &c. are deprecated (https://crbug.com/268984).
-// Don't add any new notification types, and migrate existing uses of the
-// notification types below to observers.
 enum NotificationType {
   NOTIFICATION_CHROME_START = PREVIOUS_END,
 
@@ -418,4 +426,15 @@
 
 }  // namespace chrome
 
+// **
+// ** NOTICE
+// **
+// ** The notification system is deprecated, obsolete, and is slowly being
+// ** removed. See https://crbug.com/268984.
+// **
+// ** Please don't add any new notification types, and please help migrate
+// ** existing uses of the notification types below to use the Observer and
+// ** Callback patterns.
+// **
+
 #endif  // CHROME_BROWSER_CHROME_NOTIFICATION_TYPES_H_
diff --git a/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc b/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc
index bd91aa38..4f22599b 100644
--- a/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc
@@ -196,7 +196,7 @@
   chromeos::AccessibilityManager::Get()->SetFocusRingObserverForTest(callback);
 
   ash::AccessibilityFocusRingController* controller =
-      ash::AccessibilityFocusRingController::GetInstance();
+      ash::Shell::Get()->accessibility_focus_ring_controller();
   std::vector<std::unique_ptr<ash::AccessibilityFocusRingLayer>> const&
       focus_rings = controller->focus_ring_layers_for_testing();
 
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_auth_attempt.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_auth_attempt.cc
index b7424aea..4b6c43c3 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_auth_attempt.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_auth_attempt.cc
@@ -125,12 +125,9 @@
   // result, the auth attempt will always fail.
   // TODO(sacomoto): Clean this up when the background app is not needed
   // anymore.
-  if (!app_manager_->SendAuthAttemptEvent() &&
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery)) {
-    Cancel(account_id_);
-    return false;
-  }
+  // TODO(jhawkins): Verify whether this method has important side effects or
+  // if it can be removed.
+  app_manager_->SendAuthAttemptEvent();
 
   return true;
 }
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_auth_attempt_unittest.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_auth_attempt_unittest.cc
index 9d77e3e7..b1fa37d 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_auth_attempt_unittest.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_auth_attempt_unittest.cc
@@ -257,22 +257,6 @@
   EXPECT_EQ(TestLockHandler::STATE_UNLOCK_CANCELED, lock_handler_->state());
 }
 
-TEST_F(EasyUnlockAuthAttemptUnlockTest,
-       StartWhenDispatchingAuthAttemptEventFails) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery);
-  InitScreenLock();
-  ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
-  ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
-
-  app_manager_->set_auth_attempt_should_fail(true);
-
-  EXPECT_FALSE(auth_attempt_->Start());
-
-  EXPECT_EQ(1u, app_manager_->auth_attempt_count());
-  EXPECT_EQ(TestLockHandler::STATE_UNLOCK_CANCELED, lock_handler_->state());
-}
-
 TEST_F(EasyUnlockAuthAttemptUnlockTest, ResetBeforeFinalizeUnlock) {
   InitScreenLock();
   ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
@@ -416,22 +400,6 @@
   EXPECT_EQ(TestLockHandler::STATE_SIGNIN_CANCELED, lock_handler_->state());
 }
 
-TEST_F(EasyUnlockAuthAttemptSigninTest,
-       StartWhenDispatchingAuthAttemptEventFails) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery);
-  InitScreenLock();
-  ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
-  ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
-
-  app_manager_->set_auth_attempt_should_fail(true);
-
-  EXPECT_FALSE(auth_attempt_->Start());
-
-  EXPECT_EQ(1u, app_manager_->auth_attempt_count());
-  EXPECT_EQ(TestLockHandler::STATE_SIGNIN_CANCELED, lock_handler_->state());
-}
-
 TEST_F(EasyUnlockAuthAttemptSigninTest, ResetBeforeFinalizeSignin) {
   InitScreenLock();
   ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc
index 811f44d..0f19890 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc
@@ -438,11 +438,8 @@
   // TODO(tengs): We notify ProximityAuthSystem whenever unlock attempts are
   // attempted. However, we ideally should refactor the auth attempt logic to
   // the proximity_auth component.
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery) &&
-      proximity_auth_system_) {
+  if (proximity_auth_system_)
     proximity_auth_system_->OnAuthAttempted(account_id);
-  }
 }
 
 void EasyUnlockService::FinalizeUnlock(bool success) {
@@ -730,10 +727,6 @@
 void EasyUnlockService::SetProximityAuthDevices(
     const AccountId& account_id,
     const cryptauth::RemoteDeviceList& remote_devices) {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery))
-    return;
-
   if (remote_devices.size() == 0) {
     proximity_auth_system_.reset();
     return;
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.cc
index 38d8d10..759ddb8 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.cc
@@ -183,9 +183,7 @@
 }
 
 bool EasyUnlockServiceRegular::ShouldPromote() {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery) ||
-      !base::FeatureList::IsEnabled(features::kEasyUnlockPromotions)) {
+  if (!base::FeatureList::IsEnabled(features::kEasyUnlockPromotions)) {
     return false;
   }
 
@@ -482,9 +480,7 @@
 
   // TODO(tengs): Due to badly configured browser_tests, Chrome crashes during
   // shutdown. Revisit this condition after migration is fully completed.
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery) &&
-      !base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)) {
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)) {
     // Note: There is no local state in tests.
     if (g_browser_process->local_state()) {
       pref_manager_->StartSyncingToLocalState(g_browser_process->local_state(),
@@ -532,14 +528,6 @@
 }
 
 bool EasyUnlockServiceRegular::IsEnabled() const {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery)) {
-    // The feature is enabled iff there are any paired devices set by the
-    // component app.
-    const base::ListValue* devices = GetRemoteDevices();
-    return devices && !devices->empty();
-  }
-
   return pref_manager_ && pref_manager_->IsEasyUnlockEnabled();
 }
 
@@ -695,11 +683,6 @@
   pref_manager_->SetIsEasyUnlockEnabled(false);
   ResetScreenlockState();
   registrar_.RemoveAll();
-
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery)) {
-    ReloadAppAndLockScreen();
-  }
 }
 
 void EasyUnlockServiceRegular::OnToggleEasyUnlockApiFailed(
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_signin_chromeos.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_signin_chromeos.cc
index 61aac9a..2f976af5 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_signin_chromeos.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_signin_chromeos.cc
@@ -360,14 +360,6 @@
 }
 
 bool EasyUnlockServiceSignin::IsEnabled() const {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery)) {
-    // In EasyUnlock v1, we used the presence of the hardlock state as an
-    // indicator of whether EasyUnlock is enabled.
-    EasyUnlockScreenlockStateHandler::HardlockState hardlock_state;
-    return GetPersistedHardlockState(&hardlock_state);
-  }
-
   return pref_manager_->IsEasyUnlockEnabled();
 }
 
@@ -526,12 +518,6 @@
   if (account_id == account_id_)
     NotifyUserUpdated();
 
-  // The code below delegates EasyUnlock processing to the native
-  // implementation. Skip if the app is used instead.
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery))
-    return;
-
   if (devices.empty())
     return;
 
@@ -596,9 +582,7 @@
   if (!IsAllowed() || !IsEnabled())
     return;
 
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery) &&
-      !pref_manager_->IsChromeOSLoginEnabled()) {
+  if (!pref_manager_->IsChromeOSLoginEnabled()) {
     // Show a hardlock state if the user has not enabled the login flow.
     SetHardlockStateForUser(
         account_id_,
diff --git a/chrome/browser/chromeos/policy/login_policy_test_base.cc b/chrome/browser/chromeos/policy/login_policy_test_base.cc
index 3336142..54087881 100644
--- a/chrome/browser/chromeos/policy/login_policy_test_base.cc
+++ b/chrome/browser/chromeos/policy/login_policy_test_base.cc
@@ -45,7 +45,7 @@
   GetMandatoryPoliciesValue(&mandatory);
   base::DictionaryValue recommended;
   GetRecommendedPoliciesValue(&recommended);
-  user_policy_helper_.reset(new UserPolicyTestHelper(kAccountId));
+  user_policy_helper_.reset(new UserPolicyTestHelper(GetAccount()));
   user_policy_helper_->Init(mandatory, recommended);
   OobeBaseTest::SetUp();
 }
@@ -57,8 +57,20 @@
 
 void LoginPolicyTestBase::SetUpOnMainThread() {
   SetMergeSessionParams();
-  SetupFakeGaiaForLogin(kAccountId, "", kTestRefreshToken);
+  SetupFakeGaiaForLogin(GetAccount(), "", kTestRefreshToken);
   OobeBaseTest::SetUpOnMainThread();
+
+  FakeGaia::MergeSessionParams params;
+  params.id_token = GetIdToken();
+  fake_gaia_->UpdateMergeSessionParams(params);
+}
+
+std::string LoginPolicyTestBase::GetAccount() const {
+  return kAccountId;
+}
+
+std::string LoginPolicyTestBase::GetIdToken() const {
+  return std::string();
 }
 
 void LoginPolicyTestBase::GetMandatoryPoliciesValue(
@@ -76,10 +88,11 @@
   params.auth_code = kTestAuthCode;
   params.refresh_token = kTestRefreshToken;
   params.access_token = kTestAuthLoginAccessToken;
+  params.id_token = GetIdToken();
   params.gaia_uber_token = kTestGaiaUberToken;
   params.session_sid_cookie = kTestSessionSIDCookie;
   params.session_lsid_cookie = kTestSessionLSIDCookie;
-  params.email = kAccountId;
+  params.email = GetAccount();
   fake_gaia_->SetMergeSessionParams(params);
 }
 
diff --git a/chrome/browser/chromeos/policy/login_policy_test_base.h b/chrome/browser/chromeos/policy/login_policy_test_base.h
index a70b6f2..6d17780 100644
--- a/chrome/browser/chromeos/policy/login_policy_test_base.h
+++ b/chrome/browser/chromeos/policy/login_policy_test_base.h
@@ -33,6 +33,8 @@
 
   virtual void GetMandatoryPoliciesValue(base::DictionaryValue* policy) const;
   virtual void GetRecommendedPoliciesValue(base::DictionaryValue* policy) const;
+  virtual std::string GetAccount() const;
+  virtual std::string GetIdToken() const;
 
   UserPolicyTestHelper* user_policy_helper() {
     return user_policy_helper_.get();
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_browsertest.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_browsertest.cc
index 6f1b9eb..c1fa2bd 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_browsertest.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_browsertest.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "components/policy/core/browser/browser_policy_connector.h"
 #include "components/policy/policy_constants.h"
 #include "components/user_manager/known_user.h"
 #include "components/user_manager/user.h"
@@ -30,7 +31,12 @@
 namespace {
 // The Gaia ID supplied by FakeGaia for our mocked-out signin.
 const char kTestGaiaId[] = "12345";
-const char kConsumerAccount[] = "test_user@gmail.com";
+
+const char kIdTokenChildAccount[] =
+    "dummy-header."
+    // base64 encoded: { "services": ["uca"] }
+    "eyAic2VydmljZXMiOiBbInVjYSJdIH0="
+    ".dummy-signature";
 
 // Helper class that counts the number of notifications of the specified
 // type that have been received.
@@ -209,16 +215,44 @@
             user_manager::known_user::GetProfileRequiresPolicy(account_id));
 }
 
-IN_PROC_BROWSER_TEST_F(UserCloudPolicyManagerTest, NoPolicyForConsumer) {
+class UserCloudPolicyManagerNonEnterpriseTest
+    : public UserCloudPolicyManagerTest {
+ protected:
+  UserCloudPolicyManagerNonEnterpriseTest() = default;
+  ~UserCloudPolicyManagerNonEnterpriseTest() override = default;
+
+  // UserCloudPolicyManagerTest:
+  void SetUp() override {
+    // Recognize example.com as non-enterprise account. We don't use any
+    // available public domain such as gmail.com in order to prevent possible
+    // leak of verification keys/signatures.
+    policy::BrowserPolicyConnector::SetNonEnterpriseDomainForTesting(
+        "example.com");
+    UserCloudPolicyManagerTest::SetUp();
+  }
+
+  void TearDown() override {
+    UserCloudPolicyManagerTest::TearDown();
+    policy::BrowserPolicyConnector::SetNonEnterpriseDomainForTesting(nullptr);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(UserCloudPolicyManagerNonEnterpriseTest);
+};
+
+IN_PROC_BROWSER_TEST_F(UserCloudPolicyManagerNonEnterpriseTest,
+                       NoPolicyForConsumer) {
+  EXPECT_TRUE(
+      policy::BrowserPolicyConnector::IsNonEnterpriseUser(GetAccount()));
   // If a user signs in with a known non-enterprise account there should be no
   // policy.
   AccountId account_id =
-      AccountId::FromUserEmailGaiaId(kConsumerAccount, kTestGaiaId);
+      AccountId::FromUserEmailGaiaId(GetAccount(), kTestGaiaId);
   EXPECT_EQ(user_manager::known_user::ProfileRequiresPolicy::kUnknown,
             user_manager::known_user::GetProfileRequiresPolicy(account_id));
 
   SkipToLoginScreen();
-  LogIn(kConsumerAccount, kAccountPassword);
+  LogIn(GetAccount(), kAccountPassword);
 
   // User should be marked as having a valid OAuth token.
   const user_manager::UserManager* const user_manager =
@@ -233,4 +267,43 @@
             user_manager::known_user::GetProfileRequiresPolicy(account_id));
 }
 
+class UserCloudPolicyManagerChildTest
+    : public UserCloudPolicyManagerNonEnterpriseTest {
+ protected:
+  UserCloudPolicyManagerChildTest() = default;
+  ~UserCloudPolicyManagerChildTest() override = default;
+
+  // LoginPolicyTestBase:
+  std::string GetIdToken() const override { return kIdTokenChildAccount; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(UserCloudPolicyManagerChildTest);
+};
+
+IN_PROC_BROWSER_TEST_F(UserCloudPolicyManagerChildTest, PolicyForChildUser) {
+  EXPECT_TRUE(
+      policy::BrowserPolicyConnector::IsNonEnterpriseUser(GetAccount()));
+  // If a user signs in with a known non-enterprise account there should be no
+  // policy in case user type is child.
+  AccountId account_id =
+      AccountId::FromUserEmailGaiaId(GetAccount(), kTestGaiaId);
+  EXPECT_EQ(user_manager::known_user::ProfileRequiresPolicy::kUnknown,
+            user_manager::known_user::GetProfileRequiresPolicy(account_id));
+
+  SkipToLoginScreen();
+  LogIn(GetAccount(), kAccountPassword);
+
+  // User should be marked as having a valid OAuth token.
+  const user_manager::UserManager* const user_manager =
+      user_manager::UserManager::Get();
+  EXPECT_EQ(user_manager::User::OAUTH2_TOKEN_STATUS_VALID,
+            user_manager->GetActiveUser()->oauth_token_status());
+
+  EXPECT_TRUE(user_manager->GetActiveUser()->profile_ever_initialized());
+
+  // User of CHILD type should be marked as requiring policy.
+  EXPECT_EQ(user_manager::known_user::ProfileRequiresPolicy::kPolicyRequired,
+            user_manager::known_user::GetProfileRequiresPolicy(account_id));
+}
+
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/user_policy_manager_factory_chromeos.cc b/chrome/browser/chromeos/policy/user_policy_manager_factory_chromeos.cc
index 0dfd1a4..4165c74 100644
--- a/chrome/browser/chromeos/policy/user_policy_manager_factory_chromeos.cc
+++ b/chrome/browser/chromeos/policy/user_policy_manager_factory_chromeos.cc
@@ -168,19 +168,23 @@
       chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
   CHECK(user);
 
-  // User policy exists for enterprise accounts only:
+  // User policy exists for enterprise accounts:
   // - For regular cloud-managed users (those who have a GAIA account), a
   //   |UserCloudPolicyManagerChromeOS| is created here.
   // - For Active Directory managed users, an |ActiveDirectoryPolicyManager|
   //   is created.
   // - For device-local accounts, policy is provided by
   //   |DeviceLocalAccountPolicyService|.
+  // For non-enterprise accounts only for users with type USER_TYPE_CHILD
+  //   |UserCloudPolicyManagerChromeOS| is created here.
   // All other user types do not have user policy.
   const AccountId& account_id = user->GetAccountId();
   const bool is_stub_user =
       user_manager::UserManager::Get()->IsStubAccountId(account_id);
-  if (user->IsSupervised() ||
-      BrowserPolicyConnector::IsNonEnterpriseUser(account_id.GetUserEmail())) {
+  if (user->GetType() != user_manager::USER_TYPE_CHILD &&
+      (user->GetType() == user_manager::USER_TYPE_SUPERVISED ||
+       BrowserPolicyConnector::IsNonEnterpriseUser(
+           account_id.GetUserEmail()))) {
     DLOG(WARNING) << "No policy loaded for known non-enterprise user";
     // Mark this profile as not requiring policy.
     user_manager::known_user::SetProfileRequiresPolicy(
diff --git a/chrome/browser/download/notification/download_notification_interactive_uitest.cc b/chrome/browser/download/notification/download_notification_interactive_uitest.cc
index e571f38..16fcfaa 100644
--- a/chrome/browser/download/notification/download_notification_interactive_uitest.cc
+++ b/chrome/browser/download/notification/download_notification_interactive_uitest.cc
@@ -357,7 +357,9 @@
   EXPECT_FALSE(GetNotification(notification_id()));
 }
 
-IN_PROC_BROWSER_TEST_F(DownloadNotificationTest, DownloadDangerousFile) {
+// Flaky test: crbug/822470.
+IN_PROC_BROWSER_TEST_F(DownloadNotificationTest,
+                       DISABLED_DownloadDangerousFile) {
   GURL download_url(
       embedded_test_server()->GetURL("/downloads/dangerous/dangerous.swf"));
 
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
index b0199498..1b4f42a 100644
--- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
+++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
@@ -556,43 +556,6 @@
 
 ExtensionFunction::ResponseAction
 EasyUnlockPrivateGetPermitAccessFunction::Run() {
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery)) {
-    return GetPermitAccessForExperiment();
-  }
-
-  Profile* profile = Profile::FromBrowserContext(browser_context());
-  const base::DictionaryValue* permit_value =
-      chromeos::EasyUnlockService::Get(profile)->GetPermitAccess();
-
-  if (permit_value) {
-    std::unique_ptr<easy_unlock_private::PermitRecord> permit =
-        easy_unlock_private::PermitRecord::FromValue(*permit_value);
-    return RespondNow(ArgumentList(
-        easy_unlock_private::GetPermitAccess::Results::Create(*permit)));
-  }
-
-  return RespondNow(NoArguments());
-}
-
-void EasyUnlockPrivateGetPermitAccessFunction::GetKeyPairForExperiment(
-    std::string* user_public_key,
-    std::string* user_private_key) {
-  Profile* profile = Profile::FromBrowserContext(browser_context());
-  cryptauth::CryptAuthEnrollmentManager* enrollment_manager =
-      chromeos::EasyUnlockService::Get(profile)
-          ->proximity_auth_client()
-          ->GetCryptAuthEnrollmentManager();
-  base::Base64UrlEncode(enrollment_manager->GetUserPublicKey(),
-                        base::Base64UrlEncodePolicy::INCLUDE_PADDING,
-                        user_public_key);
-  base::Base64UrlEncode(enrollment_manager->GetUserPrivateKey(),
-                        base::Base64UrlEncodePolicy::INCLUDE_PADDING,
-                        user_private_key);
-}
-
-ExtensionFunction::ResponseAction
-EasyUnlockPrivateGetPermitAccessFunction::GetPermitAccessForExperiment() {
   // Check that we are inside a user session.
   Profile* profile = Profile::FromBrowserContext(browser_context());
   chromeos::EasyUnlockService* easy_unlock_service =
@@ -624,6 +587,22 @@
   return RespondNow(OneArgument(std::move(permit_access)));
 }
 
+void EasyUnlockPrivateGetPermitAccessFunction::GetKeyPairForExperiment(
+    std::string* user_public_key,
+    std::string* user_private_key) {
+  Profile* profile = Profile::FromBrowserContext(browser_context());
+  cryptauth::CryptAuthEnrollmentManager* enrollment_manager =
+      chromeos::EasyUnlockService::Get(profile)
+          ->proximity_auth_client()
+          ->GetCryptAuthEnrollmentManager();
+  base::Base64UrlEncode(enrollment_manager->GetUserPublicKey(),
+                        base::Base64UrlEncodePolicy::INCLUDE_PADDING,
+                        user_public_key);
+  base::Base64UrlEncode(enrollment_manager->GetUserPrivateKey(),
+                        base::Base64UrlEncodePolicy::INCLUDE_PADDING,
+                        user_private_key);
+}
+
 EasyUnlockPrivateClearPermitAccessFunction::
     EasyUnlockPrivateClearPermitAccessFunction() {
 }
@@ -658,13 +637,7 @@
   for (const easy_unlock_private::Device& device : params->devices)
     devices.Append(device.ToValue());
 
-  // Store the BLE device if we are trying out the BLE experiment.
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery)) {
-    chromeos::EasyUnlockService::Get(profile)->SetRemoteBleDevices(devices);
-  } else {
-    chromeos::EasyUnlockService::Get(profile)->SetRemoteDevices(devices);
-  }
+  chromeos::EasyUnlockService::Get(profile)->SetRemoteBleDevices(devices);
 
   return RespondNow(NoArguments());
 }
@@ -678,18 +651,53 @@
 }
 
 bool EasyUnlockPrivateGetRemoteDevicesFunction::RunAsync() {
-  // Return the remote devices stored with the native CryptAuthDeviceManager if
-  // we are trying out the BLE experiment.
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery)) {
-    ReturnDevicesForExperiment();
-  } else {
-    Profile* profile = Profile::FromBrowserContext(browser_context());
-    const base::ListValue* devices =
-        chromeos::EasyUnlockService::Get(profile)->GetRemoteDevices();
-    SetResult(devices ? devices->CreateDeepCopy()
-                      : std::make_unique<base::ListValue>());
+  // Check that we are inside a user profile.
+  Profile* profile = Profile::FromBrowserContext(browser_context());
+  chromeos::EasyUnlockService* easy_unlock_service =
+      chromeos::EasyUnlockService::Get(profile);
+  if (easy_unlock_service->GetType() !=
+      chromeos::EasyUnlockService::TYPE_REGULAR) {
+    SetError("This function must be called inside a user session.");
     SendResponse(true);
+    return true;
+  }
+
+  // Get the synced unlock key data.
+  proximity_auth::ProximityAuthClient* client =
+      easy_unlock_service->proximity_auth_client();
+
+  permit_id_ = "permit://google.com/easyunlock/v1/" + client->GetAccountId();
+  secure_message_delegate_ = client->CreateSecureMessageDelegate();
+  std::vector<cryptauth::ExternalDeviceInfo> unlock_keys = GetUnlockKeys();
+  expected_devices_count_ = unlock_keys.size();
+
+  remote_devices_.reset(new base::ListValue());
+  if (expected_devices_count_ == 0) {
+    SetResult(std::move(remote_devices_));
+    SendResponse(true);
+    return true;
+  }
+
+  // If there is a BLE unlock key, then don't return anything, so the app does
+  // not try the classic Bluetooth protocol.
+  for (const auto& unlock_key : unlock_keys) {
+    if (unlock_key.bluetooth_address().empty()) {
+      SetResult(std::move(remote_devices_));
+      SendResponse(true);
+      return true;
+    }
+  }
+
+  // Derive the PSKs for the user's unlock keys.
+  PA_LOG(INFO) << "Deriving PSKs for "
+               << "chrome.easyUnlockPrivate.getRemoteDevices.\n"
+               << "Expecting " << expected_devices_count_ << " devices.";
+  for (const auto& unlock_key : unlock_keys) {
+    secure_message_delegate_->DeriveKey(
+        GetUserPrivateKey(), unlock_key.public_key(),
+        base::Bind(
+            &EasyUnlockPrivateGetRemoteDevicesFunction::OnPSKDerivedForDevice,
+            this, unlock_key));
   }
 
   return true;
@@ -714,57 +722,6 @@
   return device_manager->GetUnlockKeys();
 }
 
-void EasyUnlockPrivateGetRemoteDevicesFunction::ReturnDevicesForExperiment() {
-  // Check that we are inside a user profile.
-  Profile* profile = Profile::FromBrowserContext(browser_context());
-  chromeos::EasyUnlockService* easy_unlock_service =
-      chromeos::EasyUnlockService::Get(profile);
-  if (easy_unlock_service->GetType() !=
-      chromeos::EasyUnlockService::TYPE_REGULAR) {
-    SetError("This function must be called inside a user session.");
-    SendResponse(true);
-    return;
-  }
-
-  // Get the synced unlock key data.
-  proximity_auth::ProximityAuthClient* client =
-      easy_unlock_service->proximity_auth_client();
-
-  permit_id_ = "permit://google.com/easyunlock/v1/" + client->GetAccountId();
-  secure_message_delegate_ = client->CreateSecureMessageDelegate();
-  std::vector<cryptauth::ExternalDeviceInfo> unlock_keys = GetUnlockKeys();
-  expected_devices_count_ = unlock_keys.size();
-
-  remote_devices_.reset(new base::ListValue());
-  if (expected_devices_count_ == 0) {
-    SetResult(std::move(remote_devices_));
-    SendResponse(true);
-    return;
-  }
-
-  // If there is a BLE unlock key, then don't return anything, so the app does
-  // not try the classic Bluetooth protocol.
-  for (const auto& unlock_key : unlock_keys) {
-    if (unlock_key.bluetooth_address().empty()) {
-      SetResult(std::move(remote_devices_));
-      SendResponse(true);
-      return;
-    }
-  }
-
-  // Derive the PSKs for the user's unlock keys.
-  PA_LOG(INFO) << "Deriving PSKs for "
-               << "chrome.easyUnlockPrivate.getRemoteDevices.\n"
-               << "Expecting " << expected_devices_count_ << " devices.";
-  for (const auto& unlock_key : unlock_keys) {
-    secure_message_delegate_->DeriveKey(
-        GetUserPrivateKey(), unlock_key.public_key(),
-        base::Bind(
-            &EasyUnlockPrivateGetRemoteDevicesFunction::OnPSKDerivedForDevice,
-            this, unlock_key));
-  }
-}
-
 void EasyUnlockPrivateGetRemoteDevicesFunction::OnPSKDerivedForDevice(
     const cryptauth::ExternalDeviceInfo& device,
     const std::string& persistent_symmetric_key) {
@@ -887,9 +844,7 @@
     user.device_user_id = cryptauth::CalculateDeviceUserId(
         chromeos::EasyUnlockService::GetDeviceId(), account_id.GetUserEmail());
 
-    user.ble_discovery_enabled =
-        !base::CommandLine::ForCurrentProcess()->HasSwitch(
-            proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery);
+    user.ble_discovery_enabled = true;
     users.push_back(std::move(user));
   }
   return RespondNow(
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.h b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.h
index c81dd4b..93e6f04 100644
--- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.h
+++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.h
@@ -259,10 +259,6 @@
   // ExtensionFunction:
   ResponseAction Run() override;
 
-  // Instead of returning the value set by easyUnlockPrivate.setPermitAccess,
-  // return the permit access used by the native CryptAuthEnrollmentManager.
-  ResponseAction GetPermitAccessForExperiment();
-
   DISALLOW_COPY_AND_ASSIGN(EasyUnlockPrivateGetPermitAccessFunction);
 };
 
@@ -320,10 +316,6 @@
   // AsyncExtensionFunction:
   bool RunAsync() override;
 
-  // Returns devices managed by the native Chrome component if the
-  // kEnableBluetoothLowEnergyDiscovery flag is set.
-  void ReturnDevicesForExperiment();
-
   // Callback when the PSK of a device is derived.
   void OnPSKDerivedForDevice(const cryptauth::ExternalDeviceInfo& device,
                              const std::string& persistent_symmetric_key);
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api_chromeos_unittest.cc b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api_chromeos_unittest.cc
index d4f3cbb..bd53d6f 100644
--- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api_chromeos_unittest.cc
+++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api_chromeos_unittest.cc
@@ -126,9 +126,6 @@
 
  protected:
   void SetUp() override {
-    base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery);
-
     chromeos::DBusThreadManager::Initialize();
     if (aura::Env::GetInstance()->mode() == aura::Env::Mode::LOCAL) {
       bluez::BluezDBusManager::Initialize(
@@ -515,36 +512,4 @@
   EXPECT_TRUE(result.error.empty());
 }
 
-// Checks that the chrome.easyUnlockPrivate.getRemoteDevices API returns the
-// stored value if the kEnableBluetoothLowEnergyDiscovery switch is not set.
-TEST_F(EasyUnlockPrivateApiTest, GetRemoteDevicesNonExperimental) {
-  chromeos::EasyUnlockServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-      profile(), &BuildTestEasyUnlockService);
-
-  scoped_refptr<TestableGetRemoteDevicesFunction> function(
-      new TestableGetRemoteDevicesFunction());
-  std::unique_ptr<base::Value> value(
-      extensions::api_test_utils::RunFunctionAndReturnSingleResult(
-          function.get(), "[]", profile()));
-  ASSERT_TRUE(value.get());
-  ASSERT_EQ(base::Value::Type::LIST, value->type());
-
-  base::ListValue* list_value = static_cast<base::ListValue*>(value.get());
-  EXPECT_EQ(0u, list_value->GetSize());
-}
-
-// Checks that the chrome.easyUnlockPrivate.getPermitAccess API returns the
-// stored value if the kEnableBluetoothLowEnergyDiscovery switch is not set.
-TEST_F(EasyUnlockPrivateApiTest, GetPermitAccessNonExperimental) {
-  chromeos::EasyUnlockServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-      profile(), &BuildTestEasyUnlockService);
-
-  scoped_refptr<TestableGetPermitAccessFunction> function(
-      new TestableGetPermitAccessFunction());
-  std::unique_ptr<base::Value> value(
-      extensions::api_test_utils::RunFunctionAndReturnSingleResult(
-          function.get(), "[]", profile()));
-  EXPECT_FALSE(value);
-}
-
 }  // namespace
diff --git a/chrome/browser/extensions/display_info_provider_chromeos.cc b/chrome/browser/extensions/display_info_provider_chromeos.cc
index 1e5d830..01d994b 100644
--- a/chrome/browser/extensions/display_info_provider_chromeos.cc
+++ b/chrome/browser/extensions/display_info_provider_chromeos.cc
@@ -782,6 +782,23 @@
     }
   }
 
+  const display::ManagedDisplayInfo& display_info =
+      display_manager->GetDisplayInfo(display.id());
+  if (!display_info.manufacturer_id().empty() ||
+      !display_info.product_id().empty() ||
+      (display_info.year_of_manufacture() !=
+       display::kInvalidYearOfManufacture)) {
+    unit->edid = std::make_unique<system_display::Edid>();
+    if (!display_info.manufacturer_id().empty())
+      unit->edid->manufacturer_id = display_info.manufacturer_id();
+    if (!display_info.product_id().empty())
+      unit->edid->product_id = display_info.product_id();
+    if (display_info.year_of_manufacture() !=
+        display::kInvalidYearOfManufacture) {
+      unit->edid->year_of_manufacture = display_info.year_of_manufacture();
+    }
+  }
+
   unit->display_zoom_factor =
       display_manager->GetZoomFactorForDisplay(display.id());
   display::ManagedDisplayMode active_mode;
@@ -793,8 +810,6 @@
         display_manager->GetZoomFactorForDisplay(display.id()));
   }
 
-  const display::ManagedDisplayInfo& display_info =
-      display_manager->GetDisplayInfo(display.id());
   const float device_dpi = display_info.device_dpi();
   unit->dpi_x = device_dpi * display.size().width() /
                 display_info.bounds_in_native().width();
diff --git a/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc b/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc
index 0bd9137..fcf662b 100644
--- a/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc
+++ b/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc
@@ -1948,5 +1948,28 @@
   }
 }
 
+TEST_F(DisplayInfoProviderChromeosTest, GetEdid) {
+  UpdateDisplay("500x600, 400x200");
+  const char* kManufacturerId = "GOO";
+  const char* kProductId = "GL";
+  constexpr int32_t kYearOfManufacture = 2018;
+
+  display::ManagedDisplayInfo info(
+      GetDisplayManager()->active_display_list()[0].id(), "",
+      false /* has_overscan */);
+  info.SetBounds(gfx::Rect(0, 0, 500, 600));
+  info.set_manufacturer_id(kManufacturerId);
+  info.set_product_id(kProductId);
+  info.set_year_of_manufacture(kYearOfManufacture);
+  GetDisplayManager()->OnNativeDisplaysChanged({info});
+
+  DisplayUnitInfoList result = GetAllDisplaysInfo();
+  ASSERT_EQ(1u, result.size());
+  ASSERT_TRUE(result[0].edid);
+  EXPECT_EQ(kManufacturerId, result[0].edid->manufacturer_id);
+  EXPECT_EQ(kProductId, result[0].edid->product_id);
+  EXPECT_EQ(kYearOfManufacture, result[0].edid->year_of_manufacture);
+}
+
 }  // namespace
 }  // namespace extensions
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 2a23cdc..d84176fea 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -249,13 +249,6 @@
 const char kDriveSearchInChromeLauncherDescription[] =
     "Files from Drive will show up when searching the Chrome App Launcher.";
 
-const char kEasyUnlockBluetoothLowEnergyDiscoveryName[] =
-    "Smart Lock Bluetooth Low Energy Discovery";
-const char kEasyUnlockBluetoothLowEnergyDiscoveryDescription[] =
-    "Disables a Smart Lock setting that allows Chromebook to discover phones "
-    "over Bluetooth Low Energy in order to unlock the Chromebook when the "
-    "phone is in its proximity.";
-
 const char kEasyUnlockPromotionsName[] = "Smart Lock Promotions";
 const char kEasyUnlockPromotionsDescription[] =
     "Enables Smart Lock promotions. Promotions will be periodically display "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 850bc8a..7416282 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -188,9 +188,6 @@
 extern const char kDriveSearchInChromeLauncherName[];
 extern const char kDriveSearchInChromeLauncherDescription[];
 
-extern const char kEasyUnlockBluetoothLowEnergyDiscoveryName[];
-extern const char kEasyUnlockBluetoothLowEnergyDiscoveryDescription[];
-
 extern const char kEasyUnlockPromotionsName[];
 extern const char kEasyUnlockPromotionsDescription[];
 
diff --git a/chrome/browser/installable/installable_ambient_badge_infobar_delegate.cc b/chrome/browser/installable/installable_ambient_badge_infobar_delegate.cc
index 84fe2545..31f8eb2f 100644
--- a/chrome/browser/installable/installable_ambient_badge_infobar_delegate.cc
+++ b/chrome/browser/installable/installable_ambient_badge_infobar_delegate.cc
@@ -8,6 +8,8 @@
 
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/ui/android/infobars/installable_ambient_badge_infobar.h"
+#include "chrome/grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
 
 InstallableAmbientBadgeInfoBarDelegate::
     ~InstallableAmbientBadgeInfoBarDelegate() {}
@@ -16,6 +18,7 @@
 void InstallableAmbientBadgeInfoBarDelegate::Create(
     content::WebContents* web_contents,
     base::WeakPtr<Client> weak_client,
+    const base::string16& app_name,
     const SkBitmap& primary_icon,
     const GURL& start_url,
     bool is_installed) {
@@ -23,7 +26,8 @@
       ->AddInfoBar(std::make_unique<InstallableAmbientBadgeInfoBar>(
           std::unique_ptr<InstallableAmbientBadgeInfoBarDelegate>(
               new InstallableAmbientBadgeInfoBarDelegate(
-                  weak_client, primary_icon, start_url, is_installed))));
+                  weak_client, app_name, primary_icon, start_url,
+                  is_installed))));
 }
 
 void InstallableAmbientBadgeInfoBarDelegate::AddToHomescreen() {
@@ -33,17 +37,26 @@
   weak_client_->AddToHomescreenFromBadge();
 }
 
+const base::string16 InstallableAmbientBadgeInfoBarDelegate::GetMessageText()
+    const {
+  return l10n_util::GetStringFUTF16(
+      is_installed_ ? IDS_AMBIENT_BADGE_OPEN : IDS_AMBIENT_BADGE_INSTALL,
+      app_name_);
+}
+
 const SkBitmap& InstallableAmbientBadgeInfoBarDelegate::GetPrimaryIcon() const {
   return primary_icon_;
 }
 
 InstallableAmbientBadgeInfoBarDelegate::InstallableAmbientBadgeInfoBarDelegate(
     base::WeakPtr<Client> weak_client,
+    const base::string16& app_name,
     const SkBitmap& primary_icon,
     const GURL& start_url,
     bool is_installed)
     : infobars::InfoBarDelegate(),
       weak_client_(weak_client),
+      app_name_(app_name),
       primary_icon_(primary_icon),
       start_url_(start_url),
       is_installed_(is_installed) {}
diff --git a/chrome/browser/installable/installable_ambient_badge_infobar_delegate.h b/chrome/browser/installable/installable_ambient_badge_infobar_delegate.h
index 6dd7d77a..683bc88 100644
--- a/chrome/browser/installable/installable_ambient_badge_infobar_delegate.h
+++ b/chrome/browser/installable/installable_ambient_badge_infobar_delegate.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/strings/string16.h"
 #include "components/infobars/core/infobar_delegate.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "url/gurl.h"
@@ -33,17 +34,20 @@
   // Create and show the infobar.
   static void Create(content::WebContents* web_contents,
                      base::WeakPtr<Client> weak_client,
+                     const base::string16& app_name,
                      const SkBitmap& primary_icon,
                      const GURL& start_url,
                      bool is_installed);
 
   void AddToHomescreen();
+  const base::string16 GetMessageText() const;
   const SkBitmap& GetPrimaryIcon() const;
   const GURL& GetUrl() const { return start_url_; }
   bool is_installed() const { return is_installed_; }
 
  private:
   InstallableAmbientBadgeInfoBarDelegate(base::WeakPtr<Client> weak_client,
+                                         const base::string16& app_name,
                                          const SkBitmap& primary_icon,
                                          const GURL& start_url,
                                          bool is_installed);
@@ -52,6 +56,7 @@
   infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
 
   base::WeakPtr<Client> weak_client_;
+  const base::string16 app_name_;
   const SkBitmap primary_icon_;
   const GURL& start_url_;
 
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index b63bbb2..6c03ace2 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -787,7 +787,6 @@
   builder->set_network_quality_estimator(
       globals_->network_quality_estimator.get());
 
-  builder->set_user_agent(GetUserAgent());
   auto chrome_network_delegate = std::make_unique<ChromeNetworkDelegate>(
       extension_event_router_forwarder(), &system_enable_referrers_);
   // By default, data usage is considered off the record.
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter.cc b/chrome/browser/metrics/process_memory_metrics_emitter.cc
index 8c0aa960..3e1efd79 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter.cc
+++ b/chrome/browser/metrics/process_memory_metrics_emitter.cc
@@ -57,10 +57,14 @@
     {"blink_objects/Node", "NumberOfNodes",
      base::trace_event::MemoryAllocatorDump::kNameObjectCount,
      &Memory_Experimental::SetNumberOfNodes},
+    {"components/download", "DownloadService", kEffectiveSize,
+     &Memory_Experimental::SetDownloadService},
     {"discardable", "Discardable", kEffectiveSize,
      &Memory_Experimental::SetDiscardable},
     {"extensions/value_store", "Extensions.ValueStore", kEffectiveSize,
      &Memory_Experimental::SetExtensions_ValueStore},
+    {"font_caches", "FontCaches", kEffectiveSize,
+     &Memory_Experimental::SetFontCaches},
     {"gpu/gl", "CommandBuffer", kEffectiveSize,
      &Memory_Experimental::SetCommandBuffer},
     {"history", "History", kEffectiveSize, &Memory_Experimental::SetHistory},
@@ -75,6 +79,8 @@
     {"net", "Net", kEffectiveSize, &Memory_Experimental::SetNet},
     {"net/url_request_context", "Net.UrlRequestContext", kEffectiveSize,
      &Memory_Experimental::SetNet_UrlRequestContext},
+    {"omnibox", "OmniboxSuggestions", kEffectiveSize,
+     &Memory_Experimental::SetOmniboxSuggestions},
     {"partition_alloc", "PartitionAlloc", kEffectiveSize,
      &Memory_Experimental::SetPartitionAlloc},
     {"partition_alloc/allocated_objects", "PartitionAlloc.AllocatedObjects",
@@ -91,9 +97,10 @@
      kEffectiveSize, &Memory_Experimental::SetPartitionAlloc_Partitions_Layout},
     {"site_storage", "SiteStorage", kEffectiveSize,
      &Memory_Experimental::SetSiteStorage},
+    {"site_storage/blob_storage", "SiteStorage.BlobStorage", kEffectiveSize,
+     &Memory_Experimental::SetSiteStorage_BlobStorage},
     {"site_storage/index_db", "SiteStorage.IndexDB", kEffectiveSize,
      &Memory_Experimental::SetSiteStorage_IndexDB},
-    // TODO(ssid): This metric does not return total value.
     {"site_storage/localstorage", "SiteStorage.LocalStorage", kEffectiveSize,
      &Memory_Experimental::SetSiteStorage_LocalStorage},
     {"site_storage/session_storage", "SiteStorage.SessionStorage",
diff --git a/chrome/browser/net/chrome_http_user_agent_settings.cc b/chrome/browser/net/chrome_http_user_agent_settings.cc
index 5d2f98f9..c8e79bf2 100644
--- a/chrome/browser/net/chrome_http_user_agent_settings.cc
+++ b/chrome/browser/net/chrome_http_user_agent_settings.cc
@@ -61,13 +61,8 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   pref_accept_language_.Init(prefs::kAcceptLanguages, prefs);
   last_pref_accept_language_ = *pref_accept_language_;
-
-  const std::string accept_languages_str =
-      base::FeatureList::IsEnabled(features::kUseNewAcceptLanguageHeader)
-          ? ExpandLanguageList(last_pref_accept_language_)
-          : last_pref_accept_language_;
   last_http_accept_language_ =
-      net::HttpUtil::GenerateAcceptLanguageHeader(accept_languages_str);
+      ComputeAcceptLanguageFromPref(last_pref_accept_language_);
 
   pref_accept_language_.MoveToThread(
       content::BrowserThread::GetTaskRunnerForThread(
@@ -78,6 +73,15 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 }
 
+std::string ChromeHttpUserAgentSettings::ComputeAcceptLanguageFromPref(
+    const std::string& language_pref) {
+  std::string accept_languages_str =
+      base::FeatureList::IsEnabled(features::kUseNewAcceptLanguageHeader)
+          ? ExpandLanguageList(language_pref)
+          : language_pref;
+  return net::HttpUtil::GenerateAcceptLanguageHeader(accept_languages_str);
+}
+
 std::string ChromeHttpUserAgentSettings::ExpandLanguageList(
     const std::string& language_prefs) {
   const std::vector<std::string> languages = base::SplitString(
@@ -117,12 +121,8 @@
   std::string new_pref_accept_language = *pref_accept_language_;
 
   if (new_pref_accept_language != last_pref_accept_language_) {
-    const std::string accept_languages_str =
-        base::FeatureList::IsEnabled(features::kUseNewAcceptLanguageHeader)
-            ? ExpandLanguageList(new_pref_accept_language)
-            : new_pref_accept_language;
     last_http_accept_language_ =
-        net::HttpUtil::GenerateAcceptLanguageHeader(accept_languages_str);
+        ComputeAcceptLanguageFromPref(new_pref_accept_language);
     last_pref_accept_language_ = new_pref_accept_language;
   }
 
diff --git a/chrome/browser/net/chrome_http_user_agent_settings.h b/chrome/browser/net/chrome_http_user_agent_settings.h
index 031bb2f..a13d881 100644
--- a/chrome/browser/net/chrome_http_user_agent_settings.h
+++ b/chrome/browser/net/chrome_http_user_agent_settings.h
@@ -23,6 +23,11 @@
   // Must be called on the IO thread.
   ~ChromeHttpUserAgentSettings() override;
 
+  // Given the language setting in the Prefs::kAcceptLanguages setting, returns
+  // the appropriate value of Accept-Language header to send.
+  static std::string ComputeAcceptLanguageFromPref(
+      const std::string& language_pref);
+
   // Adds the base language if a corresponding language+region code is present.
   static std::string ExpandLanguageList(const std::string& language_prefs);
 
diff --git a/chrome/browser/net/network_context_configuration_browsertest.cc b/chrome/browser/net/network_context_configuration_browsertest.cc
index a960aa9..b84cf47 100644
--- a/chrome/browser/net/network_context_configuration_browsertest.cc
+++ b/chrome/browser/net/network_context_configuration_browsertest.cc
@@ -9,6 +9,7 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/guid.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_feature_list.h"
@@ -20,7 +21,9 @@
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_content_client.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/network_session_configurator/common/network_switches.h"
 #include "components/prefs/pref_service.h"
@@ -295,26 +298,24 @@
     controllable_http_response_->WaitForRequest();
   }
 
- private:
-  void SimulateNetworkServiceCrashIfNecessary() {
-    if (GetParam().network_service_state != NetworkServiceState::kRestarted)
-      return;
-
-    // Make sure |network_context()| is working as expected. Use '/echoheader'
-    // instead of '/echo' to avoid a disk_cache bug.
-    // See https://crbug.com/792255.
-    int net_error = content::LoadBasicRequest(
-        network_context(), embedded_test_server()->GetURL("/echoheader"));
-    // The error code could be |net::ERR_PROXY_CONNECTION_FAILED| if the test is
-    // using 'bad_server.pac'.
-    EXPECT_TRUE(net_error == net::OK ||
-                net_error == net::ERR_PROXY_CONNECTION_FAILED);
-
-    // Crash the NetworkService process. Existing interfaces should receive
-    // error notifications at some point.
-    content::SimulateNetworkServiceCrash();
-    // Flush the interface to make sure the error notification was received.
-    FlushNetworkInterface();
+  bool FetchHeaderEcho(const std::string& header_name,
+                       std::string* header_value_out) {
+    std::unique_ptr<network::ResourceRequest> request =
+        std::make_unique<network::ResourceRequest>();
+    request->url = embedded_test_server()->GetURL(
+        base::StrCat({"/echoheader?", header_name}));
+    content::SimpleURLLoaderTestHelper simple_loader_helper;
+    std::unique_ptr<network::SimpleURLLoader> simple_loader =
+        network::SimpleURLLoader::Create(std::move(request),
+                                         TRAFFIC_ANNOTATION_FOR_TESTS);
+    simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+        loader_factory(), simple_loader_helper.GetCallback());
+    simple_loader_helper.WaitForCallback();
+    if (simple_loader_helper.response_body()) {
+      *header_value_out = *simple_loader_helper.response_body();
+      return true;
+    }
+    return false;
   }
 
   void FlushNetworkInterface() {
@@ -337,6 +338,28 @@
     }
   }
 
+ private:
+  void SimulateNetworkServiceCrashIfNecessary() {
+    if (GetParam().network_service_state != NetworkServiceState::kRestarted)
+      return;
+
+    // Make sure |network_context()| is working as expected. Use '/echoheader'
+    // instead of '/echo' to avoid a disk_cache bug.
+    // See https://crbug.com/792255.
+    int net_error = content::LoadBasicRequest(
+        network_context(), embedded_test_server()->GetURL("/echoheader"));
+    // The error code could be |net::ERR_PROXY_CONNECTION_FAILED| if the test is
+    // using 'bad_server.pac'.
+    EXPECT_TRUE(net_error == net::OK ||
+                net_error == net::ERR_PROXY_CONNECTION_FAILED);
+
+    // Crash the NetworkService process. Existing interfaces should receive
+    // error notifications at some point.
+    content::SimulateNetworkServiceCrash();
+    // Flush the interface to make sure the error notification was received.
+    FlushNetworkInterface();
+  }
+
   Browser* incognito_ = nullptr;
   base::test::ScopedFeatureList feature_list_;
 
@@ -563,6 +586,44 @@
   MakeLongLivedRequestThatHangsUntilShutdown();
 }
 
+IN_PROC_BROWSER_TEST_P(NetworkContextConfigurationBrowserTest,
+                       UserAgentAndLanguagePrefs) {
+  // System network context isn't associated with any profile, so changing the
+  // language settings in the default one doesn't affect what it sends.
+  bool system =
+      (GetParam().network_context_type == NetworkContextType::kSystem);
+  const char kDefaultAcceptLanguage[] = "en-us,en";
+
+  std::string accept_language, user_agent;
+  // Check default.
+  ASSERT_TRUE(FetchHeaderEcho("accept-language", &accept_language));
+  EXPECT_EQ(system ? kDefaultAcceptLanguage : "en-US,en;q=0.9",
+            accept_language);
+  ASSERT_TRUE(FetchHeaderEcho("user-agent", &user_agent));
+  EXPECT_EQ(::GetUserAgent(), user_agent);
+
+  // Now change the profile a different language, and see if the headers
+  // get updated.
+  browser()->profile()->GetPrefs()->SetString(prefs::kAcceptLanguages, "uk");
+  FlushNetworkInterface();
+  std::string accept_language2, user_agent2;
+  ASSERT_TRUE(FetchHeaderEcho("accept-language", &accept_language2));
+  EXPECT_EQ(system ? kDefaultAcceptLanguage : "uk", accept_language2);
+  ASSERT_TRUE(FetchHeaderEcho("user-agent", &user_agent2));
+  EXPECT_EQ(::GetUserAgent(), user_agent2);
+
+  // Try a more complicated one, with multiple languages.
+  browser()->profile()->GetPrefs()->SetString(prefs::kAcceptLanguages,
+                                              "uk, en_US");
+  FlushNetworkInterface();
+  std::string accept_language3, user_agent3;
+  ASSERT_TRUE(FetchHeaderEcho("accept-language", &accept_language3));
+  EXPECT_EQ(system ? kDefaultAcceptLanguage : "uk,en_US;q=0.9",
+            accept_language3);
+  ASSERT_TRUE(FetchHeaderEcho("user-agent", &user_agent3));
+  EXPECT_EQ(::GetUserAgent(), user_agent3);
+}
+
 class NetworkContextConfigurationFixedPortBrowserTest
     : public NetworkContextConfigurationBrowserTest {
  public:
diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc
index d9d152b..2130cdc7 100644
--- a/chrome/browser/net/profile_network_context_service.cc
+++ b/chrome/browser/net/profile_network_context_service.cc
@@ -12,10 +12,12 @@
 #include "base/logging.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/net/chrome_http_user_agent_settings.h"
 #include "chrome/browser/net/default_network_context_params.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_content_client.h"
 #include "chrome/common/chrome_paths_internal.h"
 #include "chrome/common/pref_names.h"
 #include "components/pref_registry/pref_registry_syncable.h"
@@ -23,6 +25,7 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/network_service_instance.h"
+#include "content/public/browser/storage_partition.h"
 #include "content/public/common/service_names.mojom.h"
 #include "mojo/public/cpp/bindings/associated_interface_ptr.h"
 #include "net/net_features.h"
@@ -34,6 +37,10 @@
       prefs::kQuicAllowed, profile->GetPrefs(),
       base::Bind(&ProfileNetworkContextService::DisableQuicIfNotAllowed,
                  base::Unretained(this)));
+  pref_accept_language_.Init(
+      prefs::kAcceptLanguages, profile->GetPrefs(),
+      base::BindRepeating(&ProfileNetworkContextService::UpdateAcceptLanguage,
+                          base::Unretained(this)));
   // The system context must be initialized before any other network contexts.
   // TODO(mmenke): Figure out a way to enforce this.
   g_browser_process->system_network_context_manager()->GetContext();
@@ -101,6 +108,17 @@
   g_browser_process->system_network_context_manager()->DisableQuic();
 }
 
+void ProfileNetworkContextService::UpdateAcceptLanguage() {
+  content::BrowserContext::GetDefaultStoragePartition(profile_)
+      ->GetNetworkContext()
+      ->SetAcceptLanguage(ComputeAcceptLanguage());
+}
+
+std::string ProfileNetworkContextService::ComputeAcceptLanguage() const {
+  return ChromeHttpUserAgentSettings::ComputeAcceptLanguageFromPref(
+      pref_accept_language_.GetValue());
+}
+
 void ProfileNetworkContextService::FlushProxyConfigMonitorForTesting() {
   proxy_config_monitor_.FlushForTesting();
 }
@@ -113,6 +131,8 @@
 
   network_context_params->context_name = std::string("main");
 
+  network_context_params->accept_language = ComputeAcceptLanguage();
+
   // Always enable the HTTP cache.
   network_context_params->http_cache_enabled = true;
 
diff --git a/chrome/browser/net/profile_network_context_service.h b/chrome/browser/net/profile_network_context_service.h
index d35462a4..d663b63 100644
--- a/chrome/browser/net/profile_network_context_service.h
+++ b/chrome/browser/net/profile_network_context_service.h
@@ -61,6 +61,14 @@
   // Checks |quic_allowed_|, and disables QUIC if needed.
   void DisableQuicIfNotAllowed();
 
+  // Forwards changes to |pref_accept_language_| to the NetworkContext, after
+  // formatting them as appropriate.
+  void UpdateAcceptLanguage();
+
+  // Computes appropriate value of Accept-Language header based on
+  // |pref_accept_language_|
+  std::string ComputeAcceptLanguage() const;
+
   // Creates parameters for the NetworkContext. May only be called once, since
   // it initializes some class members.
   network::mojom::NetworkContextParamsPtr CreateMainNetworkContextParams();
@@ -80,6 +88,7 @@
   network::mojom::NetworkContextRequest profile_io_data_context_request_;
 
   BooleanPrefMember quic_allowed_;
+  StringPrefMember pref_accept_language_;
 
   DISALLOW_COPY_AND_ASSIGN(ProfileNetworkContextService);
 };
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc
index be5f559..b1976dd3 100644
--- a/chrome/browser/net/system_network_context_manager.cc
+++ b/chrome/browser/net/system_network_context_manager.cc
@@ -137,8 +137,13 @@
 }
 
 void SystemNetworkContextManager::FlushNetworkInterfaceForTesting() {
-  DCHECK(network_service_network_context_);
-  network_service_network_context_.FlushForTesting();
+  if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+    DCHECK(io_thread_network_context_);
+    io_thread_network_context_.FlushForTesting();
+  } else {
+    DCHECK(network_service_network_context_);
+    network_service_network_context_.FlushForTesting();
+  }
   if (url_loader_factory_)
     url_loader_factory_.FlushForTesting();
 }
diff --git a/chrome/browser/offline_pages/offline_page_request_job.cc b/chrome/browser/offline_pages/offline_page_request_job.cc
index 1b06847..08513253 100644
--- a/chrome/browser/offline_pages/offline_page_request_job.cc
+++ b/chrome/browser/offline_pages/offline_page_request_job.cc
@@ -510,7 +510,8 @@
     const OfflinePageHeader& offline_header,
     OfflinePageRequestJob::NetworkState network_state,
     content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
-    const OfflinePageItem& offline_page) {
+    const OfflinePageItem& offline_page,
+    bool archive_is_in_internal_dir) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // |web_contents_getter| is passed from IO thread. We need to check if
@@ -534,7 +535,10 @@
       OfflinePageTabHelper::FromWebContents(web_contents);
   DCHECK(tab_helper);
   tab_helper->SetOfflinePage(
-      offline_page, offline_header, true /*is_trusted*/,
+      offline_page, offline_header,
+      archive_is_in_internal_dir
+          ? OfflinePageTrustedState::TRUSTED_AS_IN_INTERNAL_DIR
+          : OfflinePageTrustedState::TRUSTED_AS_UNMODIFIED_AND_IN_PUBLIC_DIR,
       network_state ==
           OfflinePageRequestJob::NetworkState::PROHIBITIVELY_SLOW_NETWORK);
 }
@@ -787,7 +791,8 @@
       content::BrowserThread::UI, FROM_HERE,
       base::BindOnce(&VisitTrustedOfflinePageOnUI, offline_header_,
                      network_state_, delegate_->GetWebContentsGetter(request()),
-                     GetCurrentOfflinePage()));
+                     GetCurrentOfflinePage(),
+                     candidates_[candidate_index_].archive_is_in_internal_dir));
 }
 
 void OfflinePageRequestJob::SetOfflinePageNavigationUIData(
diff --git a/chrome/browser/offline_pages/offline_page_request_job_unittest.cc b/chrome/browser/offline_pages/offline_page_request_job_unittest.cc
index 9ff30e9..1ac1ff3 100644
--- a/chrome/browser/offline_pages/offline_page_request_job_unittest.cc
+++ b/chrome/browser/offline_pages/offline_page_request_job_unittest.cc
@@ -832,6 +832,13 @@
   ASSERT_TRUE(offline_page_tab_helper()->GetOfflinePageForTest());
   EXPECT_EQ(expected_offline_id,
             offline_page_tab_helper()->GetOfflinePageForTest()->offline_id);
+  OfflinePageTrustedState expected_trusted_state =
+      private_archives_dir_.IsParent(
+          offline_page_tab_helper()->GetOfflinePageForTest()->file_path)
+          ? OfflinePageTrustedState::TRUSTED_AS_IN_INTERNAL_DIR
+          : OfflinePageTrustedState::TRUSTED_AS_UNMODIFIED_AND_IN_PUBLIC_DIR;
+  EXPECT_EQ(expected_trusted_state,
+            offline_page_tab_helper()->GetTrustedStateForTest());
   if (expected_request_result !=
       OfflinePageRequestJob::AggregatedRequestResult::
           AGGREGATED_REQUEST_RESULT_MAX) {
diff --git a/chrome/browser/offline_pages/offline_page_tab_helper.cc b/chrome/browser/offline_pages/offline_page_tab_helper.cc
index 501e5af..932596a7 100644
--- a/chrome/browser/offline_pages/offline_page_tab_helper.cc
+++ b/chrome/browser/offline_pages/offline_page_tab_helper.cc
@@ -9,6 +9,7 @@
 #include "base/guid.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
 #include "chrome/browser/offline_pages/offline_page_model_factory.h"
 #include "chrome/browser/offline_pages/offline_page_request_job.h"
@@ -45,14 +46,15 @@
 }  // namespace
 
 OfflinePageTabHelper::LoadedOfflinePageInfo::LoadedOfflinePageInfo()
-    : is_trusted(false), is_showing_offline_preview(false) {}
+    : trusted_state(OfflinePageTrustedState::UNTRUSTED),
+      is_showing_offline_preview(false) {}
 
 OfflinePageTabHelper::LoadedOfflinePageInfo::~LoadedOfflinePageInfo() {}
 
 void OfflinePageTabHelper::LoadedOfflinePageInfo::Clear() {
   offline_page.reset();
   offline_header.Clear();
-  is_trusted = false;
+  trusted_state = OfflinePageTrustedState::UNTRUSTED;
   is_showing_offline_preview = false;
 }
 
@@ -108,6 +110,7 @@
   FinalizeOfflineInfo(navigation_handle);
   provisional_offline_info_.Clear();
 
+  ReportOfflinePageMetrics();
   ReportPrefetchMetrics(navigation_handle);
 
   TryLoadingOfflinePageOnNetError(navigation_handle);
@@ -129,7 +132,7 @@
       web_contents->GetContentsMimeType() == "multipart/related") {
     offline_info_.offline_page = std::make_unique<OfflinePageItem>();
     offline_info_.offline_page->offline_id = store_utils::GenerateOfflineId();
-    offline_info_.is_trusted = false;
+    offline_info_.trusted_state = OfflinePageTrustedState::UNTRUSTED;
     // TODO(jianli): Extract the url where the MHTML acrhive claims from the
     // MHTML headers and set it in OfflinePageItem::original_url.
 
@@ -174,11 +177,19 @@
   offline_info_.offline_page =
       std::move(provisional_offline_info_.offline_page);
   offline_info_.offline_header = provisional_offline_info_.offline_header;
-  offline_info_.is_trusted = provisional_offline_info_.is_trusted;
+  offline_info_.trusted_state = provisional_offline_info_.trusted_state;
   offline_info_.is_showing_offline_preview =
       provisional_offline_info_.is_showing_offline_preview;
 }
 
+void OfflinePageTabHelper::ReportOfflinePageMetrics() {
+  if (!offline_page())
+    return;
+  UMA_HISTOGRAM_ENUMERATION("OfflinePages.TrustStateOnOpen",
+                            offline_info_.trusted_state,
+                            OfflinePageTrustedState::TRUSTED_STATE_MAX);
+}
+
 void OfflinePageTabHelper::ReportPrefetchMetrics(
     content::NavigationHandle* navigation_handle) {
   if (navigation_handle->IsErrorPage())
@@ -288,7 +299,8 @@
   // the one retrieved from the metadata database. Do this only when the stored
   // offline info is not changed since last time the asynchronous query is
   // issued.
-  if (offline_info_.offline_page && !offline_info_.is_trusted &&
+  if (offline_info_.offline_page &&
+      offline_info_.trusted_state == OfflinePageTrustedState::UNTRUSTED &&
       offline_info_.offline_page->offline_id == offline_page->offline_id) {
     offline_info_.offline_page =
         std::make_unique<OfflinePageItem>(*offline_page);
@@ -300,12 +312,12 @@
 void OfflinePageTabHelper::SetOfflinePage(
     const OfflinePageItem& offline_page,
     const OfflinePageHeader& offline_header,
-    bool is_trusted,
+    OfflinePageTrustedState trusted_state,
     bool is_offline_preview) {
   provisional_offline_info_.offline_page =
       std::make_unique<OfflinePageItem>(offline_page);
   provisional_offline_info_.offline_header = offline_header;
-  provisional_offline_info_.is_trusted = is_trusted;
+  provisional_offline_info_.trusted_state = trusted_state;
   provisional_offline_info_.is_showing_offline_preview = is_offline_preview;
 }
 
@@ -315,13 +327,18 @@
 }
 
 bool OfflinePageTabHelper::IsShowingTrustedOfflinePage() const {
-  return offline_info_.offline_page && offline_info_.is_trusted;
+  return offline_info_.offline_page &&
+         (offline_info_.trusted_state != OfflinePageTrustedState::UNTRUSTED);
 }
 
 const OfflinePageItem* OfflinePageTabHelper::GetOfflinePageForTest() const {
   return provisional_offline_info_.offline_page.get();
 }
 
+OfflinePageTrustedState OfflinePageTabHelper::GetTrustedStateForTest() const {
+  return provisional_offline_info_.trusted_state;
+}
+
 const OfflinePageItem* OfflinePageTabHelper::GetOfflinePreviewItem() const {
   if (provisional_offline_info_.is_showing_offline_preview)
     return provisional_offline_info_.offline_page.get();
diff --git a/chrome/browser/offline_pages/offline_page_tab_helper.h b/chrome/browser/offline_pages/offline_page_tab_helper.h
index 956c0508..f413be4 100644
--- a/chrome/browser/offline_pages/offline_page_tab_helper.h
+++ b/chrome/browser/offline_pages/offline_page_tab_helper.h
@@ -23,6 +23,24 @@
 struct OfflinePageItem;
 class PrefetchService;
 
+// This enum is used for UMA reporting. It contains all possible trusted states
+// of the offline page.
+// NOTE: because this is used for UMA reporting, these values should not be
+// changed or reused; new values should be ended immediately before the MAX
+// value. Make sure to update the histogram enum (OfflinePageTrustedState in
+// enums.xml) accordingly.
+enum class OfflinePageTrustedState {
+  // Trusted because the archive file is in internal directory.
+  TRUSTED_AS_IN_INTERNAL_DIR,
+  // Trusted because the archive file is in public directory without
+  // modification.
+  TRUSTED_AS_UNMODIFIED_AND_IN_PUBLIC_DIR,
+  // No trusted because the archive file is in public directory and it is
+  // modified.
+  UNTRUSTED,
+  TRUSTED_STATE_MAX
+};
+
 // Per-tab class that monitors the navigations and stores the necessary info
 // to facilitate the synchronous access to offline information.
 class OfflinePageTabHelper :
@@ -33,7 +51,7 @@
 
   void SetOfflinePage(const OfflinePageItem& offline_page,
                       const OfflinePageHeader& offline_header,
-                      bool is_trusted,
+                      OfflinePageTrustedState trusted_state,
                       bool is_offline_preview);
 
   void ClearOfflinePage();
@@ -46,6 +64,10 @@
     return offline_info_.offline_header;
   }
 
+  OfflinePageTrustedState trusted_state() const {
+    return offline_info_.trusted_state;
+  }
+
   // Returns whether a trusted offline page is being displayed.
   bool IsShowingTrustedOfflinePage() const;
 
@@ -57,6 +79,9 @@
   // during unit tests.
   const OfflinePageItem* GetOfflinePageForTest() const;
 
+  // Returns trusted state of provisional offline page.
+  OfflinePageTrustedState GetTrustedStateForTest() const;
+
   // Helper function which normally should only be called by
   // OfflinePageUtils::ScheduleDownload to do the work. This is because we need
   // to ensure |web_contents| is still valid after returning from the
@@ -84,8 +109,8 @@
     // The offline header that is provided when offline page is loaded.
     OfflinePageHeader offline_header;
 
-    // Whether the page is deemed trusted or not.
-    bool is_trusted;
+    // The trusted state of the page.
+    OfflinePageTrustedState trusted_state;
 
     // Whether the page is an offline preview. Offline page previews are shown
     // when a user's effective connection type is prohibitively slow.
@@ -105,6 +130,8 @@
   // Finalize the offline info when the navigation is done.
   void FinalizeOfflineInfo(content::NavigationHandle* navigation_handle);
 
+  void ReportOfflinePageMetrics();
+
   // Report the metrics essential to PrefetchService.
   void ReportPrefetchMetrics(content::NavigationHandle* navigation_handle);
 
diff --git a/chrome/browser/offline_pages/offline_page_tab_helper_unittest.cc b/chrome/browser/offline_pages/offline_page_tab_helper_unittest.cc
index 5ffe64e..1200b4c 100644
--- a/chrome/browser/offline_pages/offline_page_tab_helper_unittest.cc
+++ b/chrome/browser/offline_pages/offline_page_tab_helper_unittest.cc
@@ -170,7 +170,9 @@
   // Simulate offline interceptor loading an offline page instead.
   OfflinePageItem offlinePage(kTestPageUrl, 0, ClientId(), base::FilePath(), 0);
   OfflinePageHeader offlineHeader;
-  tab_helper()->SetOfflinePage(offlinePage, offlineHeader, true, false);
+  tab_helper()->SetOfflinePage(
+      offlinePage, offlineHeader,
+      OfflinePageTrustedState::TRUSTED_AS_IN_INTERNAL_DIR, false);
 
   navigation_simulator()->Commit();
 
@@ -181,18 +183,43 @@
   EXPECT_EQ(0, metrics()->report_stats_count_);
 }
 
-TEST_F(OfflinePageTabHelperTest, TrustedOfflinePage) {
+TEST_F(OfflinePageTabHelperTest, TrustedInternalOfflinePage) {
   CreateNavigationSimulator(kTestPageUrl);
   navigation_simulator()->Start();
 
   OfflinePageItem offlinePage(kTestPageUrl, 0, ClientId(), base::FilePath(), 0);
   OfflinePageHeader offlineHeader(kTestHeader);
-  tab_helper()->SetOfflinePage(offlinePage, offlineHeader, true, false);
+  tab_helper()->SetOfflinePage(
+      offlinePage, offlineHeader,
+      OfflinePageTrustedState::TRUSTED_AS_IN_INTERNAL_DIR, false);
 
   navigation_simulator()->Commit();
 
   ASSERT_NE(nullptr, tab_helper()->offline_page());
   EXPECT_EQ(kTestPageUrl, tab_helper()->offline_page()->url);
+  EXPECT_EQ(OfflinePageTrustedState::TRUSTED_AS_IN_INTERNAL_DIR,
+            tab_helper()->trusted_state());
+  EXPECT_TRUE(tab_helper()->IsShowingTrustedOfflinePage());
+  EXPECT_EQ(OfflinePageHeader::Reason::DOWNLOAD,
+            tab_helper()->offline_header().reason);
+}
+
+TEST_F(OfflinePageTabHelperTest, TrustedPublicOfflinePage) {
+  CreateNavigationSimulator(kTestPageUrl);
+  navigation_simulator()->Start();
+
+  OfflinePageItem offlinePage(kTestPageUrl, 0, ClientId(), base::FilePath(), 0);
+  OfflinePageHeader offlineHeader(kTestHeader);
+  tab_helper()->SetOfflinePage(
+      offlinePage, offlineHeader,
+      OfflinePageTrustedState::TRUSTED_AS_UNMODIFIED_AND_IN_PUBLIC_DIR, false);
+
+  navigation_simulator()->Commit();
+
+  ASSERT_NE(nullptr, tab_helper()->offline_page());
+  EXPECT_EQ(kTestPageUrl, tab_helper()->offline_page()->url);
+  EXPECT_EQ(OfflinePageTrustedState::TRUSTED_AS_UNMODIFIED_AND_IN_PUBLIC_DIR,
+            tab_helper()->trusted_state());
   EXPECT_TRUE(tab_helper()->IsShowingTrustedOfflinePage());
   EXPECT_EQ(OfflinePageHeader::Reason::DOWNLOAD,
             tab_helper()->offline_header().reason);
@@ -205,6 +232,7 @@
   navigation_simulator()->Commit();
 
   ASSERT_NE(nullptr, tab_helper()->offline_page());
+  EXPECT_EQ(OfflinePageTrustedState::UNTRUSTED, tab_helper()->trusted_state());
   EXPECT_FALSE(tab_helper()->IsShowingTrustedOfflinePage());
   EXPECT_EQ(OfflinePageHeader::Reason::NONE,
             tab_helper()->offline_header().reason);
@@ -218,6 +246,7 @@
   navigation_simulator()->Commit();
 
   ASSERT_NE(nullptr, tab_helper()->offline_page());
+  EXPECT_EQ(OfflinePageTrustedState::UNTRUSTED, tab_helper()->trusted_state());
   EXPECT_FALSE(tab_helper()->IsShowingTrustedOfflinePage());
   EXPECT_EQ(OfflinePageHeader::Reason::NONE,
             tab_helper()->offline_header().reason);
diff --git a/chrome/browser/previews/previews_infobar_tab_helper_unittest.cc b/chrome/browser/previews/previews_infobar_tab_helper_unittest.cc
index 3d54c32..95d1411 100644
--- a/chrome/browser/previews/previews_infobar_tab_helper_unittest.cc
+++ b/chrome/browser/previews/previews_infobar_tab_helper_unittest.cc
@@ -240,7 +240,10 @@
   int64_t expected_file_size = .55 * item.file_size;
   offline_pages::OfflinePageHeader header;
   offline_pages::OfflinePageTabHelper::FromWebContents(web_contents())
-      ->SetOfflinePage(item, header, true, true);
+      ->SetOfflinePage(
+          item, header,
+          offline_pages::OfflinePageTrustedState::TRUSTED_AS_IN_INTERNAL_DIR,
+          true);
 
   auto* data_reduction_proxy_settings =
       DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index f2a6c72..98bd3dc6 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -33,7 +33,6 @@
 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
 #include "chrome/browser/io_thread.h"
-#include "chrome/browser/net/chrome_http_user_agent_settings.h"
 #include "chrome/browser/net/chrome_network_delegate.h"
 #include "chrome/browser/net/chrome_url_request_context_getter.h"
 #include "chrome/browser/net/loading_predictor_observer.h"
@@ -514,9 +513,6 @@
   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
       BrowserThread::GetTaskRunnerForThread(BrowserThread::IO);
 
-  chrome_http_user_agent_settings_.reset(
-      new ChromeHttpUserAgentSettings(pref_service));
-
   // These members are used only for sign in, which is not enabled
   // in incognito mode.  So no need to initialize them.
   if (!IsOffTheRecord()) {
@@ -1063,8 +1059,6 @@
   std::unique_ptr<network::URLRequestContextBuilderMojo> builder =
       std::make_unique<network::URLRequestContextBuilderMojo>();
 
-  builder->set_shared_http_user_agent_settings(
-      chrome_http_user_agent_settings_.get());
   builder->set_ssl_config_service(profile_params_->ssl_config_service);
 
   std::unique_ptr<ChromeNetworkDelegate> chrome_network_delegate(
@@ -1438,8 +1432,6 @@
   network_prediction_options_.Destroy();
   if (ct_policy_manager_)
     ct_policy_manager_->Shutdown();
-  if (chrome_http_user_agent_settings_)
-    chrome_http_user_agent_settings_->CleanupOnUIThread();
   incognito_availibility_pref_.Destroy();
 #if BUILDFLAG(ENABLE_PLUGINS)
   always_open_pdf_externally_.Destroy();
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h
index 67abf5b..0fa7a65 100644
--- a/chrome/browser/profiles/profile_io_data.h
+++ b/chrome/browser/profiles/profile_io_data.h
@@ -40,7 +40,6 @@
 #include "services/network/public/mojom/network_service.mojom.h"
 #include "services/network/url_request_context_owner.h"
 
-class ChromeHttpUserAgentSettings;
 class ChromeNetworkDelegate;
 class ChromeURLRequestContextGetter;
 class ChromeExpectCTReporter;
@@ -648,9 +647,6 @@
   mutable std::unique_ptr<chrome_browser_net::LoadingPredictorObserver>
       loading_predictor_observer_;
 
-  mutable std::unique_ptr<ChromeHttpUserAgentSettings>
-      chrome_http_user_agent_settings_;
-
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   // Is NULL if switches::kDisableExtensionsHttpThrottling is on.
   mutable std::unique_ptr<extensions::ExtensionThrottleManager>
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h
index 892a73e..7c50341 100644
--- a/chrome/browser/resource_coordinator/tab_manager.h
+++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -261,6 +261,8 @@
   FRIEND_TEST_ALL_PREFIXES(TabManagerTest, TabManagerBasics);
   FRIEND_TEST_ALL_PREFIXES(TabManagerTest, TabManagerWasDiscarded);
   FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
+                           TabManagerWasDiscardedCrossSiteSubFrame);
+  FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
                            GetUnsortedTabStatsIsInVisibleWindow);
   FRIEND_TEST_ALL_PREFIXES(TabManagerTest, DiscardTabWithNonVisibleTabs);
   FRIEND_TEST_ALL_PREFIXES(TabManagerTest, MaybeThrottleNavigation);
diff --git a/chrome/browser/resource_coordinator/tab_manager_browsertest.cc b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
index fd7497c..a53a7b3 100644
--- a/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_browsertest.cc
@@ -34,6 +34,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
 #include "net/dns/mock_host_resolver.h"
 #include "url/gurl.h"
@@ -898,6 +899,91 @@
   EXPECT_TRUE(discarded_result);
 }
 
+IN_PROC_BROWSER_TEST_F(TabManagerTest,
+                       TabManagerWasDiscardedCrossSiteSubFrame) {
+  const char kDiscardedStateJS[] =
+      "window.domAutomationController.send("
+      "window.document.wasDiscarded);";
+  // Navigate to a page with a cross-site frame.
+  content::SetupCrossSiteRedirector(embedded_test_server());
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL main_url(
+      embedded_test_server()->GetURL("a.com", "/iframe_cross_site.html"));
+  ui_test_utils::NavigateToURL(browser(), main_url);
+
+  // Grab the original frames.
+  content::WebContents* contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  content::RenderFrameHost* main_frame = contents->GetMainFrame();
+  ASSERT_LE(2u, contents->GetAllFrames().size());
+  content::RenderFrameHost* child_frame = contents->GetAllFrames()[1];
+
+  // Sanity check that in this test page the main frame and the
+  // subframe are cross-site.
+  EXPECT_FALSE(content::SiteInstance::IsSameWebSite(
+      browser()->profile(), main_frame->GetLastCommittedURL(),
+      child_frame->GetLastCommittedURL()));
+  if (content::AreAllSitesIsolatedForTesting()) {
+    EXPECT_NE(main_frame->GetProcess()->GetID(),
+              child_frame->GetProcess()->GetID());
+  }
+
+  // document.wasDiscarded is false before discard, on main frame and child
+  // frame.
+  bool before_discard_mainframe_result;
+  EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+      main_frame, kDiscardedStateJS, &before_discard_mainframe_result));
+  EXPECT_FALSE(before_discard_mainframe_result);
+
+  bool before_discard_childframe_result;
+  EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+      child_frame, kDiscardedStateJS, &before_discard_childframe_result));
+  EXPECT_FALSE(before_discard_childframe_result);
+
+  // Discard the tab. This simulates a tab discard.
+  g_browser_process->GetTabManager()->DiscardWebContentsAt(
+      0, browser()->tab_strip_model(), DiscardReason::kProactive);
+
+  // Here we simulate re-focussing the tab causing reload with navigation,
+  // the navigation will reload the tab.
+  // TODO(panicker): Consider adding a test hook on LifecycleUnit when ready.
+  ui_test_utils::NavigateToURL(browser(), main_url);
+
+  // Re-assign pointers after discarding, as they've changed.
+  contents = browser()->tab_strip_model()->GetActiveWebContents();
+  main_frame = contents->GetMainFrame();
+  ASSERT_LE(2u, contents->GetAllFrames().size());
+  child_frame = contents->GetAllFrames()[1];
+
+  // document.wasDiscarded is true after discard, on mainframe and childframe.
+  bool discarded_mainframe_result;
+  EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+      main_frame, kDiscardedStateJS, &discarded_mainframe_result));
+  EXPECT_TRUE(discarded_mainframe_result);
+
+  bool discarded_childframe_result;
+  EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+      child_frame, kDiscardedStateJS, &discarded_childframe_result));
+  EXPECT_TRUE(discarded_childframe_result);
+
+  // Navigate the child frame, wasDiscarded is not set anymore.
+  // TODO(panicker): Add test to navigate the child frame cross site.
+  GURL childframe_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
+  EXPECT_TRUE(NavigateIframeToURL(contents, "frame1", childframe_url));
+  EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+      child_frame, kDiscardedStateJS, &discarded_childframe_result));
+  EXPECT_FALSE(discarded_childframe_result);
+
+  // Navigate the main frame (same site) again, wasDiscarded is not set anymore.
+  ui_test_utils::NavigateToURL(browser(), main_url);
+  EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+      main_frame, kDiscardedStateJS, &discarded_mainframe_result));
+  EXPECT_FALSE(discarded_mainframe_result);
+
+  // TODO(panicker): Add test to go back in history and ensure wasDiscarded is
+  // still false.
+}
+
 namespace {
 
 // Ensures that |browser| has |num_tabs| open tabs.
diff --git a/chrome/browser/resources/easy_unlock/OWNERS b/chrome/browser/resources/easy_unlock/OWNERS
index 0e2febfe..5ca3e8b 100644
--- a/chrome/browser/resources/easy_unlock/OWNERS
+++ b/chrome/browser/resources/easy_unlock/OWNERS
@@ -1,3 +1,4 @@
+jhawkins@chromium.org
 tengs@chromium.org
 tbarzic@chromium.org
 
diff --git a/chrome/browser/ui/android/infobars/installable_ambient_badge_infobar.cc b/chrome/browser/ui/android/infobars/installable_ambient_badge_infobar.cc
index 9fd938b9..4031453 100644
--- a/chrome/browser/ui/android/infobars/installable_ambient_badge_infobar.cc
+++ b/chrome/browser/ui/android/infobars/installable_ambient_badge_infobar.cc
@@ -32,6 +32,8 @@
 base::android::ScopedJavaLocalRef<jobject>
 InstallableAmbientBadgeInfoBar::CreateRenderInfoBar(JNIEnv* env) {
   InstallableAmbientBadgeInfoBarDelegate* delegate = GetDelegate();
+  base::android::ScopedJavaLocalRef<jstring> java_message_text =
+      base::android::ConvertUTF16ToJavaString(env, delegate->GetMessageText());
   base::android::ScopedJavaLocalRef<jstring> java_url =
       base::android::ConvertUTF8ToJavaString(env, delegate->GetUrl().spec());
 
@@ -39,9 +41,9 @@
   base::android::ScopedJavaLocalRef<jobject> java_bitmap =
       gfx::ConvertToJavaBitmap(&delegate->GetPrimaryIcon());
 
-  return Java_InstallableAmbientBadgeInfoBar_show(env, delegate->GetIconId(),
-                                                  java_bitmap, java_url,
-                                                  delegate->is_installed());
+  return Java_InstallableAmbientBadgeInfoBar_show(
+      env, delegate->GetIconId(), java_bitmap, java_message_text, java_url,
+      delegate->is_installed());
 }
 
 void InstallableAmbientBadgeInfoBar::ProcessButton(int action) {}
diff --git a/chrome/browser/ui/app_list/search/arc/arc_app_data_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/arc/arc_app_data_search_provider_unittest.cc
new file mode 100644
index 0000000..d02252b
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/arc/arc_app_data_search_provider_unittest.cc
@@ -0,0 +1,71 @@
+// Copyright 2018 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/search/arc/arc_app_data_search_provider.h"
+
+#include <memory>
+#include <utility>
+
+#include "ash/app_list/model/search/search_result.h"
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ui/app_list/app_list_test_util.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_test.h"
+#include "chrome/browser/ui/app_list/search/arc/icon_decode_request.h"
+#include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
+
+namespace app_list {
+
+class ArcAppDataSearchProviderTest : public AppListTestBase {
+ protected:
+  ArcAppDataSearchProviderTest() = default;
+  ~ArcAppDataSearchProviderTest() override = default;
+
+  // AppListTestBase:
+  void SetUp() override {
+    AppListTestBase::SetUp();
+    arc_test_.SetUp(profile());
+    controller_ = std::make_unique<test::TestAppListControllerDelegate>();
+  }
+
+  void TearDown() override {
+    controller_.reset();
+    arc_test_.TearDown();
+    AppListTestBase::TearDown();
+  }
+
+  std::unique_ptr<ArcAppDataSearchProvider> CreateSearch(int max_results) {
+    return std::make_unique<ArcAppDataSearchProvider>(max_results, profile(),
+                                                      controller_.get());
+  }
+
+ private:
+  std::unique_ptr<test::TestAppListControllerDelegate> controller_;
+  ArcAppTest arc_test_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcAppDataSearchProviderTest);
+};
+
+TEST_F(ArcAppDataSearchProviderTest, Basic) {
+  constexpr size_t kMaxResults = 6;
+  constexpr char kQuery[] = "App Data Search";
+
+  std::unique_ptr<ArcAppDataSearchProvider> provider =
+      CreateSearch(kMaxResults);
+  EXPECT_TRUE(provider->results().empty());
+  IconDecodeRequest::DisableSafeDecodingForTesting();
+
+  provider->Start(base::UTF8ToUTF16(kQuery));
+  const auto& results = provider->results();
+  EXPECT_EQ(kMaxResults, results.size());
+  // Check that information is correctly set in each result.
+  for (size_t i = 0; i < results.size(); ++i) {
+    SCOPED_TRACE(base::StringPrintf("Testing result %zu", i));
+    EXPECT_EQ(base::UTF16ToUTF8(results[i]->title()),
+              base::StringPrintf("Label %s %zu", kQuery, i));
+    EXPECT_EQ(SearchResult::DISPLAY_TILE, results[i]->display_type());
+  }
+}
+
+}  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/arc/arc_app_data_search_result.cc b/chrome/browser/ui/app_list/search/arc/arc_app_data_search_result.cc
index f4a3225e..e732c93 100644
--- a/chrome/browser/ui/app_list/search/arc/arc_app_data_search_result.cc
+++ b/chrome/browser/ui/app_list/search/arc/arc_app_data_search_result.cc
@@ -88,10 +88,7 @@
   icon_decode_request_ = std::make_unique<IconDecodeRequest>(
       base::BindOnce(&ArcAppDataSearchResult::SetIconToAvatarIcon,
                      weak_ptr_factory_.GetWeakPtr()));
-
-  ImageDecoder::StartWithOptions(icon_decode_request_.get(), icon_png_data(),
-                                 ImageDecoder::DEFAULT_CODEC, true,
-                                 gfx::Size());
+  icon_decode_request_->StartWithOptions(icon_png_data());
 }
 
 ArcAppDataSearchResult::~ArcAppDataSearchResult() = default;
diff --git a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider_unittest.cc
index b3cb280a..4a369bfa 100644
--- a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider_unittest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/ui/app_list/app_list_test_util.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_test.h"
 #include "chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.h"
+#include "chrome/browser/ui/app_list/search/arc/icon_decode_request.h"
 #include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
 #include "chrome/test/base/testing_profile.h"
 #include "extensions/common/extension_builder.h"
@@ -74,7 +75,7 @@
   std::unique_ptr<ArcPlayStoreSearchProvider> provider =
       CreateSearch(kMaxResults);
   EXPECT_TRUE(provider->results().empty());
-  ArcPlayStoreSearchResult::DisableSafeDecodingForTesting();
+  IconDecodeRequest::DisableSafeDecodingForTesting();
 
   AddExtension(CreateExtension(extension_misc::kGmailAppId).get());
 
diff --git a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc
index d6cebc2..cc23468 100644
--- a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc
+++ b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc
@@ -19,13 +19,11 @@
 #include "components/crx_file/id_util.h"
 #include "ui/app_list/app_list_constants.h"
 #include "ui/app_list/vector_icons/vector_icons.h"
-#include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/paint_vector_icon.h"
 
 namespace {
 
-bool disable_safe_decoding_for_testing = false;
 // The id prefix to identify a Play Store search result.
 constexpr char kPlayAppPrefix[] = "play://";
 // Badge icon color, #000 at 54% opacity.
@@ -57,11 +55,6 @@
 
 namespace app_list {
 
-// static
-void ArcPlayStoreSearchResult::DisableSafeDecodingForTesting() {
-  disable_safe_decoding_for_testing = true;
-}
-
 ArcPlayStoreSearchResult::ArcPlayStoreSearchResult(
     arc::mojom::AppDiscoveryResultPtr data,
     Profile* profile,
@@ -83,21 +76,7 @@
 
   icon_decode_request_ = std::make_unique<IconDecodeRequest>(base::BindOnce(
       &ArcPlayStoreSearchResult::SetIcon, weak_ptr_factory_.GetWeakPtr()));
-  if (disable_safe_decoding_for_testing) {
-    SkBitmap bitmap;
-    if (!icon_png_data().empty() &&
-        gfx::PNGCodec::Decode(
-            reinterpret_cast<const unsigned char*>(icon_png_data().data()),
-            icon_png_data().size(), &bitmap)) {
-      icon_decode_request_->OnImageDecoded(bitmap);
-    } else {
-      icon_decode_request_->OnDecodeImageFailed();
-    }
-  } else {
-    ImageDecoder::StartWithOptions(icon_decode_request_.get(), icon_png_data(),
-                                   ImageDecoder::DEFAULT_CODEC, true,
-                                   gfx::Size());
-  }
+  icon_decode_request_->StartWithOptions(icon_png_data());
 }
 
 ArcPlayStoreSearchResult::~ArcPlayStoreSearchResult() = default;
diff --git a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.h b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.h
index fed8c66..3846780 100644
--- a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.h
+++ b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.h
@@ -39,13 +39,6 @@
   // app_list::AppContextMenuDelegate overrides:
   void ExecuteLaunchCommand(int event_flags) override;
 
-  // Disables async safe decoding requests when unit tests are executed.
-  // Icons are decoded at a separate process created by ImageDecoder. In unit
-  // tests these tasks may not finish before the test exits, which causes a
-  // failure in the base::MessageLoop::current()->IsIdleForTesting() check
-  // in test_browser_thread_bundle.cc.
-  static void DisableSafeDecodingForTesting();
-
  private:
   const base::Optional<std::string>& install_intent_uri() const {
     return data_->install_intent_uri;
diff --git a/chrome/browser/ui/app_list/search/arc/icon_decode_request.cc b/chrome/browser/ui/app_list/search/arc/icon_decode_request.cc
index 7fc64a9..f0fc7970 100644
--- a/chrome/browser/ui/app_list/search/arc/icon_decode_request.cc
+++ b/chrome/browser/ui/app_list/search/arc/icon_decode_request.cc
@@ -4,10 +4,15 @@
 
 #include "chrome/browser/ui/app_list/search/arc/icon_decode_request.h"
 
-#include "ash/app_list/model/search/search_result.h"
+#include <memory>
+#include <utility>
+#include <vector>
+
 #include "chrome/grit/component_extension_resources.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/app_list/app_list_constants.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/image/image_skia_rep.h"
 #include "ui/gfx/image/image_skia_source.h"
@@ -18,6 +23,8 @@
 
 namespace {
 
+bool disable_safe_decoding_for_testing = false;
+
 class IconSource : public gfx::ImageSkiaSource {
  public:
   IconSource(const SkBitmap& decoded_bitmap, int resource_size_in_dip);
@@ -67,11 +74,37 @@
 
 }  // namespace
 
+// static
+void IconDecodeRequest::DisableSafeDecodingForTesting() {
+  disable_safe_decoding_for_testing = true;
+}
+
 IconDecodeRequest::IconDecodeRequest(SetIconCallback set_icon_callback)
     : set_icon_callback_(std::move(set_icon_callback)) {}
 
 IconDecodeRequest::~IconDecodeRequest() = default;
 
+void IconDecodeRequest::StartWithOptions(
+    const std::vector<uint8_t>& image_data) {
+  if (disable_safe_decoding_for_testing) {
+    if (image_data.empty()) {
+      OnDecodeImageFailed();
+      return;
+    }
+    SkBitmap bitmap;
+    if (!gfx::PNGCodec::Decode(
+            reinterpret_cast<const unsigned char*>(image_data.data()),
+            image_data.size(), &bitmap)) {
+      OnDecodeImageFailed();
+      return;
+    }
+    OnImageDecoded(bitmap);
+    return;
+  }
+  ImageDecoder::StartWithOptions(this, image_data, ImageDecoder::DEFAULT_CODEC,
+                                 true, gfx::Size());
+}
+
 void IconDecodeRequest::OnImageDecoded(const SkBitmap& bitmap) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
diff --git a/chrome/browser/ui/app_list/search/arc/icon_decode_request.h b/chrome/browser/ui/app_list/search/arc/icon_decode_request.h
index 2dd1116..154e36c 100644
--- a/chrome/browser/ui/app_list/search/arc/icon_decode_request.h
+++ b/chrome/browser/ui/app_list/search/arc/icon_decode_request.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_ARC_ICON_DECODE_REQUEST_H_
 #define CHROME_BROWSER_UI_APP_LIST_SEARCH_ARC_ICON_DECODE_REQUEST_H_
 
+#include <vector>
+
 #include "base/callback.h"
 #include "base/macros.h"
 #include "chrome/browser/image_decoder.h"
@@ -22,6 +24,17 @@
   explicit IconDecodeRequest(SetIconCallback set_icon_callback);
   ~IconDecodeRequest() override;
 
+  // Disables async safe decoding requests when unit tests are executed.
+  // Icons are decoded at a separate process created by ImageDecoder. In unit
+  // tests these tasks may not finish before the test exits, which causes a
+  // failure in the base::MessageLoop::current()->IsIdleForTesting() check
+  // in test_browser_thread_bundle.cc.
+  static void DisableSafeDecodingForTesting();
+
+  // Starts image decoding. Safe asynchronous decoding is used unless
+  // DisableSafeDecodingForTesting() is called.
+  void StartWithOptions(const std::vector<uint8_t>& image_data);
+
   // ImageDecoder::ImageRequest:
   void OnImageDecoded(const SkBitmap& bitmap) override;
   void OnDecodeImageFailed() override;
diff --git a/chrome/browser/ui/bubble_anchor_util.h b/chrome/browser/ui/bubble_anchor_util.h
index 69cfe0b3..2210c98 100644
--- a/chrome/browser/ui/bubble_anchor_util.h
+++ b/chrome/browser/ui/bubble_anchor_util.h
@@ -6,12 +6,15 @@
 #define CHROME_BROWSER_UI_BUBBLE_ANCHOR_UTIL_H_
 
 #include "build/build_config.h"
+#include "ui/gfx/native_widget_types.h"
 
 namespace gfx {
+class Point;
 class Rect;
 }
 
 class Browser;
+class ExtensionInstalledBubble;
 
 namespace bubble_anchor_util {
 
@@ -38,6 +41,12 @@
 // Returns the page info anchor rect for |browser|, which is assumed to have a
 // Cocoa browser window.
 gfx::Rect GetPageInfoAnchorRectCocoa(Browser* browser);
+
+// Returns the anchor point for the extension installed bubble for |window|,
+// which is assumed to be a Cocoa browser window.
+gfx::Point GetExtensionInstalledAnchorPointCocoa(
+    gfx::NativeWindow window,
+    const ExtensionInstalledBubble* bubble);
 #endif
 
 }  // namespace bubble_anchor_util
diff --git a/chrome/browser/ui/cocoa/bubble_anchor_util_views_mac.mm b/chrome/browser/ui/cocoa/bubble_anchor_util_views_mac.mm
index 875f87e..994273a 100644
--- a/chrome/browser/ui/cocoa/bubble_anchor_util_views_mac.mm
+++ b/chrome/browser/ui/cocoa/bubble_anchor_util_views_mac.mm
@@ -4,7 +4,15 @@
 
 #include "chrome/browser/ui/views/bubble_anchor_util_views.h"
 
-#include "chrome/browser/ui/cocoa/bubble_anchor_helper.h"
+#import <Cocoa/Cocoa.h>
+
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/bubble_anchor_helper.h"
+#import "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h"
+#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
+#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
+#include "chrome/browser/ui/extensions/extension_installed_bubble.h"
+#include "ui/base/cocoa/cocoa_base_utils.h"
 #include "ui/base/ui_features.h"
 #include "ui/gfx/geometry/rect.h"
 #import "ui/gfx/mac/coordinate_conversion.h"
@@ -21,6 +29,41 @@
       gfx::Size());
 }
 
+gfx::Point GetExtensionInstalledAnchorPointCocoa(
+    gfx::NativeWindow window,
+    const ExtensionInstalledBubble* bubble) {
+  BrowserWindowController* window_controller =
+      [BrowserWindowController browserWindowControllerForWindow:window];
+  ToolbarController* toolbar_controller = [window_controller toolbarController];
+
+  NSPoint arrow_point;
+  switch (bubble->anchor_position()) {
+    case ExtensionInstalledBubble::ANCHOR_ACTION: {
+      BrowserActionsController* controller =
+          [toolbar_controller browserActionsController];
+      arrow_point = [controller popupPointForId:bubble->extension()->id()];
+      break;
+    }
+    case ExtensionInstalledBubble::ANCHOR_OMNIBOX: {
+      LocationBarViewMac* locationBarView =
+          [window_controller locationBarBridge];
+      arrow_point = locationBarView->GetPageInfoBubblePoint();
+      break;
+    }
+    case ExtensionInstalledBubble::ANCHOR_APP_MENU: {
+      arrow_point = [toolbar_controller appMenuBubblePoint];
+      break;
+    }
+    default: {
+      NOTREACHED();
+      break;
+    }
+  }
+  // Convert to screen coordinates.
+  arrow_point = ui::ConvertPointFromWindowToScreen(window, arrow_point);
+  return gfx::ScreenPointFromNSPoint(arrow_point);
+}
+
 #if !BUILDFLAG(MAC_VIEWS_BROWSER)
 gfx::Rect GetPageInfoAnchorRect(Browser* browser) {
   return GetPageInfoAnchorRectCocoa(browser);
diff --git a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm
index 79b722f..d63f754 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm
@@ -20,6 +20,7 @@
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/bubble_anchor_util.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/cocoa/browser_dialogs_views_mac.h"
 #include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
@@ -123,44 +124,8 @@
 
 gfx::Point ExtensionInstalledBubble::GetAnchorPoint(
     gfx::NativeWindow window) const {
-  BrowserWindowController* windowController =
-      [BrowserWindowController browserWindowControllerForWindow:window];
-
-  auto getAppMenuButtonAnchorPoint = [windowController]() {
-    // Point at the bottom of the app menu menu.
-    NSView* appMenuButton =
-        [[windowController toolbarController] appMenuButton];
-    const NSRect bounds = [appMenuButton bounds];
-    NSPoint anchor = NSMakePoint(NSMidX(bounds), NSMaxY(bounds));
-    return [appMenuButton convertPoint:anchor toView:nil];
-  };
-
-  NSPoint arrowPoint;
-  switch (anchor_position()) {
-    case ExtensionInstalledBubble::ANCHOR_ACTION: {
-      BrowserActionsController* controller =
-          [[windowController toolbarController] browserActionsController];
-      arrowPoint = [controller popupPointForId:extension()->id()];
-      break;
-    }
-    case ExtensionInstalledBubble::ANCHOR_OMNIBOX: {
-      LocationBarViewMac* locationBarView =
-          [windowController locationBarBridge];
-      arrowPoint = locationBarView->GetPageInfoBubblePoint();
-      break;
-    }
-    case ExtensionInstalledBubble::ANCHOR_APP_MENU: {
-      arrowPoint = getAppMenuButtonAnchorPoint();
-      break;
-    }
-    default: {
-      NOTREACHED();
-      break;
-    }
-  }
-  // Convert to screen coordinates.
-  arrowPoint = ui::ConvertPointFromWindowToScreen(window, arrowPoint);
-  return gfx::ScreenPointFromNSPoint(arrowPoint);
+  return bubble_anchor_util::GetExtensionInstalledAnchorPointCocoa(window,
+                                                                   this);
 }
 
 // Implemented here to create the platform specific instance of the BubbleUi.
diff --git a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
index 6f33e99..60728e7 100644
--- a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/bubble_anchor_util.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/extensions/extension_installed_bubble.h"
 #include "chrome/browser/ui/singleton_tabs.h"
@@ -77,14 +78,15 @@
 #if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
 views::View* AnchorViewForBrowser(ExtensionInstalledBubble* controller,
                                   Browser* browser) {
-  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
-  views::View* reference_view = nullptr;
-
-#if defined(OS_MACOSX)
+// The Cocoa browser always needs to use an anchor point.
+#if BUILDFLAG(MAC_VIEWS_BROWSER)
   if (views_mode_controller::IsViewsBrowserCocoa())
     return nullptr;
 #endif
 
+  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
+  views::View* reference_view = nullptr;
+
   switch (controller->anchor_position()) {
     case ExtensionInstalledBubble::ANCHOR_ACTION: {
       BrowserActionsContainer* container =
@@ -109,10 +111,12 @@
     return browser_view->button_provider()->GetAppMenuButton();
   return reference_view;
 }
-#else
+#else  // OS_MACOSX && !MAC_VIEWS_BROWSER
+// Always use an anchor point in non-Views Mac builds. This needs a separate
+// implementation because non-Views Mac builds can't even reference BrowserView.
 views::View* AnchorViewForBrowser(ExtensionInstalledBubble* controller,
                                   Browser* browser) {
-  return nullptr;  // Always use the anchor point.
+  return nullptr;
 }
 #endif
 
@@ -387,6 +391,13 @@
 
 // Views (BrowserView) specific implementation.
 bool ExtensionInstalledBubble::ShouldShow() {
+#if BUILDFLAG(MAC_VIEWS_BROWSER)
+  // Cocoa browser windows can always show the bubble - no need to check for an
+  // animation.
+  // TODO(ellyjones): Is that actually true?
+  if (views_mode_controller::IsViewsBrowserCocoa())
+    return true;
+#endif
   if (anchor_position() == ANCHOR_ACTION) {
     BrowserActionsContainer* container =
         BrowserView::GetBrowserViewForBrowser(browser())
@@ -399,6 +410,11 @@
 
 gfx::Point ExtensionInstalledBubble::GetAnchorPoint(
     gfx::NativeWindow window) const {
+#if BUILDFLAG(MAC_VIEWS_BROWSER)
+  DCHECK(views_mode_controller::IsViewsBrowserCocoa());
+  return bubble_anchor_util::GetExtensionInstalledAnchorPointCocoa(window,
+                                                                   this);
+#endif
   NOTREACHED();  // There is always an anchor view.
   return gfx::Point();
 }
diff --git a/chrome/browser/ui/views/frame/hosted_app_button_container.cc b/chrome/browser/ui/views/frame/hosted_app_button_container.cc
index e3d70cc..7a977f3 100644
--- a/chrome/browser/ui/views/frame/hosted_app_button_container.cc
+++ b/chrome/browser/ui/views/frame/hosted_app_button_container.cc
@@ -24,6 +24,7 @@
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/paint_vector_icon.h"
+#include "ui/views/animation/ink_drop.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/widget/native_widget_aura.h"
@@ -33,6 +34,8 @@
 // Padding around content setting icons.
 constexpr int kContentSettingIconInteriorPadding = 4;
 
+constexpr int kMenuHighlightFadeDurationMs = 800;
+
 constexpr base::TimeDelta kContentSettingsFadeInDuration =
     base::TimeDelta::FromMilliseconds(500);
 
@@ -183,11 +186,34 @@
 
 void HostedAppButtonContainer::StartTitlebarAnimation(
     base::TimeDelta origin_text_slide_duration) {
+  app_menu_button_->StartHighlightAnimation(origin_text_slide_duration);
+
   fade_in_content_setting_buttons_timer_.Start(
       FROM_HERE, origin_text_slide_duration, content_settings_container_,
       &ContentSettingsContainer::FadeIn);
 }
 
+void HostedAppButtonContainer::AppMenuButton::StartHighlightAnimation(
+    base::TimeDelta duration) {
+  GetInkDrop()->SetHoverHighlightFadeDurationMs(kMenuHighlightFadeDurationMs);
+  GetInkDrop()->SetHovered(true);
+  GetInkDrop()->UseDefaultHoverHighlightFadeDuration();
+
+  highlight_off_timer_.Start(
+      FROM_HERE,
+      duration -
+          base::TimeDelta::FromMilliseconds(kMenuHighlightFadeDurationMs),
+      this, &HostedAppButtonContainer::AppMenuButton::FadeHighlightOff);
+}
+
+void HostedAppButtonContainer::AppMenuButton::FadeHighlightOff() {
+  if (!ShouldEnterHoveredState()) {
+    GetInkDrop()->SetHoverHighlightFadeDurationMs(kMenuHighlightFadeDurationMs);
+    GetInkDrop()->SetHovered(false);
+    GetInkDrop()->UseDefaultHoverHighlightFadeDuration();
+  }
+}
+
 HostedAppButtonContainer::HostedAppButtonContainer(BrowserView* browser_view,
                                                    SkColor active_icon_color,
                                                    SkColor inactive_icon_color)
diff --git a/chrome/browser/ui/views/frame/hosted_app_button_container.h b/chrome/browser/ui/views/frame/hosted_app_button_container.h
index 5e2015e..4a377eb8 100644
--- a/chrome/browser/ui/views/frame/hosted_app_button_container.h
+++ b/chrome/browser/ui/views/frame/hosted_app_button_container.h
@@ -66,7 +66,12 @@
 
     AppMenu* menu() { return menu_.get(); }
 
+    // Fades the menu button highlight on and off.
+    void StartHighlightAnimation(base::TimeDelta duration);
+
    private:
+    void FadeHighlightOff();
+
     // The containing browser view.
     BrowserView* browser_view_;
 
@@ -76,6 +81,8 @@
     std::unique_ptr<HostedAppMenuModel> menu_model_;
     std::unique_ptr<AppMenu> menu_;
 
+    base::OneShotTimer highlight_off_timer_;
+
     DISALLOW_COPY_AND_ASSIGN(AppMenuButton);
   };
 
diff --git a/chrome/browser/ui/webui/settings/settings_cookies_view_handler.cc b/chrome/browser/ui/webui/settings/settings_cookies_view_handler.cc
index b103257..9b31e54 100644
--- a/chrome/browser/ui/webui/settings/settings_cookies_view_handler.cc
+++ b/chrome/browser/ui/webui/settings/settings_cookies_view_handler.cc
@@ -333,6 +333,7 @@
 
   AllowJavascript();
   cookies_tree_model_.reset();
+  filter_.clear();
   sorted_sites_.clear();
   EnsureCookiesTreeModelCreated();
 }
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index a47403e2..fac872d 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -390,7 +390,7 @@
     "//components/security_state/core",
     "//components/toolbar:vector_icons",
     "//content/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//skia",
     "//testing/gtest",
     "//ui/accessibility:ax_enums_mojo",
diff --git a/chrome/browser/vr/elements/linear_layout.cc b/chrome/browser/vr/elements/linear_layout.cc
index 3b75a0b9..035b3ec 100644
--- a/chrome/browser/vr/elements/linear_layout.cc
+++ b/chrome/browser/vr/elements/linear_layout.cc
@@ -77,10 +77,31 @@
   for (auto& child : children()) {
     if (!child->requires_layout())
       continue;
-    float extent = GetExtent(*child, horizontal);
-    float offset = cumulative_offset + 0.5 * extent;
-    child->SetLayoutOffset(offset * x_factor, offset * y_factor);
-    cumulative_offset += extent + margin_;
+    float child_extent = GetExtent(*child, horizontal);
+    float child_minor_extent = GetExtent(*child, !horizontal);
+    float offset = cumulative_offset + 0.5 * child_extent;
+    float x_align_offset = 0.0f;
+    float y_align_offset = 0.0f;
+    if (Horizontal()) {
+      DCHECK_NE(RIGHT, child->x_anchoring());
+      DCHECK_NE(LEFT, child->x_anchoring());
+      if (child->y_anchoring() == TOP || child->y_anchoring() == BOTTOM) {
+        y_align_offset = 0.5f * (minor_extent - child_minor_extent);
+        if (child->y_anchoring() == BOTTOM)
+          y_align_offset *= -1.0f;
+      }
+    } else {
+      DCHECK_NE(TOP, child->y_anchoring());
+      DCHECK_NE(BOTTOM, child->y_anchoring());
+      if (child->x_anchoring() == RIGHT || child->x_anchoring() == LEFT) {
+        x_align_offset = 0.5f * (minor_extent - child_minor_extent);
+        if (child->x_anchoring() == LEFT)
+          x_align_offset *= -1.0f;
+      }
+    }
+    child->SetLayoutOffset(offset * x_factor + x_align_offset,
+                           offset * y_factor + y_align_offset);
+    cumulative_offset += child_extent + margin_;
   }
 
   SetSize(horizontal ? total_extent : minor_extent,
diff --git a/chrome/browser/vr/elements/linear_layout_unittest.cc b/chrome/browser/vr/elements/linear_layout_unittest.cc
index b3d8d0c..c325fad 100644
--- a/chrome/browser/vr/elements/linear_layout_unittest.cc
+++ b/chrome/browser/vr/elements/linear_layout_unittest.cc
@@ -26,7 +26,7 @@
 
 }  // namespace
 
-TEST(LinearLayout, HorizontalLayout) {
+TEST(LinearLayout, HorizontalVerticalLayout) {
   LinearLayout layout(LinearLayout::kRight);
   layout.set_margin(10);
   auto element = std::make_unique<UiElement>();
@@ -62,6 +62,72 @@
 
   rect_a->set_requires_layout(false);
   layout.LayOutChildren();
+
+  EXPECT_FLOAT_EQ(20.0f, layout.size().width());
+}
+
+TEST(LinearLayout, Alignment) {
+  LinearLayout layout(LinearLayout::kRight);
+  layout.set_margin(10);
+  auto element = std::make_unique<UiElement>();
+  UiElement* rect_a = element.get();
+  rect_a->SetSize(1, 1);
+  layout.AddChild(std::move(element));
+  element = std::make_unique<UiElement>();
+  UiElement* rect_b = element.get();
+
+  rect_b->SetSize(10, 10);
+  rect_b->SetScale(2.0f, 2.0f, 0.0f);
+  layout.AddChild(std::move(element));
+
+  gfx::Point3F position_a;
+  rect_a->set_y_anchoring(TOP);
+  layout.LayOutChildren();
+  rect_a->LocalTransform().TransformPoint(&position_a);
+  EXPECT_FLOAT_EQ(9.5f, position_a.y());
+  position_a = gfx::Point3F();
+  rect_a->set_y_anchoring(BOTTOM);
+  layout.LayOutChildren();
+  rect_a->LocalTransform().TransformPoint(&position_a);
+  EXPECT_FLOAT_EQ(-9.5f, position_a.y());
+
+  layout.set_direction(LinearLayout::kLeft);
+  position_a = gfx::Point3F();
+  rect_a->set_y_anchoring(TOP);
+  layout.LayOutChildren();
+  rect_a->LocalTransform().TransformPoint(&position_a);
+  EXPECT_FLOAT_EQ(9.5f, position_a.y());
+  position_a = gfx::Point3F();
+  rect_a->set_y_anchoring(BOTTOM);
+  layout.LayOutChildren();
+  rect_a->LocalTransform().TransformPoint(&position_a);
+  EXPECT_FLOAT_EQ(-9.5f, position_a.y());
+
+  layout.set_direction(LinearLayout::kDown);
+  position_a = gfx::Point3F();
+  rect_a->set_x_anchoring(LEFT);
+  rect_a->set_y_anchoring(NONE);
+  layout.LayOutChildren();
+  rect_a->LocalTransform().TransformPoint(&position_a);
+  EXPECT_FLOAT_EQ(-9.5f, position_a.x());
+  position_a = gfx::Point3F();
+  rect_a->set_x_anchoring(RIGHT);
+  layout.LayOutChildren();
+  rect_a->LocalTransform().TransformPoint(&position_a);
+  EXPECT_FLOAT_EQ(9.5f, position_a.x());
+
+  layout.set_direction(LinearLayout::kUp);
+  position_a = gfx::Point3F();
+  rect_a->set_x_anchoring(LEFT);
+  rect_a->set_y_anchoring(NONE);
+  layout.LayOutChildren();
+  rect_a->LocalTransform().TransformPoint(&position_a);
+  EXPECT_FLOAT_EQ(-9.5f, position_a.x());
+  position_a = gfx::Point3F();
+  rect_a->set_x_anchoring(RIGHT);
+  layout.LayOutChildren();
+  rect_a->LocalTransform().TransformPoint(&position_a);
+  EXPECT_FLOAT_EQ(9.5f, position_a.x());
 }
 
 TEST(LinearLayout, Orientations) {
diff --git a/chrome/browser/vr/ui_scene_creator.cc b/chrome/browser/vr/ui_scene_creator.cc
index 56fab4be..a921d4166 100644
--- a/chrome/browser/vr/ui_scene_creator.cc
+++ b/chrome/browser/vr/ui_scene_creator.cc
@@ -1032,6 +1032,7 @@
       VR_BIND_LAMBDA([](ContentElement* e,
                         const EditedText& value) { e->UpdateInput(value); },
                      base::Unretained(main_content.get()))));
+
   shadow->AddChild(std::move(main_content));
   resizer->AddChild(std::move(shadow));
   scene_->AddUiElement(k2dBrowsingContentGroup, std::move(resizer));
@@ -1965,7 +1966,6 @@
   omnibox_text_field->set_hit_testable(false);
   omnibox_text_field->SetHintText(
       l10n_util::GetStringUTF16(IDS_SEARCH_OR_TYPE_WEB_ADDRESS));
-  omnibox_text_field->set_x_anchoring(LEFT);
   omnibox_text_field->SetSize(kOmniboxWidthDMM - 2 * kOmniboxTextMarginDMM -
                                   kOmniboxTextFieldIconButtonSizeDMM -
                                   kOmniboxTextFieldRightMargin,
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 8de55780..4f1731b 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -262,7 +262,7 @@
     "//gpu/config",
     "//ipc",
     "//media",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/bindings",
     "//pdf:features",
     "//ppapi/features",
diff --git a/chrome/common/profiling/BUILD.gn b/chrome/common/profiling/BUILD.gn
index 2080ad8..1247f88 100644
--- a/chrome/common/profiling/BUILD.gn
+++ b/chrome/common/profiling/BUILD.gn
@@ -28,7 +28,7 @@
     "//base/allocator:buildflags",
     "//chrome/common:constants",
     "//content/public/common",
-    "//mojo/edk/system",
+    "//mojo/edk",
   ]
 }
 
@@ -51,7 +51,7 @@
   deps = [
     ":profiling",
     "//base",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//testing/gtest",
   ]
 }
diff --git a/chrome/common/stack_sampling_configuration.cc b/chrome/common/stack_sampling_configuration.cc
index 0f97dcc..94fb216 100644
--- a/chrome/common/stack_sampling_configuration.cc
+++ b/chrome/common/stack_sampling_configuration.cc
@@ -72,29 +72,20 @@
     : configuration_(GenerateConfiguration()) {
 }
 
-base::StackSamplingProfiler::SamplingParams
-StackSamplingConfiguration::GetSamplingParamsForCurrentProcess() const {
-  base::StackSamplingProfiler::SamplingParams params;
-  params.bursts = 1;
-  params.initial_delay = base::TimeDelta::FromMilliseconds(0);
-  params.sampling_interval = base::TimeDelta::FromMilliseconds(0);
-  params.samples_per_burst = 0;
-
-  if (IsProfilerEnabledForCurrentProcess()) {
-    const base::TimeDelta duration = base::TimeDelta::FromSeconds(30);
-    params.sampling_interval = base::TimeDelta::FromMilliseconds(100);
-    params.samples_per_burst = duration / params.sampling_interval;
-  }
-
-  return params;
-}
-
-bool StackSamplingConfiguration::IsProfilerEnabledForCurrentProcess() const {
+bool StackSamplingConfiguration::IsProfilerEnabledForThread(
+    metrics::CallStackProfileParams::Thread thread) const {
   if (IsBrowserProcess()) {
     return configuration_ == PROFILE_ENABLED ||
            configuration_ == PROFILE_CONTROL;
   }
 
+#if defined(OS_MACOSX)
+  // Disabled pending a resolution to crashes on Intel GPU tests. See
+  // https://crbug.com/774682.
+  if (thread == metrics::CallStackProfileParams::GPU_MAIN_THREAD)
+    return false;
+#endif
+
   DCHECK_EQ(PROFILE_FROM_COMMAND_LINE, configuration_);
   // This is a child process. The |kStartStackProfiler| switch passed by the
   // browser process determines whether the profiler is enabled for the process.
diff --git a/chrome/common/stack_sampling_configuration.h b/chrome/common/stack_sampling_configuration.h
index 8a51ae92..e430dba3 100644
--- a/chrome/common/stack_sampling_configuration.h
+++ b/chrome/common/stack_sampling_configuration.h
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/profiler/stack_sampling_profiler.h"
+#include "components/metrics/call_stack_profile_params.h"
 
 namespace base {
 class CommandLine;
@@ -23,12 +24,10 @@
  public:
   StackSamplingConfiguration();
 
-  // Get the stack sampling params to use for this process.
-  base::StackSamplingProfiler::SamplingParams
-      GetSamplingParamsForCurrentProcess() const;
-
-  // Returns true if the profiler should be started for the current process.
-  bool IsProfilerEnabledForCurrentProcess() const;
+  // Returns true if the profiler should be started for the specified thread in
+  // the current process.
+  bool IsProfilerEnabledForThread(
+      metrics::CallStackProfileParams::Thread thread) const;
 
   // Get the synthetic field trial configuration. Returns true if a synthetic
   // field trial should be registered. This should only be called from the
diff --git a/chrome/common/thread_profiler.cc b/chrome/common/thread_profiler.cc
index f199b782..9ae9d7f 100644
--- a/chrome/common/thread_profiler.cc
+++ b/chrome/common/thread_profiler.cc
@@ -124,8 +124,10 @@
 
 void ThreadProfiler::SetMainThreadTaskRunner(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
-  if (!StackSamplingConfiguration::Get()->IsProfilerEnabledForCurrentProcess())
+  if (!StackSamplingConfiguration::Get()->IsProfilerEnabledForThread(
+          periodic_profile_params_.thread)) {
     return;
+  }
 
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
@@ -139,7 +141,7 @@
 // static
 void ThreadProfiler::StartOnChildThread(
     metrics::CallStackProfileParams::Thread thread) {
-  if (!StackSamplingConfiguration::Get()->IsProfilerEnabledForCurrentProcess())
+  if (!StackSamplingConfiguration::Get()->IsProfilerEnabledForThread(thread))
     return;
 
   auto profiler = std::unique_ptr<ThreadProfiler>(
@@ -149,9 +151,6 @@
 
 void ThreadProfiler::SetServiceManagerConnectorForChildProcess(
     service_manager::Connector* connector) {
-  if (!StackSamplingConfiguration::Get()->IsProfilerEnabledForCurrentProcess())
-    return;
-
   DCHECK_NE(metrics::CallStackProfileParams::BROWSER_PROCESS, GetProcess());
 
   metrics::mojom::CallStackProfileCollectorPtr browser_interface;
@@ -194,7 +193,7 @@
           metrics::CallStackProfileParams::PERIODIC_COLLECTION,
           metrics::CallStackProfileParams::MAY_SHUFFLE),
       weak_factory_(this) {
-  if (!StackSamplingConfiguration::Get()->IsProfilerEnabledForCurrentProcess())
+  if (!StackSamplingConfiguration::Get()->IsProfilerEnabledForThread(thread))
     return;
 
   startup_profiler_ = std::make_unique<base::StackSamplingProfiler>(
diff --git a/chrome/profiling/BUILD.gn b/chrome/profiling/BUILD.gn
index 9e3c6dc..5c1d7c45 100644
--- a/chrome/profiling/BUILD.gn
+++ b/chrome/profiling/BUILD.gn
@@ -39,7 +39,7 @@
     "//base",
     "//chrome/common",
     "//content/public/child",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//services/resource_coordinator/public/cpp:resource_coordinator_cpp",
     "//third_party/zlib",
   ]
diff --git a/chrome/service/BUILD.gn b/chrome/service/BUILD.gn
index 31ea147d..e408961 100644
--- a/chrome/service/BUILD.gn
+++ b/chrome/service/BUILD.gn
@@ -66,7 +66,7 @@
     "//components/printing/common",
     "//google_apis",
     "//jingle:notifier",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//net",
     "//printing",
     "//skia",
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 12b8b0ca..5e5eae9f 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -4311,6 +4311,7 @@
       "../browser/ui/app_list/profile_loader_unittest.cc",
       "../browser/ui/app_list/search/answer_card/answer_card_result_unittest.cc",
       "../browser/ui/app_list/search/answer_card/answer_card_search_provider_unittest.cc",
+      "../browser/ui/app_list/search/arc/arc_app_data_search_provider_unittest.cc",
       "../browser/ui/app_list/search/arc/arc_playstore_search_provider_unittest.cc",
       "../browser/ui/app_list/search/launcher_search/launcher_search_icon_image_loader_unittest.cc",
       "../browser/ui/app_list/search/tests/app_search_provider_unittest.cc",
@@ -4666,7 +4667,7 @@
       "//crypto:test_support",
       "//extensions/buildflags",
       "//google_apis:test_support",
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//net",
       "//net:net_resources",
       "//net:test_support",
@@ -4834,7 +4835,7 @@
         "//ash/resources",
         "//chrome/browser/media/router:test_support",
         "//chromeos",
-        "//mojo/edk/system",
+        "//mojo/edk",
       ]
 
       data += [
diff --git a/chrome/test/chromedriver/capabilities.cc b/chrome/test/chromedriver/capabilities.cc
index 6ffc4cb..7c29240 100644
--- a/chrome/test/chromedriver/capabilities.cc
+++ b/chrome/test/chromedriver/capabilities.cc
@@ -66,10 +66,11 @@
 Status ParseTimeDelta(base::TimeDelta* to_set,
                       const base::Value& option,
                       Capabilities* capabilities) {
-  int milliseconds;
-  Status status = ParseInterval(&milliseconds, option, capabilities);
-  if (status.IsError())
-    return status;
+  int milliseconds = 0;
+  if (!option.GetAsInteger(&milliseconds))
+    return Status(kUnknownError, "must be an integer");
+  if (milliseconds < 0)
+    return Status(kUnknownError, "must be positive or zero");
   *to_set = base::TimeDelta::FromMilliseconds(milliseconds);
   return Status(kOk);
 }
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index c16322f..00cb328 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -258,14 +258,6 @@
         'ChromeDriverTest.testEmulateNetworkConditionsOffline',
         'ChromeDriverTest.testEmulateNetworkConditionsSpeed',
         'ChromeDriverTest.testEmulateNetworkConditionsName',
-        # The WebView shell that we test against (on KitKat) does not yet
-        # support Synthetic Gesture DevTools commands.
-        # TODO(samuong): reenable when it does.
-        'ChromeDriverTest.testHasTouchScreen',
-        'ChromeDriverTest.testTouchScrollElement',
-        'ChromeDriverTest.testTouchDoubleTapElement',
-        'ChromeDriverTest.testTouchLongPressElement',
-        'ChromeDriverTest.testTouchPinch',
         # WebView shell doesn't support popups or popup blocking.
         'ChromeDriverTest.testPopups',
         'ChromeDriverTest.testDontGoBackOrGoForward',
@@ -1448,15 +1440,6 @@
     width_after_pinch = self._driver.ExecuteScript('return window.innerWidth;')
     self.assertAlmostEqual(2.0, float(width_before_pinch) / width_after_pinch)
 
-  def testBrowserDoesntSupportSyntheticGestures(self):
-    # WebView on KitKat does not support synthetic gesture commands in DevTools,
-    # so touch action tests have been disabled for chromedriver_webview_shell.
-    # TODO(samuong): when this test starts failing, re-enable touch tests and
-    # delete this test.
-    if _ANDROID_PACKAGE_KEY:
-      if _ANDROID_PACKAGE_KEY == 'chromedriver_webview_shell':
-        self.assertFalse(self._driver.capabilities['hasTouchScreen'])
-
   def testHasTouchScreen(self):
     self.assertIn('hasTouchScreen', self._driver.capabilities)
     if _ANDROID_PACKAGE_KEY:
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index 758e3be..0e5668e 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -323,13 +323,12 @@
         'TypingTest.testShouldReportKeyCodeOfArrowKeys',
          # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1006
         'ClickScrollingTest.testShouldBeAbleToClickElementThatIsOutOfViewInANestedFrameThatIsOutOfView',
+	 # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2330
+	 'VisibilityTest.testShouldModifyTheVisibilityOfAnElementDynamically',
          # Not applicable on ChromeDriverWebViewShell (doesn't support tabs).
         'WindowSwitchingTest.*',
 
         'TakesScreenshotTest.testShouldCaptureScreenshot',
-        # TODO(gmanikpure): re-enable this test when we stop supporting
-        # WebView on KitKat.
-        'ClickTest.testCanClickAnImageMapArea',
     ]
 )
 
diff --git a/chrome/test/media_router/media_router_integration_browsertest.cc b/chrome/test/media_router/media_router_integration_browsertest.cc
index afa3c9f4..7281872e 100644
--- a/chrome/test/media_router/media_router_integration_browsertest.cc
+++ b/chrome/test/media_router/media_router_integration_browsertest.cc
@@ -706,7 +706,7 @@
 // Tests that creating a route with a local file opens the file in a new tab.
 // TODO(crbug.com/818767): Fails when run with Chromium component.
 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
-                       DISABLED_OpenLocalMediaFileInCurrentTab) {
+                       MANUAL_OpenLocalMediaFileInCurrentTab) {
   // Start at a new tab, the file should open in the same tab.
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
   // Make sure there is 1 tab.
@@ -755,7 +755,7 @@
 // Tests that creating a route with a local file opens in fullscreen.
 // TODO(crbug.com/822029): Fails on msan; fix and re-enable.
 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
-                       DISABLED_OpenLocalMediaFileFullscreen) {
+                       MANUAL_OpenLocalMediaFileFullscreen) {
   // Start at a new tab, the file should open in the same tab.
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
   // Make sure there is 1 tab.
@@ -887,7 +887,7 @@
   RunBasicTest();
 }
 
-// TODO(crbug.com/822300): Flaky test.
+// TODO(crbug.com/822300): Flaky in Chromium waterfall.
 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationIncognitoBrowserTest,
                        MANUAL_ReconnectSession) {
   RunReconnectSessionTest();
diff --git a/chrome/test/media_router/media_router_integration_ui_browsertest.cc b/chrome/test/media_router/media_router_integration_ui_browsertest.cc
index 6f76ef67..a2373c06f 100644
--- a/chrome/test/media_router/media_router_integration_ui_browsertest.cc
+++ b/chrome/test/media_router/media_router_integration_ui_browsertest.cc
@@ -133,8 +133,9 @@
   LOG(INFO) << "Closed dialog, end of test";
 }
 
+// TODO(crbug.com/822301): Flaky in Chromium waterfall.
 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
-                       Dialog_RouteCreationTimedOut) {
+                       MANUAL_Dialog_RouteCreationTimedOut) {
   SetTestData(FILE_PATH_LITERAL("route_creation_timed_out.json"));
   OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
   content::WebContents* web_contents =
diff --git a/chrome/test/media_router/media_router_one_ua_integration_browsertest.cc b/chrome/test/media_router/media_router_one_ua_integration_browsertest.cc
index 13e56fc..e5d96d21 100644
--- a/chrome/test/media_router/media_router_one_ua_integration_browsertest.cc
+++ b/chrome/test/media_router/media_router_one_ua_integration_browsertest.cc
@@ -42,18 +42,20 @@
   }
 };
 
-IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUABrowserTest, Basic) {
+// TODO(crbug.com/822231): Flaky in Chromium waterfall.
+IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUABrowserTest, MANUAL_Basic) {
   RunBasicTest();
 }
 
+// TODO(crbug.com/822216): Flaky in Chromium waterfall.
 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUABrowserTest,
-                       SendAndOnMessage) {
+                       MANUAL_SendAndOnMessage) {
   RunSendMessageTest("foo");
 }
 
 // TODO(crbug.com/821717): Flaky in Chromium waterfall.
 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUABrowserTest,
-                       DISABLED_ReceiverCloseConnection) {
+                       MANUAL_ReceiverCloseConnection) {
   WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
   CheckSessionValidity(web_contents);
   ExecuteJavaScriptAPI(web_contents, kInitiateCloseFromReceiverPageScript);
@@ -66,13 +68,13 @@
 
 // TODO(crbug.com/821717): Flaky in Chromium waterfall.
 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUABrowserTest,
-                       DISABLED_ReconnectSession) {
+                       MANUAL_ReconnectSession) {
   RunReconnectSessionTest();
 }
 
 // TODO(crbug.com/821717): Flaky in Chromium waterfall.
 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUABrowserTest,
-                       DISABLED_ReconnectSessionSameTab) {
+                       MANUAL_ReconnectSessionSameTab) {
   RunReconnectSessionSameTabTest();
 }
 
@@ -85,14 +87,15 @@
   }
 };
 
+// TODO(crbug.com/822179,822337): Flaky in Chromium waterfall.
 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUANoReceiverBrowserTest,
-                       Basic) {
+                       MANUAL_Basic) {
   RunBasicTest();
 }
 
 // TODO(crbug.com/821717): Flaky in Chromium waterfall.
 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationOneUANoReceiverBrowserTest,
-                       DISABLED_Fail_SendMessage) {
+                       MANUAL_Fail_SendMessage) {
   RunFailToSendMessageTest();
 }
 
diff --git a/chrome/test/vr/auto_bisect.py b/chrome/test/vr/auto_bisect.py
index b14496c9..2debc78 100755
--- a/chrome/test/vr/auto_bisect.py
+++ b/chrome/test/vr/auto_bisect.py
@@ -74,7 +74,8 @@
           'received %d' % len(split_arg))
     return {split_arg[0]: split_arg[1]}
   parser.add_argument('--checkout-override', action='append',
-                      type=comma_separated, dest='checkout_overrides',
+                      type=comma_separated, default=[],
+                      dest='checkout_overrides',
                       help='A comma-separated path/revision key/value pair. '
                            'Each git checkout at the specified path will be '
                            'synced to the specified revision after the normal '
@@ -396,6 +397,8 @@
     unknown_args: The unknown args parsed by the argument parser
   """
   with TempDir() as output_dir:
+    # Ensure that we also sync any APKs we use
+    os.environ['DOWNLOAD_VR_TEST_APKS'] = '1'
     try:
       if args.good_value == None:
         args.good_value = GetValueAtRevision(args, unknown_args,
diff --git a/chromecast/app/BUILD.gn b/chromecast/app/BUILD.gn
index ff92e91..a1660b36 100644
--- a/chromecast/app/BUILD.gn
+++ b/chromecast/app/BUILD.gn
@@ -81,7 +81,7 @@
     "//chromecast/base",
     "//content/test:test_support",
     "//ipc",
-    "//mojo/edk/embedder:headers",
+    "//mojo/edk",
   ]
 }
 
diff --git a/chromecast/graphics/BUILD.gn b/chromecast/graphics/BUILD.gn
index 42332da1..63a58718 100644
--- a/chromecast/graphics/BUILD.gn
+++ b/chromecast/graphics/BUILD.gn
@@ -87,7 +87,7 @@
     deps = [
       ":graphics",
       "//base/test:test_support",
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//testing/gtest",
       "//ui/aura",
       "//ui/aura:test_support",
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn
index ebc57b2..e0f8f6e 100644
--- a/components/arc/BUILD.gn
+++ b/components/arc/BUILD.gn
@@ -93,7 +93,7 @@
     "//device/usb/mojo",
     "//device/usb/public/mojom",
     "//google_apis",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//services/device/public/mojom",
     "//skia",
     "//third_party/re2:re2",
@@ -164,7 +164,7 @@
     "//components/prefs",
     "//components/signin/core/account_id",
     "//components/user_manager",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//ui/aura",
   ]
 
@@ -223,7 +223,7 @@
     "//components/user_prefs",
     "//content/test:test_support",
     "//mojo/common:common_base",
-    "//mojo/edk/embedder:headers",
+    "//mojo/edk",
   ]
 }
 
diff --git a/components/arc/test/fake_app_instance.cc b/components/arc/test/fake_app_instance.cc
index 928bd54..c47238a 100644
--- a/components/arc/test/fake_app_instance.cc
+++ b/components/arc/test/fake_app_instance.cc
@@ -345,8 +345,22 @@
     const std::string& query,
     int32_t max_results,
     GetIcingGlobalQueryResultsCallback callback) {
+  // Fake successful app data search results.
+  std::vector<arc::mojom::AppDataResultPtr> fake_app_data_results;
+  for (int i = 0; i < max_results; ++i) {
+    // Fake icon data.
+    std::string png_data_as_string;
+    GetFakeIcon(mojom::ScaleFactor::SCALE_FACTOR_100P, &png_data_as_string);
+    std::vector<uint8_t> fake_icon_png_data(png_data_as_string.begin(),
+                                            png_data_as_string.end());
+
+    fake_app_data_results.emplace_back(mojom::AppDataResult::New(
+        base::StringPrintf("LaunchIntentUri %d", i),
+        base::StringPrintf("Label %s %d", query.c_str(), i),
+        fake_icon_png_data));
+  }
   std::move(callback).Run(arc::mojom::AppDataRequestState::REQUEST_SUCCESS,
-                          std::vector<arc::mojom::AppDataResultPtr>());
+                          std::move(fake_app_data_results));
 }
 
 void FakeAppInstance::StartPaiFlow() {
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn
index 1efe718..5d4d32d 100644
--- a/components/exo/BUILD.gn
+++ b/components/exo/BUILD.gn
@@ -198,7 +198,7 @@
     "//cc:test_support",
     "//components/viz/test:test_support",
     "//device/gamepad:test_helpers",
-    "//mojo/edk/embedder:headers",
+    "//mojo/edk",
     "//testing/gtest",
     "//ui/aura",
     "//ui/aura:test_support",
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc
index 142d5c9..c8ad99a 100644
--- a/components/exo/client_controlled_shell_surface.cc
+++ b/components/exo/client_controlled_shell_surface.cc
@@ -364,21 +364,14 @@
     state_changed_callback_.Run(current_state, next_state);
 }
 
-void ClientControlledShellSurface::StartResize(int component) {
-  TRACE_EVENT1("exo", "ClientControlledShellSurface::StartResize", "component",
-               component);
+void ClientControlledShellSurface::StartDrag(int component,
+                                             const gfx::Point& location) {
+  TRACE_EVENT2("exo", "ClientControlledShellSurface::StartResize", "component",
+               component, "location", location.ToString());
 
-  if (!widget_ || client_controlled_move_resize_)
+  if (!widget_ || (client_controlled_move_resize_ && component != HTCAPTION))
     return;
-  AttemptToStartDrag(component, GetMouseLocation());
-}
-
-void ClientControlledShellSurface::StartMove(const gfx::Point& location) {
-  TRACE_EVENT0("exo", "ClientControlledShellSurface::StartMove");
-
-  if (!widget_)
-    return;
-  AttemptToStartDrag(HTCAPTION, location);
+  AttemptToStartDrag(component, location);
 }
 
 void ClientControlledShellSurface::AttemptToStartDrag(
diff --git a/components/exo/client_controlled_shell_surface.h b/components/exo/client_controlled_shell_surface.h
index b046bf3..8653ae1 100644
--- a/components/exo/client_controlled_shell_surface.h
+++ b/components/exo/client_controlled_shell_surface.h
@@ -150,10 +150,8 @@
   void OnDragStarted(int component);
   void OnDragFinished(bool cancel, const gfx::Point& location);
 
-  void StartResize(int component);
-
-  // Starts the move-by-drag operation.
-  void StartMove(const gfx::Point& location);
+  // Starts the drag operation.
+  void StartDrag(int component, const gfx::Point& location);
 
   // Set if the surface can be maximzied.
   void SetCanMaximize(bool can_maximize);
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc
index a0e69eb..669b847 100644
--- a/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -876,9 +876,8 @@
   surface->Attach(desktop_buffer.get());
   shell_surface->SetGeometry(gfx::Rect(window_size));
   surface->Commit();
-
   EXPECT_TRUE(shell_surface->GetWidget()->widget_delegate()->CanResize());
-  shell_surface->StartResize(HTTOP);
+  shell_surface->StartDrag(HTTOP, gfx::Point(0, 0));
 
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   // Client cannot start drag if mouse isn't pressed.
@@ -889,7 +888,7 @@
   ui::test::EventGenerator& event_generator = GetEventGenerator();
   event_generator.MoveMouseToCenterOf(window);
   event_generator.PressLeftButton();
-  shell_surface->StartResize(HTTOP);
+  shell_surface->StartDrag(HTTOP, gfx::Point(0, 0));
   ASSERT_TRUE(window_state->is_dragged());
   event_generator.ReleaseLeftButton();
   ASSERT_FALSE(window_state->is_dragged());
@@ -897,7 +896,7 @@
   // Press pressed outside of the window.
   event_generator.MoveMouseTo(gfx::Point(200, 50));
   event_generator.PressLeftButton();
-  shell_surface->StartResize(HTTOP);
+  shell_surface->StartDrag(HTTOP, gfx::Point(0, 0));
   ASSERT_FALSE(window_state->is_dragged());
 }
 
diff --git a/components/exo/wayland/BUILD.gn b/components/exo/wayland/BUILD.gn
index 4244919..0094ab1e 100644
--- a/components/exo/wayland/BUILD.gn
+++ b/components/exo/wayland/BUILD.gn
@@ -336,7 +336,7 @@
     "//cc:test_support",
     "//components/exo",
     "//components/viz/test:test_support",
-    "//mojo/edk/embedder:headers",
+    "//mojo/edk",
     "//testing/perf",
     "//ui/aura",
     "//ui/aura:test_support",
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc
index 543b2e0..dfcba8b7 100644
--- a/components/exo/wayland/server.cc
+++ b/components/exo/wayland/server.cc
@@ -2126,9 +2126,7 @@
   }
 }
 
-void remote_surface_resize(wl_client* client,
-                           wl_resource* resource,
-                           uint32_t direction) {
+void remote_surface_resize(wl_client* client, wl_resource* resource) {
   // DEPRECATED
 }
 
@@ -2143,8 +2141,8 @@
                                wl_resource* resource,
                                int32_t x,
                                int32_t y) {
-  GetUserDataAs<ClientControlledShellSurface>(resource)->StartMove(
-      gfx::Point(x, y));
+  GetUserDataAs<ClientControlledShellSurface>(resource)->StartDrag(
+      HTCAPTION, gfx::Point(x, y));
 }
 
 void remote_surface_set_can_maximize(wl_client* client, wl_resource* resource) {
@@ -2184,9 +2182,11 @@
 
 void remote_surface_start_resize(wl_client* client,
                                  wl_resource* resource,
-                                 uint32_t direction) {
-  GetUserDataAs<ClientControlledShellSurface>(resource)->StartResize(
-      Component(direction));
+                                 uint32_t direction,
+                                 int32_t x,
+                                 int32_t y) {
+  GetUserDataAs<ClientControlledShellSurface>(resource)->StartDrag(
+      Component(direction), gfx::Point(x, y));
 }
 
 const struct zcr_remote_surface_v1_interface remote_surface_implementation = {
diff --git a/components/nacl/broker/BUILD.gn b/components/nacl/broker/BUILD.gn
index 07ffe2a..fe238f3 100644
--- a/components/nacl/broker/BUILD.gn
+++ b/components/nacl/broker/BUILD.gn
@@ -28,7 +28,7 @@
     "//components/nacl/common:switches",
     "//content/public/common:static_switches",
     "//ipc",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//sandbox",
     "//services/service_manager/public/cpp",
   ]
diff --git a/components/nacl/browser/BUILD.gn b/components/nacl/browser/BUILD.gn
index 467443a..43079fb 100644
--- a/components/nacl/browser/BUILD.gn
+++ b/components/nacl/browser/BUILD.gn
@@ -40,7 +40,7 @@
     "//content/public/browser",
     "//content/public/common",
     "//content/public/common:zygote_buildflags",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//native_client/src/trusted/service_runtime:sel_main_chrome",
     "//net",
     "//ppapi/host",
diff --git a/components/nacl/common/BUILD.gn b/components/nacl/common/BUILD.gn
index 39c38292..84e81bf3 100644
--- a/components/nacl/common/BUILD.gn
+++ b/components/nacl/common/BUILD.gn
@@ -37,7 +37,7 @@
       "//base",
       "//base:base_static",
       "//content/public/common:service_names",
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//services/service_manager/public/cpp",
     ]
   }
diff --git a/components/nacl/loader/BUILD.gn b/components/nacl/loader/BUILD.gn
index 4ebb4e9..d6715af 100644
--- a/components/nacl/loader/BUILD.gn
+++ b/components/nacl/loader/BUILD.gn
@@ -36,7 +36,7 @@
     "//components/nacl/common:mojo_bindings",
     "//crypto",
     "//ipc",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//native_client/src/trusted/service_runtime:sel_main_chrome",
     "//ppapi/c",
     "//ppapi/proxy:ipc",
@@ -126,7 +126,7 @@
       "//content/public/common",
       "//crypto",
       "//ipc",
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//sandbox/linux:sandbox_services",
       "//services/service_manager/sandbox",
       "//url/ipc:url_ipc",
@@ -205,7 +205,7 @@
       "//components/nacl/broker",
       "//components/nacl/common:switches",
       "//content/public/common:static_switches",
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//sandbox",
       "//services/service_manager/sandbox:sandbox",
     ]
@@ -235,7 +235,7 @@
       "//components/tracing",
       "//content",
       "//ipc",
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//native_client/src/nonsfi/irt:nacl_sys_private",
       "//native_client/src/nonsfi/loader:elf_loader",
 
diff --git a/components/policy/core/browser/browser_policy_connector.cc b/components/policy/core/browser/browser_policy_connector.cc
index d5ccf3e..3970c5e0 100644
--- a/components/policy/core/browser/browser_policy_connector.cc
+++ b/components/policy/core/browser/browser_policy_connector.cc
@@ -65,6 +65,8 @@
   L"consumer\\.example\\.com",
 };
 
+const char* non_managed_domain_for_testing = nullptr;
+
 // Returns true if |domain| matches the regex |pattern|.
 bool MatchDomain(const base::string16& domain, const base::string16& pattern,
                  size_t index) {
@@ -145,10 +147,20 @@
     if (MatchDomain(domain, pattern, i))
       return true;
   }
+  if (non_managed_domain_for_testing &&
+      domain == base::UTF8ToUTF16(non_managed_domain_for_testing)) {
+    return true;
+  }
   return false;
 }
 
 // static
+void BrowserPolicyConnector::SetNonEnterpriseDomainForTesting(
+    const char* domain) {
+  non_managed_domain_for_testing = domain;
+}
+
+// static
 std::string BrowserPolicyConnector::GetDeviceManagementUrl() {
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(switches::kDeviceManagementUrl))
diff --git a/components/policy/core/browser/browser_policy_connector.h b/components/policy/core/browser/browser_policy_connector.h
index 1730b4a..0210043 100644
--- a/components/policy/core/browser/browser_policy_connector.h
+++ b/components/policy/core/browser/browser_policy_connector.h
@@ -54,6 +54,11 @@
   // false if the username is empty.
   static bool IsNonEnterpriseUser(const std::string& username);
 
+  // Allows to register domain for tests that is recognized as non-enterprise.
+  // Note that |domain| basically needs to live until this method is invoked
+  // with a nullptr.
+  static void SetNonEnterpriseDomainForTesting(const char* domain);
+
   // Returns the URL for the device management service endpoint.
   static std::string GetDeviceManagementUrl();
 
diff --git a/components/proximity_auth/BUILD.gn b/components/proximity_auth/BUILD.gn
index c297d7ed..5a5c99b 100644
--- a/components/proximity_auth/BUILD.gn
+++ b/components/proximity_auth/BUILD.gn
@@ -8,10 +8,6 @@
 
 static_library("proximity_auth") {
   sources = [
-    "bluetooth_connection.cc",
-    "bluetooth_connection.h",
-    "bluetooth_connection_finder.cc",
-    "bluetooth_connection_finder.h",
     "bluetooth_low_energy_connection_finder.cc",
     "bluetooth_low_energy_connection_finder.h",
     "bluetooth_low_energy_setup_connection_finder.cc",
@@ -99,8 +95,6 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
-    "bluetooth_connection_finder_unittest.cc",
-    "bluetooth_connection_unittest.cc",
     "bluetooth_low_energy_connection_finder_unittest.cc",
     "messenger_impl_unittest.cc",
     "promotion_manager_unittests.cc",
diff --git a/components/proximity_auth/bluetooth_connection.cc b/components/proximity_auth/bluetooth_connection.cc
deleted file mode 100644
index b67ea0f..0000000
--- a/components/proximity_auth/bluetooth_connection.cc
+++ /dev/null
@@ -1,210 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/proximity_auth/bluetooth_connection.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/location.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/cryptauth/remote_device.h"
-#include "components/cryptauth/wire_message.h"
-#include "components/proximity_auth/logging/logging.h"
-#include "device/bluetooth/bluetooth_adapter_factory.h"
-#include "device/bluetooth/bluetooth_device.h"
-#include "net/base/io_buffer.h"
-
-namespace proximity_auth {
-namespace {
-const int kReceiveBufferSizeBytes = 1024;
-}
-
-BluetoothConnection::BluetoothConnection(
-    const cryptauth::RemoteDevice& remote_device,
-    const device::BluetoothUUID& uuid)
-    : cryptauth::Connection(remote_device),
-      uuid_(uuid),
-      weak_ptr_factory_(this) {}
-
-BluetoothConnection::~BluetoothConnection() {
-  if (status() != DISCONNECTED)
-    Disconnect();
-}
-
-void BluetoothConnection::Connect() {
-  if (status() != DISCONNECTED) {
-    PA_LOG(WARNING)
-        << "Ignoring attempt to connect a non-disconnected connection.";
-    return;
-  }
-
-  if (!device::BluetoothAdapterFactory::IsBluetoothSupported()) {
-    PA_LOG(WARNING)
-        << "Connection failed: Bluetooth is unsupported on this platform.";
-    return;
-  }
-
-  SetStatus(IN_PROGRESS);
-  device::BluetoothAdapterFactory::GetAdapter(
-      base::Bind(&BluetoothConnection::OnAdapterInitialized,
-                 weak_ptr_factory_.GetWeakPtr()));
-}
-
-void BluetoothConnection::Disconnect() {
-  if (status() == DISCONNECTED) {
-    PA_LOG(WARNING)
-        << "Ignoring attempt to disconnect a non-connected connection.";
-    return;
-  }
-
-  // Set status as disconnected now, rather than after the socket closes, so
-  // this connection is not reused.
-  SetStatus(DISCONNECTED);
-  if (socket_.get()) {
-    socket_->Disconnect(base::DoNothing());
-    socket_ = nullptr;
-  }
-  if (adapter_.get()) {
-    adapter_->RemoveObserver(this);
-    adapter_ = nullptr;
-  }
-}
-
-void BluetoothConnection::SendMessageImpl(
-    std::unique_ptr<cryptauth::WireMessage> message) {
-  DCHECK_EQ(status(), CONNECTED);
-
-  // Serialize the message.
-  std::string serialized_message = message->Serialize();
-  int message_length = base::checked_cast<int>(serialized_message.size());
-  scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(message_length);
-  memcpy(buffer->data(), serialized_message.c_str(), message_length);
-
-  // Send it.
-  pending_message_ = std::move(message);
-  base::WeakPtr<BluetoothConnection> weak_this = weak_ptr_factory_.GetWeakPtr();
-  socket_->Send(buffer,
-                message_length,
-                base::Bind(&BluetoothConnection::OnSend, weak_this),
-                base::Bind(&BluetoothConnection::OnSendError, weak_this));
-}
-
-void BluetoothConnection::DeviceChanged(device::BluetoothAdapter* adapter,
-                                        device::BluetoothDevice* device) {
-  DCHECK_EQ(adapter, adapter_.get());
-  if (device->GetAddress() == remote_device().bluetooth_address &&
-      status() != DISCONNECTED && !device->IsConnected()) {
-    PA_LOG(INFO) << "Device disconnected...";
-    Disconnect();
-  }
-}
-
-void BluetoothConnection::DeviceRemoved(device::BluetoothAdapter* adapter,
-                                        device::BluetoothDevice* device) {
-  DCHECK_EQ(adapter, adapter_.get());
-  if (device->GetAddress() != remote_device().bluetooth_address)
-    return;
-
-  DCHECK_NE(status(), DISCONNECTED);
-  PA_LOG(INFO) << "Device disconnected...";
-  if (status() != DISCONNECTED)
-    Disconnect();
-}
-
-void BluetoothConnection::StartReceive() {
-  base::WeakPtr<BluetoothConnection> weak_this = weak_ptr_factory_.GetWeakPtr();
-  socket_->Receive(kReceiveBufferSizeBytes,
-                   base::Bind(&BluetoothConnection::OnReceive, weak_this),
-                   base::Bind(&BluetoothConnection::OnReceiveError, weak_this));
-}
-
-void BluetoothConnection::OnAdapterInitialized(
-    scoped_refptr<device::BluetoothAdapter> adapter) {
-  const std::string address = remote_device().bluetooth_address;
-  device::BluetoothDevice* bluetooth_device = adapter->GetDevice(address);
-  if (!bluetooth_device) {
-    PA_LOG(WARNING) << "Device with address " << address
-                    << " is not known to the system Bluetooth daemon.";
-    // TODO(isherman): Optimistically attempt to seek the device and connect
-    // anyway, as was previously implemented in BluetoothConnectionFinder.
-    Disconnect();
-    return;
-  }
-
-  adapter_ = adapter;
-  adapter_->AddObserver(this);
-
-  base::WeakPtr<BluetoothConnection> weak_this = weak_ptr_factory_.GetWeakPtr();
-  bluetooth_device->ConnectToServiceInsecurely(
-      uuid_,
-      base::Bind(&BluetoothConnection::OnConnected, weak_this),
-      base::Bind(&BluetoothConnection::OnConnectionError, weak_this));
-}
-
-void BluetoothConnection::OnConnected(
-    scoped_refptr<device::BluetoothSocket> socket) {
-  if (status() != IN_PROGRESS) {
-    // This case is reachable if the client of |this| connection called
-    // |Disconnect()| while the backing Bluetooth connection was pending.
-    DCHECK_EQ(status(), DISCONNECTED);
-    PA_LOG(WARNING) << "Ignoring successful backend Bluetooth connection to an "
-                    << "already disconnected logical connection.";
-    return;
-  }
-
-  PA_LOG(INFO) << "Connection established with "
-               << remote_device().bluetooth_address;
-  socket_ = socket;
-  SetStatus(CONNECTED);
-  StartReceive();
-}
-
-void BluetoothConnection::OnConnectionError(const std::string& error_message) {
-  PA_LOG(WARNING) << "Connection failed: " << error_message;
-  Disconnect();
-}
-
-void BluetoothConnection::OnSend(int bytes_sent) {
-  PA_LOG(INFO) << "Successfully sent " << bytes_sent << " bytes.";
-  OnDidSendMessage(*pending_message_, true);
-  pending_message_.reset();
-}
-
-void BluetoothConnection::OnSendError(const std::string& error_message) {
-  PA_LOG(WARNING) << "Error when sending bytes: " << error_message;
-  OnDidSendMessage(*pending_message_, false);
-  pending_message_.reset();
-
-  Disconnect();
-}
-
-void BluetoothConnection::OnReceive(int bytes_received,
-                                    scoped_refptr<net::IOBuffer> buffer) {
-  PA_LOG(INFO) << "Received " << bytes_received << " bytes.";
-  OnBytesReceived(std::string(buffer->data(), bytes_received));
-
-  // Post a task to delay the read until the socket is available, as
-  // calling StartReceive at this point would error with ERR_IO_PENDING.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(&BluetoothConnection::StartReceive,
-                            weak_ptr_factory_.GetWeakPtr()));
-}
-
-void BluetoothConnection::OnReceiveError(
-    device::BluetoothSocket::ErrorReason error_reason,
-    const std::string& error_message) {
-  PA_LOG(WARNING) << "Error receiving bytes: " << error_message;
-
-  // Post a task to delay the read until the socket is available, as
-  // calling StartReceive at this point would error with ERR_IO_PENDING.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(&BluetoothConnection::StartReceive,
-                            weak_ptr_factory_.GetWeakPtr()));
-}
-
-}  // namespace proximity_auth
diff --git a/components/proximity_auth/bluetooth_connection.h b/components/proximity_auth/bluetooth_connection.h
deleted file mode 100644
index 4099f57f..0000000
--- a/components/proximity_auth/bluetooth_connection.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PROXIMITY_AUTH_BLUETOOTH_CONNECTION_H
-#define COMPONENTS_PROXIMITY_AUTH_BLUETOOTH_CONNECTION_H
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "components/cryptauth/connection.h"
-#include "device/bluetooth/bluetooth_adapter.h"
-#include "device/bluetooth/bluetooth_device.h"
-#include "device/bluetooth/bluetooth_socket.h"
-#include "device/bluetooth/bluetooth_uuid.h"
-
-namespace net {
-class IOBuffer;
-}
-
-namespace cryptauth {
-struct RemoteDevice;
-}
-
-namespace proximity_auth {
-
-// Represents a Bluetooth connection with a remote device. The connection is a
-// persistent bidirectional channel for sending and receiving wire messages.
-class BluetoothConnection : public cryptauth::Connection,
-                            public device::BluetoothAdapter::Observer {
- public:
-  // Constructs a Bluetooth connection to the service with |uuid| on the
-  // |remote_device|. The |remote_device| must already be known to the system
-  // Bluetooth daemon.
-  BluetoothConnection(const cryptauth::RemoteDevice& remote_device,
-                      const device::BluetoothUUID& uuid);
-  ~BluetoothConnection() override;
-
-  // Connection:
-  void Connect() override;
-  void Disconnect() override;
-
- protected:
-  // Connection:
-  void SendMessageImpl(
-      std::unique_ptr<cryptauth::WireMessage> message) override;
-
-  // BluetoothAdapter::Observer:
-  void DeviceChanged(device::BluetoothAdapter* adapter,
-                     device::BluetoothDevice* device) override;
-  void DeviceRemoved(device::BluetoothAdapter* adapter,
-                     device::BluetoothDevice* device) override;
-
- private:
-  // Registers receive callbacks with the backing |socket_|.
-  void StartReceive();
-
-  // Callbacks for asynchronous Bluetooth operations.
-  void OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter);
-  void OnConnected(scoped_refptr<device::BluetoothSocket> socket);
-  void OnConnectionError(const std::string& error_message);
-  void OnSend(int bytes_sent);
-  void OnSendError(const std::string& error_message);
-  void OnReceive(int bytes_received, scoped_refptr<net::IOBuffer> buffer);
-  void OnReceiveError(device::BluetoothSocket::ErrorReason error_reason,
-                      const std::string& error_message);
-
-  // The UUID (universally unique identifier) of the Bluetooth service on the
-  // remote device that |this| connection should connect to.
-  const device::BluetoothUUID uuid_;
-
-  // The Bluetooth adapter over which this connection is made. Non-null iff
-  // |this| connection is registered as an observer of the |adapter_|.
-  scoped_refptr<device::BluetoothAdapter> adapter_;
-
-  // The Bluetooth socket that backs this connection. NULL iff the connection is
-  // not in a connected state.
-  scoped_refptr<device::BluetoothSocket> socket_;
-
-  // The message that was sent over the backing |socket_|. NULL iff there is no
-  // send operation in progress.
-  std::unique_ptr<cryptauth::WireMessage> pending_message_;
-
-  base::WeakPtrFactory<BluetoothConnection> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(BluetoothConnection);
-};
-
-}  // namespace proximity_auth
-
-#endif  // COMPONENTS_PROXIMITY_AUTH_BLUETOOTH_CONNECTION_H
diff --git a/components/proximity_auth/bluetooth_connection_finder.cc b/components/proximity_auth/bluetooth_connection_finder.cc
deleted file mode 100644
index 1cacfdb..0000000
--- a/components/proximity_auth/bluetooth_connection_finder.cc
+++ /dev/null
@@ -1,211 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/proximity_auth/bluetooth_connection_finder.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/cryptauth/connection.h"
-#include "components/proximity_auth/bluetooth_connection.h"
-#include "components/proximity_auth/logging/logging.h"
-#include "device/bluetooth/bluetooth_adapter_factory.h"
-
-using device::BluetoothAdapter;
-
-namespace proximity_auth {
-
-BluetoothConnectionFinder::BluetoothConnectionFinder(
-    const cryptauth::RemoteDevice& remote_device,
-    const device::BluetoothUUID& uuid,
-    const base::TimeDelta& polling_interval)
-    : remote_device_(remote_device),
-      uuid_(uuid),
-      polling_interval_(polling_interval),
-      has_delayed_poll_scheduled_(false),
-      weak_ptr_factory_(this) {}
-
-BluetoothConnectionFinder::~BluetoothConnectionFinder() {
-  UnregisterAsObserver();
-}
-
-void BluetoothConnectionFinder::Find(
-    const cryptauth::ConnectionFinder::ConnectionCallback&
-        connection_callback) {
-  if (!device::BluetoothAdapterFactory::IsBluetoothSupported()) {
-    PA_LOG(WARNING) << "Bluetooth is unsupported on this platform. Aborting.";
-    return;
-  }
-
-  DCHECK(start_time_.is_null());
-
-  start_time_ = base::TimeTicks::Now();
-  connection_callback_ = connection_callback;
-
-  device::BluetoothAdapterFactory::GetAdapter(
-      base::Bind(&BluetoothConnectionFinder::OnAdapterInitialized,
-                 weak_ptr_factory_.GetWeakPtr()));
-}
-
-std::unique_ptr<cryptauth::Connection>
-BluetoothConnectionFinder::CreateConnection() {
-  return std::unique_ptr<cryptauth::Connection>(
-      new BluetoothConnection(remote_device_, uuid_));
-}
-
-void BluetoothConnectionFinder::SeekDeviceByAddress(
-    const std::string& bluetooth_address,
-    const base::Closure& callback,
-    const bluetooth_util::ErrorCallback& error_callback) {
-  bluetooth_util::SeekDeviceByAddress(
-      bluetooth_address, callback, error_callback,
-      base::ThreadTaskRunnerHandle::Get().get());
-}
-
-bool BluetoothConnectionFinder::IsReadyToPoll() {
-  bool is_adapter_available =
-      adapter_.get() && adapter_->IsPresent() && adapter_->IsPowered();
-  PA_LOG(INFO) << "Readiness: adapter="
-               << (is_adapter_available ? "available" : "unavailable");
-  return is_adapter_available;
-}
-
-void BluetoothConnectionFinder::PollIfReady() {
-  if (!IsReadyToPoll())
-    return;
-
-  // If there is a pending task to poll at a later time, the time requisite
-  // timeout has not yet elapsed since the previous polling attempt. In that
-  // case, keep waiting until the delayed task comes in.
-  if (has_delayed_poll_scheduled_)
-    return;
-
-  // If the |connection_| is pending, wait for it to connect or fail prior to
-  // polling again.
-  if (connection_ &&
-      connection_->status() != cryptauth::Connection::DISCONNECTED)
-    return;
-
-  // This SeekDeviceByAddress operation is needed to connect to a device if
-  // it is not already known to the adapter.
-  if (!adapter_->GetDevice(remote_device_.bluetooth_address)) {
-    PA_LOG(INFO) << "Remote device [" << remote_device_.bluetooth_address
-                 << "] is not known. "
-                 << "Seeking device directly by address...";
-
-    SeekDeviceByAddress(
-        remote_device_.bluetooth_address,
-        base::Bind(&BluetoothConnectionFinder::OnSeekedDeviceByAddress,
-                   weak_ptr_factory_.GetWeakPtr()),
-        base::Bind(&BluetoothConnectionFinder::OnSeekedDeviceByAddressError,
-                   weak_ptr_factory_.GetWeakPtr()));
-  } else {
-    PA_LOG(INFO) << "Remote device known, connecting...";
-    connection_ = CreateConnection();
-    connection_->AddObserver(this);
-    connection_->Connect();
-  }
-}
-
-void BluetoothConnectionFinder::PostDelayedPoll() {
-  if (has_delayed_poll_scheduled_) {
-    PA_LOG(WARNING) << "Delayed poll already scheduled, skipping.";
-    return;
-  }
-
-  PA_LOG(INFO) << "Posting delayed poll..";
-  has_delayed_poll_scheduled_ = true;
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, base::Bind(&BluetoothConnectionFinder::OnDelayedPoll,
-                            weak_ptr_factory_.GetWeakPtr()),
-      polling_interval_);
-}
-
-void BluetoothConnectionFinder::OnDelayedPoll() {
-  // Note that there is no longer a pending task, and therefore polling is
-  // permitted.
-  has_delayed_poll_scheduled_ = false;
-  PollIfReady();
-}
-
-void BluetoothConnectionFinder::OnSeekedDeviceByAddress() {
-  // Sanity check that the remote device is now known by the adapter.
-  if (adapter_->GetDevice(remote_device_.bluetooth_address))
-    PollIfReady();
-  else
-    PostDelayedPoll();
-}
-
-void BluetoothConnectionFinder::OnSeekedDeviceByAddressError(
-    const std::string& error_message) {
-  PA_LOG(ERROR) << "Failed to seek device: " << error_message;
-  PostDelayedPoll();
-}
-
-void BluetoothConnectionFinder::UnregisterAsObserver() {
-  if (connection_) {
-    connection_->RemoveObserver(this);
-    // The connection is about to be released or destroyed, so no need to clear
-    // it explicitly here.
-  }
-
-  if (adapter_.get()) {
-    adapter_->RemoveObserver(this);
-    adapter_ = nullptr;
-  }
-}
-
-void BluetoothConnectionFinder::OnAdapterInitialized(
-    scoped_refptr<BluetoothAdapter> adapter) {
-  adapter_ = adapter;
-  adapter_->AddObserver(this);
-  PollIfReady();
-}
-
-void BluetoothConnectionFinder::AdapterPresentChanged(BluetoothAdapter* adapter,
-                                                      bool present) {
-  PollIfReady();
-}
-
-void BluetoothConnectionFinder::AdapterPoweredChanged(BluetoothAdapter* adapter,
-                                                      bool powered) {
-  PollIfReady();
-}
-
-void BluetoothConnectionFinder::OnConnectionStatusChanged(
-    cryptauth::Connection* connection,
-    cryptauth::Connection::Status old_status,
-    cryptauth::Connection::Status new_status) {
-  DCHECK_EQ(connection, connection_.get());
-
-  if (connection_->IsConnected()) {
-    base::TimeDelta elapsed = base::TimeTicks::Now() - start_time_;
-    PA_LOG(WARNING) << "Connection found! Elapsed Time: "
-                    << elapsed.InMilliseconds() << "ms.";
-    UnregisterAsObserver();
-
-    // If we invoke the callback now, the callback function may install its own
-    // observer to |connection_|. Because we are in the
-    // cryptauth::ConnectionObserver
-    // callstack, this new observer will receive this connection event.
-    // Therefore, we need to invoke the callback asynchronously.
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(&BluetoothConnectionFinder::InvokeCallbackAsync,
-                              weak_ptr_factory_.GetWeakPtr()));
-  } else if (old_status == cryptauth::Connection::IN_PROGRESS) {
-    PA_LOG(WARNING)
-        << "Connection failed! Scheduling another polling iteration.";
-    PostDelayedPoll();
-  }
-}
-
-void BluetoothConnectionFinder::InvokeCallbackAsync() {
-  connection_callback_.Run(std::move(connection_));
-}
-
-}  // namespace proximity_auth
diff --git a/components/proximity_auth/bluetooth_connection_finder.h b/components/proximity_auth/bluetooth_connection_finder.h
deleted file mode 100644
index c3625fe..0000000
--- a/components/proximity_auth/bluetooth_connection_finder.h
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PROXIMITY_AUTH_BLUETOOTH_CONNECTION_FINDER_H
-#define COMPONENTS_PROXIMITY_AUTH_BLUETOOTH_CONNECTION_FINDER_H
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "components/cryptauth/connection.h"
-#include "components/cryptauth/connection_finder.h"
-#include "components/cryptauth/connection_observer.h"
-#include "components/cryptauth/remote_device.h"
-#include "components/proximity_auth/bluetooth_util.h"
-#include "device/bluetooth/bluetooth_adapter.h"
-#include "device/bluetooth/bluetooth_uuid.h"
-
-namespace proximity_auth {
-
-// This cryptauth::ConnectionFinder implementation tries to find a Bluetooth
-// connection to
-// the remote device by polling at a fixed interval.
-class BluetoothConnectionFinder : public cryptauth::ConnectionFinder,
-                                  public cryptauth::ConnectionObserver,
-                                  public device::BluetoothAdapter::Observer {
- public:
-  BluetoothConnectionFinder(const cryptauth::RemoteDevice& remote_device,
-                            const device::BluetoothUUID& uuid,
-                            const base::TimeDelta& polling_interval);
-  ~BluetoothConnectionFinder() override;
-
-  // cryptauth::ConnectionFinder:
-  void Find(const cryptauth::ConnectionFinder::ConnectionCallback&
-                connection_callback) override;
-
- protected:
-  // Exposed for mocking out the connection in tests.
-  virtual std::unique_ptr<cryptauth::Connection> CreateConnection();
-
-  // Calls bluetooth_util::SeekDeviceByAddress. Exposed for testing, as this
-  // utility function is platform dependent.
-  virtual void SeekDeviceByAddress(
-      const std::string& bluetooth_address,
-      const base::Closure& callback,
-      const bluetooth_util::ErrorCallback& error_callback);
-
-  // BluetoothAdapter::Observer:
-  void AdapterPresentChanged(device::BluetoothAdapter* adapter,
-                             bool present) override;
-  void AdapterPoweredChanged(device::BluetoothAdapter* adapter,
-                             bool powered) override;
-
- private:
-  // Returns true iff the Bluetooth adapter is ready to make connections.
-  bool IsReadyToPoll();
-
-  // Attempts to connect to the |remote_device_| if the system is ready for
-  // another iteration of polling.
-  void PollIfReady();
-
-  // Posts a delayed task to call |PollIfReady|. |OnDelayedPoll()| will be
-  // called when the task fires.
-  void PostDelayedPoll();
-  void OnDelayedPoll();
-
-  // Callbacks for bluetooth_util::SeekDeviceByAddress().
-  void OnSeekedDeviceByAddress();
-  void OnSeekedDeviceByAddressError(const std::string& error_message);
-
-  // Unregisters |this| instance as an observer from all objects that it might
-  // have registered with.
-  void UnregisterAsObserver();
-
-  // Callback to be called when the Bluetooth adapter is initialized.
-  void OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter);
-
-  // ConnectionObserver:
-  void OnConnectionStatusChanged(
-      cryptauth::Connection* connection,
-      cryptauth::Connection::Status old_status,
-      cryptauth::Connection::Status new_status) override;
-
-  // Used to invoke |connection_callback_| asynchronously, decoupling the
-  // callback invocation from the ConnectionObserver callstack.
-  void InvokeCallbackAsync();
-
-  // The remote device to connect to.
-  const cryptauth::RemoteDevice remote_device_;
-
-  // The UUID of the service on the remote device.
-  const device::BluetoothUUID uuid_;
-
-  // The time to wait between polling attempts.
-  const base::TimeDelta polling_interval_;
-
-  // Records the time at which the finder began searching for connections.
-  base::TimeTicks start_time_;
-
-  // The callback that should be called upon a successful connection.
-  cryptauth::ConnectionFinder::ConnectionCallback connection_callback_;
-
-  // The Bluetooth adapter over which the Bluetooth connection will be made.
-  scoped_refptr<device::BluetoothAdapter> adapter_;
-
-  // The Bluetooth connection that will be opened.
-  std::unique_ptr<cryptauth::Connection> connection_;
-
-  // Whether there is currently a polling task scheduled.
-  bool has_delayed_poll_scheduled_;
-
-  // Used to schedule everything else.
-  base::WeakPtrFactory<BluetoothConnectionFinder> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(BluetoothConnectionFinder);
-};
-
-// TODO(isherman): Make sure to wire up the controller to listen for screen lock
-// state change events, and create or destroy the connection finder as
-// appropriate.
-
-}  // namespace proximity_auth
-
-#endif  // COMPONENTS_PROXIMITY_AUTH_BLUETOOTH_CONNECTION_FINDER_H
diff --git a/components/proximity_auth/bluetooth_connection_finder_unittest.cc b/components/proximity_auth/bluetooth_connection_finder_unittest.cc
deleted file mode 100644
index b939d7b..0000000
--- a/components/proximity_auth/bluetooth_connection_finder_unittest.cc
+++ /dev/null
@@ -1,368 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/proximity_auth/bluetooth_connection_finder.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/bind.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/run_loop.h"
-#include "base/time/time.h"
-#include "components/cryptauth/cryptauth_test_util.h"
-#include "components/cryptauth/remote_device.h"
-#include "components/cryptauth/wire_message.h"
-#include "device/bluetooth/bluetooth_adapter_factory.h"
-#include "device/bluetooth/bluetooth_uuid.h"
-#include "device/bluetooth/test/mock_bluetooth_adapter.h"
-#include "device/bluetooth/test/mock_bluetooth_device.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::_;
-using testing::NiceMock;
-using testing::Return;
-using testing::StrictMock;
-
-namespace proximity_auth {
-namespace {
-
-const char kUuid[] = "DEADBEEF-CAFE-FEED-FOOD-D15EA5EBEEF";
-
-class MockConnection : public cryptauth::Connection {
- public:
-  MockConnection()
-      : Connection(cryptauth::CreateClassicRemoteDeviceForTest()),
-        do_not_destroy_(false) {}
-  ~MockConnection() override { EXPECT_FALSE(do_not_destroy_); }
-
-  MOCK_METHOD0(Connect, void());
-
-  void SetStatus(cryptauth::Connection::Status status) {
-    // This object should not be destroyed after setting the status and calling
-    // observers.
-    do_not_destroy_ = true;
-    cryptauth::Connection::SetStatus(status);
-    do_not_destroy_ = false;
-  }
-
- private:
-  void Disconnect() override {}
-  void SendMessageImpl(
-      std::unique_ptr<cryptauth::WireMessage> message) override {}
-
-  // If true, we do not expect |this| object to be destroyed until this value is
-  // toggled back to false.
-  bool do_not_destroy_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockConnection);
-};
-
-class MockBluetoothConnectionFinder : public BluetoothConnectionFinder {
- public:
-  MockBluetoothConnectionFinder()
-      : BluetoothConnectionFinder(cryptauth::CreateClassicRemoteDeviceForTest(),
-                                  device::BluetoothUUID(kUuid),
-                                  base::TimeDelta()) {}
-  ~MockBluetoothConnectionFinder() override {}
-
-  MOCK_METHOD0(CreateConnectionProxy, cryptauth::Connection*());
-
-  // Creates a mock connection and sets an expectation that the mock connection
-  // finder's CreateConnection() method will be called and will return the
-  // created connection. Returns a reference to the created connection.
-  // NOTE: The returned connection's lifetime is managed by the connection
-  // finder.
-  MockConnection* ExpectCreateConnection() {
-    std::unique_ptr<MockConnection> connection(new NiceMock<MockConnection>());
-    MockConnection* connection_alias = connection.get();
-    EXPECT_CALL(*this, CreateConnectionProxy())
-        .WillOnce(Return(connection.release()));
-    return connection_alias;
-  }
-
-  using BluetoothConnectionFinder::AdapterPresentChanged;
-  using BluetoothConnectionFinder::AdapterPoweredChanged;
-
-  void ClearSeekCallbacks() {
-    seek_callback_ = base::Closure();
-    seek_error_callback_ = bluetooth_util::ErrorCallback();
-  }
-
-  const base::Closure& seek_callback() { return seek_callback_; }
-  const bluetooth_util::ErrorCallback& seek_error_callback() {
-    return seek_error_callback_;
-  }
-
- protected:
-  // BluetoothConnectionFinder:
-  std::unique_ptr<cryptauth::Connection> CreateConnection() override {
-    return base::WrapUnique(CreateConnectionProxy());
-  }
-
-  void SeekDeviceByAddress(
-      const std::string& bluetooth_address,
-      const base::Closure& callback,
-      const bluetooth_util::ErrorCallback& error_callback) override {
-    EXPECT_EQ(cryptauth::kTestRemoteDeviceBluetoothAddress, bluetooth_address);
-    seek_callback_ = callback;
-    seek_error_callback_ = error_callback;
-  }
-
- private:
-  base::Closure seek_callback_;
-  bluetooth_util::ErrorCallback seek_error_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockBluetoothConnectionFinder);
-};
-
-}  // namespace
-
-class ProximityAuthBluetoothConnectionFinderTest : public testing::Test {
- protected:
-  ProximityAuthBluetoothConnectionFinderTest()
-      : adapter_(new NiceMock<device::MockBluetoothAdapter>),
-        bluetooth_device_(new NiceMock<device::MockBluetoothDevice>(
-            adapter_.get(),
-            static_cast<uint32_t>(device::BluetoothDeviceType::PHONE),
-            cryptauth::kTestRemoteDeviceName,
-            cryptauth::kTestRemoteDeviceBluetoothAddress,
-            true,
-            false)),
-        connection_callback_(base::Bind(
-            &ProximityAuthBluetoothConnectionFinderTest::OnConnectionFound,
-            base::Unretained(this))) {
-    device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_);
-
-    // By default, configure the environment to allow polling. Individual tests
-    // can override this as needed.
-    ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(true));
-    ON_CALL(*adapter_, IsPowered()).WillByDefault(Return(true));
-
-    // By default, the remote device is known to |adapter_| so
-    // |SeekDeviceByAddress()| will not be called.
-    ON_CALL(*adapter_, GetDevice(cryptauth::kTestRemoteDeviceBluetoothAddress))
-        .WillByDefault(Return(bluetooth_device_.get()));
-  }
-
-  MOCK_METHOD1(OnConnectionFoundProxy, void(cryptauth::Connection* connection));
-  void OnConnectionFound(std::unique_ptr<cryptauth::Connection> connection) {
-    OnConnectionFoundProxy(connection.get());
-    last_found_connection_ = std::move(connection);
-  }
-
-  // Starts |connection_finder_|. If |expect_connection| is true, then we set an
-  // expectation that an in-progress connection will be created and returned.
-  MockConnection* StartConnectionFinder(bool expect_connection) {
-    MockConnection* connection = nullptr;
-    if (expect_connection)
-      connection = connection_finder_.ExpectCreateConnection();
-    connection_finder_.Find(connection_callback_);
-    return connection;
-  }
-
-  // Given an in-progress |connection| returned by |StartConnectionFinder()|,
-  // simulate it transitioning to the CONNECTED state.
-  void SimulateDeviceConnection(MockConnection* connection) {
-    connection->SetStatus(cryptauth::Connection::IN_PROGRESS);
-    base::RunLoop run_loop;
-    EXPECT_CALL(*this, OnConnectionFoundProxy(_));
-    connection->SetStatus(cryptauth::Connection::CONNECTED);
-    run_loop.RunUntilIdle();
-  }
-
-  scoped_refptr<device::MockBluetoothAdapter> adapter_;
-  StrictMock<MockBluetoothConnectionFinder> connection_finder_;
-  std::unique_ptr<device::MockBluetoothDevice> bluetooth_device_;
-  cryptauth::ConnectionFinder::ConnectionCallback connection_callback_;
-
- private:
-  // Save a pointer to the last found connection, to extend its lifetime.
-  std::unique_ptr<cryptauth::Connection> last_found_connection_;
-
-  base::MessageLoop message_loop_;
-};
-
-TEST_F(ProximityAuthBluetoothConnectionFinderTest,
-       ConstructAndDestroyDoesntCrash) {
-  // Destroying a BluetoothConnectionFinder for which Find() has not been called
-  // should not crash.
-  BluetoothConnectionFinder connection_finder(
-      cryptauth::CreateClassicRemoteDeviceForTest(),
-      device::BluetoothUUID(kUuid), base::TimeDelta::FromMilliseconds(1));
-}
-
-TEST_F(ProximityAuthBluetoothConnectionFinderTest, Find_NoBluetoothAdapter) {
-  // Some platforms do not support Bluetooth. This test is only meaningful on
-  // those platforms.
-  adapter_ = nullptr;
-  if (device::BluetoothAdapterFactory::IsBluetoothSupported())
-    return;
-
-  // The StrictMock will verify that no connection is created.
-  StartConnectionFinder(false);
-}
-
-TEST_F(ProximityAuthBluetoothConnectionFinderTest,
-       Find_BluetoothAdapterNotPresent) {
-  // The StrictMock will verify that no connection is created.
-  ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(false));
-  StartConnectionFinder(false);
-}
-
-TEST_F(ProximityAuthBluetoothConnectionFinderTest,
-       Find_BluetoothAdapterNotPowered) {
-  ON_CALL(*adapter_, IsPowered()).WillByDefault(Return(false));
-  // The StrictMock will verify that no connection is created.
-  StartConnectionFinder(false);
-}
-
-TEST_F(ProximityAuthBluetoothConnectionFinderTest, Find_ConnectionSucceeds) {
-  MockConnection* connection = StartConnectionFinder(true);
-  SimulateDeviceConnection(connection);
-}
-
-TEST_F(ProximityAuthBluetoothConnectionFinderTest,
-       Find_ConnectionSucceeds_UnregistersAsObserver) {
-  MockConnection* connection = StartConnectionFinder(true);
-  SimulateDeviceConnection(connection);
-
-  // If for some reason the connection sends more status updates, they should
-  // be ignored.
-  base::RunLoop run_loop;
-  EXPECT_CALL(*this, OnConnectionFoundProxy(_)).Times(0);
-  connection->SetStatus(cryptauth::Connection::IN_PROGRESS);
-  connection->SetStatus(cryptauth::Connection::CONNECTED);
-  run_loop.RunUntilIdle();
-}
-
-TEST_F(ProximityAuthBluetoothConnectionFinderTest,
-       Find_ConnectionFails_PostsTaskToPollAgain) {
-  MockConnection* connection = StartConnectionFinder(true);
-
-  // Simulate a connection that fails to connect.
-  connection->SetStatus(cryptauth::Connection::IN_PROGRESS);
-  connection->SetStatus(cryptauth::Connection::DISCONNECTED);
-
-  // A task should have been posted to poll again.
-  base::RunLoop run_loop;
-  connection_finder_.ExpectCreateConnection();
-  run_loop.RunUntilIdle();
-}
-
-TEST_F(ProximityAuthBluetoothConnectionFinderTest, Find_PollsOnAdapterPresent) {
-  ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(false));
-  EXPECT_CALL(connection_finder_, CreateConnectionProxy()).Times(0);
-  connection_finder_.Find(connection_callback_);
-
-  ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(true));
-  connection_finder_.ExpectCreateConnection();
-  connection_finder_.AdapterPresentChanged(adapter_.get(), true);
-}
-
-TEST_F(ProximityAuthBluetoothConnectionFinderTest, Find_PollsOnAdapterPowered) {
-  ON_CALL(*adapter_, IsPowered()).WillByDefault(Return(false));
-  EXPECT_CALL(connection_finder_, CreateConnectionProxy()).Times(0);
-  connection_finder_.Find(connection_callback_);
-
-  ON_CALL(*adapter_, IsPowered()).WillByDefault(Return(true));
-  connection_finder_.ExpectCreateConnection();
-  connection_finder_.AdapterPoweredChanged(adapter_.get(), true);
-}
-
-TEST_F(ProximityAuthBluetoothConnectionFinderTest,
-       Find_DoesNotPollIfConnectionPending) {
-  MockConnection* connection = StartConnectionFinder(true);
-
-  connection->SetStatus(cryptauth::Connection::IN_PROGRESS);
-
-  // At this point, there is a pending connection in progress. Hence, an event
-  // that would normally trigger a new polling iteration should not do so now,
-  // because the delay interval between successive polling attempts has not yet
-  // expired.
-  EXPECT_CALL(connection_finder_, CreateConnectionProxy()).Times(0);
-  connection_finder_.AdapterPresentChanged(adapter_.get(), true);
-}
-
-TEST_F(ProximityAuthBluetoothConnectionFinderTest,
-       Find_ConnectionFails_PostsTaskToPollAgain_PollWaitsForTask) {
-  MockConnection* connection = StartConnectionFinder(true);
-
-  connection->SetStatus(cryptauth::Connection::IN_PROGRESS);
-  connection->SetStatus(cryptauth::Connection::DISCONNECTED);
-
-  // At this point, there is a pending poll scheduled. Hence, an event that
-  // would normally trigger a new polling iteration should not do so now,
-  // because the delay interval between successive polling attempts has not yet
-  // expired.
-  EXPECT_CALL(connection_finder_, CreateConnectionProxy()).Times(0);
-  connection_finder_.AdapterPresentChanged(adapter_.get(), true);
-
-  // Now, allow the pending task to run, but fail early, so that no new task is
-  // posted.
-  ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(false));
-  base::RunLoop run_loop;
-  run_loop.RunUntilIdle();
-  ON_CALL(*adapter_, IsPresent()).WillByDefault(Return(true));
-
-  // Now that there is no pending task, events should once again trigger new
-  // polling iterations.
-  connection_finder_.ExpectCreateConnection();
-  connection_finder_.AdapterPresentChanged(adapter_.get(), true);
-}
-
-TEST_F(ProximityAuthBluetoothConnectionFinderTest,
-       Find_DeviceNotKnown_SeekDeviceSucceeds) {
-  // If the BluetoothDevice is not known by the adapter, |connection_finder|
-  // will call SeekDeviceByAddress() first to make it known.
-  ON_CALL(*adapter_, GetDevice(cryptauth::kTestRemoteDeviceBluetoothAddress))
-      .WillByDefault(Return(nullptr));
-  connection_finder_.Find(connection_callback_);
-  ASSERT_FALSE(connection_finder_.seek_callback().is_null());
-  EXPECT_FALSE(connection_finder_.seek_error_callback().is_null());
-
-  // After seeking is successful, the normal flow should resume.
-  ON_CALL(*adapter_, GetDevice(cryptauth::kTestRemoteDeviceBluetoothAddress))
-      .WillByDefault(Return(bluetooth_device_.get()));
-  MockConnection* connection = connection_finder_.ExpectCreateConnection();
-  connection_finder_.seek_callback().Run();
-  SimulateDeviceConnection(connection);
-}
-
-TEST_F(ProximityAuthBluetoothConnectionFinderTest,
-       Find_DeviceNotKnown_SeekDeviceFailThenSucceeds) {
-  // If the BluetoothDevice is not known by the adapter, |connection_finder|
-  // will call SeekDeviceByAddress() first to make it known.
-  ON_CALL(*adapter_, GetDevice(cryptauth::kTestRemoteDeviceBluetoothAddress))
-      .WillByDefault(Return(nullptr));
-  connection_finder_.Find(connection_callback_);
-  EXPECT_FALSE(connection_finder_.seek_callback().is_null());
-  ASSERT_FALSE(connection_finder_.seek_error_callback().is_null());
-
-  // If the seek fails, then |connection_finder| will post a delayed poll to
-  // reattempt the seek.
-  connection_finder_.seek_error_callback().Run("Seek failed for test.");
-  connection_finder_.ClearSeekCallbacks();
-  EXPECT_TRUE(connection_finder_.seek_callback().is_null());
-  EXPECT_TRUE(connection_finder_.seek_error_callback().is_null());
-
-  // Check that seek is reattempted.
-  base::RunLoop run_loop;
-  run_loop.RunUntilIdle();
-  ASSERT_FALSE(connection_finder_.seek_callback().is_null());
-  EXPECT_FALSE(connection_finder_.seek_error_callback().is_null());
-
-  // Successfully connect to the Bluetooth device.
-  ON_CALL(*adapter_, GetDevice(cryptauth::kTestRemoteDeviceBluetoothAddress))
-      .WillByDefault(Return(bluetooth_device_.get()));
-  MockConnection* connection = connection_finder_.ExpectCreateConnection();
-  connection_finder_.seek_callback().Run();
-  SimulateDeviceConnection(connection);
-}
-
-}  // namespace proximity_auth
diff --git a/components/proximity_auth/bluetooth_connection_unittest.cc b/components/proximity_auth/bluetooth_connection_unittest.cc
deleted file mode 100644
index bdd1f0b..0000000
--- a/components/proximity_auth/bluetooth_connection_unittest.cc
+++ /dev/null
@@ -1,489 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/proximity_auth/bluetooth_connection.h"
-
-#include <utility>
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/run_loop.h"
-#include "components/cryptauth/cryptauth_test_util.h"
-#include "components/cryptauth/remote_device.h"
-#include "components/cryptauth/wire_message.h"
-#include "device/bluetooth/bluetooth_adapter_factory.h"
-#include "device/bluetooth/bluetooth_uuid.h"
-#include "device/bluetooth/test/mock_bluetooth_adapter.h"
-#include "device/bluetooth/test/mock_bluetooth_device.h"
-#include "device/bluetooth/test/mock_bluetooth_socket.h"
-#include "net/base/io_buffer.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::_;
-using testing::AnyNumber;
-using testing::NiceMock;
-using testing::Ref;
-using testing::Return;
-using testing::SaveArg;
-using testing::StrictMock;
-
-namespace proximity_auth {
-namespace {
-
-const char kOtherDeviceName[] = "Other device name";
-const char kOtherBluetoothAddress[] = "FF:BB:CC:DD:EE:FF";
-
-const char kSerializedMessage[] = "Yarrr, this be a serialized message. Yarr!";
-const int kSerializedMessageLength = strlen(kSerializedMessage);
-
-const char kUuid[] = "DEADBEEF-CAFE-FEED-FOOD-D15EA5EBEEF";
-
-const int kReceiveBufferSize = 6;
-const char kReceiveBufferContents[] = "bytes";
-
-// Create a buffer for testing received data.
-scoped_refptr<net::IOBuffer> CreateReceiveBuffer() {
-  scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kReceiveBufferSize);
-  memcpy(buffer->data(), kReceiveBufferContents, kReceiveBufferSize);
-  return buffer;
-}
-
-class MockBluetoothConnection : public BluetoothConnection {
- public:
-  MockBluetoothConnection()
-      : BluetoothConnection(cryptauth::CreateClassicRemoteDeviceForTest(),
-                            device::BluetoothUUID(kUuid)) {}
-
-  // Calls back into the parent Connection class.
-  MOCK_METHOD1(SetStatusProxy, void(Status status));
-  MOCK_METHOD1(OnBytesReceived, void(const std::string& bytes));
-  MOCK_METHOD2(OnDidSendMessage,
-               void(const cryptauth::WireMessage& message, bool success));
-
-  void SetStatus(Status status) override {
-    SetStatusProxy(status);
-    BluetoothConnection::SetStatus(status);
-  }
-
-  using BluetoothConnection::status;
-  using BluetoothConnection::Connect;
-  using BluetoothConnection::DeviceChanged;
-  using BluetoothConnection::DeviceRemoved;
-  using BluetoothConnection::Disconnect;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockBluetoothConnection);
-};
-
-class TestWireMessage : public cryptauth::WireMessage {
- public:
-  TestWireMessage() : cryptauth::WireMessage("payload", "feature") {}
-  ~TestWireMessage() override {}
-
-  std::string Serialize() const override { return kSerializedMessage; }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestWireMessage);
-};
-
-}  // namespace
-
-class ProximityAuthBluetoothConnectionTest : public testing::Test {
- public:
-  ProximityAuthBluetoothConnectionTest()
-      : adapter_(new device::MockBluetoothAdapter),
-        device_(adapter_.get(),
-                0,
-                cryptauth::kTestRemoteDeviceName,
-                cryptauth::kTestRemoteDeviceBluetoothAddress,
-                true,
-                true),
-        socket_(new StrictMock<device::MockBluetoothSocket>),
-        uuid_(kUuid) {
-    device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_);
-
-    // Suppress uninteresting Gmock call warnings.
-    EXPECT_CALL(*adapter_, GetDevice(_)).Times(AnyNumber());
-  }
-
-  // Transition the connection into an in-progress state.
-  void BeginConnecting(MockBluetoothConnection* connection) {
-    EXPECT_EQ(cryptauth::Connection::DISCONNECTED, connection->status());
-    ON_CALL(device_, IsConnected()).WillByDefault(Return(false));
-
-    ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(&device_));
-    EXPECT_CALL(*connection,
-                SetStatusProxy(cryptauth::Connection::IN_PROGRESS));
-    EXPECT_CALL(*adapter_, AddObserver(connection));
-    EXPECT_CALL(device_, ConnectToServiceInsecurely(uuid_, _, _));
-    connection->Connect();
-
-    EXPECT_EQ(cryptauth::Connection::IN_PROGRESS, connection->status());
-  }
-
-  // Transition the connection into a connected state.
-  // Saves the success and error callbacks passed into OnReceive(), which can be
-  // accessed via receive_callback() and receive_success_callback().
-  void Connect(MockBluetoothConnection* connection) {
-    EXPECT_EQ(cryptauth::Connection::DISCONNECTED, connection->status());
-
-    device::BluetoothDevice::ConnectToServiceCallback callback;
-    ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(&device_));
-    EXPECT_CALL(*connection,
-                SetStatusProxy(cryptauth::Connection::IN_PROGRESS));
-    EXPECT_CALL(*adapter_, AddObserver(connection));
-    EXPECT_CALL(device_, ConnectToServiceInsecurely(_, _, _))
-        .WillOnce(SaveArg<1>(&callback));
-    connection->Connect();
-    ASSERT_FALSE(callback.is_null());
-
-    EXPECT_CALL(*connection, SetStatusProxy(cryptauth::Connection::CONNECTED));
-    EXPECT_CALL(*socket_, Receive(_, _, _))
-        .WillOnce(DoAll(SaveArg<1>(&receive_callback_),
-                        SaveArg<2>(&receive_error_callback_)));
-    callback.Run(socket_);
-
-    EXPECT_EQ(cryptauth::Connection::CONNECTED, connection->status());
-    ON_CALL(device_, IsConnected()).WillByDefault(Return(true));
-  }
-
-  device::BluetoothSocket::ReceiveCompletionCallback* receive_callback() {
-    return &receive_callback_;
-  }
-  device::BluetoothSocket::ReceiveErrorCompletionCallback*
-  receive_error_callback() {
-    return &receive_error_callback_;
-  }
-
- protected:
-  // Mocks used for verifying interactions with the Bluetooth subsystem.
-  scoped_refptr<device::MockBluetoothAdapter> adapter_;
-  NiceMock<device::MockBluetoothDevice> device_;
-  scoped_refptr<StrictMock<device::MockBluetoothSocket>> socket_;
-
-  device::BluetoothUUID uuid_;
-
- private:
-  base::MessageLoop message_loop_;
-
-  device::BluetoothSocket::ReceiveCompletionCallback receive_callback_;
-  device::BluetoothSocket::ReceiveErrorCompletionCallback
-      receive_error_callback_;
-};
-
-TEST_F(ProximityAuthBluetoothConnectionTest, Connect_ConnectionWasInProgress) {
-  // Create an in-progress connection.
-  StrictMock<MockBluetoothConnection> connection;
-  BeginConnecting(&connection);
-
-  // A second call to Connect() should be ignored.
-  EXPECT_CALL(connection, SetStatusProxy(_)).Times(0);
-  connection.Connect();
-
-  // The connection cleans up after itself upon destruction.
-  EXPECT_CALL(*adapter_, RemoveObserver(&connection));
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest, Connect_ConnectionWasConnected) {
-  // Create a connected connection.
-  StrictMock<MockBluetoothConnection> connection;
-  Connect(&connection);
-
-  // A second call to Connect() should be ignored.
-  EXPECT_CALL(connection, SetStatusProxy(_)).Times(0);
-  connection.Connect();
-
-  // The connection disconnects and unregisters as an observer upon destruction.
-  EXPECT_CALL(*socket_, Disconnect(_));
-  EXPECT_CALL(*adapter_, RemoveObserver(&connection));
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest, Connect_NoBluetoothAdapter) {
-  // Some platforms do not support Bluetooth. This test is only meaningful on
-  // those platforms.
-  adapter_ = nullptr;
-  if (device::BluetoothAdapterFactory::IsBluetoothSupported())
-    return;
-
-  StrictMock<MockBluetoothConnection> connection;
-  EXPECT_CALL(connection, SetStatusProxy(_)).Times(0);
-  connection.Connect();
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest, Connect_DeviceMissing) {
-  StrictMock<MockBluetoothConnection> connection;
-
-  ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(nullptr));
-  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::IN_PROGRESS));
-  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
-  connection.Connect();
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest,
-       Connect_DeviceRemovedWhileConnecting) {
-  // Create an in-progress connection.
-  StrictMock<MockBluetoothConnection> connection;
-  BeginConnecting(&connection);
-
-  // Remove the device while the connection is in-progress. This should cause
-  // the connection to disconnect.
-  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
-  EXPECT_CALL(*adapter_, RemoveObserver(&connection));
-  connection.DeviceRemoved(adapter_.get(), &device_);
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest,
-       Connect_OtherDeviceRemovedWhileConnecting) {
-  // Create an in-progress connection.
-  StrictMock<MockBluetoothConnection> connection;
-  BeginConnecting(&connection);
-
-  // Remove a device other than the one that is being connected to. This should
-  // not have any effect on the connection.
-  NiceMock<device::MockBluetoothDevice> other_device(
-      adapter_.get(), 0, kOtherDeviceName, kOtherBluetoothAddress, true, true);
-  EXPECT_CALL(connection, SetStatusProxy(_)).Times(0);
-  connection.DeviceRemoved(adapter_.get(), &other_device);
-
-  // The connection removes itself as an observer when it is destroyed.
-  EXPECT_CALL(*adapter_, RemoveObserver(&connection));
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest, Connect_ConnectionFails) {
-  StrictMock<MockBluetoothConnection> connection;
-
-  device::BluetoothDevice::ConnectToServiceErrorCallback error_callback;
-  ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(&device_));
-  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::IN_PROGRESS));
-  EXPECT_CALL(*adapter_, AddObserver(&connection));
-  EXPECT_CALL(device_, ConnectToServiceInsecurely(uuid_, _, _))
-      .WillOnce(SaveArg<2>(&error_callback));
-  connection.Connect();
-  ASSERT_FALSE(error_callback.is_null());
-
-  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
-  EXPECT_CALL(*adapter_, RemoveObserver(&connection));
-  error_callback.Run("super descriptive error message");
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest, Connect_ConnectionSucceeds) {
-  StrictMock<MockBluetoothConnection> connection;
-  Connect(&connection);
-
-  // The connection disconnects and unregisters as an observer upon destruction.
-  EXPECT_CALL(*socket_, Disconnect(_));
-  EXPECT_CALL(*adapter_, RemoveObserver(&connection));
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest,
-       Connect_ConnectionSucceeds_ThenDeviceRemoved) {
-  StrictMock<MockBluetoothConnection> connection;
-  Connect(&connection);
-
-  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
-  EXPECT_CALL(*socket_, Disconnect(_));
-  EXPECT_CALL(*adapter_, RemoveObserver(&connection));
-  connection.DeviceRemoved(adapter_.get(), &device_);
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest,
-       Connect_ConnectionSucceeds_ReceiveData) {
-  StrictMock<MockBluetoothConnection> connection;
-  Connect(&connection);
-  ASSERT_TRUE(receive_callback() && !receive_callback()->is_null());
-
-  // Receive some data. Once complete, the connection should re-register to be
-  // ready receive more data.
-  scoped_refptr<net::IOBuffer> buffer = CreateReceiveBuffer();
-  EXPECT_CALL(
-      connection,
-      OnBytesReceived(std::string(kReceiveBufferContents, kReceiveBufferSize)));
-  EXPECT_CALL(*socket_, Receive(_, _, _));
-  receive_callback()->Run(kReceiveBufferSize, buffer);
-  base::RunLoop run_loop;
-  run_loop.RunUntilIdle();
-
-  // The connection disconnects and unregisters as an observer upon destruction.
-  EXPECT_CALL(*socket_, Disconnect(_));
-  EXPECT_CALL(*adapter_, RemoveObserver(&connection));
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest,
-       Connect_ConnectionSucceeds_ReceiveDataAfterReceiveError) {
-  StrictMock<MockBluetoothConnection> connection;
-  Connect(&connection);
-  ASSERT_TRUE(receive_error_callback() && !receive_error_callback()->is_null());
-
-  // Simulate an error while receiving data. The connection should re-register
-  // to be ready receive more data despite the error.
-  device::BluetoothSocket::ReceiveCompletionCallback receive_callback;
-  EXPECT_CALL(*socket_, Receive(_, _, _))
-      .WillOnce(SaveArg<1>(&receive_callback));
-  receive_error_callback()->Run(device::BluetoothSocket::kSystemError,
-                                "The system is down. They're taking over!");
-  base::RunLoop run_loop;
-  run_loop.RunUntilIdle();
-  ASSERT_FALSE(receive_callback.is_null());
-
-  // Receive some data.
-  scoped_refptr<net::IOBuffer> buffer = CreateReceiveBuffer();
-  EXPECT_CALL(
-      connection,
-      OnBytesReceived(std::string(kReceiveBufferContents, kReceiveBufferSize)));
-  EXPECT_CALL(*socket_, Receive(_, _, _));
-  receive_callback.Run(kReceiveBufferSize, buffer);
-  base::RunLoop run_loop2;
-  run_loop2.RunUntilIdle();
-
-  // The connection disconnects and unregisters as an observer upon destruction.
-  EXPECT_CALL(*socket_, Disconnect(_));
-  EXPECT_CALL(*adapter_, RemoveObserver(&connection));
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest,
-       Disconnect_ConnectionWasAlreadyDisconnected) {
-  StrictMock<MockBluetoothConnection> connection;
-  EXPECT_CALL(connection, SetStatusProxy(_)).Times(0);
-  connection.Disconnect();
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest,
-       Disconnect_ConnectionWasInProgress) {
-  // Create an in-progress connection.
-  StrictMock<MockBluetoothConnection> connection;
-  BeginConnecting(&connection);
-
-  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
-  EXPECT_CALL(*adapter_, RemoveObserver(&connection));
-  connection.Disconnect();
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest,
-       Disconnect_ConnectionWasConnected) {
-  // Create a connected connection.
-  StrictMock<MockBluetoothConnection> connection;
-  Connect(&connection);
-
-  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
-  EXPECT_CALL(*socket_, Disconnect(_));
-  EXPECT_CALL(*adapter_, RemoveObserver(&connection));
-  connection.Disconnect();
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest,
-       Connect_ThenDisconnectWhileInProgress_ThenBackingConnectionSucceeds) {
-  StrictMock<MockBluetoothConnection> connection;
-  device::BluetoothDevice::ConnectToServiceCallback callback;
-  ON_CALL(*adapter_, GetDevice(_)).WillByDefault(Return(&device_));
-  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::IN_PROGRESS));
-  EXPECT_CALL(*adapter_, AddObserver(&connection));
-  EXPECT_CALL(device_, ConnectToServiceInsecurely(uuid_, _, _))
-      .WillOnce(SaveArg<1>(&callback));
-  connection.Connect();
-  ASSERT_FALSE(callback.is_null());
-
-  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
-  EXPECT_CALL(*adapter_, RemoveObserver(&connection));
-  connection.Disconnect();
-
-  EXPECT_CALL(connection, SetStatusProxy(_)).Times(0);
-  EXPECT_CALL(*socket_, Receive(_, _, _)).Times(0);
-  callback.Run(socket_);
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest,
-       SendMessage_SendsExpectedDataOverTheWire) {
-  // Create a connected connection.
-  StrictMock<MockBluetoothConnection> connection;
-  Connect(&connection);
-
-  scoped_refptr<net::IOBuffer> buffer;
-  std::unique_ptr<TestWireMessage> wire_message(new TestWireMessage);
-  EXPECT_CALL(*socket_, Send(_, kSerializedMessageLength, _, _))
-      .WillOnce(SaveArg<0>(&buffer));
-  connection.SendMessage(std::move(wire_message));
-  ASSERT_TRUE(buffer.get());
-  EXPECT_EQ(kSerializedMessage,
-            std::string(buffer->data(), kSerializedMessageLength));
-
-  // The connection disconnects and unregisters as an observer upon destruction.
-  EXPECT_CALL(*socket_, Disconnect(_));
-  EXPECT_CALL(*adapter_, RemoveObserver(&connection));
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest, SendMessage_Success) {
-  // Create a connected connection.
-  StrictMock<MockBluetoothConnection> connection;
-  Connect(&connection);
-
-  std::unique_ptr<TestWireMessage> wire_message(new TestWireMessage);
-  // Ownership will be transfered below, so grab a reference here.
-  TestWireMessage* expected_wire_message = wire_message.get();
-
-  device::BluetoothSocket::SendCompletionCallback callback;
-  EXPECT_CALL(*socket_, Send(_, _, _, _)).WillOnce(SaveArg<2>(&callback));
-  connection.SendMessage(std::move(wire_message));
-  ASSERT_FALSE(callback.is_null());
-
-  EXPECT_CALL(connection, OnDidSendMessage(Ref(*expected_wire_message), true));
-  callback.Run(kSerializedMessageLength);
-
-  // The connection disconnects and unregisters as an observer upon destruction.
-  EXPECT_CALL(*socket_, Disconnect(_));
-  EXPECT_CALL(*adapter_, RemoveObserver(&connection));
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest, SendMessage_Failure) {
-  // Create a connected connection.
-  StrictMock<MockBluetoothConnection> connection;
-  Connect(&connection);
-
-  std::unique_ptr<TestWireMessage> wire_message(new TestWireMessage);
-  // Ownership will be transfered below, so grab a reference here.
-  TestWireMessage* expected_wire_message = wire_message.get();
-
-  device::BluetoothSocket::ErrorCompletionCallback error_callback;
-  EXPECT_CALL(*socket_, Send(_, _, _, _)).WillOnce(SaveArg<3>(&error_callback));
-  connection.SendMessage(std::move(wire_message));
-
-  ASSERT_FALSE(error_callback.is_null());
-  EXPECT_CALL(connection, OnDidSendMessage(Ref(*expected_wire_message), false));
-  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
-  EXPECT_CALL(*socket_, Disconnect(_));
-  EXPECT_CALL(*adapter_, RemoveObserver(&connection));
-  error_callback.Run("The most helpful of error messages");
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest, DeviceChanged_Disconnected) {
-  // Create a connected connection.
-  StrictMock<MockBluetoothConnection> connection;
-  Connect(&connection);
-  EXPECT_TRUE(connection.IsConnected());
-
-  // If the remote device disconnects, |connection| should also disconnect.
-  ON_CALL(device_, IsConnected()).WillByDefault(Return(false));
-  EXPECT_CALL(connection, SetStatusProxy(cryptauth::Connection::DISCONNECTED));
-  EXPECT_CALL(*socket_, Disconnect(_));
-  EXPECT_CALL(*adapter_, RemoveObserver(&connection));
-  connection.DeviceChanged(adapter_.get(), &device_);
-  EXPECT_FALSE(connection.IsConnected());
-}
-
-TEST_F(ProximityAuthBluetoothConnectionTest, DeviceChanged_NotDisconnected) {
-  // Nothing should happen if DeviceChanged is called, but the remote device is
-  // not disconnected.
-  StrictMock<MockBluetoothConnection> connection;
-  Connect(&connection);
-  EXPECT_TRUE(connection.IsConnected());
-  connection.DeviceChanged(adapter_.get(), &device_);
-  EXPECT_TRUE(connection.IsConnected());
-
-  // The connection disconnects and unregisters as an observer upon destruction.
-  EXPECT_CALL(*socket_, Disconnect(_));
-  EXPECT_CALL(*adapter_, RemoveObserver(&connection));
-}
-
-}  // namespace proximity_auth
diff --git a/components/proximity_auth/remote_device_life_cycle_impl.cc b/components/proximity_auth/remote_device_life_cycle_impl.cc
index c70228ea..d050d83 100644
--- a/components/proximity_auth/remote_device_life_cycle_impl.cc
+++ b/components/proximity_auth/remote_device_life_cycle_impl.cc
@@ -16,8 +16,6 @@
 #include "components/cryptauth/device_to_device_authenticator.h"
 #include "components/cryptauth/secure_context.h"
 #include "components/cryptauth/secure_message_delegate.h"
-#include "components/proximity_auth/bluetooth_connection.h"
-#include "components/proximity_auth/bluetooth_connection_finder.h"
 #include "components/proximity_auth/bluetooth_low_energy_connection_finder.h"
 #include "components/proximity_auth/logging/logging.h"
 #include "components/proximity_auth/messenger_impl.h"
@@ -28,10 +26,6 @@
 
 namespace {
 
-// The UUID of the Smart Lock classic Bluetooth service.
-const char kClassicBluetoothServiceUUID[] =
-    "704EE561-3782-405A-A14B-2D47A2DDCDDF";
-
 // The time to wait, in seconds, after authentication fails, before retrying
 // another connection.
 const int kAuthenticationRecoveryTimeSeconds = 10;
@@ -85,14 +79,7 @@
 
 std::unique_ptr<cryptauth::ConnectionFinder>
 RemoteDeviceLifeCycleImpl::CreateConnectionFinder() {
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kDisableBluetoothLowEnergyDiscovery)) {
-    return std::make_unique<BluetoothLowEnergyConnectionFinder>(remote_device_);
-  } else {
-    return std::make_unique<BluetoothConnectionFinder>(
-        remote_device_, device::BluetoothUUID(kClassicBluetoothServiceUUID),
-        base::TimeDelta::FromSeconds(3));
-  }
+  return std::make_unique<BluetoothLowEnergyConnectionFinder>(remote_device_);
 }
 
 std::unique_ptr<cryptauth::Authenticator>
diff --git a/components/proximity_auth/switches.cc b/components/proximity_auth/switches.cc
index 9d08bcc0..8eec5b7 100644
--- a/components/proximity_auth/switches.cc
+++ b/components/proximity_auth/switches.cc
@@ -7,10 +7,6 @@
 namespace proximity_auth {
 namespace switches {
 
-// Disables discovery of the phone over Bluetooth Low Energy.
-const char kDisableBluetoothLowEnergyDiscovery[] =
-    "disable-proximity-auth-bluetooth-low-energy-discovery";
-
 // Enables forcing the user to reauth with their password after X hours (e.g.
 // 20) without password entry.
 const char kEnableForcePasswordReauth[] = "force-password-reauth";
diff --git a/components/proximity_auth/switches.h b/components/proximity_auth/switches.h
index 70ed565..66d8b2fb 100644
--- a/components/proximity_auth/switches.h
+++ b/components/proximity_auth/switches.h
@@ -8,7 +8,6 @@
 namespace proximity_auth {
 namespace switches {
 
-extern const char kDisableBluetoothLowEnergyDiscovery[];
 extern const char kEnableForcePasswordReauth[];
 extern const char kForceLoadEasyUnlockAppInTests[];
 
diff --git a/components/proximity_auth/webui/proximity_auth_webui_handler.cc b/components/proximity_auth/webui/proximity_auth_webui_handler.cc
index c46957e..6581fb66 100644
--- a/components/proximity_auth/webui/proximity_auth_webui_handler.cc
+++ b/components/proximity_auth/webui/proximity_auth_webui_handler.cc
@@ -22,7 +22,6 @@
 #include "components/cryptauth/secure_context.h"
 #include "components/cryptauth/secure_message_delegate.h"
 #include "components/prefs/pref_service.h"
-#include "components/proximity_auth/bluetooth_connection_finder.h"
 #include "components/proximity_auth/logging/logging.h"
 #include "components/proximity_auth/messenger.h"
 #include "components/proximity_auth/remote_device_life_cycle_impl.h"
diff --git a/components/safe_browsing/db/notification_types.h b/components/safe_browsing/db/notification_types.h
index 14826033..57280dd 100644
--- a/components/safe_browsing/db/notification_types.h
+++ b/components/safe_browsing/db/notification_types.h
@@ -5,6 +5,17 @@
 #ifndef COMPONENTS_SAFE_BROWSING_DB_NOTIFICATION_TYPES_H_
 #define COMPONENTS_SAFE_BROWSING_DB_NOTIFICATION_TYPES_H_
 
+// **
+// ** NOTICE
+// **
+// ** The notification system is deprecated, obsolete, and is slowly being
+// ** removed. See https://crbug.com/268984.
+// **
+// ** Please don't add any new notification types, and please help migrate
+// ** existing uses of the notification types below to use the Observer and
+// ** Callback patterns.
+// **
+
 // Lists of Safe Browsing related notifications, used with NotificationService.
 namespace safe_browsing {
 
@@ -27,4 +38,15 @@
 
 }  // namespace safe_browsing
 
+// **
+// ** NOTICE
+// **
+// ** The notification system is deprecated, obsolete, and is slowly being
+// ** removed. See https://crbug.com/268984.
+// **
+// ** Please don't add any new notification types, and please help migrate
+// ** existing uses of the notification types below to use the Observer and
+// ** Callback patterns.
+// **
+
 #endif  // COMPONENTS_SAFE_BROWSING_DB_NOTIFICATION_TYPES_H_
diff --git a/components/test/BUILD.gn b/components/test/BUILD.gn
index a2ca370..c60e9d1 100644
--- a/components/test/BUILD.gn
+++ b/components/test/BUILD.gn
@@ -18,7 +18,7 @@
     "//components/content_settings/core/common",
     "//components/gcm_driver:gcm_driver",
     "//components/signin/core/browser",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//net",
     "//testing/gtest",
     "//ui/base",
@@ -65,7 +65,9 @@
   # There is only one service in catalog, which depends on printing feature.
   # When more services are added, the condition can be moved inside of catalog.
   catalog("components_unittests_catalog") {
-    embedded_services = [ "//components/printing/service:pdf_compositor_service_unittest_manifest" ]
+    embedded_services = [
+      "//components/printing/service:pdf_compositor_service_unittest_manifest",
+    ]
   }
 
   catalog_cpp_source("components_unittests_catalog_source") {
diff --git a/components/variations/processed_study.cc b/components/variations/processed_study.cc
index 8af4c593..0ffe2c54 100644
--- a/components/variations/processed_study.cc
+++ b/components/variations/processed_study.cc
@@ -39,10 +39,10 @@
 
   bool multiple_assigned_groups = false;
   bool found_default_group = false;
-  std::string single_feature_name_seen;
-  bool has_multiple_features = false;
 
   std::set<std::string> experiment_names;
+  std::set<std::string> features_to_associate;
+
   for (int i = 0; i < study.experiment_size(); ++i) {
     const Study_Experiment& experiment = study.experiment(i);
     if (experiment.name().empty()) {
@@ -55,25 +55,17 @@
       return false;
     }
 
-    if (!has_multiple_features) {
+    // Note: This checks for ACTIVATION_EXPLICIT, since there is no reason to
+    // have this association with ACTIVATION_AUTO (where the trial starts
+    // active), as well as allowing flexibility to disable this behavior in the
+    // future from the server by introducing a new activation type.
+    if (study.activation_type() == Study_ActivationType_ACTIVATION_EXPLICIT) {
       const auto& features = experiment.feature_association();
       for (int i = 0; i < features.enable_feature_size(); ++i) {
-        const std::string& feature_name = features.enable_feature(i);
-        if (single_feature_name_seen.empty()) {
-          single_feature_name_seen = feature_name;
-        } else if (feature_name != single_feature_name_seen) {
-          has_multiple_features = true;
-          break;
-        }
+        features_to_associate.insert(features.enable_feature(i));
       }
       for (int i = 0; i < features.disable_feature_size(); ++i) {
-        const std::string& feature_name = features.disable_feature(i);
-        if (single_feature_name_seen.empty()) {
-          single_feature_name_seen = feature_name;
-        } else if (feature_name != single_feature_name_seen) {
-          has_multiple_features = true;
-          break;
-        }
+        features_to_associate.insert(features.disable_feature(i));
       }
     }
 
@@ -97,18 +89,13 @@
     return false;
   }
 
-  // Check if this study enables/disables a single feature and uses explicit
-  // activation (i.e. the trial should be activated when queried). If so, ensure
-  // that groups that don't explicitly enable/disable that feature are still
-  // associated with it (i.e. so "Default" group gets reported).
-  //
-  // Note: This checks for ACTIVATION_EXPLICIT, since there is no reason to
-  // have this association with ACTIVATION_AUTO (where the trial starts active),
-  // as well as allowing flexibility to disable this behavior in the future from
-  // the server by introducing a new activation type.
-  if (!has_multiple_features && !single_feature_name_seen.empty() &&
-      study.activation_type() == Study_ActivationType_ACTIVATION_EXPLICIT) {
-    associated_features->push_back(single_feature_name_seen);
+  // Ensure that groups that don't explicitly enable/disable that feature get
+  // associated with all features in the study (i.e. so "Default" group gets
+  // reported).
+  if (!features_to_associate.empty()) {
+    associated_features->insert(associated_features->end(),
+                                features_to_associate.begin(),
+                                features_to_associate.end());
   }
 
   *total_probability = divisor;
diff --git a/components/variations/variations_seed_processor_unittest.cc b/components/variations/variations_seed_processor_unittest.cc
index b1c4d25..376b3a1e 100644
--- a/components/variations/variations_seed_processor_unittest.cc
+++ b/components/variations/variations_seed_processor_unittest.cc
@@ -404,7 +404,7 @@
   EXPECT_FALSE(processed_study.Init(&study, false));
 }
 
-TEST_F(VariationsSeedProcessorTest, ValidateStudySingleFeature) {
+TEST_F(VariationsSeedProcessorTest, ValidateStudyWithAssociatedFeatures) {
   Study study;
   study.set_default_experiment_name("def");
   Study_Experiment* exp1 = AddExperiment("exp1", 100, &study);
@@ -430,9 +430,10 @@
   exp1->mutable_feature_association()->add_enable_feature(kFeature1Name);
   exp1->mutable_feature_association()->add_enable_feature(kFeature2Name);
   EXPECT_TRUE(processed_study.Init(&study, false));
-  // Since there's multiple different features, |associated_features| should be
-  // unset.
-  EXPECT_THAT(processed_study.associated_features(), IsEmpty());
+  // Since there's multiple different features, |associated_features| should now
+  // contain them all.
+  EXPECT_THAT(processed_study.associated_features(),
+              ElementsAre(kFeature1Name, kFeature2Name));
 
   exp1->clear_feature_association();
   exp1->mutable_feature_association()->add_enable_feature(kFeature1Name);
@@ -443,9 +444,16 @@
               ElementsAre(kFeature1Name));
 
   // Setting a different feature name on exp2 should cause |associated_features|
-  // to be not set.
+  // to contain both feature names.
   exp2->mutable_feature_association()->set_enable_feature(0, kFeature2Name);
   EXPECT_TRUE(processed_study.Init(&study, false));
+  EXPECT_THAT(processed_study.associated_features(),
+              ElementsAre(kFeature1Name, kFeature2Name));
+
+  // Setting a different activation type should result in empty
+  // |associated_features|.
+  study.set_activation_type(Study_ActivationType_ACTIVATION_AUTO);
+  EXPECT_TRUE(processed_study.Init(&study, false));
   EXPECT_THAT(processed_study.associated_features(), IsEmpty());
 }
 
diff --git a/components/viz/BUILD.gn b/components/viz/BUILD.gn
index b06ce94..2fc61aa 100644
--- a/components/viz/BUILD.gn
+++ b/components/viz/BUILD.gn
@@ -19,7 +19,7 @@
     "//components/viz/test:test_suite",
     "//components/viz/test:test_support",
     "//components/viz/test:unit_tests",
-    "//mojo/edk/system",
+    "//mojo/edk",
   ]
 
   data = [
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn
index 8cea726..ae65bd8 100644
--- a/components/viz/common/BUILD.gn
+++ b/components/viz/common/BUILD.gn
@@ -118,6 +118,7 @@
     "resources/resource_id.h",
     "resources/resource_settings.cc",
     "resources/resource_settings.h",
+    "resources/resource_sizes.h",
     "resources/resource_texture_hint.h",
     "resources/resource_type.h",
     "resources/returned_resource.h",
diff --git a/components/viz/common/quads/shared_bitmap.cc b/components/viz/common/quads/shared_bitmap.cc
index d58bbd3..26628cd6 100644
--- a/components/viz/common/quads/shared_bitmap.cc
+++ b/components/viz/common/quads/shared_bitmap.cc
@@ -32,60 +32,6 @@
   return id;
 }
 
-// static
-bool SharedBitmap::SizeInBytes(const gfx::Size& size,
-                               ResourceFormat format,
-                               size_t* size_in_bytes) {
-  DCHECK(IsBitmapFormatSupported(format));
-  if (size.IsEmpty())
-    return false;
-  DCHECK_EQ(0, BitsPerPixel(format) % 8);
-  base::CheckedNumeric<size_t> s = BitsPerPixel(format) / 8;
-  s *= size.width();
-  s *= size.height();
-  if (!s.IsValid())
-    return false;
-  *size_in_bytes = s.ValueOrDie();
-  return true;
-}
-
-// static
-size_t SharedBitmap::CheckedSizeInBytes(const gfx::Size& size,
-                                        ResourceFormat format) {
-  DCHECK(IsBitmapFormatSupported(format));
-  CHECK(!size.IsEmpty());
-  DCHECK_EQ(0, BitsPerPixel(format) % 8);
-  base::CheckedNumeric<size_t> s = BitsPerPixel(format) / 8;
-  s *= size.width();
-  s *= size.height();
-  return s.ValueOrDie();
-}
-
-// static
-size_t SharedBitmap::UncheckedSizeInBytes(const gfx::Size& size,
-                                          ResourceFormat format) {
-  DCHECK(IsBitmapFormatSupported(format));
-  DCHECK(VerifySizeInBytes(size, format));
-  DCHECK_EQ(0, BitsPerPixel(format) % 8);
-  size_t s = BitsPerPixel(format) / 8;
-  s *= size.width();
-  s *= size.height();
-  return s;
-}
-
-// static
-bool SharedBitmap::VerifySizeInBytes(const gfx::Size& size,
-                                     ResourceFormat format) {
-  DCHECK(IsBitmapFormatSupported(format));
-  if (size.IsEmpty())
-    return false;
-  DCHECK_EQ(0, BitsPerPixel(format) % 8);
-  base::CheckedNumeric<size_t> s = BitsPerPixel(format) / 8;
-  s *= size.width();
-  s *= size.height();
-  return s.IsValid();
-}
-
 base::trace_event::MemoryAllocatorDumpGuid GetSharedBitmapGUIDForTracing(
     const SharedBitmapId& bitmap_id) {
   auto bitmap_id_hex = base::HexEncode(bitmap_id.name, sizeof(bitmap_id.name));
diff --git a/components/viz/common/quads/shared_bitmap.h b/components/viz/common/quads/shared_bitmap.h
index 29ec2ccb..aa48b9b 100644
--- a/components/viz/common/quads/shared_bitmap.h
+++ b/components/viz/common/quads/shared_bitmap.h
@@ -51,21 +51,6 @@
   // use via shared memory. Otherwise, this returns empty.
   virtual base::UnguessableToken GetCrossProcessGUID() const = 0;
 
-  // Returns true if the size is valid and false otherwise.
-  static bool SizeInBytes(const gfx::Size& size,
-                          ResourceFormat format,
-                          size_t* size_in_bytes);
-  // Dies with a CRASH() if the size can not be represented as a positive number
-  // of bytes.
-  static size_t CheckedSizeInBytes(const gfx::Size& size,
-                                   ResourceFormat format);
-  // Returns the size in bytes but may overflow or return 0. Only do this for
-  // sizes that have already been checked.
-  static size_t UncheckedSizeInBytes(const gfx::Size& size,
-                                     ResourceFormat format);
-  // Returns true if the size is valid and false otherwise.
-  static bool VerifySizeInBytes(const gfx::Size& size, ResourceFormat format);
-
   static SharedBitmapId GenerateId();
 
  private:
diff --git a/components/viz/common/resources/DEPS b/components/viz/common/resources/DEPS
index 8424994..899f6b52 100644
--- a/components/viz/common/resources/DEPS
+++ b/components/viz/common/resources/DEPS
@@ -1,6 +1,9 @@
 # Please consult components/viz/README.md about allowable dependencies.
 
 include_rules = [
+  # TODO(staraz): cc/base was added because ResourceSizes includes
+  # cc::MathUtil. Remove it once cc/base/math_util* are moved to viz.
+  "+cc/base",
   "+gpu/command_buffer/common",
   "+gpu/GLES2",
   "+mojo/public/cpp/system/buffer.h",
diff --git a/components/viz/common/resources/bitmap_allocation.cc b/components/viz/common/resources/bitmap_allocation.cc
index c64cca8..3924c58b 100644
--- a/components/viz/common/resources/bitmap_allocation.cc
+++ b/components/viz/common/resources/bitmap_allocation.cc
@@ -9,8 +9,8 @@
 #include "base/memory/shared_memory.h"
 #include "base/process/memory.h"
 #include "build/build_config.h"
-#include "components/viz/common/quads/shared_bitmap.h"
 #include "components/viz/common/resources/resource_format_utils.h"
+#include "components/viz/common/resources/resource_sizes.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -57,7 +57,7 @@
     ResourceFormat format) {
   DCHECK(IsBitmapFormatSupported(format));
   size_t bytes = 0;
-  if (!SharedBitmap::SizeInBytes(size, format, &bytes)) {
+  if (!ResourceSizes::MaybeSizeInBytes(size, format, &bytes)) {
     DLOG(ERROR) << "AllocateMappedBitmap with size that overflows";
     CollectMemoryUsageAndDie(size, format, std::numeric_limits<int>::max());
   }
diff --git a/components/viz/common/resources/resource_sizes.h b/components/viz/common/resources/resource_sizes.h
new file mode 100644
index 0000000..68de6fb
--- /dev/null
+++ b/components/viz/common/resources/resource_sizes.h
@@ -0,0 +1,277 @@
+// 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_VIZ_COMMON_RESOURCES_RESOURCE_SIZES_H_
+#define COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_SIZES_H_
+
+#include <stddef.h>
+
+#include <limits>
+
+#include "base/macros.h"
+#include "base/numerics/safe_math.h"
+#include "cc/base/math_util.h"
+#include "components/viz/common/resources/resource_format.h"
+#include "components/viz/common/resources/resource_format_utils.h"
+#include "components/viz/common/viz_common_export.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace viz {
+
+class VIZ_COMMON_EXPORT ResourceSizes {
+ public:
+  // Returns true if the width is valid and fits in bytes, false otherwise.
+  template <typename T>
+  static bool VerifyWidthInBytes(int width, ResourceFormat format);
+  // Returns true if the size is valid and fits in bytes, false otherwise.
+  template <typename T>
+  static bool VerifySizeInBytes(const gfx::Size& size, ResourceFormat format);
+
+  // Returns true if the width is valid and fits in bytes, false otherwise.
+  // Sets the bytes result in the out parameter |bytes|.
+  template <typename T>
+  static bool MaybeWidthInBytes(int width, ResourceFormat format, T* bytes);
+  // Returns true if the size is valid and fits in bytes, false otherwise.
+  // Sets the bytes result in the out parameter |bytes|.
+  template <typename T>
+  static bool MaybeSizeInBytes(const gfx::Size& size,
+                               ResourceFormat format,
+                               T* bytes);
+
+  // Dies with a CRASH() if the width can not be represented as a positive
+  // number of bytes.
+  template <typename T>
+  static T CheckedWidthInBytes(int width, ResourceFormat format);
+  // Dies with a CRASH() if the size can not be represented as a positive
+  // number of bytes.
+  template <typename T>
+  static T CheckedSizeInBytes(const gfx::Size& size, ResourceFormat format);
+
+  // Returns the width in bytes but may overflow or return 0. Only do this for
+  // computing widths for sizes that have already been checked.
+  template <typename T>
+  static T UncheckedWidthInBytes(int width, ResourceFormat format);
+  // Returns the size in bytes but may overflow or return 0. Only do this for
+  // sizes that have already been checked.
+  template <typename T>
+  static T UncheckedSizeInBytes(const gfx::Size& size, ResourceFormat format);
+  // Returns the width in bytes aligned but may overflow or return 0. Only do
+  // this for computing widths for sizes that have already been checked.
+  template <typename T>
+  static T UncheckedWidthInBytesAligned(int width, ResourceFormat format);
+  // Returns the size in bytes aligned but may overflow or return 0. Only do
+  // this for sizes that have already been checked.
+  template <typename T>
+  static T UncheckedSizeInBytesAligned(const gfx::Size& size,
+                                       ResourceFormat format);
+
+ private:
+  template <typename T>
+  static inline void VerifyType();
+
+  template <typename T>
+  static bool VerifyFitsInBytesInternal(int width,
+                                        int height,
+                                        ResourceFormat format,
+                                        bool verify_size,
+                                        bool aligned);
+
+  template <typename T>
+  static T BytesInternal(int width,
+                         int height,
+                         ResourceFormat format,
+                         bool verify_size,
+                         bool aligned);
+
+  // Not instantiable.
+  ResourceSizes() = delete;
+};
+
+template <typename T>
+bool ResourceSizes::VerifyWidthInBytes(int width, ResourceFormat format) {
+  VerifyType<T>();
+  if (width <= 0)
+    return false;
+  return VerifyFitsInBytesInternal<T>(width, 0, format, false, false);
+}
+
+template <typename T>
+bool ResourceSizes::VerifySizeInBytes(const gfx::Size& size,
+                                      ResourceFormat format) {
+  VerifyType<T>();
+  if (size.IsEmpty())
+    return false;
+  return VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true,
+                                      false);
+}
+
+template <typename T>
+bool ResourceSizes::MaybeWidthInBytes(int width,
+                                      ResourceFormat format,
+                                      T* bytes) {
+  VerifyType<T>();
+  if (width <= 0)
+    return false;
+  base::CheckedNumeric<T> checked_value = BitsPerPixel(format);
+  checked_value *= width;
+  checked_value =
+      cc::MathUtil::CheckedRoundUp<T>(checked_value.ValueOrDie(), 8);
+  checked_value /= 8;
+  if (!checked_value.IsValid())
+    return false;
+  *bytes = checked_value.ValueOrDie();
+  return true;
+}
+
+template <typename T>
+bool ResourceSizes::MaybeSizeInBytes(const gfx::Size& size,
+                                     ResourceFormat format,
+                                     T* bytes) {
+  VerifyType<T>();
+  if (size.IsEmpty())
+    return false;
+  base::CheckedNumeric<T> checked_value = BitsPerPixel(format);
+  checked_value *= size.width();
+  checked_value =
+      cc::MathUtil::CheckedRoundUp<T>(checked_value.ValueOrDie(), 8);
+  checked_value /= 8;
+  checked_value *= size.height();
+  if (!checked_value.IsValid())
+    return false;
+  *bytes = checked_value.ValueOrDie();
+  return true;
+}
+
+template <typename T>
+T ResourceSizes::CheckedWidthInBytes(int width, ResourceFormat format) {
+  VerifyType<T>();
+  CHECK_GT(width, 0);
+  DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, false));
+  base::CheckedNumeric<T> checked_value = BitsPerPixel(format);
+  checked_value *= width;
+  checked_value =
+      cc::MathUtil::CheckedRoundUp<T>(checked_value.ValueOrDie(), 8);
+  checked_value /= 8;
+  return checked_value.ValueOrDie();
+}
+
+template <typename T>
+T ResourceSizes::CheckedSizeInBytes(const gfx::Size& size,
+                                    ResourceFormat format) {
+  VerifyType<T>();
+  CHECK(!size.IsEmpty());
+  DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true,
+                                      false));
+  base::CheckedNumeric<T> checked_value = BitsPerPixel(format);
+  checked_value *= size.width();
+  checked_value =
+      cc::MathUtil::CheckedRoundUp<T>(checked_value.ValueOrDie(), 8);
+  checked_value /= 8;
+  checked_value *= size.height();
+  return checked_value.ValueOrDie();
+}
+
+template <typename T>
+T ResourceSizes::UncheckedWidthInBytes(int width, ResourceFormat format) {
+  VerifyType<T>();
+  DCHECK_GT(width, 0);
+  DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, false));
+  return BytesInternal<T>(width, 0, format, false, false);
+}
+
+template <typename T>
+T ResourceSizes::UncheckedSizeInBytes(const gfx::Size& size,
+                                      ResourceFormat format) {
+  VerifyType<T>();
+  DCHECK(!size.IsEmpty());
+  DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true,
+                                      false));
+  return BytesInternal<T>(size.width(), size.height(), format, true, false);
+}
+
+template <typename T>
+T ResourceSizes::UncheckedWidthInBytesAligned(int width,
+                                              ResourceFormat format) {
+  VerifyType<T>();
+  DCHECK_GT(width, 0);
+  DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, true));
+  return BytesInternal<T>(width, 0, format, false, true);
+}
+
+template <typename T>
+T ResourceSizes::UncheckedSizeInBytesAligned(const gfx::Size& size,
+                                             ResourceFormat format) {
+  VerifyType<T>();
+  CHECK(!size.IsEmpty());
+  DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true,
+                                      true));
+  return BytesInternal<T>(size.width(), size.height(), format, true, true);
+}
+
+template <typename T>
+void ResourceSizes::VerifyType() {
+  static_assert(
+      std::numeric_limits<T>::is_integer && !std::is_same<T, bool>::value,
+      "T must be non-bool integer type. Preferred type is size_t.");
+}
+
+template <typename T>
+bool ResourceSizes::VerifyFitsInBytesInternal(int width,
+                                              int height,
+                                              ResourceFormat format,
+                                              bool verify_size,
+                                              bool aligned) {
+  base::CheckedNumeric<T> checked_value = BitsPerPixel(format);
+  checked_value *= width;
+  if (!checked_value.IsValid())
+    return false;
+
+  // Roundup bits to byte (8 bits) boundary. If width is 3 and BitsPerPixel is
+  // 4, then it should return 16, so that row pixels do not get truncated.
+  checked_value =
+      cc::MathUtil::UncheckedRoundUp<T>(checked_value.ValueOrDie(), 8);
+
+  // If aligned is true, bytes are aligned on 4-bytes boundaries for upload
+  // performance, assuming that GL_PACK_ALIGNMENT or GL_UNPACK_ALIGNMENT have
+  // not changed from default.
+  if (aligned) {
+    checked_value /= 8;
+    if (!checked_value.IsValid())
+      return false;
+    checked_value =
+        cc::MathUtil::UncheckedRoundUp<T>(checked_value.ValueOrDie(), 4);
+    checked_value *= 8;
+  }
+
+  if (verify_size)
+    checked_value *= height;
+  if (!checked_value.IsValid())
+    return false;
+  T value = checked_value.ValueOrDie();
+  if ((value % 8) != 0)
+    return false;
+  return true;
+}
+
+template <typename T>
+T ResourceSizes::BytesInternal(int width,
+                               int height,
+                               ResourceFormat format,
+                               bool verify_size,
+                               bool aligned) {
+  T bytes = BitsPerPixel(format);
+  bytes *= width;
+  bytes = cc::MathUtil::UncheckedRoundUp<T>(bytes, 8);
+  bytes /= 8;
+  if (aligned)
+    bytes = cc::MathUtil::UncheckedRoundUp<T>(bytes, 4);
+  if (verify_size)
+    bytes *= height;
+
+  return bytes;
+}
+
+}  // namespace viz
+
+#endif  // COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_SIZES_H_
diff --git a/components/viz/host/BUILD.gn b/components/viz/host/BUILD.gn
index f5362cb..d52ccab 100644
--- a/components/viz/host/BUILD.gn
+++ b/components/viz/host/BUILD.gn
@@ -82,6 +82,6 @@
     ":host",
     "//base/test:test_support",
     "//components/viz/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
   ]
 }
diff --git a/components/viz/service/display/display_scheduler.cc b/components/viz/service/display/display_scheduler.cc
index bf1a237..402eecc 100644
--- a/components/viz/service/display/display_scheduler.cc
+++ b/components/viz/service/display/display_scheduler.cc
@@ -70,7 +70,11 @@
 void DisplayScheduler::SetRootSurfaceResourcesLocked(bool locked) {
   TRACE_EVENT1("viz", "DisplayScheduler::SetRootSurfaceResourcesLocked",
                "locked", locked);
+  if (root_surface_resources_locked_ == locked)
+    return;
+
   root_surface_resources_locked_ = locked;
+  MaybeStartObservingBeginFrames();
   ScheduleBeginFrameDeadline();
 }
 
@@ -292,7 +296,8 @@
 bool DisplayScheduler::ShouldDraw() {
   // Note: When any of these cases becomes true, MaybeStartObservingBeginFrames
   // must be called to ensure the draw will happen.
-  return needs_draw_ && !output_surface_lost_ && visible_;
+  return needs_draw_ && !output_surface_lost_ && visible_ &&
+         !root_surface_resources_locked_;
 }
 
 void DisplayScheduler::OnBeginFrameSourcePausedChanged(bool paused) {
@@ -478,7 +483,7 @@
   begin_frame_deadline_task_time_ = base::TimeTicks();
 
   if (ShouldDraw()) {
-    if (pending_swaps_ < max_pending_swaps_ && !root_surface_resources_locked_)
+    if (pending_swaps_ < max_pending_swaps_)
       return DrawAndSwap();
   } else {
     // We are going idle, so reset expectations.
diff --git a/components/viz/service/display/display_scheduler_unittest.cc b/components/viz/service/display/display_scheduler_unittest.cc
index 335f33a..a013500 100644
--- a/components/viz/service/display/display_scheduler_unittest.cc
+++ b/components/viz/service/display/display_scheduler_unittest.cc
@@ -629,10 +629,14 @@
 
   //  Deadline triggers normally when root resources are unlocked.
   AdvanceTimeAndBeginFrameForTest({sid1, root_surface_id});
-  late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
+  EXPECT_FALSE(scheduler_.inside_begin_frame_deadline_interval());
   SurfaceDamaged(sid1);
+
+  // The deadline is not updated because the display scheduler does not receive
+  // a BeginFrame while root resources are locked.
   EXPECT_EQ(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
   scheduler_.SetRootSurfaceResourcesLocked(false);
+  EXPECT_TRUE(scheduler_.inside_begin_frame_deadline_interval());
   SurfaceDamaged(root_surface_id);
   EXPECT_EQ(base::TimeTicks(),
             scheduler_.DesiredBeginFrameDeadlineTimeForTest());
diff --git a/components/viz/service/display_embedder/server_shared_bitmap_manager.cc b/components/viz/service/display_embedder/server_shared_bitmap_manager.cc
index e132e21..a9745b9 100644
--- a/components/viz/service/display_embedder/server_shared_bitmap_manager.cc
+++ b/components/viz/service/display_embedder/server_shared_bitmap_manager.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/process_memory_dump.h"
+#include "components/viz/common/resources/resource_sizes.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -86,7 +87,7 @@
   DCHECK(IsBitmapFormatSupported(format));
   base::AutoLock lock(lock_);
   size_t bitmap_size;
-  if (!SharedBitmap::SizeInBytes(size, format, &bitmap_size))
+  if (!ResourceSizes::MaybeSizeInBytes(size, format, &bitmap_size))
     return nullptr;
 
   scoped_refptr<BitmapData> data(new BitmapData(bitmap_size));
@@ -112,7 +113,7 @@
   BitmapData* data = it->second.get();
 
   size_t bitmap_size;
-  if (!SharedBitmap::SizeInBytes(size, format, &bitmap_size) ||
+  if (!ResourceSizes::MaybeSizeInBytes(size, format, &bitmap_size) ||
       bitmap_size > data->buffer_size)
     return nullptr;
 
diff --git a/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc b/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc
index d7c7e78a..cce61d2 100644
--- a/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc
+++ b/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
 
+#include "components/viz/common/resources/resource_sizes.h"
 #include "components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -29,7 +30,7 @@
   gfx::Size bitmap_size(1, 1);
   size_t size_in_bytes;
   EXPECT_TRUE(
-      SharedBitmap::SizeInBytes(bitmap_size, RGBA_8888, &size_in_bytes));
+      ResourceSizes::MaybeSizeInBytes(bitmap_size, RGBA_8888, &size_in_bytes));
   std::unique_ptr<base::SharedMemory> bitmap(new base::SharedMemory());
   bitmap->CreateAndMapAnonymous(size_in_bytes);
   memset(bitmap->memory(), 0xff, size_in_bytes);
@@ -94,7 +95,7 @@
   gfx::Size bitmap_size(1, 1);
   size_t size_in_bytes;
   EXPECT_TRUE(
-      SharedBitmap::SizeInBytes(bitmap_size, RGBA_8888, &size_in_bytes));
+      ResourceSizes::MaybeSizeInBytes(bitmap_size, RGBA_8888, &size_in_bytes));
   std::unique_ptr<base::SharedMemory> bitmap(new base::SharedMemory());
   bitmap->CreateAndMapAnonymous(size_in_bytes);
   memset(bitmap->memory(), 0xff, size_in_bytes);
@@ -130,7 +131,7 @@
   gfx::Size bitmap_size(1, 1);
   size_t size_in_bytes;
   EXPECT_TRUE(
-      SharedBitmap::SizeInBytes(bitmap_size, RGBA_8888, &size_in_bytes));
+      ResourceSizes::MaybeSizeInBytes(bitmap_size, RGBA_8888, &size_in_bytes));
   std::unique_ptr<base::SharedMemory> bitmap(new base::SharedMemory());
   bitmap->CreateAndMapAnonymous(size_in_bytes);
   memset(bitmap->memory(), 0xff, size_in_bytes);
@@ -166,7 +167,7 @@
   gfx::Size bitmap_size(1, 1);
   size_t size_in_bytes;
   EXPECT_TRUE(
-      SharedBitmap::SizeInBytes(bitmap_size, RGBA_8888, &size_in_bytes));
+      ResourceSizes::MaybeSizeInBytes(bitmap_size, RGBA_8888, &size_in_bytes));
   std::unique_ptr<base::SharedMemory> bitmap(new base::SharedMemory());
   bitmap->CreateAndMapAnonymous(size_in_bytes);
   memset(bitmap->memory(), 0xff, size_in_bytes);
diff --git a/components/viz/service/display_embedder/software_output_device_win.cc b/components/viz/service/display_embedder/software_output_device_win.cc
index 413c2d7..61213e77 100644
--- a/components/viz/service/display_embedder/software_output_device_win.cc
+++ b/components/viz/service/display_embedder/software_output_device_win.cc
@@ -6,7 +6,7 @@
 
 #include "base/debug/alias.h"
 #include "base/memory/shared_memory.h"
-#include "components/viz/common/quads/shared_bitmap.h"
+#include "components/viz/common/resources/resource_sizes.h"
 #include "skia/ext/platform_canvas.h"
 #include "skia/ext/skia_utils_win.h"
 #include "ui/base/win/internal_constants.h"
@@ -55,7 +55,7 @@
     return backing_.get();
   size_t expected_byte_size = GetMaxByteSize();
   size_t required_size;
-  if (!SharedBitmap::SizeInBytes(size, RGBA_8888, &required_size))
+  if (!ResourceSizes::MaybeSizeInBytes(size, RGBA_8888, &required_size))
     return nullptr;
   if (required_size > expected_byte_size)
     return nullptr;
@@ -73,8 +73,8 @@
   size_t max_size = 1;
   for (const SoftwareOutputDeviceWin* device : devices_) {
     size_t current_size;
-    if (!SharedBitmap::SizeInBytes(device->viewport_pixel_size(), RGBA_8888,
-                                   &current_size))
+    if (!ResourceSizes::MaybeSizeInBytes(device->viewport_pixel_size(),
+                                         RGBA_8888, &current_size))
       continue;
     if (current_size > kMaxBitmapSizeBytes)
       continue;
diff --git a/components/webcrypto/BUILD.gn b/components/webcrypto/BUILD.gn
index fdb059b..7c9fffd9 100644
--- a/components/webcrypto/BUILD.gn
+++ b/components/webcrypto/BUILD.gn
@@ -109,7 +109,7 @@
     "//base",
     "//crypto",
     "//crypto:platform",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//third_party/WebKit/public:blink",
   ]
 }
diff --git a/components/zucchini/main_utils.cc b/components/zucchini/main_utils.cc
index ee0332a..3a7055a 100644
--- a/components/zucchini/main_utils.cc
+++ b/components/zucchini/main_utils.cc
@@ -8,10 +8,17 @@
 
 #include <memory>
 #include <ostream>
+#include <string>
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
 #include "base/logging.h"
+#include "base/process/process_handle.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "components/zucchini/io_utils.h"
@@ -64,6 +71,66 @@
     {"crc32", "-crc32 <file>", 1, &MainCrc32},
 };
 
+/******** GetPeakMemoryMetrics ********/
+
+#if defined(OS_LINUX)
+// Linux does not have an exact mapping to the values used on Windows so use a
+// close approximation:
+// peak_virtual_memory ~= peak_page_file_usage
+// resident_set_size_hwm (high water mark) ~= peak_working_set_size
+//
+// On failure the input values will be set to 0.
+void GetPeakMemoryMetrics(size_t* peak_virtual_memory,
+                          size_t* resident_set_size_hwm) {
+  *peak_virtual_memory = 0;
+  *resident_set_size_hwm = 0;
+  auto status_path =
+      base::FilePath("/proc")
+          .Append(base::IntToString(base::GetCurrentProcessHandle()))
+          .Append("status");
+  std::string contents_string;
+  base::ReadFileToString(status_path, &contents_string);
+  std::vector<base::StringPiece> lines = base::SplitStringPiece(
+      contents_string, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+
+  for (const auto& line : lines) {
+    // Tokens should generally be of the form "Metric: <val> kB"
+    std::vector<base::StringPiece> tokens = base::SplitStringPiece(
+        line, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+    if (tokens.size() < 2)
+      continue;
+
+    if (tokens[0] == "VmPeak:") {
+      if (base::StringToSizeT(tokens[1], peak_virtual_memory)) {
+        *peak_virtual_memory *= 1024;  // in kiB
+        if (*resident_set_size_hwm)
+          return;
+      }
+    } else if (tokens[0] == "VmHWM:") {
+      if (base::StringToSizeT(tokens[1], resident_set_size_hwm)) {
+        *resident_set_size_hwm *= 1024;  // in kiB
+        if (*peak_virtual_memory)
+          return;
+      }
+    }
+  }
+}
+#endif  // defined(OS_LINUX)
+
+#if defined(OS_WIN)
+// On failure the input values will be set to 0.
+void GetPeakMemoryMetrics(size_t* peak_page_file_usage,
+                          size_t* peak_working_set_size) {
+  *peak_page_file_usage = 0;
+  *peak_working_set_size = 0;
+  PROCESS_MEMORY_COUNTERS pmc;
+  if (::GetProcessMemoryInfo(::GetCurrentProcess(), &pmc, sizeof(pmc))) {
+    *peak_page_file_usage = pmc.PeakPagefileUsage;
+    *peak_working_set_size = pmc.PeakWorkingSetSize;
+  }
+}
+#endif  // defined(OS_WIN)
+
 /******** ScopedResourceUsageTracker ********/
 
 // A class to track and log system resource usage.
@@ -73,27 +140,20 @@
   ScopedResourceUsageTracker() {
     start_time_ = base::TimeTicks::Now();
 
-#if defined(OS_WIN)
-    PROCESS_MEMORY_COUNTERS pmc;
-    if (::GetProcessMemoryInfo(::GetCurrentProcess(), &pmc, sizeof(pmc))) {
-      start_peak_page_file_usage_ = pmc.PeakPagefileUsage;
-      start_peak_working_set_size_ = pmc.PeakWorkingSetSize;
-    }
-#endif
+#if defined(OS_LINUX) || defined(OS_WIN)
+    GetPeakMemoryMetrics(&start_peak_page_file_usage_,
+                         &start_peak_working_set_size_);
+#endif  // defined(OS_LINUX) || defined(OS_WIN)
   }
 
   // Computes and prints usage.
   ~ScopedResourceUsageTracker() {
     base::TimeTicks end_time = base::TimeTicks::Now();
 
-#if defined(OS_WIN)
+#if defined(OS_LINUX) || defined(OS_WIN)
     size_t cur_peak_page_file_usage = 0;
     size_t cur_peak_working_set_size = 0;
-    PROCESS_MEMORY_COUNTERS pmc;
-    if (::GetProcessMemoryInfo(::GetCurrentProcess(), &pmc, sizeof(pmc))) {
-      cur_peak_page_file_usage = pmc.PeakPagefileUsage;
-      cur_peak_working_set_size = pmc.PeakWorkingSetSize;
-    }
+    GetPeakMemoryMetrics(&cur_peak_page_file_usage, &cur_peak_working_set_size);
 
     LOG(INFO) << "Zucchini.PeakPagefileUsage "
               << cur_peak_page_file_usage / 1024 << " KiB";
@@ -106,7 +166,7 @@
               << (cur_peak_working_set_size - start_peak_working_set_size_) /
                      1024
               << " KiB";
-#endif  // !defined(OS_MACOSX)
+#endif  // defined(OS_LINUX) || defined(OS_WIN)
 
     LOG(INFO) << "Zucchini.TotalTime " << (end_time - start_time_).InSecondsF()
               << " s";
@@ -114,10 +174,10 @@
 
  private:
   base::TimeTicks start_time_;
-#if defined(OS_WIN)
+#if defined(OS_LINUX) || defined(OS_WIN)
   size_t start_peak_page_file_usage_ = 0;
   size_t start_peak_working_set_size_ = 0;
-#endif  // !defined(OS_MACOSX)
+#endif  // defined(OS_LINUX) || defined(OS_WIN)
 };
 
 /******** Helper functions ********/
diff --git a/content/app/BUILD.gn b/content/app/BUILD.gn
index 176868f..19447fb 100644
--- a/content/app/BUILD.gn
+++ b/content/app/BUILD.gn
@@ -32,7 +32,7 @@
     "//services/service_manager/embedder",
     "//services/service_manager/public/mojom",
     "//services/service_manager/runner/common",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//ppapi/features",
     "//ui/base",
     "//ui/gfx",
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index b52bb2d..96fd01d 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -109,7 +109,7 @@
     "//media/mojo/services",
     "//mojo/common",
     "//mojo/common:values_struct_traits",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/bindings",
     "//mojo/public/js:resources",
     "//net",
@@ -598,6 +598,8 @@
     "devtools/devtools_traceable_screenshot.h",
     "devtools/devtools_url_interceptor_request_job.cc",
     "devtools/devtools_url_interceptor_request_job.h",
+    "devtools/devtools_url_loader_interceptor.cc",
+    "devtools/devtools_url_loader_interceptor.h",
     "devtools/devtools_url_request_interceptor.cc",
     "devtools/devtools_url_request_interceptor.h",
     "devtools/forwarding_agent_host.cc",
diff --git a/content/browser/android/content_view_core.cc b/content/browser/android/content_view_core.cc
index f5bce609..d79bc8a 100644
--- a/content/browser/android/content_view_core.cc
+++ b/content/browser/android/content_view_core.cc
@@ -266,13 +266,6 @@
   return java_ref_.get(env);
 }
 
-jint ContentViewCore::GetBackgroundColor(JNIEnv* env, jobject obj) {
-  RenderWidgetHostViewAndroid* rwhva = GetRenderWidgetHostViewAndroid();
-  if (!rwhva)
-    return SK_ColorWHITE;
-  return rwhva->GetCachedBackgroundColor();
-}
-
 void ContentViewCore::SendScreenRectsAndResizeWidget() {
   RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
   if (view) {
@@ -421,15 +414,6 @@
   return content::GetContentClient()->UsingSynchronousCompositing();
 }
 
-void ContentViewCore::HidePopupsAndPreserveSelection() {
-  JNIEnv* env = AttachCurrentThread();
-  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
-  if (obj.is_null())
-    return;
-
-  Java_ContentViewCoreImpl_hidePopupsAndPreserveSelection(env, obj);
-}
-
 void ContentViewCore::WebContentsDestroyed() {
   WebContentsViewAndroid* wcva = static_cast<WebContentsViewAndroid*>(
       static_cast<WebContentsImpl*>(web_contents())->GetView());
diff --git a/content/browser/android/content_view_core.h b/content/browser/android/content_view_core.h
index 32ae955..9954566 100644
--- a/content/browser/android/content_view_core.h
+++ b/content/browser/android/content_view_core.h
@@ -75,14 +75,6 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
       jint orientation);
-  jboolean SendMouseWheelEvent(JNIEnv* env,
-                               const base::android::JavaParamRef<jobject>& obj,
-                               jlong time_ms,
-                               jfloat x,
-                               jfloat y,
-                               jfloat ticks_x,
-                               jfloat ticks_y,
-                               jfloat pixels_per_tick);
 
   void ResetGestureDetection(JNIEnv* env,
                              const base::android::JavaParamRef<jobject>& obj);
@@ -103,8 +95,6 @@
                    const base::android::JavaParamRef<jobject>& obj,
                    jfloat dipScale);
 
-  jint GetBackgroundColor(JNIEnv* env, jobject obj);
-
   void SetTextTrackSettings(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
@@ -117,29 +107,14 @@
       const base::android::JavaParamRef<jstring>& textTrackTextShadow,
       const base::android::JavaParamRef<jstring>& textTrackTextSize);
 
-  void SetBackgroundOpaque(JNIEnv* env,
-                           const base::android::JavaParamRef<jobject>& jobj,
-                           jboolean opaque);
-
   jboolean UsingSynchronousCompositing(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
 
   // --------------------------------------------------------------------------
-  // Public methods that call to Java via JNI
-  // --------------------------------------------------------------------------
-
-  void HidePopupsAndPreserveSelection();
-
-  // Returns the context with which the ContentViewCore was created, typically
-  // the Activity context.
-  base::android::ScopedJavaLocalRef<jobject> GetContext() const;
-
-  // --------------------------------------------------------------------------
   // Methods called from native code
   // --------------------------------------------------------------------------
 
-  void UpdateCursor(const content::CursorInfo& info);
   void OnTouchDown(const base::android::ScopedJavaLocalRef<jobject>& event);
 
   ui::ViewAndroid* GetViewAndroid() const;
diff --git a/content/browser/android/selection_popup_controller.cc b/content/browser/android/selection_popup_controller.cc
index 3fa42e0..df52381 100644
--- a/content/browser/android/selection_popup_controller.cc
+++ b/content/browser/android/selection_popup_controller.cc
@@ -10,6 +10,7 @@
 #include "content/browser/android/composited_touch_handle_drawable.h"
 #include "content/browser/renderer_host/render_widget_host_view_android.h"
 #include "content/browser/web_contents/web_contents_impl.h"
+#include "content/browser/web_contents/web_contents_view_android.h"
 #include "content/public/common/context_menu_params.h"
 #include "jni/SelectionPopupControllerImpl_jni.h"
 #include "third_party/WebKit/public/web/WebContextMenuData.h"
@@ -43,6 +44,9 @@
     WebContents* web_contents)
     : RenderWidgetHostConnector(web_contents) {
   java_obj_ = JavaObjectWeakGlobalRef(env, obj);
+  auto* wcva = static_cast<WebContentsViewAndroid*>(
+      static_cast<WebContentsImpl*>(web_contents)->GetView());
+  wcva->set_selection_popup_controller(this);
 }
 
 ScopedJavaLocalRef<jobject> SelectionPopupController::GetContext() const {
@@ -197,4 +201,13 @@
       env, obj, did_select, start_adjust, end_adjust);
 }
 
+void SelectionPopupController::HidePopupsAndPreserveSelection() {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = java_obj_.get(env);
+  if (obj.is_null())
+    return;
+
+  Java_SelectionPopupControllerImpl_hidePopupsAndPreserveSelection(env, obj);
+}
+
 }  // namespace content
diff --git a/content/browser/android/selection_popup_controller.h b/content/browser/android/selection_popup_controller.h
index 9ff98ef7..27d5367 100644
--- a/content/browser/android/selection_popup_controller.h
+++ b/content/browser/android/selection_popup_controller.h
@@ -46,6 +46,7 @@
   void OnSelectWordAroundCaretAck(bool did_select,
                                   int start_adjust,
                                   int end_adjust);
+  void HidePopupsAndPreserveSelection();
   std::unique_ptr<ui::TouchHandleDrawable> CreateTouchHandleDrawable();
   void MoveRangeSelectionExtent(const gfx::PointF& extent);
 
diff --git a/content/browser/appcache/appcache.cc b/content/browser/appcache/appcache.cc
index 061c95de..bf1a0ec4 100644
--- a/content/browser/appcache/appcache.cc
+++ b/content/browser/appcache/appcache.cc
@@ -74,12 +74,11 @@
 const AppCacheEntry* AppCache::GetEntryAndUrlWithResponseId(
     int64_t response_id,
     GURL* optional_url_out) {
-  for (EntryMap::const_iterator iter = entries_.begin();
-       iter !=  entries_.end(); ++iter) {
-    if (iter->second.response_id() == response_id) {
+  for (const auto& pair : entries_) {
+    if (pair.second.response_id() == response_id) {
       if (optional_url_out)
-        *optional_url_out = iter->first;
-      return &iter->second;
+        *optional_url_out = pair.first;
+      return &pair.second;
     }
   }
   return nullptr;
@@ -174,15 +173,14 @@
   cache_record->update_time = update_time_;
   cache_record->cache_size = 0;
 
-  for (EntryMap::const_iterator iter = entries_.begin();
-       iter != entries_.end(); ++iter) {
+  for (const auto& pair : entries_) {
     entries->push_back(AppCacheDatabase::EntryRecord());
     AppCacheDatabase::EntryRecord& record = entries->back();
-    record.url = iter->first;
+    record.url = pair.first;
     record.cache_id = cache_id_;
-    record.flags = iter->second.types();
-    record.response_id = iter->second.response_id();
-    record.response_size = iter->second.response_size();
+    record.flags = pair.second.types();
+    record.response_id = pair.second.response_id();
+    record.response_size = pair.second.response_size();
     cache_record->cache_size += record.response_size;
   }
 
@@ -266,19 +264,18 @@
 
 void AppCache::ToResourceInfoVector(AppCacheResourceInfoVector* infos) const {
   DCHECK(infos && infos->empty());
-  for (EntryMap::const_iterator iter = entries_.begin();
-       iter !=  entries_.end(); ++iter) {
+  for (const auto& pair : entries_) {
     infos->push_back(AppCacheResourceInfo());
     AppCacheResourceInfo& info = infos->back();
-    info.url = iter->first;
-    info.is_master = iter->second.IsMaster();
-    info.is_manifest = iter->second.IsManifest();
-    info.is_intercept = iter->second.IsIntercept();
-    info.is_fallback = iter->second.IsFallback();
-    info.is_foreign = iter->second.IsForeign();
-    info.is_explicit = iter->second.IsExplicit();
-    info.size = iter->second.response_size();
-    info.response_id = iter->second.response_id();
+    info.url = pair.first;
+    info.is_master = pair.second.IsMaster();
+    info.is_manifest = pair.second.IsManifest();
+    info.is_intercept = pair.second.IsIntercept();
+    info.is_fallback = pair.second.IsFallback();
+    info.is_foreign = pair.second.IsForeign();
+    info.is_explicit = pair.second.IsExplicit();
+    info.size = pair.second.response_size();
+    info.response_id = pair.second.response_id();
   }
 }
 
diff --git a/content/browser/appcache/appcache.h b/content/browser/appcache/appcache.h
index f2fdc95..f468b5de 100644
--- a/content/browser/appcache/appcache.h
+++ b/content/browser/appcache/appcache.h
@@ -41,8 +41,8 @@
 class CONTENT_EXPORT AppCache
     : public base::RefCounted<AppCache> {
  public:
-  typedef std::map<GURL, AppCacheEntry> EntryMap;
-  typedef std::set<AppCacheHost*> AppCacheHosts;
+  using EntryMap = std::map<GURL, AppCacheEntry>;
+  using AppCacheHosts = std::set<AppCacheHost*>;
 
   AppCache(AppCacheStorage* storage, int64_t cache_id);
 
diff --git a/content/browser/appcache/appcache_backend_impl.h b/content/browser/appcache/appcache_backend_impl.h
index abde0b3..cf6d435 100644
--- a/content/browser/appcache/appcache_backend_impl.h
+++ b/content/browser/appcache/appcache_backend_impl.h
@@ -56,7 +56,7 @@
     return (it != hosts_.end()) ? (it->second.get()) : nullptr;
   }
 
-  typedef base::hash_map<int, std::unique_ptr<AppCacheHost>> HostMap;
+  using HostMap = base::hash_map<int, std::unique_ptr<AppCacheHost>>;
   const HostMap& hosts() { return hosts_; }
 
   // Methods to support cross site navigations. Hosts are transferred
diff --git a/content/browser/appcache/appcache_database.cc b/content/browser/appcache/appcache_database.cc
index d0a87ed0..f705614 100644
--- a/content/browser/appcache/appcache_database.cc
+++ b/content/browser/appcache/appcache_database.cc
@@ -224,11 +224,8 @@
     return 0;
 
   int64_t origin_usage = 0;
-  std::vector<CacheRecord>::const_iterator iter = records.begin();
-  while (iter != records.end()) {
-    origin_usage += iter->cache_size;
-    ++iter;
-  }
+  for (const auto& record : records)
+    origin_usage += record.cache_size;
   return origin_usage;
 }
 
@@ -236,10 +233,8 @@
   std::set<GURL> origins;
   if (!FindOriginsWithGroups(&origins))
     return false;
-  for (std::set<GURL>::const_iterator origin = origins.begin();
-       origin != origins.end(); ++origin) {
-    (*usage_map)[*origin] = GetOriginUsage(*origin);
-  }
+  for (const auto& origin : origins)
+    (*usage_map)[origin] = GetOriginUsage(origin);
   return true;
 }
 
@@ -534,11 +529,9 @@
     return false;
 
   CacheRecord cache_record;
-  std::vector<GroupRecord>::const_iterator iter = group_records.begin();
-  while (iter != group_records.end()) {
-    if (FindCacheForGroup(iter->group_id, &cache_record))
+  for (const auto& record : group_records) {
+    if (FindCacheForGroup(record.group_id, &cache_record))
       records->push_back(cache_record);
-    ++iter;
   }
   return true;
 }
@@ -668,11 +661,9 @@
   sql::Transaction transaction(db_.get());
   if (!transaction.Begin())
     return false;
-  std::vector<EntryRecord>::const_iterator iter = records.begin();
-  while (iter != records.end()) {
-    if (!InsertEntry(&(*iter)))
+  for (const auto& record : records) {
+    if (!InsertEntry(&record))
       return false;
-    ++iter;
   }
   return transaction.Commit();
 }
@@ -776,11 +767,9 @@
   sql::Transaction transaction(db_.get());
   if (!transaction.Begin())
     return false;
-  std::vector<NamespaceRecord>::const_iterator iter = records.begin();
-  while (iter != records.end()) {
-    if (!InsertNamespace(&(*iter)))
+  for (const auto& record : records) {
+    if (!InsertNamespace(&record))
       return false;
-    ++iter;
   }
   return transaction.Commit();
 }
@@ -844,11 +833,9 @@
   sql::Transaction transaction(db_.get());
   if (!transaction.Begin())
     return false;
-  std::vector<OnlineWhiteListRecord>::const_iterator iter = records.begin();
-  while (iter != records.end()) {
-    if (!InsertOnlineWhiteList(&(*iter)))
+  for (const auto& record : records) {
+    if (!InsertOnlineWhiteList(&record))
       return false;
-    ++iter;
   }
   return transaction.Commit();
 }
@@ -915,13 +902,11 @@
 
   sql::Statement statement(db_->GetCachedStatement(statement_id, sql));
 
-  std::vector<int64_t>::const_iterator iter = ids.begin();
-  while (iter != ids.end()) {
-    statement.BindInt64(0, *iter);
+  for (const auto& id : ids) {
+    statement.BindInt64(0, id);
     if (!statement.Run())
       return false;
     statement.Reset(true);
-    ++iter;
   }
 
   return transaction.Commit();
diff --git a/content/browser/appcache/appcache_database.h b/content/browser/appcache/appcache_database.h
index 47ef0b144..7511e60d 100644
--- a/content/browser/appcache/appcache_database.h
+++ b/content/browser/appcache/appcache_database.h
@@ -93,7 +93,7 @@
     AppCacheNamespace namespace_;
   };
 
-  typedef std::vector<NamespaceRecord> NamespaceRecordVector;
+  using NamespaceRecordVector = std::vector<NamespaceRecord>;
 
   struct OnlineWhiteListRecord {
     OnlineWhiteListRecord() : cache_id(0), is_pattern(false) {}
diff --git a/content/browser/appcache/appcache_disk_cache.cc b/content/browser/appcache/appcache_disk_cache.cc
index 1efce0f1..d718034 100644
--- a/content/browser/appcache/appcache_disk_cache.cc
+++ b/content/browser/appcache/appcache_disk_cache.cc
@@ -245,9 +245,8 @@
   // We need to close open file handles in order to reinitalize the
   // appcache system on the fly. File handles held in both entries and in
   // the main disk_cache::Backend class need to be released.
-  for (OpenEntries::const_iterator iter = open_entries_.begin();
-       iter != open_entries_.end(); ++iter) {
-    (*iter)->Abandon();
+  for (EntryImpl* entry : open_entries_) {
+    entry->Abandon();
   }
   open_entries_.clear();
   disk_cache_.reset();
@@ -370,25 +369,24 @@
   }
 
   // Service pending calls that were queued up while we were initializing.
-  for (PendingCalls::const_iterator iter = pending_calls_.begin();
-       iter < pending_calls_.end(); ++iter) {
+  for (const auto& call : pending_calls_) {
     rv = net::ERR_FAILED;
-    switch (iter->call_type) {
+    switch (call.call_type) {
       case CREATE:
-        rv = CreateEntry(iter->key, iter->entry, iter->callback);
+        rv = CreateEntry(call.key, call.entry, call.callback);
         break;
       case OPEN:
-        rv = OpenEntry(iter->key, iter->entry, iter->callback);
+        rv = OpenEntry(call.key, call.entry, call.callback);
         break;
       case DOOM:
-        rv = DoomEntry(iter->key, iter->callback);
+        rv = DoomEntry(call.key, call.callback);
         break;
       default:
         NOTREACHED();
         break;
     }
     if (rv != net::ERR_IO_PENDING)
-      iter->callback.Run(rv);
+      call.callback.Run(rv);
   }
   pending_calls_.clear();
 }
diff --git a/content/browser/appcache/appcache_disk_cache.h b/content/browser/appcache/appcache_disk_cache.h
index 876e8ec..5eba6053 100644
--- a/content/browser/appcache/appcache_disk_cache.h
+++ b/content/browser/appcache/appcache_disk_cache.h
@@ -89,11 +89,11 @@
 
     ~PendingCall();
   };
-  typedef std::vector<PendingCall> PendingCalls;
+  using PendingCalls = std::vector<PendingCall>;
 
   class ActiveCall;
-  typedef std::set<ActiveCall*> ActiveCalls;
-  typedef std::set<EntryImpl*> OpenEntries;
+  using ActiveCalls = std::set<ActiveCall*>;
+  using OpenEntries = std::set<EntryImpl*>;
 
   bool is_initializing_or_waiting_to_initialize() const {
     return create_backend_callback_.get() != NULL || is_waiting_to_initialize_;
diff --git a/content/browser/appcache/appcache_disk_cache_unittest.cc b/content/browser/appcache/appcache_disk_cache_unittest.cc
index 61857e2..e6e94b70 100644
--- a/content/browser/appcache/appcache_disk_cache_unittest.cc
+++ b/content/browser/appcache/appcache_disk_cache_unittest.cc
@@ -71,9 +71,8 @@
 
   EXPECT_EQ(nullptr, entry);
   EXPECT_EQ(4u, completion_results_.size());
-  for (std::vector<int>::const_iterator iter = completion_results_.begin();
-       iter < completion_results_.end(); ++iter) {
-    EXPECT_EQ(net::ERR_ABORTED, *iter);
+  for (const auto& result : completion_results_) {
+    EXPECT_EQ(net::ERR_ABORTED, result);
   }
 
   // Ensure the directory can be deleted at this point.
diff --git a/content/browser/appcache/appcache_group.cc b/content/browser/appcache/appcache_group.cc
index 06cca4c..85e6be0e 100644
--- a/content/browser/appcache/appcache_group.cc
+++ b/content/browser/appcache/appcache_group.cc
@@ -98,13 +98,13 @@
     newest_complete_cache_ = complete_cache;
 
     // Update hosts of older caches to add a reference to the newest cache.
-    for (Caches::iterator it = old_caches_.begin();
-         it != old_caches_.end(); ++it) {
-      AppCache::AppCacheHosts& hosts = (*it)->associated_hosts();
-      for (AppCache::AppCacheHosts::iterator host_it = hosts.begin();
-           host_it != hosts.end(); ++host_it) {
-        (*host_it)->SetSwappableCache(this);
-      }
+    // (This loop mutates |old_caches_| so a range-based for-loop cannot be
+    // used, because it caches the end iterator.)
+    for (Caches::iterator it = old_caches_.begin(); it != old_caches_.end();
+         ++it) {
+      AppCache* cache = *it;
+      for (AppCacheHost* host : cache->associated_hosts())
+        host->SetSwappableCache(this);
     }
   } else {
     old_caches_.push_back(complete_cache);
@@ -211,9 +211,8 @@
   queued_updates_.swap(updates_to_run);
   DCHECK(queued_updates_.empty());
 
-  for (QueuedUpdates::iterator it = updates_to_run.begin();
-       it != updates_to_run.end(); ++it) {
-    AppCacheHost* host = it->second.first;
+  for (auto& pair : updates_to_run) {
+    AppCacheHost* host = pair.second.first;
     host->RemoveObserver(host_observer_.get());
     if (FindObserver(host, queued_observers_)) {
       queued_observers_.RemoveObserver(host);
@@ -221,7 +220,7 @@
     }
 
     if (!is_obsolete() && !is_being_deleted())
-      StartUpdateWithNewMasterEntry(host, it->second.second);
+      StartUpdateWithNewMasterEntry(host, pair.second.second);
   }
 }
 
diff --git a/content/browser/appcache/appcache_group.h b/content/browser/appcache/appcache_group.h
index beb00e3..c119f59 100644
--- a/content/browser/appcache/appcache_group.h
+++ b/content/browser/appcache/appcache_group.h
@@ -127,9 +127,9 @@
 
   ~AppCacheGroup();
 
-  typedef std::vector<AppCache*> Caches;
-  typedef std::map<UpdateObserver*, std::pair<AppCacheHost*, GURL>>
-      QueuedUpdates;
+  using Caches = std::vector<AppCache*>;
+  using QueuedUpdates =
+      std::map<UpdateObserver*, std::pair<AppCacheHost*, GURL>>;
 
   static const int kUpdateRestartDelayMs = 1000;
 
diff --git a/content/browser/appcache/appcache_host.h b/content/browser/appcache/appcache_host.h
index 4941f54..9385306 100644
--- a/content/browser/appcache/appcache_host.h
+++ b/content/browser/appcache/appcache_host.h
@@ -56,9 +56,9 @@
 class AppCacheUpdateJobTest;
 }
 
-typedef base::OnceCallback<void(AppCacheStatus)> GetStatusCallback;
-typedef base::OnceCallback<void(bool)> StartUpdateCallback;
-typedef base::OnceCallback<void(bool)> SwapCacheCallback;
+using GetStatusCallback = base::OnceCallback<void(AppCacheStatus)>;
+using StartUpdateCallback = base::OnceCallback<void(bool)>;
+using SwapCacheCallback = base::OnceCallback<void(bool)>;
 
 // Server-side representation of an application cache host.
 class CONTENT_EXPORT AppCacheHost
diff --git a/content/browser/appcache/appcache_quota_client.cc b/content/browser/appcache/appcache_quota_client.cc
index 5c05e97..53246cd 100644
--- a/content/browser/appcache/appcache_quota_client.cc
+++ b/content/browser/appcache/appcache_quota_client.cc
@@ -180,12 +180,10 @@
     return;
   }
 
-  const AppCacheStorage::UsageMap* map = GetUsageMap();
   std::set<url::Origin> origins;
-  for (AppCacheStorage::UsageMap::const_iterator iter = map->begin();
-       iter != map->end(); ++iter) {
-    if (opt_host.empty() || iter->first.host_piece() == opt_host)
-      origins.insert(url::Origin::Create(iter->first));
+  for (const auto& pair : *GetUsageMap()) {
+    if (opt_host.empty() || pair.first.host_piece() == opt_host)
+      origins.insert(url::Origin::Create(pair.first));
   }
   std::move(callback).Run(origins);
 }
diff --git a/content/browser/appcache/appcache_response.h b/content/browser/appcache/appcache_response.h
index ec28aca2..fb85715 100644
--- a/content/browser/appcache/appcache_response.h
+++ b/content/browser/appcache/appcache_response.h
@@ -28,7 +28,7 @@
 
 static const int kUnkownResponseDataSize = -1;
 
-typedef base::OnceCallback<void(int)> OnceCompletionCallback;
+using OnceCompletionCallback = base::OnceCallback<void(int)>;
 
 // Response info for a particular response id. Instances are tracked in
 // the working set.
diff --git a/content/browser/appcache/appcache_service_impl.cc b/content/browser/appcache/appcache_service_impl.cc
index 163feb5..74cf843b 100644
--- a/content/browser/appcache/appcache_service_impl.cc
+++ b/content/browser/appcache/appcache_service_impl.cc
@@ -188,9 +188,8 @@
   successes_ = 0;
   failures_ = 0;
   num_caches_to_delete_ = static_cast<int>(caches_to_delete.size());
-  for (AppCacheInfoVector::const_iterator iter = caches_to_delete.begin();
-       iter != caches_to_delete.end(); ++iter) {
-    service_->storage()->LoadOrCreateGroup(iter->manifest_url, this);
+  for (const auto& cache : caches_to_delete) {
+    service_->storage()->LoadOrCreateGroup(cache.manifest_url, this);
   }
 }
 
diff --git a/content/browser/appcache/appcache_storage.cc b/content/browser/appcache/appcache_storage.cc
index 30a61a02..5b4c80b 100644
--- a/content/browser/appcache/appcache_storage.cc
+++ b/content/browser/appcache/appcache_storage.cc
@@ -118,11 +118,10 @@
 
 void AppCacheStorage::ClearUsageMapAndNotify() {
   if (service()->quota_manager_proxy()) {
-    for (UsageMap::const_iterator iter = usage_map_.begin();
-         iter != usage_map_.end(); ++iter) {
+    for (const auto& pair : usage_map_) {
       service()->quota_manager_proxy()->NotifyStorageModified(
-          storage::QuotaClient::kAppcache, url::Origin::Create(iter->first),
-          blink::mojom::StorageType::kTemporary, -(iter->second));
+          storage::QuotaClient::kAppcache, url::Origin::Create(pair.first),
+          blink::mojom::StorageType::kTemporary, -(pair.second));
     }
   }
   usage_map_.clear();
diff --git a/content/browser/appcache/appcache_storage.h b/content/browser/appcache/appcache_storage.h
index c73fcb8..e787fa2b 100644
--- a/content/browser/appcache/appcache_storage.h
+++ b/content/browser/appcache/appcache_storage.h
@@ -44,7 +44,7 @@
 
 class CONTENT_EXPORT AppCacheStorage {
  public:
-  typedef std::map<GURL, int64_t> UsageMap;
+  using UsageMap = std::map<GURL, int64_t>;
 
   class CONTENT_EXPORT Delegate {
    public:
@@ -224,14 +224,13 @@
   friend class content::appcache_storage_unittest::AppCacheStorageTest;
 
   // Helper to call a collection of delegates.
-  #define FOR_EACH_DELEGATE(delegates, func_and_args)                \
-    do {                                                             \
-      for (DelegateReferenceVector::iterator it = delegates.begin(); \
-           it != delegates.end(); ++it) {                            \
-        if (it->get()->delegate)                                     \
-          it->get()->delegate->func_and_args;                        \
-      }                                                              \
-    } while (0)
+#define FOR_EACH_DELEGATE(delegates, func_and_args)                 \
+  do {                                                              \
+    for (const scoped_refptr<DelegateReference>& ref : delegates) { \
+      if (ref.get()->delegate)                                      \
+        ref.get()->delegate->func_and_args;                         \
+    }                                                               \
+  } while (0)
 
   // Helper used to manage multiple references to a 'delegate' and to
   // allow all pending callbacks to that delegate to be easily cancelled.
@@ -253,9 +252,8 @@
 
     virtual ~DelegateReference();
   };
-  typedef std::map<Delegate*, DelegateReference*> DelegateReferenceMap;
-  typedef std::vector<scoped_refptr<DelegateReference> >
-      DelegateReferenceVector;
+  using DelegateReferenceMap = std::map<Delegate*, DelegateReference*>;
+  using DelegateReferenceVector = std::vector<scoped_refptr<DelegateReference>>;
 
   // Helper used to manage an async LoadResponseInfo calls on behalf of
   // multiple callers.
diff --git a/content/browser/appcache/appcache_storage_impl.cc b/content/browser/appcache/appcache_storage_impl.cc
index 407c1a2d..054d40fa 100644
--- a/content/browser/appcache/appcache_storage_impl.cc
+++ b/content/browser/appcache/appcache_storage_impl.cc
@@ -108,26 +108,22 @@
     return;
   }
 
-  std::set<GURL>::const_iterator origin;
-  DCHECK(special_storage_policy.get());
-  for (origin = origins.begin(); origin != origins.end(); ++origin) {
-    if (!special_storage_policy->IsStorageSessionOnly(*origin))
+  for (const GURL& origin : origins) {
+    if (!special_storage_policy->IsStorageSessionOnly(origin))
       continue;
-    if (special_storage_policy->IsStorageProtected(*origin))
+    if (special_storage_policy->IsStorageProtected(origin))
       continue;
 
     std::vector<AppCacheDatabase::GroupRecord> groups;
-    database->FindGroupsForOrigin(*origin, &groups);
-    std::vector<AppCacheDatabase::GroupRecord>::const_iterator group;
-    for (group = groups.begin(); group != groups.end(); ++group) {
+    database->FindGroupsForOrigin(origin, &groups);
+    for (const auto& group : groups) {
       sql::Transaction transaction(connection);
       if (!transaction.Begin()) {
         NOTREACHED() << "Failed to start transaction";
         return;
       }
       std::vector<int64_t> deletable_response_ids;
-      bool success = DeleteGroupAndRelatedRecords(database,
-                                                  group->group_id,
+      bool success = DeleteGroupAndRelatedRecords(database, group.group_id,
                                                   &deletable_response_ids);
       success = success && transaction.Commit();
       DCHECK(success);
@@ -365,25 +361,21 @@
 void AppCacheStorageImpl::GetAllInfoTask::Run() {
   std::set<GURL> origins;
   database_->FindOriginsWithGroups(&origins);
-  for (std::set<GURL>::const_iterator origin = origins.begin();
-       origin != origins.end(); ++origin) {
-    AppCacheInfoVector& infos =
-        info_collection_->infos_by_origin[*origin];
+  for (const GURL& origin : origins) {
+    AppCacheInfoVector& infos = info_collection_->infos_by_origin[origin];
     std::vector<AppCacheDatabase::GroupRecord> groups;
-    database_->FindGroupsForOrigin(*origin, &groups);
-    for (std::vector<AppCacheDatabase::GroupRecord>::const_iterator
-         group = groups.begin();
-         group != groups.end(); ++group) {
+    database_->FindGroupsForOrigin(origin, &groups);
+    for (const auto& group : groups) {
       AppCacheDatabase::CacheRecord cache_record;
-      database_->FindCacheForGroup(group->group_id, &cache_record);
+      database_->FindCacheForGroup(group.group_id, &cache_record);
       AppCacheInfo info;
-      info.manifest_url = group->manifest_url;
-      info.creation_time = group->creation_time;
+      info.manifest_url = group.manifest_url;
+      info.creation_time = group.creation_time;
       info.size = cache_record.cache_size;
-      info.last_access_time = group->last_access_time;
+      info.last_access_time = group.last_access_time;
       info.last_update_time = cache_record.update_time;
       info.cache_id = cache_record.cache_id;
-      info.group_id = group->group_id;
+      info.group_id = group.group_id;
       info.is_complete = true;
       infos.push_back(info);
     }
@@ -487,12 +479,11 @@
 
   // We have to update foriegn entries if MarkEntryAsForeignTasks
   // are in flight.
-  std::vector<GURL> urls;
-  storage_->GetPendingForeignMarkingsForCache(cache->get()->cache_id(), &urls);
-  for (std::vector<GURL>::iterator iter = urls.begin();
-       iter != urls.end(); ++iter) {
-    DCHECK(cache->get()->GetEntry(*iter));
-    cache->get()->GetEntry(*iter)->add_types(AppCacheEntry::FOREIGN);
+  std::vector<GURL> urls =
+      storage_->GetPendingForeignMarkingsForCache(cache->get()->cache_id());
+  for (const auto& url : urls) {
+    DCHECK(cache->get()->GetEntry(url));
+    cache->get()->GetEntry(url)->add_types(AppCacheEntry::FOREIGN);
   }
 
   storage_->NotifyStorageAccessed(group_record_.origin);
@@ -725,19 +716,12 @@
                                               &existing_response_ids);
 
       // Remove those that remain in the new cache.
-      std::vector<AppCacheDatabase::EntryRecord>::const_iterator entry_iter =
-          entry_records_.begin();
-      while (entry_iter != entry_records_.end()) {
-        existing_response_ids.erase(entry_iter->response_id);
-        ++entry_iter;
-      }
+      for (const auto& entry : entry_records_)
+        existing_response_ids.erase(entry.response_id);
 
       // The rest are deletable.
-      std::set<int64_t>::const_iterator id_iter = existing_response_ids.begin();
-      while (id_iter != existing_response_ids.end()) {
-        newly_deletable_response_ids_.push_back(*id_iter);
-        ++id_iter;
-      }
+      for (const auto& id : existing_response_ids)
+        newly_deletable_response_ids_.push_back(id);
 
       success_ =
           database_->DeleteCache(cache.cache_id) &&
@@ -864,8 +848,7 @@
   }
 
   bool IsInNetworkNamespace(const GURL& url, int64_t cache_id) {
-    typedef std::pair<WhiteListMap::iterator, bool> InsertResult;
-    InsertResult result = namespaces_map_.insert(
+    std::pair<WhiteListMap::iterator, bool> result = namespaces_map_.insert(
         WhiteListMap::value_type(cache_id, AppCacheNamespaceVector()));
     if (result.second)
       GetOnlineWhiteListForCache(cache_id, &result.first->second);
@@ -876,22 +859,21 @@
   void GetOnlineWhiteListForCache(int64_t cache_id,
                                   AppCacheNamespaceVector* namespaces) {
     DCHECK(namespaces && namespaces->empty());
-    typedef std::vector<AppCacheDatabase::OnlineWhiteListRecord>
-        WhiteListVector;
+    using WhiteListVector =
+        std::vector<AppCacheDatabase::OnlineWhiteListRecord>;
     WhiteListVector records;
     if (!database_->FindOnlineWhiteListForCache(cache_id, &records))
       return;
-    WhiteListVector::const_iterator iter = records.begin();
-    while (iter != records.end()) {
-      namespaces->push_back(
-            AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE, iter->namespace_url,
-                GURL(), iter->is_pattern));
-      ++iter;
+
+    for (const auto& record : records) {
+      namespaces->push_back(AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE,
+                                              record.namespace_url, GURL(),
+                                              record.is_pattern));
     }
   }
 
   // Key is cache id
-  typedef std::map<int64_t, AppCacheNamespaceVector> WhiteListMap;
+  using WhiteListMap = std::map<int64_t, AppCacheNamespaceVector>;
   WhiteListMap namespaces_map_;
   AppCacheDatabase* database_;
 };
@@ -908,10 +890,8 @@
         preferred_manifest_url_(preferred_manifest_url),
         cache_id_(kAppCacheNoCacheId), group_id_(0) {
     if (groups_in_use) {
-      for (AppCacheWorkingSet::GroupMap::const_iterator it =
-               groups_in_use->begin();
-           it != groups_in_use->end(); ++it) {
-        AppCacheGroup* group = it->second;
+      for (const auto& pair : *groups_in_use) {
+        AppCacheGroup* group = pair.second;
         AppCache* cache = group->newest_complete_cache();
         if (group->is_obsolete() || !cache)
           continue;
@@ -928,8 +908,8 @@
   ~FindMainResponseTask() override {}
 
  private:
-  typedef std::vector<AppCacheDatabase::NamespaceRecord*>
-      NamespaceRecordPtrVector;
+  using NamespaceRecordPtrVector =
+      std::vector<AppCacheDatabase::NamespaceRecord*>;
 
   bool FindExactMatch(int64_t preferred_id);
   bool FindNamespaceMatch(int64_t preferred_id);
@@ -997,17 +977,16 @@
               SortByCachePreference(preferred_cache_id, cache_ids_in_use_));
 
     // Take the first with a valid, non-foreign entry.
-    std::vector<AppCacheDatabase::EntryRecord>::iterator iter;
-    for (iter = entries.begin(); iter < entries.end(); ++iter) {
+    for (const auto& entry : entries) {
       AppCacheDatabase::GroupRecord group_record;
-      if ((iter->flags & AppCacheEntry::FOREIGN) ||
-          !database_->FindGroupForCache(iter->cache_id, &group_record)) {
+      if ((entry.flags & AppCacheEntry::FOREIGN) ||
+          !database_->FindGroupForCache(entry.cache_id, &group_record)) {
         continue;
       }
       manifest_url_ = group_record.manifest_url;
       group_id_ = group_record.group_id;
-      entry_ = AppCacheEntry(iter->flags, iter->response_id);
-      cache_id_ = iter->cache_id;
+      entry_ = AppCacheEntry(entry.flags, entry.response_id);
+      cache_id_ = entry.cache_id;
       return true;  // We found an exact match.
     }
   }
@@ -1047,24 +1026,25 @@
   NamespaceRecordPtrVector preferred_namespaces;
   NamespaceRecordPtrVector inuse_namespaces;
   NamespaceRecordPtrVector other_namespaces;
-  std::vector<AppCacheDatabase::NamespaceRecord>::iterator iter;
-  for (iter = namespaces->begin(); iter < namespaces->end(); ++iter) {
+  for (auto& namespace_record : *namespaces) {
     // Skip those that aren't a match.
-    if (!iter->namespace_.IsMatch(url_))
+    if (!namespace_record.namespace_.IsMatch(url_))
       continue;
 
     // Skip namespaces where the requested url falls into a network
     // namespace of its containing appcache.
-    if (network_namespace_helper->IsInNetworkNamespace(url_, iter->cache_id))
+    if (network_namespace_helper->IsInNetworkNamespace(
+            url_, namespace_record.cache_id))
       continue;
 
     // Bin them into one of our three buckets.
-    if (iter->cache_id == preferred_cache_id)
-      preferred_namespaces.push_back(&(*iter));
-    else if (cache_ids_in_use_.find(iter->cache_id) != cache_ids_in_use_.end())
-      inuse_namespaces.push_back(&(*iter));
+    if (namespace_record.cache_id == preferred_cache_id)
+      preferred_namespaces.push_back(&namespace_record);
+    else if (cache_ids_in_use_.find(namespace_record.cache_id) !=
+             cache_ids_in_use_.end())
+      inuse_namespaces.push_back(&namespace_record);
     else
-      other_namespaces.push_back(&(*iter));
+      other_namespaces.push_back(&namespace_record);
   }
 
   if (FindFirstValidNamespace(preferred_namespaces) ||
@@ -1080,10 +1060,10 @@
 FindMainResponseTask::FindFirstValidNamespace(
     const NamespaceRecordPtrVector& namespaces) {
   // Take the first with a valid, non-foreign entry.
-  NamespaceRecordPtrVector::const_iterator iter;
-  for (iter = namespaces.begin(); iter < namespaces.end();  ++iter) {
+  for (auto* namespace_record : namespaces) {
     AppCacheDatabase::EntryRecord entry_record;
-    if (database_->FindEntry((*iter)->cache_id, (*iter)->namespace_.target_url,
+    if (database_->FindEntry(namespace_record->cache_id,
+                             namespace_record->namespace_.target_url,
                              &entry_record)) {
       AppCacheDatabase::GroupRecord group_record;
       if ((entry_record.flags & AppCacheEntry::FOREIGN) ||
@@ -1092,9 +1072,9 @@
       }
       manifest_url_ = group_record.manifest_url;
       group_id_ = group_record.group_id;
-      cache_id_ = (*iter)->cache_id;
-      namespace_entry_url_ = (*iter)->namespace_.target_url;
-      if ((*iter)->namespace_.type == APPCACHE_FALLBACK_NAMESPACE)
+      cache_id_ = namespace_record->cache_id;
+      namespace_entry_url_ = namespace_record->namespace_.target_url;
+      if (namespace_record->namespace_.type == APPCACHE_FALLBACK_NAMESPACE)
         fallback_entry_ = AppCacheEntry(entry_record.flags,
                                         entry_record.response_id);
       else
@@ -1399,9 +1379,9 @@
       weak_factory_(this) {}
 
 AppCacheStorageImpl::~AppCacheStorageImpl() {
-  for (auto* task : pending_quota_queries_)
+  for (StoreGroupAndCacheTask* task : pending_quota_queries_)
     task->CancelCompletion();
-  for (auto* task : scheduled_database_tasks_)
+  for (DatabaseTask* task : scheduled_database_tasks_)
     task->CancelCompletion();
 
   if (database_ &&
@@ -1569,11 +1549,9 @@
           return;
       }
     } else {
-      for (AppCacheWorkingSet::GroupMap::const_iterator it =
-              groups_in_use->begin();
-           it != groups_in_use->end(); ++it) {
-        if (FindResponseForMainRequestInGroup(
-                it->second, *url_ptr, delegate)) {
+      for (const auto& pair : *groups_in_use) {
+        if (FindResponseForMainRequestInGroup(pair.second, *url_ptr,
+                                              delegate)) {
           return;
         }
       }
@@ -1853,15 +1831,14 @@
   return nullptr;
 }
 
-void AppCacheStorageImpl::GetPendingForeignMarkingsForCache(
-    int64_t cache_id,
-    std::vector<GURL>* urls) {
-  PendingForeignMarkings::iterator iter = pending_foreign_markings_.begin();
-  while (iter != pending_foreign_markings_.end()) {
-    if (iter->second == cache_id)
-      urls->push_back(iter->first);
-    ++iter;
+std::vector<GURL> AppCacheStorageImpl::GetPendingForeignMarkingsForCache(
+    int64_t cache_id) {
+  std::vector<GURL> urls;
+  for (const auto& pair : pending_foreign_markings_) {
+    if (pair.second == cache_id)
+      urls.push_back(pair.first);
   }
+  return urls;
 }
 
 void AppCacheStorageImpl::ScheduleSimpleTask(base::OnceClosure task) {
diff --git a/content/browser/appcache/appcache_storage_impl.h b/content/browser/appcache/appcache_storage_impl.h
index 022ae2f4..51b0bb1 100644
--- a/content/browser/appcache/appcache_storage_impl.h
+++ b/content/browser/appcache/appcache_storage_impl.h
@@ -109,8 +109,7 @@
 
   CacheLoadTask* GetPendingCacheLoadTask(int64_t cache_id);
   GroupLoadTask* GetPendingGroupLoadTask(const GURL& manifest_url);
-  void GetPendingForeignMarkingsForCache(int64_t cache_id,
-                                         std::vector<GURL>* urls);
+  std::vector<GURL> GetPendingForeignMarkingsForCache(int64_t cache_id);
 
   void ScheduleSimpleTask(base::OnceClosure task);
   void RunOnePendingSimpleTask();
diff --git a/content/browser/appcache/appcache_storage_impl_unittest.cc b/content/browser/appcache/appcache_storage_impl_unittest.cc
index 6693b44..75959a74 100644
--- a/content/browser/appcache/appcache_storage_impl_unittest.cc
+++ b/content/browser/appcache/appcache_storage_impl_unittest.cc
@@ -1062,13 +1062,10 @@
                               &fallbacks,
                               &whitelists);
 
-    std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
-        entries.begin();
-    while (iter != entries.end()) {
+    for (const auto& entry : entries) {
       // MakeCacheAndGroup has inserted the default entry record already.
-      if (iter->url != kDefaultEntryUrl)
-        EXPECT_TRUE(database()->InsertEntry(&(*iter)));
-      ++iter;
+      if (entry.url != kDefaultEntryUrl)
+        EXPECT_TRUE(database()->InsertEntry(&entry));
     }
 
     EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks));
@@ -1136,13 +1133,10 @@
                               &fallbacks,
                               &whitelists);
 
-    std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
-        entries.begin();
-    while (iter != entries.end()) {
+    for (const auto& entry : entries) {
       // MakeCacheAndGroup has inserted  the default entry record already
-      if (iter->url != kDefaultEntryUrl)
-        EXPECT_TRUE(database()->InsertEntry(&(*iter)));
-      ++iter;
+      if (entry.url != kDefaultEntryUrl)
+        EXPECT_TRUE(database()->InsertEntry(&entry));
     }
 
     EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts));
@@ -1203,13 +1197,10 @@
                               &fallbacks,
                               &whitelists);
 
-    std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
-        entries.begin();
-    while (iter != entries.end()) {
+    for (const auto& entry : entries) {
       // MakeCacheAndGroup has inserted  the default entry record already
-      if (iter->url != kDefaultEntryUrl)
-        EXPECT_TRUE(database()->InsertEntry(&(*iter)));
-      ++iter;
+      if (entry.url != kDefaultEntryUrl)
+        EXPECT_TRUE(database()->InsertEntry(&entry));
     }
 
     EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts));
@@ -1290,13 +1281,10 @@
                               &fallbacks,
                               &whitelists);
 
-    std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
-        entries.begin();
-    while (iter != entries.end()) {
+    for (const auto& entry : entries) {
       // MakeCacheAndGroup has inserted the default entry record already.
-      if (iter->url != kDefaultEntryUrl)
-        EXPECT_TRUE(database()->InsertEntry(&(*iter)));
-      ++iter;
+      if (entry.url != kDefaultEntryUrl)
+        EXPECT_TRUE(database()->InsertEntry(&entry));
     }
 
     EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks));
diff --git a/content/browser/appcache/appcache_storage_unittest.cc b/content/browser/appcache/appcache_storage_unittest.cc
index 8ef6dcb..15cead2 100644
--- a/content/browser/appcache/appcache_storage_unittest.cc
+++ b/content/browser/appcache/appcache_storage_unittest.cc
@@ -79,8 +79,8 @@
 }
 
 TEST_F(AppCacheStorageTest, DelegateReferences) {
-  typedef scoped_refptr<AppCacheStorage::DelegateReference>
-      ScopedDelegateReference;
+  using ScopedDelegateReference =
+      scoped_refptr<AppCacheStorage::DelegateReference>;
   MockAppCacheService service;
   MockStorageDelegate delegate;
   ScopedDelegateReference delegate_reference1;
diff --git a/content/browser/appcache/appcache_update_job.cc b/content/browser/appcache/appcache_update_job.cc
index 10630d9..9e0ca2c 100644
--- a/content/browser/appcache/appcache_update_job.cc
+++ b/content/browser/appcache/appcache_update_job.cc
@@ -97,63 +97,56 @@
 // so that only one notification is sent for all hosts using the same frontend.
 class HostNotifier {
  public:
-  typedef std::vector<int> HostIds;
-  typedef std::map<AppCacheFrontend*, HostIds> NotifyHostMap;
+  using HostIds = std::vector<int>;
+  using NotifyHostMap = std::map<AppCacheFrontend*, HostIds>;
 
   // Caller is responsible for ensuring there will be no duplicate hosts.
   void AddHost(AppCacheHost* host) {
-    std::pair<NotifyHostMap::iterator, bool> ret = hosts_to_notify.insert(
+    std::pair<NotifyHostMap::iterator, bool> ret = hosts_to_notify_.insert(
         NotifyHostMap::value_type(host->frontend(), HostIds()));
     ret.first->second.push_back(host->host_id());
   }
 
   void AddHosts(const std::set<AppCacheHost*>& hosts) {
-    for (std::set<AppCacheHost*>::const_iterator it = hosts.begin();
-         it != hosts.end(); ++it) {
-      AddHost(*it);
-    }
+    for (AppCacheHost* host : hosts)
+      AddHost(host);
   }
 
   void SendNotifications(AppCacheEventID event_id) {
-    for (NotifyHostMap::iterator it = hosts_to_notify.begin();
-         it != hosts_to_notify.end(); ++it) {
-      AppCacheFrontend* frontend = it->first;
-      frontend->OnEventRaised(it->second, event_id);
+    for (auto& pair : hosts_to_notify_) {
+      AppCacheFrontend* frontend = pair.first;
+      frontend->OnEventRaised(pair.second, event_id);
     }
   }
 
   void SendProgressNotifications(const GURL& url,
                                  int num_total,
                                  int num_complete) {
-    for (NotifyHostMap::iterator it = hosts_to_notify.begin();
-         it != hosts_to_notify.end(); ++it) {
-      AppCacheFrontend* frontend = it->first;
-      frontend->OnProgressEventRaised(it->second, url, num_total, num_complete);
+    for (const auto& pair : hosts_to_notify_) {
+      AppCacheFrontend* frontend = pair.first;
+      frontend->OnProgressEventRaised(pair.second, url, num_total,
+                                      num_complete);
     }
   }
 
   void SendErrorNotifications(const AppCacheErrorDetails& details) {
     DCHECK(!details.message.empty());
-    for (NotifyHostMap::iterator it = hosts_to_notify.begin();
-         it != hosts_to_notify.end(); ++it) {
-      AppCacheFrontend* frontend = it->first;
-      frontend->OnErrorEventRaised(it->second, details);
+    for (const auto& pair : hosts_to_notify_) {
+      AppCacheFrontend* frontend = pair.first;
+      frontend->OnErrorEventRaised(pair.second, details);
     }
   }
 
   void SendLogMessage(const std::string& message) {
-    for (NotifyHostMap::iterator it = hosts_to_notify.begin();
-         it != hosts_to_notify.end(); ++it) {
-      AppCacheFrontend* frontend = it->first;
-      for (HostIds::iterator id = it->second.begin(); id != it->second.end();
-           ++id) {
-        frontend->OnLogMessage(*id, APPCACHE_LOG_WARNING, message);
-      }
+    for (const auto& pair : hosts_to_notify_) {
+      AppCacheFrontend* frontend = pair.first;
+      for (const auto& id : pair.second)
+        frontend->OnLogMessage(id, APPCACHE_LOG_WARNING, message);
     }
   }
 
  private:
-  NotifyHostMap hosts_to_notify;
+  NotifyHostMap hosts_to_notify_;
 };
 AppCacheUpdateJob::UrlToFetch::UrlToFetch(const GURL& url,
                                           bool checked,
@@ -467,13 +460,10 @@
   inprogress_cache_->InitializeWithManifest(&manifest);
 
   // Associate all pending master hosts with the newly created cache.
-  for (PendingMasters::iterator it = pending_master_entries_.begin();
-       it != pending_master_entries_.end(); ++it) {
-    PendingHosts& hosts = it->second;
-    for (PendingHosts::iterator host_it = hosts.begin();
-         host_it != hosts.end(); ++host_it) {
-      (*host_it)
-          ->AssociateIncompleteCache(inprogress_cache_.get(), manifest_url_);
+  for (const auto& pair : pending_master_entries_) {
+    const PendingHosts& hosts = pair.second;
+    for (AppCacheHost* host : hosts) {
+      host->AssociateIncompleteCache(inprogress_cache_.get(), manifest_url_);
     }
   }
 
@@ -630,16 +620,12 @@
     if (!inprogress_cache_.get()) {
       // TODO(michaeln): defer until the updated cache has been stored
       DCHECK(cache == group_->newest_complete_cache());
-      for (PendingHosts::iterator host_it = hosts.begin();
-           host_it != hosts.end(); ++host_it) {
-        (*host_it)->AssociateCompleteCache(cache);
-      }
+      for (AppCacheHost* host : hosts)
+        host->AssociateCompleteCache(cache);
     }
   } else {
     HostNotifier host_notifier;
-    for (PendingHosts::iterator host_it = hosts.begin();
-         host_it != hosts.end(); ++host_it) {
-      AppCacheHost* host = *host_it;
+    for (AppCacheHost* host : hosts) {
       host_notifier.AddHost(host);
 
       // In downloading case, disassociate host from inprogress cache.
@@ -863,11 +849,8 @@
     host_notifier->AddHosts(inprogress_cache_->associated_hosts());
   }
 
-  AppCacheGroup::Caches old_caches = group_->old_caches();
-  for (AppCacheGroup::Caches::const_iterator it = old_caches.begin();
-       it != old_caches.end(); ++it) {
-    host_notifier->AddHosts((*it)->associated_hosts());
-  }
+  for (AppCache* cache : group_->old_caches())
+    host_notifier->AddHosts(cache->associated_hosts());
 
   AppCache* newest_cache = group_->newest_complete_cache();
   if (newest_cache)
@@ -942,35 +925,21 @@
 }
 
 void AppCacheUpdateJob::BuildUrlFileList(const AppCacheManifest& manifest) {
-  for (base::hash_set<std::string>::const_iterator it =
-           manifest.explicit_urls.begin();
-       it != manifest.explicit_urls.end(); ++it) {
-    AddUrlToFileList(GURL(*it), AppCacheEntry::EXPLICIT);
-  }
+  for (const std::string& explicit_url : manifest.explicit_urls)
+    AddUrlToFileList(GURL(explicit_url), AppCacheEntry::EXPLICIT);
 
-  const std::vector<AppCacheNamespace>& intercepts =
-      manifest.intercept_namespaces;
-  for (std::vector<AppCacheNamespace>::const_iterator it = intercepts.begin();
-       it != intercepts.end(); ++it) {
-    AddUrlToFileList(it->target_url, AppCacheEntry::INTERCEPT);
-  }
+  for (const auto& intercept : manifest.intercept_namespaces)
+    AddUrlToFileList(intercept.target_url, AppCacheEntry::INTERCEPT);
 
-  const std::vector<AppCacheNamespace>& fallbacks =
-      manifest.fallback_namespaces;
-  for (std::vector<AppCacheNamespace>::const_iterator it = fallbacks.begin();
-       it != fallbacks.end(); ++it) {
-     AddUrlToFileList(it->target_url, AppCacheEntry::FALLBACK);
-  }
+  for (const auto& fallback : manifest.fallback_namespaces)
+    AddUrlToFileList(fallback.target_url, AppCacheEntry::FALLBACK);
 
   // Add all master entries from newest complete cache.
   if (update_type_ == UPGRADE_ATTEMPT) {
-    const AppCache::EntryMap& entries =
-        group_->newest_complete_cache()->entries();
-    for (AppCache::EntryMap::const_iterator it = entries.begin();
-         it != entries.end(); ++it) {
-      const AppCacheEntry& entry = it->second;
+    for (const auto& pair : group_->newest_complete_cache()->entries()) {
+      const AppCacheEntry& entry = pair.second;
       if (entry.IsMaster())
-        AddUrlToFileList(it->first, AppCacheEntry::MASTER);
+        AddUrlToFileList(pair.first, AppCacheEntry::MASTER);
     }
   }
 }
@@ -1033,10 +1002,8 @@
 
 void AppCacheUpdateJob::CancelAllUrlFetches() {
   // Cancel any pending URL requests.
-  for (PendingUrlFetches::iterator it = pending_url_fetches_.begin();
-       it != pending_url_fetches_.end(); ++it) {
-    delete it->second;
-  }
+  for (auto& pair : pending_url_fetches_)
+    delete pair.second;
 
   url_fetches_completed_ +=
       pending_url_fetches_.size() + urls_to_fetch_.size();
@@ -1127,10 +1094,8 @@
         PendingMasters::iterator found = pending_master_entries_.find(url);
         DCHECK(found != pending_master_entries_.end());
         PendingHosts& hosts = found->second;
-        for (PendingHosts::iterator host_it = hosts.begin();
-             host_it != hosts.end(); ++host_it) {
-          (*host_it)->AssociateCompleteCache(cache);
-        }
+        for (AppCacheHost* host : hosts)
+          host->AssociateCompleteCache(cache);
       }
     } else {
       URLFetcher* fetcher = new URLFetcher(url, URLFetcher::MASTER_ENTRY_FETCH,
@@ -1151,10 +1116,9 @@
   // directly.
 
   // Cancel all in-progress fetches.
-  for (PendingUrlFetches::iterator it = master_entry_fetches_.begin();
-       it != master_entry_fetches_.end(); ++it) {
-    delete it->second;
-    master_entries_to_fetch_.insert(it->first);  // back in unfetched list
+  for (auto& pair : master_entry_fetches_) {
+    delete pair.second;
+    master_entries_to_fetch_.insert(pair.first);  // back in unfetched list
   }
   master_entry_fetches_.clear();
 
@@ -1169,9 +1133,7 @@
     PendingMasters::iterator found = pending_master_entries_.find(url);
     DCHECK(found != pending_master_entries_.end());
     PendingHosts& hosts = found->second;
-    for (PendingHosts::iterator host_it = hosts.begin();
-         host_it != hosts.end(); ++host_it) {
-      AppCacheHost* host = *host_it;
+    for (AppCacheHost* host : hosts) {
       host->AssociateNoCache(GURL());
       host_notifier.AddHost(host);
       host->RemoveObserver(this);
@@ -1340,16 +1302,12 @@
     manifest_fetcher_ = nullptr;
   }
 
-  for (PendingUrlFetches::iterator it = pending_url_fetches_.begin();
-       it != pending_url_fetches_.end(); ++it) {
-    delete it->second;
-  }
+  for (auto& pair : pending_url_fetches_)
+    delete pair.second;
   pending_url_fetches_.clear();
 
-  for (PendingUrlFetches::iterator it = master_entry_fetches_.begin();
-       it != master_entry_fetches_.end(); ++it) {
-    delete it->second;
-  }
+  for (auto& pair : master_entry_fetches_)
+    delete pair.second;
   master_entry_fetches_.clear();
 
   ClearPendingMasterEntries();
@@ -1363,13 +1321,10 @@
 }
 
 void AppCacheUpdateJob::ClearPendingMasterEntries() {
-  for (PendingMasters::iterator it = pending_master_entries_.begin();
-       it != pending_master_entries_.end(); ++it) {
-    PendingHosts& hosts = it->second;
-    for (PendingHosts::iterator host_it = hosts.begin();
-         host_it != hosts.end(); ++host_it) {
-      (*host_it)->RemoveObserver(this);
-    }
+  for (auto& pair : pending_master_entries_) {
+    PendingHosts& hosts = pair.second;
+    for (AppCacheHost* host : hosts)
+      host->RemoveObserver(this);
   }
 
   pending_master_entries_.clear();
@@ -1390,10 +1345,8 @@
   if (!inprogress_cache_.get()) {
     // We have to undo the changes we made, if any, to the existing cache.
     if (group_ && group_->newest_complete_cache()) {
-      for (std::vector<GURL>::iterator iter = added_master_entries_.begin();
-           iter != added_master_entries_.end(); ++iter) {
-        group_->newest_complete_cache()->RemoveEntry(*iter);
-      }
+      for (auto& url : added_master_entries_)
+        group_->newest_complete_cache()->RemoveEntry(url);
     }
     added_master_entries_.clear();
     return;
diff --git a/content/browser/appcache/appcache_update_job.h b/content/browser/appcache/appcache_update_job.h
index 6b75f215..262da88 100644
--- a/content/browser/appcache/appcache_update_job.h
+++ b/content/browser/appcache/appcache_update_job.h
@@ -72,10 +72,10 @@
 
   // Master entries have multiple hosts, for example, the same page is opened
   // in different tabs.
-  typedef std::vector<AppCacheHost*> PendingHosts;
-  typedef std::map<GURL, PendingHosts> PendingMasters;
-  typedef std::map<GURL, URLFetcher*> PendingUrlFetches;
-  typedef std::map<int64_t, GURL> LoadingResponses;
+  using PendingHosts = std::vector<AppCacheHost*>;
+  using PendingMasters = std::map<GURL, PendingHosts>;
+  using PendingUrlFetches = std::map<GURL, URLFetcher*>;
+  using LoadingResponses = std::map<int64_t, GURL>;
 
   static const int kRerunDelayMs = 1000;
 
diff --git a/content/browser/appcache/appcache_update_job_unittest.cc b/content/browser/appcache/appcache_update_job_unittest.cc
index c78e912c..6fe4e36 100644
--- a/content/browser/appcache/appcache_update_job_unittest.cc
+++ b/content/browser/appcache/appcache_update_job_unittest.cc
@@ -261,11 +261,9 @@
 
     // Trigger additional updates if requested.
     if (event_id == start_update_trigger_ && update_) {
-      for (std::vector<AppCacheHost*>::iterator it = update_hosts_.begin();
-           it != update_hosts_.end(); ++it) {
-        AppCacheHost* host = *it;
-        update_->StartUpdate(host,
-            (host ? host->pending_master_entry_url() : GURL()));
+      for (AppCacheHost* host : update_hosts_) {
+        update_->StartUpdate(
+            host, (host ? host->pending_master_entry_url() : GURL()));
       }
       update_hosts_.clear();  // only trigger once
     }
@@ -349,9 +347,9 @@
     update_hosts_.push_back(host);
   }
 
-  typedef std::vector<int> HostIds;
-  typedef std::pair<HostIds, AppCacheEventID> RaisedEvent;
-  typedef std::vector<RaisedEvent> RaisedEvents;
+  using HostIds = std::vector<int>;
+  using RaisedEvent = std::pair<HostIds, AppCacheEventID>;
+  using RaisedEvents = std::vector<RaisedEvent>;
   RaisedEvents raised_events_;
   std::string error_message_;
 
@@ -3607,22 +3605,19 @@
         EXPECT_TRUE(storage->IsCacheStored(group_->newest_complete_cache()));
 
         // Check that all entries in the newest cache were stored.
-        const AppCache::EntryMap& entries =
-            group_->newest_complete_cache()->entries();
-        for (AppCache::EntryMap::const_iterator it = entries.begin();
-             it != entries.end(); ++it) {
-          EXPECT_NE(kAppCacheNoResponseId, it->second.response_id());
+        for (const auto& pair : group_->newest_complete_cache()->entries()) {
+          EXPECT_NE(kAppCacheNoResponseId, pair.second.response_id());
 
           // Check that any copied entries have the expected response id
           // and that entries that are not copied have a different response id.
           std::map<GURL, int64_t>::iterator found =
-              expect_response_ids_.find(it->first);
+              expect_response_ids_.find(pair.first);
           if (found != expect_response_ids_.end()) {
-            EXPECT_EQ(found->second, it->second.response_id());
+            EXPECT_EQ(found->second, pair.second.response_id());
           } else if (expect_old_cache_) {
-            AppCacheEntry* old_entry = expect_old_cache_->GetEntry(it->first);
+            AppCacheEntry* old_entry = expect_old_cache_->GetEntry(pair.first);
             if (old_entry)
-              EXPECT_NE(old_entry->response_id(), it->second.response_id());
+              EXPECT_NE(old_entry->response_id(), pair.second.response_id());
           }
         }
       }
@@ -3712,11 +3707,10 @@
     ASSERT_TRUE(entry);
     EXPECT_EQ(AppCacheEntry::FALLBACK, entry->types());
 
-    for (AppCache::EntryMap::iterator i = expect_extra_entries_.begin();
-         i != expect_extra_entries_.end(); ++i) {
-      entry = cache->GetEntry(i->first);
+    for (const auto& pair : expect_extra_entries_) {
+      entry = cache->GetEntry(pair.first);
       ASSERT_TRUE(entry);
-      EXPECT_EQ(i->second.types(), entry->types());
+      EXPECT_EQ(pair.second.types(), entry->types());
     }
 
     expected = 1;
@@ -3874,7 +3868,7 @@
 
   // Response infos used by an async test that need to live until update job
   // finishes.
-  std::vector<scoped_refptr<AppCacheResponseInfo> > response_infos_;
+  std::vector<scoped_refptr<AppCacheResponseInfo>> response_infos_;
 
   // Flag indicating if test cares to verify the update after update finishes.
   bool do_checks_after_update_finished_;
diff --git a/content/browser/appcache/appcache_working_set.h b/content/browser/appcache/appcache_working_set.h
index e9483b6..d24f0cd 100644
--- a/content/browser/appcache/appcache_working_set.h
+++ b/content/browser/appcache/appcache_working_set.h
@@ -23,7 +23,7 @@
 // currently in memory.
 class CONTENT_EXPORT AppCacheWorkingSet {
  public:
-  typedef std::map<GURL, AppCacheGroup*> GroupMap;
+  using GroupMap = std::map<GURL, AppCacheGroup*>;
 
   AppCacheWorkingSet();
   ~AppCacheWorkingSet();
@@ -57,9 +57,9 @@
   }
 
  private:
-  typedef base::hash_map<int64_t, AppCache*> CacheMap;
-  typedef std::map<GURL, GroupMap> GroupsByOriginMap;
-  typedef base::hash_map<int64_t, AppCacheResponseInfo*> ResponseInfoMap;
+  using CacheMap = base::hash_map<int64_t, AppCache*>;
+  using GroupsByOriginMap = std::map<GURL, GroupMap>;
+  using ResponseInfoMap = base::hash_map<int64_t, AppCacheResponseInfo*>;
 
   GroupMap* GetMutableGroupsInOrigin(const GURL& origin_url) {
     GroupsByOriginMap::iterator it = groups_by_origin_.find(origin_url);
diff --git a/content/browser/appcache/mock_appcache_storage.cc b/content/browser/appcache/mock_appcache_storage.cc
index b9ff16c7..79bf39b0 100644
--- a/content/browser/appcache/mock_appcache_storage.cc
+++ b/content/browser/appcache/mock_appcache_storage.cc
@@ -191,11 +191,8 @@
     const std::vector<int64_t>& response_ids) {
   // We don't bother with actually removing responses from the disk-cache,
   // just keep track of which ids have been doomed or deleted
-  std::vector<int64_t>::const_iterator it = response_ids.begin();
-  while (it != response_ids.end()) {
-    doomed_response_ids_.insert(*it);
-    ++it;
-  }
+  for (const auto& id : response_ids)
+    doomed_response_ids_.insert(id);
 }
 
 bool MockAppCacheStorage::IsInitialized() {
@@ -353,9 +350,8 @@
   FoundCandidate found_fallback_candidate;
   GURL found_fallback_candidate_namespace;
 
-  for (StoredGroupMap::const_iterator it = stored_groups_.begin();
-       it != stored_groups_.end(); ++it) {
-    AppCacheGroup* group = it->second.get();
+  for (const auto& pair : stored_groups_) {
+    AppCacheGroup* group = pair.second.get();
     AppCache* cache = group->newest_complete_cache();
     if (group->is_obsolete() || !cache ||
         (url.GetOrigin() != group->manifest_url().GetOrigin())) {
@@ -501,11 +497,8 @@
 
 void MockAppCacheStorage::RemoveStoredCaches(
     const AppCacheGroup::Caches& caches) {
-  AppCacheGroup::Caches::const_iterator it = caches.begin();
-  while (it != caches.end()) {
-    RemoveStoredCache(*it);
-    ++it;
-  }
+  for (AppCache* cache : caches)
+    RemoveStoredCache(cache);
 }
 
 void MockAppCacheStorage::AddStoredGroup(AppCacheGroup* group) {
@@ -541,13 +534,10 @@
 
   // If any of the old caches are "in use", then the group must also
   // be memory resident and not require async loading.
-  const AppCacheGroup::Caches& old_caches = group->old_caches();
-  AppCacheGroup::Caches::const_iterator it = old_caches.begin();
-  while (it != old_caches.end()) {
+  for (const AppCache* cache : group->old_caches()) {
     // "in use" caches don't require async loading
-    if (!ShouldCacheLoadAppearAsync(*it))
+    if (!ShouldCacheLoadAppearAsync(cache))
       return false;
-    ++it;
   }
 
   return true;
diff --git a/content/browser/appcache/mock_appcache_storage.h b/content/browser/appcache/mock_appcache_storage.h
index 8605a47..09a1fbd 100644
--- a/content/browser/appcache/mock_appcache_storage.h
+++ b/content/browser/appcache/mock_appcache_storage.h
@@ -93,11 +93,11 @@
   friend class appcache_update_job_unittest::AppCacheUpdateJobTest;
   friend class MockAppCacheStorageTest;
 
-  typedef base::hash_map<int64_t, scoped_refptr<AppCache>> StoredCacheMap;
-  typedef std::map<GURL, scoped_refptr<AppCacheGroup> > StoredGroupMap;
-  typedef std::set<int64_t> DoomedResponseIds;
-  typedef std::map<int64_t, std::pair<base::Time, base::Time>>
-      StoredEvictionTimesMap;
+  using StoredCacheMap = base::hash_map<int64_t, scoped_refptr<AppCache>>;
+  using StoredGroupMap = std::map<GURL, scoped_refptr<AppCacheGroup>>;
+  using DoomedResponseIds = std::set<int64_t>;
+  using StoredEvictionTimesMap =
+      std::map<int64_t, std::pair<base::Time, base::Time>>;
 
   void ProcessGetAllInfo(scoped_refptr<DelegateReference> delegate_ref);
   void ProcessLoadCache(int64_t id,
diff --git a/content/browser/devtools/devtools_network_interceptor.cc b/content/browser/devtools/devtools_network_interceptor.cc
index 812f543d..8213acf 100644
--- a/content/browser/devtools/devtools_network_interceptor.cc
+++ b/content/browser/devtools/devtools_network_interceptor.cc
@@ -3,6 +3,9 @@
 // found in the LICENSE file.
 
 #include "content/browser/devtools/devtools_network_interceptor.h"
+#include "base/strings/pattern.h"
+#include "content/browser/devtools/protocol/network_handler.h"
+#include "url/gurl.h"
 
 namespace content {
 
@@ -22,4 +25,50 @@
 DevToolsNetworkInterceptor::FilterEntry::FilterEntry(FilterEntry&&) {}
 DevToolsNetworkInterceptor::FilterEntry::~FilterEntry() {}
 
+DevToolsNetworkInterceptor::Modifications::Modifications()
+    : mark_as_canceled(false) {}
+
+DevToolsNetworkInterceptor::Modifications::Modifications(
+    base::Optional<net::Error> error_reason,
+    base::Optional<std::string> raw_response,
+    protocol::Maybe<std::string> modified_url,
+    protocol::Maybe<std::string> modified_method,
+    protocol::Maybe<std::string> modified_post_data,
+    protocol::Maybe<protocol::Network::Headers> modified_headers,
+    protocol::Maybe<protocol::Network::AuthChallengeResponse>
+        auth_challenge_response,
+    bool mark_as_canceled)
+    : error_reason(std::move(error_reason)),
+      raw_response(std::move(raw_response)),
+      modified_url(std::move(modified_url)),
+      modified_method(std::move(modified_method)),
+      modified_post_data(std::move(modified_post_data)),
+      modified_headers(std::move(modified_headers)),
+      auth_challenge_response(std::move(auth_challenge_response)),
+      mark_as_canceled(mark_as_canceled) {}
+
+DevToolsNetworkInterceptor::Modifications::~Modifications() {}
+
+DevToolsNetworkInterceptor::Pattern::~Pattern() = default;
+
+DevToolsNetworkInterceptor::Pattern::Pattern(const Pattern& other) = default;
+
+DevToolsNetworkInterceptor::Pattern::Pattern(
+    const std::string& url_pattern,
+    base::flat_set<ResourceType> resource_types,
+    InterceptionStage interception_stage)
+    : url_pattern(url_pattern),
+      resource_types(std::move(resource_types)),
+      interception_stage(interception_stage) {}
+
+bool DevToolsNetworkInterceptor::Pattern::Matches(
+    const std::string& url,
+    ResourceType resource_type) const {
+  if (!resource_types.empty() &&
+      resource_types.find(resource_type) == resource_types.end()) {
+    return false;
+  }
+  return base::MatchPattern(url, url_pattern);
+}
+
 }  // namespace content
diff --git a/content/browser/devtools/devtools_network_interceptor.h b/content/browser/devtools/devtools_network_interceptor.h
index 59769bf..97c64bc6 100644
--- a/content/browser/devtools/devtools_network_interceptor.h
+++ b/content/browser/devtools/devtools_network_interceptor.h
@@ -35,6 +35,8 @@
 
 class DevToolsNetworkInterceptor {
  public:
+  virtual ~DevToolsNetworkInterceptor() = default;
+
   using RequestInterceptedCallback =
       base::RepeatingCallback<void(std::unique_ptr<InterceptedRequestInfo>)>;
   using ContinueInterceptedRequestCallback =
@@ -43,6 +45,7 @@
       protocol::Network::Backend::GetResponseBodyForInterceptionCallback;
 
   struct Modifications {
+    Modifications();
     Modifications(base::Optional<net::Error> error_reason,
                   base::Optional<std::string> raw_response,
                   protocol::Maybe<std::string> modified_url,
@@ -73,25 +76,27 @@
   };
 
   enum InterceptionStage {
-    REQUEST,
-    RESPONSE,
+    DONT_INTERCEPT = 0,
+    REQUEST = (1 << 0),
+    RESPONSE = (1 << 1),
     // Note: Both is not sent from front-end. It is used if both Request
     // and HeadersReceived was found it upgrades it to Both.
-    BOTH,
-    DONT_INTERCEPT
+    BOTH = (REQUEST | RESPONSE),
   };
 
   struct Pattern {
    public:
-    Pattern();
     ~Pattern();
     Pattern(const Pattern& other);
     Pattern(const std::string& url_pattern,
             base::flat_set<ResourceType> resource_types,
             InterceptionStage interception_stage);
+
+    bool Matches(const std::string& url, ResourceType resource_type) const;
+
     const std::string url_pattern;
     const base::flat_set<ResourceType> resource_types;
-    InterceptionStage interception_stage;
+    const InterceptionStage interception_stage;
   };
 
   struct FilterEntry {
@@ -121,6 +126,13 @@
       std::unique_ptr<ContinueInterceptedRequestCallback> callback) = 0;
 };
 
+inline DevToolsNetworkInterceptor::InterceptionStage& operator|=(
+    DevToolsNetworkInterceptor::InterceptionStage& a,
+    const DevToolsNetworkInterceptor::InterceptionStage& b) {
+  a = static_cast<DevToolsNetworkInterceptor::InterceptionStage>(a | b);
+  return a;
+}
+
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_INTERCEPTOR_H_
diff --git a/content/browser/devtools/devtools_url_interceptor_request_job.cc b/content/browser/devtools/devtools_url_interceptor_request_job.cc
index 6cc6452..15c7ed7b 100644
--- a/content/browser/devtools/devtools_url_interceptor_request_job.cc
+++ b/content/browser/devtools/devtools_url_interceptor_request_job.cc
@@ -1069,6 +1069,10 @@
       sub_request_->Cancel();
       sub_request_.reset();
     }
+    if (response_headers_callback_) {
+      response_headers_callback_.Run(
+          mock_response_details_->response_headers());
+    }
     NotifyHeadersComplete();
     return;
   }
diff --git a/content/browser/devtools/devtools_url_loader_interceptor.cc b/content/browser/devtools/devtools_url_loader_interceptor.cc
new file mode 100644
index 0000000..985ca00
--- /dev/null
+++ b/content/browser/devtools/devtools_url_loader_interceptor.cc
@@ -0,0 +1,1054 @@
+// Copyright 2018 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/devtools/devtools_url_loader_interceptor.h"
+#include "base/base64.h"
+#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
+#include "base/unguessable_token.h"
+#include "content/browser/devtools/protocol/network_handler.h"
+#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/public/browser/browser_thread.h"
+#include "mojo/common/data_pipe_drainer.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "net/base/mime_sniffer.h"
+#include "net/http/http_util.h"
+#include "net/url_request/url_request.h"
+#include "services/network/public/cpp/resource_request_body.h"
+
+namespace content {
+
+namespace {
+
+using RequestInterceptedCallback =
+    DevToolsNetworkInterceptor::RequestInterceptedCallback;
+using ContinueInterceptedRequestCallback =
+    DevToolsNetworkInterceptor::ContinueInterceptedRequestCallback;
+using GetResponseBodyForInterceptionCallback =
+    DevToolsNetworkInterceptor::GetResponseBodyForInterceptionCallback;
+using Modifications = DevToolsNetworkInterceptor::Modifications;
+using InterceptionStage = DevToolsNetworkInterceptor::InterceptionStage;
+using protocol::Response;
+
+struct CreateLoaderParameters {
+  CreateLoaderParameters(
+      int32_t routing_id,
+      int32_t request_id,
+      uint32_t options,
+      network::ResourceRequest request,
+      net::MutableNetworkTrafficAnnotationTag traffic_annotation)
+      : routing_id(routing_id),
+        request_id(request_id),
+        options(options),
+        request(request),
+        traffic_annotation(traffic_annotation) {}
+
+  const int32_t routing_id;
+  const int32_t request_id;
+  const uint32_t options;
+  network::ResourceRequest request;
+  const net::MutableNetworkTrafficAnnotationTag traffic_annotation;
+};
+
+class BodyReader : public mojo::common::DataPipeDrainer::Client {
+ public:
+  explicit BodyReader(base::OnceClosure download_complete_callback)
+      : download_complete_callback_(std::move(download_complete_callback)) {}
+
+  void StartReading(mojo::ScopedDataPipeConsumerHandle body);
+
+  void AddCallback(
+      std::unique_ptr<GetResponseBodyForInterceptionCallback> callback) {
+    callbacks_.push_back(std::move(callback));
+    if (data_complete_) {
+      DCHECK_EQ(1UL, callbacks_.size());
+      BrowserThread::PostTask(
+          BrowserThread::UI, FROM_HERE,
+          base::BindOnce(&BodyReader::DispatchBodyOnUI, std::move(callbacks_),
+                         encoded_body_));
+    }
+  }
+
+  bool data_complete() const { return data_complete_; }
+  const std::string& body() const { return body_; }
+
+  void CancelWithError(std::string error) {
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE,
+        base::BindOnce(&BodyReader::DispatchErrorOnUI, std::move(callbacks_),
+                       std::move(error)));
+  }
+
+ private:
+  using CallbackVector =
+      std::vector<std::unique_ptr<GetResponseBodyForInterceptionCallback>>;
+  static void DispatchBodyOnUI(const CallbackVector& callbacks,
+                               const std::string& body);
+  static void DispatchErrorOnUI(const CallbackVector& callbacks,
+                                const std::string& error);
+
+  void OnDataAvailable(const void* data, size_t num_bytes) override {
+    DCHECK(!data_complete_);
+    body_.append(std::string(static_cast<const char*>(data), num_bytes));
+  }
+
+  void OnDataComplete() override;
+
+  std::unique_ptr<mojo::common::DataPipeDrainer> body_pipe_drainer_;
+  CallbackVector callbacks_;
+  base::OnceClosure download_complete_callback_;
+  std::string body_;
+  std::string encoded_body_;
+  bool data_complete_ = false;
+};
+
+void BodyReader::StartReading(mojo::ScopedDataPipeConsumerHandle body) {
+  DCHECK(!callbacks_.empty());
+  DCHECK(!body_pipe_drainer_);
+  DCHECK(!data_complete_);
+
+  body_pipe_drainer_.reset(
+      new mojo::common::DataPipeDrainer(this, std::move(body)));
+}
+
+void BodyReader::OnDataComplete() {
+  DCHECK(!data_complete_);
+  data_complete_ = true;
+  body_pipe_drainer_.reset();
+  // TODO(caseq): only encode if necessary.
+  base::Base64Encode(body_, &encoded_body_);
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                          base::BindOnce(&BodyReader::DispatchBodyOnUI,
+                                         std::move(callbacks_), encoded_body_));
+  std::move(download_complete_callback_).Run();
+}
+
+// static
+void BodyReader::DispatchBodyOnUI(const CallbackVector& callbacks,
+                                  const std::string& encoded_body) {
+  for (const auto& cb : callbacks)
+    cb->sendSuccess(encoded_body, true);
+}
+
+// static
+void BodyReader::DispatchErrorOnUI(const CallbackVector& callbacks,
+                                   const std::string& error) {
+  for (const auto& cb : callbacks)
+    cb->sendFailure(Response::Error(error));
+}
+
+struct ResponseMetadata {
+  ResponseMetadata() = default;
+  explicit ResponseMetadata(const network::ResourceResponseHead& head)
+      : head(head) {}
+
+  network::ResourceResponseHead head;
+  std::unique_ptr<net::RedirectInfo> redirect_info;
+  base::Optional<net::SSLInfo> ssl_info;
+  network::mojom::DownloadedTempFilePtr downloaded_file;
+  std::vector<uint8_t> cached_metadata;
+  size_t encoded_length = 0;
+  size_t transfer_size = 0;
+  network::URLLoaderCompletionStatus status;
+};
+
+class InterceptionJob : public network::mojom::URLLoaderClient,
+                        public network::mojom::URLLoader {
+ public:
+  InterceptionJob(DevToolsURLLoaderInterceptor::Impl* interceptor,
+                  const std::string& id,
+                  const base::UnguessableToken& frame_token,
+                  std::unique_ptr<CreateLoaderParameters> create_loader_params,
+                  network::mojom::URLLoaderRequest loader_request,
+                  network::mojom::URLLoaderClientPtr client,
+                  network::mojom::URLLoaderFactoryPtr target_factory);
+
+  void GetResponseBody(
+      std::unique_ptr<GetResponseBodyForInterceptionCallback> callback);
+  void ContinueInterceptedRequest(
+      std::unique_ptr<Modifications> modifications,
+      std::unique_ptr<ContinueInterceptedRequestCallback> callback);
+  void Detach();
+
+ private:
+  ~InterceptionJob() override {}
+
+  Response InnerContinueRequest(std::unique_ptr<Modifications> modifications);
+  Response ProcessResponseOverride(const std::string& response);
+  Response ProcessRedirectByClient(const std::string& location);
+  void SendResponse(const base::StringPiece& body);
+  void ApplyModificationsToRequest(
+      std::unique_ptr<Modifications> modifications);
+
+  void StartRequest();
+  void CancelRequest();
+  void Shutdown();
+
+  std::unique_ptr<InterceptedRequestInfo> BuildRequestInfo(
+      const network::ResourceResponseHead* head);
+  void NotifyClient(std::unique_ptr<InterceptedRequestInfo> request_info);
+
+  void ResponseBodyComplete();
+
+  bool ShouldBypassForResponse() const {
+    DCHECK_EQ(!!response_metadata_, !!body_reader_);
+    DCHECK_EQ(state_, State::kResponseReceived);
+    return !response_metadata_;
+  }
+
+  // network::mojom::URLLoader methods
+  void FollowRedirect() override;
+  void ProceedWithResponse() override;
+  void SetPriority(net::RequestPriority priority,
+                   int32_t intra_priority_value) override;
+  void PauseReadingBodyFromNet() override;
+  void ResumeReadingBodyFromNet() override;
+
+  // network::mojom::URLLoaderClient methods
+  void OnReceiveResponse(
+      const network::ResourceResponseHead& head,
+      const base::Optional<net::SSLInfo>& ssl_info,
+      network::mojom::DownloadedTempFilePtr downloaded_file) override;
+  void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
+                         const network::ResourceResponseHead& head) override;
+  void OnDataDownloaded(int64_t data_length, int64_t encoded_length) override;
+  void OnUploadProgress(int64_t current_position,
+                        int64_t total_size,
+                        OnUploadProgressCallback callback) override;
+  void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override;
+  void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
+  void OnStartLoadingResponseBody(
+      mojo::ScopedDataPipeConsumerHandle body) override;
+  void OnComplete(const network::URLLoaderCompletionStatus& status) override;
+
+  const std::string id_;
+  const base::UnguessableToken frame_token_;
+  const base::TimeTicks start_ticks_;
+  const base::Time start_time_;
+  const bool report_upload_;
+
+  DevToolsURLLoaderInterceptor::Impl* interceptor_;
+  InterceptionStage stage_;
+
+  std::unique_ptr<CreateLoaderParameters> create_loader_params_;
+
+  mojo::Binding<network::mojom::URLLoaderClient> client_binding_;
+  mojo::Binding<network::mojom::URLLoader> loader_binding_;
+
+  network::mojom::URLLoaderClientPtr client_;
+  network::mojom::URLLoaderPtr loader_;
+  network::mojom::URLLoaderFactoryPtr target_factory_;
+
+  enum State {
+    kNotStarted,
+    kRequestSent,
+    kRedirectReceived,
+    kResponseReceived,
+  };
+
+  State state_;
+  bool waiting_for_resolution_;
+
+  std::unique_ptr<BodyReader> body_reader_;
+  std::unique_ptr<ResponseMetadata> response_metadata_;
+
+  base::Optional<std::pair<net::RequestPriority, int32_t>> priority_;
+
+  DISALLOW_COPY_AND_ASSIGN(InterceptionJob);
+};
+
+}  // namespace
+
+class DevToolsURLLoaderInterceptor::Impl
+    : public base::SupportsWeakPtr<DevToolsURLLoaderInterceptor::Impl> {
+ public:
+  explicit Impl(RequestInterceptedCallback callback)
+      : request_intercepted_callback_(callback) {}
+  ~Impl() {
+    for (auto const& entry : jobs_)
+      entry.second->Detach();
+  }
+
+  void CreateJob(const base::UnguessableToken& frame_token,
+                 std::unique_ptr<CreateLoaderParameters> create_params,
+                 network::mojom::URLLoaderRequest loader_request,
+                 network::mojom::URLLoaderClientPtr client,
+                 network::mojom::URLLoaderFactoryPtr target_factory) {
+    DCHECK(!frame_token.is_empty());
+
+    static int last_id = 0;
+
+    std::string id = base::StringPrintf("interception-job-%d", ++last_id);
+    InterceptionJob* job =
+        new InterceptionJob(this, id, frame_token, std::move(create_params),
+                            std::move(loader_request), std::move(client),
+                            std::move(target_factory));
+    jobs_.emplace(std::move(id), job);
+  }
+
+  void SetPatterns(std::vector<DevToolsNetworkInterceptor::Pattern> patterns) {
+    patterns_ = std::move(patterns);
+  }
+
+  InterceptionStage GetInterceptionStage(const GURL& url,
+                                         ResourceType resource_type) const {
+    InterceptionStage stage = InterceptionStage::DONT_INTERCEPT;
+    std::string url_str = protocol::NetworkHandler::ClearUrlRef(url).spec();
+    for (const auto& pattern : patterns_) {
+      if (pattern.Matches(url_str, resource_type))
+        stage |= pattern.interception_stage;
+    }
+    return stage;
+  }
+
+  void GetResponseBody(
+      const std::string& interception_id,
+      std::unique_ptr<GetResponseBodyForInterceptionCallback> callback) {
+    if (InterceptionJob* job = FindJob(interception_id, &callback))
+      job->GetResponseBody(std::move(callback));
+  }
+
+  void ContinueInterceptedRequest(
+      const std::string& interception_id,
+      std::unique_ptr<Modifications> modifications,
+      std::unique_ptr<ContinueInterceptedRequestCallback> callback) {
+    if (InterceptionJob* job = FindJob(interception_id, &callback)) {
+      job->ContinueInterceptedRequest(std::move(modifications),
+                                      std::move(callback));
+    }
+  }
+
+ private:
+  friend class InterceptionJob;
+
+  template <typename Callback>
+  InterceptionJob* FindJob(const std::string& id,
+                           std::unique_ptr<Callback>* callback) {
+    auto it = jobs_.find(id);
+    if (it != jobs_.end())
+      return it->second;
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE,
+        base::BindOnce(
+            &Callback::sendFailure, std::move(*callback),
+            protocol::Response::InvalidParams("Invalid InterceptionId.")));
+    return nullptr;
+  }
+
+  void RemoveJob(const std::string& id) { jobs_.erase(id); }
+
+  std::map<std::string, InterceptionJob*> jobs_;
+  RequestInterceptedCallback request_intercepted_callback_;
+  std::vector<DevToolsNetworkInterceptor::Pattern> patterns_;
+
+  DISALLOW_COPY_AND_ASSIGN(Impl);
+};
+
+class DevToolsURLLoaderFactoryProxy : public network::mojom::URLLoaderFactory {
+ public:
+  DevToolsURLLoaderFactoryProxy(
+      const base::UnguessableToken& frame_token,
+      network::mojom::URLLoaderFactoryRequest loader_request,
+      network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
+      base::WeakPtr<DevToolsURLLoaderInterceptor::Impl> interceptor);
+  ~DevToolsURLLoaderFactoryProxy() override;
+
+ private:
+  // network::mojom::URLLoaderFactory implementation
+  void CreateLoaderAndStart(network::mojom::URLLoaderRequest loader,
+                            int32_t routing_id,
+                            int32_t request_id,
+                            uint32_t options,
+                            const network::ResourceRequest& request,
+                            network::mojom::URLLoaderClientPtr client,
+                            const net::MutableNetworkTrafficAnnotationTag&
+                                traffic_annotation) override;
+  void Clone(network::mojom::URLLoaderFactoryRequest request) override;
+
+  void StartOnIO(network::mojom::URLLoaderFactoryRequest loader_request,
+                 network::mojom::URLLoaderFactoryPtrInfo target_factory_info);
+  void OnProxyBindingError();
+  void OnTargetFactoryError();
+
+  const base::UnguessableToken frame_token_;
+
+  network::mojom::URLLoaderFactoryPtr target_factory_;
+  base::WeakPtr<DevToolsURLLoaderInterceptor::Impl> interceptor_;
+  mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+};
+
+DevToolsURLLoaderFactoryProxy::DevToolsURLLoaderFactoryProxy(
+    const base::UnguessableToken& frame_token,
+    network::mojom::URLLoaderFactoryRequest loader_request,
+    network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
+    base::WeakPtr<DevToolsURLLoaderInterceptor::Impl> interceptor)
+    : frame_token_(frame_token), interceptor_(std::move(interceptor)) {
+  DETACH_FROM_SEQUENCE(sequence_checker_);
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::BindOnce(&DevToolsURLLoaderFactoryProxy::StartOnIO,
+                     base::Unretained(this), std::move(loader_request),
+                     std::move(target_factory_info)));
+}
+
+DevToolsURLLoaderFactoryProxy::~DevToolsURLLoaderFactoryProxy() {}
+
+void DevToolsURLLoaderFactoryProxy::CreateLoaderAndStart(
+    network::mojom::URLLoaderRequest loader,
+    int32_t routing_id,
+    int32_t request_id,
+    uint32_t options,
+    const network::ResourceRequest& request,
+    network::mojom::URLLoaderClientPtr client,
+    const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  DevToolsURLLoaderInterceptor::Impl* interceptor = interceptor_.get();
+  if (!interceptor_) {
+    target_factory_->CreateLoaderAndStart(
+        std::move(loader), routing_id, request_id, options, request,
+        std::move(client), traffic_annotation);
+    return;
+  }
+  auto creation_params = std::make_unique<CreateLoaderParameters>(
+      routing_id, request_id, options, request, traffic_annotation);
+  network::mojom::URLLoaderFactoryPtr factory_clone;
+  target_factory_->Clone(MakeRequest(&factory_clone));
+  interceptor->CreateJob(frame_token_, std::move(creation_params),
+                         std::move(loader), std::move(client),
+                         std::move(factory_clone));
+}
+
+void DevToolsURLLoaderFactoryProxy::StartOnIO(
+    network::mojom::URLLoaderFactoryRequest loader_request,
+    network::mojom::URLLoaderFactoryPtrInfo target_factory_info) {
+  target_factory_.Bind(std::move(target_factory_info));
+  target_factory_.set_connection_error_handler(
+      base::BindOnce(&DevToolsURLLoaderFactoryProxy::OnTargetFactoryError,
+                     base::Unretained(this)));
+
+  bindings_.AddBinding(this, std::move(loader_request));
+  bindings_.set_connection_error_handler(
+      base::BindRepeating(&DevToolsURLLoaderFactoryProxy::OnProxyBindingError,
+                          base::Unretained(this)));
+}
+
+void DevToolsURLLoaderFactoryProxy::Clone(
+    network::mojom::URLLoaderFactoryRequest request) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  bindings_.AddBinding(this, std::move(request));
+}
+
+void DevToolsURLLoaderFactoryProxy::OnTargetFactoryError() {
+  DCHECK(!target_factory_.is_bound());
+  delete this;
+}
+
+void DevToolsURLLoaderFactoryProxy::OnProxyBindingError() {
+  if (bindings_.empty())
+    delete this;
+}
+
+DevToolsURLLoaderInterceptor::DevToolsURLLoaderInterceptor(
+    FrameTreeNode* const local_root,
+    RequestInterceptedCallback callback)
+    : local_root_(local_root),
+      enabled_(false),
+      impl_(new DevToolsURLLoaderInterceptor::Impl(std::move(callback)),
+            base::OnTaskRunnerDeleter(
+                BrowserThread::GetTaskRunnerForThread(BrowserThread::IO))),
+      weak_impl_(impl_->AsWeakPtr()) {}
+
+DevToolsURLLoaderInterceptor::~DevToolsURLLoaderInterceptor() {
+  UpdateSubresourceLoaderFactories();
+};
+
+void DevToolsURLLoaderInterceptor::UpdateSubresourceLoaderFactories() {
+  base::queue<FrameTreeNode*> queue;
+  queue.push(local_root_);
+  while (!queue.empty()) {
+    FrameTreeNode* node = queue.front();
+    queue.pop();
+    RenderFrameHostImpl* host = node->current_frame_host();
+    if (node != local_root_ && host->IsCrossProcessSubframe())
+      continue;
+    host->UpdateSubresourceLoaderFactories();
+    for (size_t i = 0; i < node->child_count(); ++i)
+      queue.push(node->child_at(i));
+  }
+}
+
+void DevToolsURLLoaderInterceptor::SetPatterns(
+    std::vector<DevToolsNetworkInterceptor::Pattern> patterns) {
+  if (enabled_ != !!patterns.size()) {
+    enabled_ = !!patterns.size();
+    UpdateSubresourceLoaderFactories();
+  }
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::BindOnce(&Impl::SetPatterns, base::Unretained(impl_.get()),
+                     std::move(patterns)));
+}
+
+void DevToolsURLLoaderInterceptor::GetResponseBody(
+    const std::string& interception_id,
+    std::unique_ptr<GetResponseBodyForInterceptionCallback> callback) {
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::BindOnce(&Impl::GetResponseBody, base::Unretained(impl_.get()),
+                     interception_id, std::move(callback)));
+}
+
+void DevToolsURLLoaderInterceptor::ContinueInterceptedRequest(
+    const std::string& interception_id,
+    std::unique_ptr<Modifications> modifications,
+    std::unique_ptr<ContinueInterceptedRequestCallback> callback) {
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::BindOnce(&Impl::ContinueInterceptedRequest,
+                     base::Unretained(impl_.get()), interception_id,
+                     std::move(modifications), std::move(callback)));
+}
+
+bool DevToolsURLLoaderInterceptor::CreateProxyForInterception(
+    const base::UnguessableToken frame_token,
+    network::mojom::URLLoaderFactoryRequest* request) const {
+  if (!enabled_)
+    return false;
+  network::mojom::URLLoaderFactoryRequest original_request =
+      std::move(*request);
+  network::mojom::URLLoaderFactoryPtrInfo target_ptr_info;
+  *request = MakeRequest(&target_ptr_info);
+
+  new DevToolsURLLoaderFactoryProxy(frame_token, std::move(original_request),
+                                    std::move(target_ptr_info), weak_impl_);
+  return true;
+}
+
+InterceptionJob::InterceptionJob(
+    DevToolsURLLoaderInterceptor::Impl* interceptor,
+    const std::string& id,
+    const base::UnguessableToken& frame_token,
+    std::unique_ptr<CreateLoaderParameters> create_loader_params,
+    network::mojom::URLLoaderRequest loader_request,
+    network::mojom::URLLoaderClientPtr client,
+    network::mojom::URLLoaderFactoryPtr target_factory)
+    : id_(std::move(id)),
+      frame_token_(frame_token),
+      start_ticks_(base::TimeTicks::Now()),
+      start_time_(base::Time::Now()),
+      report_upload_(!!create_loader_params->request.request_body),
+      interceptor_(interceptor),
+      create_loader_params_(std::move(create_loader_params)),
+      client_binding_(this),
+      loader_binding_(this),
+      client_(std::move(client)),
+      target_factory_(std::move(target_factory)),
+      state_(kNotStarted),
+      waiting_for_resolution_(false) {
+  const network::ResourceRequest& request = create_loader_params_->request;
+  stage_ = interceptor_->GetInterceptionStage(
+      request.url, static_cast<ResourceType>(request.resource_type));
+
+  loader_binding_.Bind(std::move(loader_request));
+  loader_binding_.set_connection_error_handler(
+      base::BindOnce(&InterceptionJob::Shutdown, base::Unretained(this)));
+
+  if (stage_ & InterceptionStage::REQUEST) {
+    NotifyClient(BuildRequestInfo(nullptr));
+    return;
+  }
+
+  StartRequest();
+}
+
+void InterceptionJob::GetResponseBody(
+    std::unique_ptr<GetResponseBodyForInterceptionCallback> callback) {
+  std::string error_reason;
+
+  if (!(stage_ & InterceptionStage::RESPONSE)) {
+    error_reason =
+        "Can only get response body on HeadersReceived pattern matched "
+        "requests.";
+  } else if (state_ != kResponseReceived) {
+    DCHECK(waiting_for_resolution_);
+    error_reason =
+        "Can only get response body on requests captured after headers "
+        "received.";
+  }
+  if (!error_reason.empty()) {
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE,
+        base::BindOnce(&GetResponseBodyForInterceptionCallback::sendFailure,
+                       std::move(callback),
+                       Response::Error(std::move(error_reason))));
+    return;
+  }
+
+  if (!body_reader_) {
+    body_reader_ = std::make_unique<BodyReader>(base::BindOnce(
+        &InterceptionJob::ResponseBodyComplete, base::Unretained(this)));
+    client_binding_.ResumeIncomingMethodCallProcessing();
+    loader_->ResumeReadingBodyFromNet();
+  }
+  body_reader_->AddCallback(std::move(callback));
+}
+
+void InterceptionJob::ContinueInterceptedRequest(
+    std::unique_ptr<Modifications> modifications,
+    std::unique_ptr<ContinueInterceptedRequestCallback> callback) {
+  Response response = InnerContinueRequest(std::move(modifications));
+  // |this| may be destroyed at this pont.
+  bool success = response.isSuccess();
+  base::OnceClosure task =
+      success ? base::BindOnce(&ContinueInterceptedRequestCallback::sendSuccess,
+                               std::move(callback))
+              : base::BindOnce(&ContinueInterceptedRequestCallback::sendFailure,
+                               std::move(callback), std::move(response));
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, std::move(task));
+}
+
+void InterceptionJob::Detach() {
+  stage_ = InterceptionStage::DONT_INTERCEPT;
+  interceptor_ = nullptr;
+  if (waiting_for_resolution_)
+    InnerContinueRequest(std::make_unique<Modifications>());
+}
+
+Response InterceptionJob::InnerContinueRequest(
+    std::unique_ptr<Modifications> modifications) {
+  if (!waiting_for_resolution_)
+    return Response::Error("Invalid state for continueInterceptedRequest");
+  waiting_for_resolution_ = false;
+
+  if (modifications->mark_as_canceled || modifications->error_reason) {
+    int error = modifications->error_reason
+                    ? *modifications->error_reason
+                    : (modifications->mark_as_canceled ? net::ERR_ABORTED
+                                                       : net::ERR_FAILED);
+    network::URLLoaderCompletionStatus status(error);
+    status.completion_time = base::TimeTicks::Now();
+    client_->OnComplete(status);
+    Shutdown();
+    return Response::OK();
+  }
+
+  if (modifications->raw_response)
+    return ProcessResponseOverride(*modifications->raw_response);
+
+  if (state_ == State::kRedirectReceived) {
+    // TODO(caseq): report error if other modifications are present.
+    if (modifications->modified_url.isJust()) {
+      std::string location = modifications->modified_url.fromJust();
+      CancelRequest();
+      auto* headers = response_metadata_->head.headers.get();
+      headers->RemoveHeader("location");
+      headers->AddHeader("location: " + location);
+      return ProcessRedirectByClient(location);
+    }
+    client_->OnReceiveRedirect(*response_metadata_->redirect_info,
+                               response_metadata_->head);
+    return Response::OK();
+  }
+
+  if (body_reader_) {
+    if (body_reader_->data_complete())
+      SendResponse(body_reader_->body());
+
+    // There are read callbacks pending, so let the reader do its job and come
+    // back when it's done.
+    return Response::OK();
+  }
+
+  if (response_metadata_) {
+    // TODO(caseq): report error if other modifications are present.
+    DCHECK_EQ(State::kResponseReceived, state_);
+    DCHECK(!body_reader_);
+    client_->OnReceiveResponse(response_metadata_->head,
+                               response_metadata_->ssl_info,
+                               std::move(response_metadata_->downloaded_file));
+    response_metadata_.reset();
+    loader_->ResumeReadingBodyFromNet();
+    client_binding_.ResumeIncomingMethodCallProcessing();
+    return Response::OK();
+  }
+
+  DCHECK_EQ(State::kNotStarted, state_);
+  ApplyModificationsToRequest(std::move(modifications));
+  StartRequest();
+  return Response::OK();
+}
+
+void InterceptionJob::ApplyModificationsToRequest(
+    std::unique_ptr<Modifications> modifications) {
+  network::ResourceRequest* request = &create_loader_params_->request;
+
+  // Note this redirect is not visible to the page by design. If they want a
+  // visible redirect they can mock a response with a 302.
+  if (modifications->modified_url.isJust())
+    request->url = GURL(modifications->modified_url.fromJust());
+
+  if (modifications->modified_method.isJust())
+    request->method = modifications->modified_method.fromJust();
+
+  if (modifications->modified_post_data.isJust()) {
+    const std::string& post_data = modifications->modified_post_data.fromJust();
+    request->request_body = network::ResourceRequestBody::CreateFromBytes(
+        post_data.data(), post_data.size());
+  }
+
+  if (modifications->modified_headers.isJust()) {
+    request->headers.Clear();
+    std::unique_ptr<protocol::DictionaryValue> headers =
+        modifications->modified_headers.fromJust()->toValue();
+    for (size_t i = 0; i < headers->size(); i++) {
+      protocol::DictionaryValue::Entry entry = headers->at(i);
+      std::string value;
+      if (!entry.second->asString(&value))
+        continue;
+      if (base::EqualsCaseInsensitiveASCII(entry.first,
+                                           net::HttpRequestHeaders::kReferer)) {
+        request->referrer = GURL(value);
+        request->referrer_policy = net::URLRequest::NEVER_CLEAR_REFERRER;
+      } else {
+        request->headers.SetHeader(entry.first, value);
+      }
+    }
+  }
+}
+
+Response InterceptionJob::ProcessResponseOverride(const std::string& response) {
+  CancelRequest();
+
+  std::string raw_headers;
+  int header_size =
+      net::HttpUtil::LocateEndOfHeaders(response.c_str(), response.size());
+  if (header_size == -1) {
+    LOG(WARNING) << "Can't find headers in result";
+    header_size = 0;
+  } else {
+    raw_headers =
+        net::HttpUtil::AssembleRawHeaders(response.c_str(), header_size);
+  }
+  CHECK_LE(static_cast<size_t>(header_size), response.size());
+  size_t body_size = response.size() - header_size;
+
+  response_metadata_ = std::make_unique<ResponseMetadata>();
+  network::ResourceResponseHead* head = &response_metadata_->head;
+
+  head->request_time = start_time_;
+  head->response_time = base::Time::Now();
+  head->headers = new net::HttpResponseHeaders(std::move(raw_headers));
+  head->headers->GetMimeTypeAndCharset(&head->mime_type, &head->charset);
+  if (head->mime_type.empty()) {
+    net::SniffMimeType(response.data() + header_size, body_size,
+                       create_loader_params_->request.url, "",
+                       net::ForceSniffFileUrlsForHtml::kDisabled,
+                       &head->mime_type);
+  }
+  head->content_length = body_size;
+  head->encoded_data_length = header_size;
+  head->encoded_body_length = 0;
+  head->request_start = start_ticks_;
+  head->response_start = base::TimeTicks::Now();
+
+  std::string location_url;
+  if (head->headers->IsRedirect(&location_url))
+    return ProcessRedirectByClient(location_url);
+
+  response_metadata_->transfer_size = body_size;
+
+  response_metadata_->status.completion_time = base::TimeTicks::Now();
+  response_metadata_->status.encoded_data_length = response.size();
+  response_metadata_->status.encoded_body_length = body_size;
+  response_metadata_->status.decoded_body_length = body_size;
+
+  SendResponse(base::StringPiece(response.data() + header_size, body_size));
+  return Response::OK();
+}
+
+Response InterceptionJob::ProcessRedirectByClient(const std::string& location) {
+  GURL redirect_url = create_loader_params_->request.url.Resolve(location);
+
+  if (!redirect_url.is_valid())
+    return Response::Error("Invalid redirect URL in overriden headers");
+
+  const net::HttpResponseHeaders& headers = *response_metadata_->head.headers;
+  const network::ResourceRequest& request = create_loader_params_->request;
+
+  auto first_party_url_policy =
+      request.update_first_party_url_on_redirect
+          ? net::URLRequest::FirstPartyURLPolicy::
+                UPDATE_FIRST_PARTY_URL_ON_REDIRECT
+          : net::URLRequest::FirstPartyURLPolicy::NEVER_CHANGE_FIRST_PARTY_URL;
+
+  response_metadata_->redirect_info = std::make_unique<net::RedirectInfo>(
+      net::RedirectInfo::ComputeRedirectInfo(
+          request.method, request.url, request.site_for_cookies,
+          first_party_url_policy, request.referrer_policy,
+          request.referrer.spec(), &headers, headers.response_code(),
+          redirect_url, false /* token_binding_negotiated */,
+          false /* copy_fragment */));
+
+  client_->OnReceiveRedirect(*response_metadata_->redirect_info,
+                             response_metadata_->head);
+  return Response::OK();
+}
+
+void InterceptionJob::SendResponse(const base::StringPiece& body) {
+  client_->OnReceiveResponse(response_metadata_->head,
+                             response_metadata_->ssl_info,
+                             std::move(response_metadata_->downloaded_file));
+
+  // We shouldn't be able to transfer a string that big over the protocol,
+  // but just in case...
+  DCHECK_LE(body.size(), UINT32_MAX)
+      << "Response bodies larger than " << UINT32_MAX << " are not supported";
+  mojo::DataPipe pipe(body.size());
+  uint32_t num_bytes = body.size();
+  MojoResult res = pipe.producer_handle->WriteData(body.data(), &num_bytes,
+                                                   MOJO_WRITE_DATA_FLAG_NONE);
+  DCHECK_EQ(0u, res);
+  DCHECK_EQ(num_bytes, body.size());
+
+  if (!response_metadata_->cached_metadata.empty())
+    client_->OnReceiveCachedMetadata(response_metadata_->cached_metadata);
+  client_->OnStartLoadingResponseBody(std::move(pipe.consumer_handle));
+  if (response_metadata_->transfer_size)
+    client_->OnTransferSizeUpdated(response_metadata_->transfer_size);
+
+  client_->OnComplete(response_metadata_->status);
+  Shutdown();
+}
+
+void InterceptionJob::ResponseBodyComplete() {
+  if (waiting_for_resolution_)
+    return;
+  // We're here only if client has already told us to proceed with unmodified
+  // response.
+  SendResponse(body_reader_->body());
+}
+
+void InterceptionJob::StartRequest() {
+  DCHECK_EQ(State::kNotStarted, state_);
+  DCHECK(!response_metadata_);
+
+  state_ = State::kRequestSent;
+
+  network::mojom::URLLoaderClientPtr loader_client;
+  client_binding_.Bind(MakeRequest(&loader_client));
+  client_binding_.set_connection_error_handler(
+      base::BindOnce(&InterceptionJob::Shutdown, base::Unretained(this)));
+
+  target_factory_->CreateLoaderAndStart(
+      MakeRequest(&loader_), create_loader_params_->routing_id,
+      create_loader_params_->request_id, create_loader_params_->options,
+      create_loader_params_->request, std::move(loader_client),
+      create_loader_params_->traffic_annotation);
+
+  if (priority_)
+    loader_->SetPriority(priority_->first, priority_->second);
+}
+
+void InterceptionJob::CancelRequest() {
+  if (state_ == State::kNotStarted)
+    return;
+  client_binding_.Close();
+  loader_.reset();
+  if (body_reader_) {
+    body_reader_->CancelWithError(
+        "Another command has cancelled the fetch request");
+    body_reader_.reset();
+  }
+  state_ = State::kNotStarted;
+}
+
+std::unique_ptr<InterceptedRequestInfo> InterceptionJob::BuildRequestInfo(
+    const network::ResourceResponseHead* head) {
+  auto result = std::make_unique<InterceptedRequestInfo>();
+  result->interception_id = id_;
+  result->network_request =
+      protocol::NetworkHandler::CreateRequestFromResourceRequest(
+          create_loader_params_->request);
+  result->frame_id = frame_token_;
+  ResourceType resource_type =
+      static_cast<ResourceType>(create_loader_params_->request.resource_type);
+  result->resource_type = resource_type;
+  result->is_navigation = resource_type == RESOURCE_TYPE_MAIN_FRAME ||
+                          resource_type == RESOURCE_TYPE_SUB_FRAME;
+
+  // TODO(caseq): merge with NetworkHandler::BuildResponse()
+  if (head && head->headers) {
+    result->http_response_status_code = head->headers->response_code();
+    auto headers_dict = protocol::DictionaryValue::create();
+    size_t iter = 0;
+    std::string name;
+    std::string value;
+    while (head->headers->EnumerateHeaderLines(&iter, &name, &value)) {
+      std::string old_value;
+      bool merge_with_another = headers_dict->getString(name, &old_value);
+      headers_dict->setString(
+          name, merge_with_another ? old_value + '\n' + value : value);
+    }
+    result->response_headers =
+        protocol::Object::fromValue(headers_dict.get(), nullptr);
+  }
+  return result;
+}
+
+void InterceptionJob::NotifyClient(
+    std::unique_ptr<InterceptedRequestInfo> request_info) {
+  waiting_for_resolution_ = true;
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::BindOnce(interceptor_->request_intercepted_callback_,
+                     std::move(request_info)));
+}
+
+void InterceptionJob::Shutdown() {
+  if (interceptor_)
+    interceptor_->RemoveJob(id_);
+  delete this;
+}
+
+// URLLoader methods
+void InterceptionJob::FollowRedirect() {
+  DCHECK(!waiting_for_resolution_);
+
+  network::ResourceRequest* request = &create_loader_params_->request;
+  const net::RedirectInfo& info = *response_metadata_->redirect_info;
+  request->method = info.new_method;
+  request->url = info.new_url;
+  request->site_for_cookies = info.new_site_for_cookies;
+  request->referrer_policy = info.new_referrer_policy;
+  request->referrer = GURL(info.new_referrer);
+  response_metadata_.reset();
+  if (interceptor_) {
+    stage_ = interceptor_->GetInterceptionStage(
+        request->url, static_cast<ResourceType>(request->resource_type));
+  }
+  if (state_ == State::kRedirectReceived) {
+    state_ = State::kRequestSent;
+    loader_->FollowRedirect();
+    return;
+  }
+
+  DCHECK_EQ(State::kNotStarted, state_);
+  StartRequest();
+}
+
+void InterceptionJob::ProceedWithResponse() {
+  NOTREACHED();
+}
+
+void InterceptionJob::SetPriority(net::RequestPriority priority,
+                                  int32_t intra_priority_value) {
+  priority_ = std::make_pair(priority, intra_priority_value);
+
+  if (state_ != State::kNotStarted)
+    loader_->SetPriority(priority, intra_priority_value);
+}
+
+void InterceptionJob::PauseReadingBodyFromNet() {
+  if (state_ != State::kNotStarted && !body_reader_)
+    loader_->PauseReadingBodyFromNet();
+}
+
+void InterceptionJob::ResumeReadingBodyFromNet() {
+  if (state_ != State::kNotStarted && !body_reader_)
+    loader_->ResumeReadingBodyFromNet();
+}
+
+// URLLoaderClient methods
+void InterceptionJob::OnReceiveResponse(
+    const network::ResourceResponseHead& head,
+    const base::Optional<net::SSLInfo>& ssl_info,
+    network::mojom::DownloadedTempFilePtr downloaded_file) {
+  state_ = State::kResponseReceived;
+  DCHECK(!response_metadata_);
+  if (!(stage_ & InterceptionStage::RESPONSE)) {
+    client_->OnReceiveResponse(head, ssl_info, std::move(downloaded_file));
+    return;
+  }
+  loader_->PauseReadingBodyFromNet();
+  client_binding_.PauseIncomingMethodCallProcessing();
+
+  response_metadata_ = std::make_unique<ResponseMetadata>(head);
+  response_metadata_->ssl_info = ssl_info;
+  response_metadata_->downloaded_file = std::move(downloaded_file);
+
+  NotifyClient(BuildRequestInfo(&head));
+}
+
+void InterceptionJob::OnReceiveRedirect(
+    const net::RedirectInfo& redirect_info,
+    const network::ResourceResponseHead& head) {
+  DCHECK_EQ(State::kRequestSent, state_);
+  state_ = State::kRedirectReceived;
+  response_metadata_ = std::make_unique<ResponseMetadata>(head);
+  response_metadata_->redirect_info =
+      std::make_unique<net::RedirectInfo>(redirect_info);
+
+  if (!(stage_ & InterceptionStage::REQUEST)) {
+    client_->OnReceiveRedirect(redirect_info, head);
+    return;
+  }
+
+  std::unique_ptr<InterceptedRequestInfo> request_info =
+      BuildRequestInfo(&head);
+  request_info->http_response_status_code = redirect_info.status_code;
+  request_info->redirect_url = redirect_info.new_url.spec();
+  NotifyClient(std::move(request_info));
+}
+
+void InterceptionJob::OnDataDownloaded(int64_t data_length,
+                                       int64_t encoded_length) {
+  if (ShouldBypassForResponse())
+    client_->OnDataDownloaded(data_length, encoded_length);
+}
+
+void InterceptionJob::OnUploadProgress(int64_t current_position,
+                                       int64_t total_size,
+                                       OnUploadProgressCallback callback) {
+  if (!report_upload_)
+    return;
+  client_->OnUploadProgress(current_position, total_size, std::move(callback));
+}
+
+void InterceptionJob::OnReceiveCachedMetadata(
+    const std::vector<uint8_t>& data) {
+  if (ShouldBypassForResponse())
+    client_->OnReceiveCachedMetadata(data);
+  else
+    response_metadata_->cached_metadata = data;
+}
+
+void InterceptionJob::OnTransferSizeUpdated(int32_t transfer_size_diff) {
+  if (ShouldBypassForResponse())
+    client_->OnTransferSizeUpdated(transfer_size_diff);
+  else
+    response_metadata_->transfer_size += transfer_size_diff;
+}
+
+void InterceptionJob::OnStartLoadingResponseBody(
+    mojo::ScopedDataPipeConsumerHandle body) {
+  if (ShouldBypassForResponse())
+    client_->OnStartLoadingResponseBody(std::move(body));
+  else
+    body_reader_->StartReading(std::move(body));
+}
+
+void InterceptionJob::OnComplete(
+    const network::URLLoaderCompletionStatus& status) {
+  if (ShouldBypassForResponse()) {
+    client_->OnComplete(status);
+    Shutdown();
+    return;
+  }
+  response_metadata_->status = status;
+}
+
+}  // namespace content
diff --git a/content/browser/devtools/devtools_url_loader_interceptor.h b/content/browser/devtools/devtools_url_loader_interceptor.h
new file mode 100644
index 0000000..a865337
--- /dev/null
+++ b/content/browser/devtools/devtools_url_loader_interceptor.h
@@ -0,0 +1,56 @@
+// Copyright 2018 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_DEVTOOLS_DEVTOOLS_URL_LOADER_INTERCEPTOR_H_
+#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_URL_LOADER_INTERCEPTOR_H_
+
+#include "base/memory/weak_ptr.h"
+#include "content/browser/devtools/devtools_network_interceptor.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+
+namespace content {
+
+class FrameTreeNode;
+
+class DevToolsURLLoaderInterceptor {
+ public:
+  class Impl;
+
+  DevToolsURLLoaderInterceptor(
+      FrameTreeNode* local_root,
+      DevToolsNetworkInterceptor::RequestInterceptedCallback callback);
+  ~DevToolsURLLoaderInterceptor();
+
+  void SetPatterns(std::vector<DevToolsNetworkInterceptor::Pattern> patterns);
+
+  void GetResponseBody(
+      const std::string& interception_id,
+      std::unique_ptr<
+          DevToolsNetworkInterceptor::GetResponseBodyForInterceptionCallback>
+          callback);
+  void ContinueInterceptedRequest(
+      const std::string& interception_id,
+      std::unique_ptr<DevToolsNetworkInterceptor::Modifications> modifications,
+      std::unique_ptr<
+          DevToolsNetworkInterceptor::ContinueInterceptedRequestCallback>
+          callback);
+
+  bool CreateProxyForInterception(
+      const base::UnguessableToken frame_token,
+      network::mojom::URLLoaderFactoryRequest* request) const;
+
+ private:
+  void UpdateSubresourceLoaderFactories();
+
+  FrameTreeNode* const local_root_;
+  bool enabled_;
+  std::unique_ptr<Impl, base::OnTaskRunnerDeleter> impl_;
+  base::WeakPtr<Impl> weak_impl_;
+
+  DISALLOW_COPY_AND_ASSIGN(DevToolsURLLoaderInterceptor);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_URL_LOADER_INTERCEPTOR_H_
diff --git a/content/browser/devtools/devtools_url_request_interceptor.cc b/content/browser/devtools/devtools_url_request_interceptor.cc
index 3f361e8e..4130dea 100644
--- a/content/browser/devtools/devtools_url_request_interceptor.cc
+++ b/content/browser/devtools/devtools_url_request_interceptor.cc
@@ -42,20 +42,6 @@
   // DevToolsURLRequestInterceptorUserData explicitly.
 }
 
-DevToolsURLRequestInterceptor::Pattern::Pattern() = default;
-
-DevToolsURLRequestInterceptor::Pattern::~Pattern() = default;
-
-DevToolsURLRequestInterceptor::Pattern::Pattern(const Pattern& other) = default;
-
-DevToolsURLRequestInterceptor::Pattern::Pattern(
-    const std::string& url_pattern,
-    base::flat_set<ResourceType> resource_types,
-    InterceptionStage interception_stage)
-    : url_pattern(url_pattern),
-      resource_types(std::move(resource_types)),
-      interception_stage(interception_stage) {}
-
 const DevToolsTargetRegistry::TargetInfo*
 DevToolsURLRequestInterceptor::TargetInfoForRequestInfo(
     const ResourceRequestInfo* request_info) const {
@@ -318,25 +304,4 @@
                      controller_, interception_id));
 }
 
-DevToolsURLRequestInterceptor::Modifications::Modifications(
-    base::Optional<net::Error> error_reason,
-    base::Optional<std::string> raw_response,
-    protocol::Maybe<std::string> modified_url,
-    protocol::Maybe<std::string> modified_method,
-    protocol::Maybe<std::string> modified_post_data,
-    protocol::Maybe<protocol::Network::Headers> modified_headers,
-    protocol::Maybe<protocol::Network::AuthChallengeResponse>
-        auth_challenge_response,
-    bool mark_as_canceled)
-    : error_reason(std::move(error_reason)),
-      raw_response(std::move(raw_response)),
-      modified_url(std::move(modified_url)),
-      modified_method(std::move(modified_method)),
-      modified_post_data(std::move(modified_post_data)),
-      modified_headers(std::move(modified_headers)),
-      auth_challenge_response(std::move(auth_challenge_response)),
-      mark_as_canceled(mark_as_canceled) {}
-
-DevToolsURLRequestInterceptor::Modifications::~Modifications() {}
-
 }  // namespace content
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index 4721c1a..3071929 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -19,6 +19,7 @@
 #include "base/time/time.h"
 #include "content/browser/devtools/devtools_interceptor_controller.h"
 #include "content/browser/devtools/devtools_session.h"
+#include "content/browser/devtools/devtools_url_loader_interceptor.h"
 #include "content/browser/devtools/protocol/page.h"
 #include "content/browser/devtools/protocol/security.h"
 #include "content/browser/frame_host/frame_tree_node.h"
@@ -38,6 +39,7 @@
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
 #include "net/base/net_errors.h"
@@ -53,6 +55,7 @@
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/data_element.h"
+#include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/http_raw_request_response_info.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/resource_response.h"
@@ -809,6 +812,7 @@
   enabled_ = false;
   user_agent_ = std::string();
   interception_handle_.reset();
+  url_loader_interceptor_.reset();
   SetNetworkConditions(nullptr);
   extra_headers_.clear();
   return Response::FallThrough();
@@ -1385,18 +1389,9 @@
 DispatchResponse NetworkHandler::SetRequestInterception(
     std::unique_ptr<protocol::Array<protocol::Network::RequestPattern>>
         patterns) {
-  WebContents* web_contents = WebContents::FromRenderFrameHost(host_);
-  if (!web_contents)
-    return Response::InternalError();
-
-  DevToolsInterceptorController* interceptor =
-      DevToolsInterceptorController::FromBrowserContext(
-          web_contents->GetBrowserContext());
-  if (!interceptor)
-    return Response::Error("Interception not supported");
-
   if (!patterns->length()) {
     interception_handle_.reset();
+    url_loader_interceptor_.reset();
     return Response::OK();
   }
 
@@ -1416,13 +1411,37 @@
             protocol::Network::InterceptionStageEnum::Request))));
   }
 
+  if (!host_)
+    return Response::InternalError();
+
+  if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+    if (!url_loader_interceptor_) {
+      url_loader_interceptor_ = std::make_unique<DevToolsURLLoaderInterceptor>(
+          host_->frame_tree_node(),
+          base::BindRepeating(&NetworkHandler::RequestIntercepted,
+                              weak_factory_.GetWeakPtr()));
+    }
+    url_loader_interceptor_->SetPatterns(interceptor_patterns);
+    return Response::OK();
+  }
+
+  WebContents* web_contents = WebContents::FromRenderFrameHost(host_);
+  if (!web_contents)
+    return Response::InternalError();
+
+  DevToolsInterceptorController* interceptor =
+      DevToolsInterceptorController::FromBrowserContext(
+          web_contents->GetBrowserContext());
+  if (!interceptor)
+    return Response::Error("Interception not supported");
+
   if (interception_handle_) {
-    interception_handle_->UpdatePatterns(std::move(interceptor_patterns));
+    interception_handle_->UpdatePatterns(interceptor_patterns);
   } else {
     interception_handle_ = interceptor->StartInterceptingRequests(
-        host_->frame_tree_node(), std::move(interceptor_patterns),
-        base::Bind(&NetworkHandler::RequestIntercepted,
-                   weak_factory_.GetWeakPtr()));
+        host_->frame_tree_node(), interceptor_patterns,
+        base::BindRepeating(&NetworkHandler::RequestIntercepted,
+                            weak_factory_.GetWeakPtr()));
   }
 
   return Response::OK();
@@ -1438,13 +1457,6 @@
     Maybe<protocol::Network::Headers> headers,
     Maybe<protocol::Network::AuthChallengeResponse> auth_challenge_response,
     std::unique_ptr<ContinueInterceptedRequestCallback> callback) {
-  DevToolsInterceptorController* interceptor =
-      DevToolsInterceptorController::FromBrowserContext(browser_context_);
-  if (!interceptor) {
-    callback->sendFailure(Response::InternalError());
-    return;
-  }
-
   base::Optional<std::string> raw_response;
   if (base64_raw_response.isJust()) {
     std::string decoded;
@@ -1468,18 +1480,37 @@
     mark_as_canceled = true;
   }
 
-  interceptor->ContinueInterceptedRequest(
-      interception_id,
+  auto modifications =
       std::make_unique<DevToolsNetworkInterceptor::Modifications>(
           std::move(error), std::move(raw_response), std::move(url),
           std::move(method), std::move(post_data), std::move(headers),
-          std::move(auth_challenge_response), mark_as_canceled),
-      std::move(callback));
+          std::move(auth_challenge_response), mark_as_canceled);
+
+  if (url_loader_interceptor_) {
+    url_loader_interceptor_->ContinueInterceptedRequest(
+        interception_id, std::move(modifications), std::move(callback));
+    return;
+  }
+
+  DevToolsInterceptorController* interceptor =
+      DevToolsInterceptorController::FromBrowserContext(browser_context_);
+  if (!interceptor) {
+    callback->sendFailure(Response::InternalError());
+    return;
+  }
+  interceptor->ContinueInterceptedRequest(
+      interception_id, std::move(modifications), std::move(callback));
 }
 
 void NetworkHandler::GetResponseBodyForInterception(
     const String& interception_id,
     std::unique_ptr<GetResponseBodyForInterceptionCallback> callback) {
+  if (url_loader_interceptor_) {
+    url_loader_interceptor_->GetResponseBody(interception_id,
+                                             std::move(callback));
+    return;
+  }
+
   DevToolsInterceptorController* interceptor =
       DevToolsInterceptorController::FromBrowserContext(browser_context_);
   if (!interceptor) {
@@ -1499,6 +1530,31 @@
 }
 
 // static
+std::unique_ptr<Network::Request>
+NetworkHandler::CreateRequestFromResourceRequest(
+    const network::ResourceRequest& request) {
+  std::unique_ptr<DictionaryValue> headers_dict(DictionaryValue::create());
+  for (net::HttpRequestHeaders::Iterator it(request.headers); it.GetNext();)
+    headers_dict->setString(it.name(), it.value());
+  if (request.referrer.is_valid()) {
+    headers_dict->setString(net::HttpRequestHeaders::kReferer,
+                            request.referrer.spec());
+  }
+  std::unique_ptr<protocol::Network::Request> request_object =
+      Network::Request::Create()
+          .SetUrl(ClearUrlRef(request.url).spec())
+          .SetMethod(request.method)
+          .SetHeaders(Object::fromValue(headers_dict.get(), nullptr))
+          .SetInitialPriority(resourcePriority(request.priority))
+          .SetReferrerPolicy(referrerPolicy(request.referrer_policy))
+          .Build();
+  std::string post_data;
+  if (request.request_body && GetPostData(*request.request_body, &post_data))
+    request_object->SetPostData(std::move(post_data));
+  return request_object;
+}
+
+// static
 std::unique_ptr<Network::Request> NetworkHandler::CreateRequestFromURLRequest(
     const net::URLRequest* request) {
   std::unique_ptr<DictionaryValue> headers_dict(DictionaryValue::create());
@@ -1544,6 +1600,14 @@
   return interceptor && interceptor->ShouldCancelNavigation(global_request_id);
 }
 
+bool NetworkHandler::MaybeCreateProxyForInterception(
+    const base::UnguessableToken& frame_token,
+    network::mojom::URLLoaderFactoryRequest* target_factory_request) {
+  return url_loader_interceptor_ &&
+         url_loader_interceptor_->CreateProxyForInterception(
+             frame_token, target_factory_request);
+}
+
 void NetworkHandler::ApplyOverrides(net::HttpRequestHeaders* headers,
                                     bool* skip_service_worker,
                                     bool* disable_cache) {
diff --git a/content/browser/devtools/protocol/network_handler.h b/content/browser/devtools/protocol/network_handler.h
index f28d42d4..bb2cd9a 100644
--- a/content/browser/devtools/protocol/network_handler.h
+++ b/content/browser/devtools/protocol/network_handler.h
@@ -11,12 +11,17 @@
 #include "base/containers/flat_set.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "content/browser/devtools/devtools_url_loader_interceptor.h"
 #include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/network.h"
 #include "net/base/net_errors.h"
 #include "net/cookies/canonical_cookie.h"
 #include "services/network/public/mojom/network_service.mojom.h"
 
+namespace base {
+class UnguessableToken;
+};
+
 namespace net {
 class HttpRequestHeaders;
 class URLRequest;
@@ -120,6 +125,10 @@
       std::unique_ptr<GetResponseBodyForInterceptionCallback> callback)
       override;
 
+  bool MaybeCreateProxyForInterception(
+      const base::UnguessableToken& frame_token,
+      network::mojom::URLLoaderFactoryRequest* target_factory_request);
+
   void ApplyOverrides(net::HttpRequestHeaders* headers,
                       bool* skip_service_worker,
                       bool* disable_cache);
@@ -146,6 +155,8 @@
   Network::Frontend* frontend() const { return frontend_.get(); }
 
   static GURL ClearUrlRef(const GURL& url);
+  static std::unique_ptr<Network::Request> CreateRequestFromResourceRequest(
+      const network::ResourceRequest& request);
   static std::unique_ptr<Network::Request> CreateRequestFromURLRequest(
       const net::URLRequest* request);
 
@@ -169,6 +180,7 @@
   std::vector<std::pair<std::string, std::string>> extra_headers_;
   std::string host_id_;
   std::unique_ptr<InterceptionHandle> interception_handle_;
+  std::unique_ptr<DevToolsURLLoaderInterceptor> url_loader_interceptor_;
   bool bypass_service_worker_;
   bool cache_disabled_;
   base::WeakPtrFactory<NetworkHandler> weak_factory_;
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 511e294f..d4ec0a06 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -272,6 +272,7 @@
   net::HttpRequestHeaders headers;
   headers.AddHeadersFromString(begin_params->headers);
   for (auto* network : protocol::NetworkHandler::ForAgentHost(agent_host)) {
+    // TODO(caseq): consider chaining intercepting proxies from multiple agents.
     if (!network->enabled())
       continue;
     *report_raw_headers = true;
@@ -289,6 +290,24 @@
 }
 
 // static
+bool RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory(
+    FrameTreeNode* frame_tree_node,
+    network::mojom::URLLoaderFactoryRequest* target_factory_request) {
+  base::UnguessableToken frame_token = frame_tree_node->devtools_frame_token();
+  frame_tree_node = GetFrameTreeNodeAncestor(frame_tree_node);
+  RenderFrameDevToolsAgentHost* agent_host = FindAgentHost(frame_tree_node);
+  if (!agent_host)
+    return false;
+  for (auto* network : protocol::NetworkHandler::ForAgentHost(agent_host)) {
+    if (network->MaybeCreateProxyForInterception(frame_token,
+                                                 target_factory_request)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// static
 void RenderFrameDevToolsAgentHost::OnNavigationRequestWillBeSent(
     const NavigationRequest& navigation_request) {
   DispatchToAgents(navigation_request.frame_tree_node(),
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h
index 8692f9e..0f4abaf 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.h
+++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -18,6 +18,7 @@
 #include "content/common/navigation_params.mojom.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "net/base/net_errors.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "third_party/WebKit/public/web/devtools_agent.mojom.h"
 
 #if defined(OS_ANDROID)
@@ -69,6 +70,10 @@
   static void ApplyOverrides(FrameTreeNode* frame_tree_node,
                              mojom::BeginNavigationParams* begin_params,
                              bool* report_raw_headers);
+  static bool WillCreateURLLoaderFactory(
+      FrameTreeNode* frame_tree_node,
+      network::mojom::URLLoaderFactoryRequest* loader_factory_request);
+
   static void OnNavigationRequestWillBeSent(
       const NavigationRequest& navigation_request);
   static void OnNavigationResponseReceived(
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 8169536..8698b7d 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -164,11 +164,7 @@
 #if defined(OS_ANDROID)
 #include "content/browser/android/java_interfaces_impl.h"
 #include "content/browser/frame_host/render_frame_host_android.h"
-#include "content/browser/media/android/media_player_renderer.h"
 #include "content/public/browser/android/java_interfaces.h"
-#include "media/base/audio_renderer_sink.h"
-#include "media/base/video_renderer_sink.h"
-#include "media/mojo/services/mojo_renderer_service.h"  // nogncheck
 #endif
 
 #if defined(OS_MACOSX)
@@ -403,27 +399,6 @@
 bool RenderFrameHost::IsDataUrlNavigationAllowedForAndroidWebView() {
   return g_allow_data_url_navigation;
 }
-
-void CreateMediaPlayerRenderer(int process_id,
-                               int routing_id,
-                               RenderFrameHostDelegate* delegate,
-                               media::mojom::RendererRequest request) {
-  std::unique_ptr<MediaPlayerRenderer> renderer =
-      std::make_unique<MediaPlayerRenderer>(process_id, routing_id,
-                                            delegate->GetAsWebContents());
-
-  // base::Unretained is safe here because the lifetime of the MediaPlayerRender
-  // is tied to the lifetime of the MojoRendererService.
-  media::MojoRendererService::InitiateSurfaceRequestCB surface_request_cb =
-      base::Bind(&MediaPlayerRenderer::InitiateScopedSurfaceRequest,
-                 base::Unretained(renderer.get()));
-
-  media::MojoRendererService::Create(
-      nullptr,  // CDMs are not supported.
-      nullptr,  // Manages its own audio_sink.
-      nullptr,  // Does not use video_sink. See StreamTextureWrapper instead.
-      std::move(renderer), surface_request_cb, std::move(request));
-}
 #endif  // defined(OS_ANDROID)
 
 // static
@@ -3129,13 +3104,6 @@
   registry_->AddInterface(
       base::Bind(&MediaSessionServiceImpl::Create, base::Unretained(this)));
 
-#if defined(OS_ANDROID)
-  // Creates a MojoRendererService, passing it a MediaPlayerRender.
-  registry_->AddInterface<media::mojom::Renderer>(
-      base::Bind(&content::CreateMediaPlayerRenderer, GetProcess()->GetID(),
-                 GetRoutingID(), delegate_));
-#endif  // defined(OS_ANDROID)
-
   registry_->AddInterface(base::Bind(
       base::IgnoreResult(&RenderFrameHostImpl::CreateWebBluetoothService),
       base::Unretained(this)));
@@ -3598,6 +3566,9 @@
       auto factory_request = mojo::MakeRequest(&factory_proxy_info);
       GetContentClient()->browser()->WillCreateURLLoaderFactory(
           this, false /* is_navigation */, &factory_request);
+      // Keep DevTools proxy lasy, i.e. closest to the network.
+      RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory(
+          frame_tree_node_, &factory_request);
       factory.second->Clone(std::move(factory_request));
       subresource_loader_factories->factories_info().emplace(
           factory.first, std::move(factory_proxy_info));
@@ -4128,10 +4099,10 @@
     GrantFileAccessFromResourceRequestBody(*common_params.post_data);
 }
 
-void RenderFrameHostImpl::OnNetworkServiceConnectionError() {
+void RenderFrameHostImpl::UpdateSubresourceLoaderFactories() {
   DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
-  DCHECK(network_service_connection_error_handler_holder_.is_bound() &&
-         network_service_connection_error_handler_holder_.encountered_error());
+  DCHECK(network_service_connection_error_handler_holder_.is_bound());
+
   network::mojom::URLLoaderFactoryPtrInfo default_factory_info;
   CreateNetworkServiceDefaultFactoryAndObserve(
       mojo::MakeRequest(&default_factory_info));
@@ -4149,6 +4120,9 @@
   auto* context = GetSiteInstance()->GetBrowserContext();
   GetContentClient()->browser()->WillCreateURLLoaderFactory(
       this, false /* is_navigation */, &default_factory_request);
+  // Keep DevTools proxy lasy, i.e. closest to the network.
+  RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory(
+      frame_tree_node_, &default_factory_request);
   StoragePartitionImpl* storage_partition = static_cast<StoragePartitionImpl*>(
       BrowserContext::GetStoragePartition(context, GetSiteInstance()));
   if (g_create_network_factory_callback_for_test.Get().is_null()) {
@@ -4171,7 +4145,7 @@
         GetProcess()->GetID());
     network_service_connection_error_handler_holder_
         .set_connection_error_handler(base::BindOnce(
-            &RenderFrameHostImpl::OnNetworkServiceConnectionError,
+            &RenderFrameHostImpl::UpdateSubresourceLoaderFactories,
             weak_ptr_factory_.GetWeakPtr()));
   }
 }
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index e495d0d..85c38ec 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -708,6 +708,11 @@
   // Returns the current size for this frame.
   const base::Optional<gfx::Size>& frame_size() const { return frame_size_; }
 
+  // Re-creates loader factories and pushes them to |RenderFrame|.
+  // Used in case we need to add or remove intercepting proxies to the
+  // running renderer, or in case of Network Service connection errors.
+  void UpdateSubresourceLoaderFactories();
+
  protected:
   friend class RenderFrameHostFactory;
 
@@ -944,10 +949,6 @@
       const CommonNavigationParams& common_params,
       const RequestNavigationParams& request_params);
 
-  // Handle Network Service connection errors. Will re-create broken Network
-  // Service-backed factories and send to |RenderFrame|.
-  void OnNetworkServiceConnectionError();
-
   // Creates a Network Service-backed factory from appropriate |NetworkContext|
   // and sets a connection error handler to trigger
   // |OnNetworkServiceConnectionError()| if the factory is out-of-process.
diff --git a/content/browser/loader/navigation_url_loader_network_service.cc b/content/browser/loader/navigation_url_loader_network_service.cc
index 7ce141a..362ff64 100644
--- a/content/browser/loader/navigation_url_loader_network_service.cc
+++ b/content/browser/loader/navigation_url_loader_network_service.cc
@@ -16,6 +16,7 @@
 #include "content/browser/appcache/appcache_navigation_handle.h"
 #include "content/browser/appcache/appcache_request_handler.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
+#include "content/browser/devtools/render_frame_devtools_agent_host.h"
 #include "content/browser/file_url_loader_factory.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/navigation_request_info.h"
@@ -1047,9 +1048,14 @@
     // connected if the request type supports proxying.
     network::mojom::URLLoaderFactoryPtrInfo factory_info;
     auto factory_request = mojo::MakeRequest(&factory_info);
-    if (GetContentClient()->browser()->WillCreateURLLoaderFactory(
-            frame_tree_node->current_frame_host(), true /* is_navigation */,
-            &factory_request)) {
+    bool use_proxy = GetContentClient()->browser()->WillCreateURLLoaderFactory(
+        frame_tree_node->current_frame_host(), true /* is_navigation */,
+        &factory_request);
+    if (RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory(
+            frame_tree_node, &factory_request)) {
+      use_proxy = true;
+    }
+    if (use_proxy) {
       proxied_factory_request = std::move(factory_request);
       proxied_factory_info = std::move(factory_info);
     }
diff --git a/content/browser/media/media_interface_proxy.cc b/content/browser/media/media_interface_proxy.cc
index 86ec886c..074f9f43 100644
--- a/content/browser/media/media_interface_proxy.cc
+++ b/content/browser/media/media_interface_proxy.cc
@@ -10,7 +10,8 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/strings/string_util.h"
-#include "build/build_config.h"
+#include "content/browser/frame_host/render_frame_host_delegate.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/common/content_client.h"
@@ -43,6 +44,11 @@
 #endif  // defined(OS_MACOSX)
 #endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)
 
+#if defined(OS_ANDROID)
+#include "content/browser/media/android/media_player_renderer.h"
+#include "media/mojo/services/mojo_renderer_service.h"  // nogncheck
+#endif
+
 namespace content {
 
 #if BUILDFLAG(ENABLE_LIBRARY_CDMS) && defined(OS_MACOSX)
@@ -145,12 +151,21 @@
 }
 
 void MediaInterfaceProxy::CreateRenderer(
-    const std::string& audio_device_id,
+    media::mojom::HostedRendererType type,
+    const std::string& type_specific_id,
     media::mojom::RendererRequest request) {
   DCHECK(thread_checker_.CalledOnValidThread());
+
+#if defined(OS_ANDROID)
+  if (type == media::mojom::HostedRendererType::kMediaPlayer) {
+    CreateMediaPlayerRenderer(std::move(request));
+    return;
+  }
+#endif
+
   InterfaceFactory* factory = GetMediaInterfaceFactory();
   if (factory)
-    factory->CreateRenderer(audio_device_id, std::move(request));
+    factory->CreateRenderer(type, type_specific_id, std::move(request));
 }
 
 void MediaInterfaceProxy::CreateCdm(
@@ -355,4 +370,25 @@
 }
 #endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)
 
+#if defined(OS_ANDROID)
+void MediaInterfaceProxy::CreateMediaPlayerRenderer(
+    media::mojom::RendererRequest request) {
+  auto renderer = std::make_unique<MediaPlayerRenderer>(
+      render_frame_host_->GetProcess()->GetID(),
+      render_frame_host_->GetRoutingID(),
+      static_cast<RenderFrameHostImpl*>(render_frame_host_)
+          ->delegate()
+          ->GetAsWebContents());
+
+  // base::Unretained is safe here because the lifetime of the MediaPlayerRender
+  // is tied to the lifetime of the MojoRendererService.
+  media::MojoRendererService::InitiateSurfaceRequestCB surface_request_cb =
+      base::BindRepeating(&MediaPlayerRenderer::InitiateScopedSurfaceRequest,
+                          base::Unretained(renderer.get()));
+
+  media::MojoRendererService::Create(std::move(renderer), surface_request_cb,
+                                     std::move(request));
+}
+#endif  // defined(OS_ANDROID)
+
 }  // namespace content
diff --git a/content/browser/media/media_interface_proxy.h b/content/browser/media/media_interface_proxy.h
index b2c2839cc..aa06d8c 100644
--- a/content/browser/media/media_interface_proxy.h
+++ b/content/browser/media/media_interface_proxy.h
@@ -11,6 +11,7 @@
 
 #include "base/macros.h"
 #include "base/threading/thread_checker.h"
+#include "build/build_config.h"
 #include "media/media_features.h"
 #include "media/mojo/interfaces/content_decryption_module.mojom.h"
 #include "media/mojo/interfaces/interface_factory.mojom.h"
@@ -45,7 +46,8 @@
   // media::mojom::InterfaceFactory implementation.
   void CreateAudioDecoder(media::mojom::AudioDecoderRequest request) final;
   void CreateVideoDecoder(media::mojom::VideoDecoderRequest request) final;
-  void CreateRenderer(const std::string& audio_device_id,
+  void CreateRenderer(media::mojom::HostedRendererType type,
+                      const std::string& type_specific_id,
                       media::mojom::RendererRequest request) final;
   void CreateCdm(const std::string& key_system,
                  media::mojom::ContentDecryptionModuleRequest request) final;
@@ -95,6 +97,10 @@
                               media::mojom::CdmProxyRequest request);
 #endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)
 
+#if defined(OS_ANDROID)
+  void CreateMediaPlayerRenderer(media::mojom::RendererRequest request);
+#endif
+
   // Safe to hold a raw pointer since |this| is owned by RenderFrameHostImpl.
   RenderFrameHost* const render_frame_host_;
 
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index c54d6d8..8b78d8d 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -708,23 +708,19 @@
 }
 
 network::mojom::NetworkContext* StoragePartitionImpl::GetNetworkContext() {
-  // Create the NetworkContext as needed, when the network service is disabled.
-  if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
-    if (network_context_)
-      return network_context_.get();
-    DCHECK(!network_context_owner_);
-    network_context_owner_ = std::make_unique<NetworkContextOwner>();
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::BindOnce(&NetworkContextOwner::Initialize,
-                       base::Unretained(network_context_owner_.get()),
-                       MakeRequest(&network_context_), url_request_context_));
-    return network_context_.get();
-  }
-
   if (!network_context_.is_bound() || network_context_.encountered_error()) {
     network_context_ = GetContentClient()->browser()->CreateNetworkContext(
         browser_context_, is_in_memory_, relative_partition_path_);
+    if (!network_context_) {
+      DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
+      DCHECK(!network_context_owner_);
+      network_context_owner_ = std::make_unique<NetworkContextOwner>();
+      BrowserThread::PostTask(
+          BrowserThread::IO, FROM_HERE,
+          base::BindOnce(&NetworkContextOwner::Initialize,
+                         base::Unretained(network_context_owner_.get()),
+                         MakeRequest(&network_context_), url_request_context_));
+    }
   }
   return network_context_.get();
 }
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index a4ac154..6841945 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -4945,11 +4945,6 @@
     rwhv->SetMainFrameAXTreeID(GetMainFrame()->GetAXTreeID());
 
   notify_disconnection_ = true;
-  // TODO(avi): Remove. http://crbug.com/170921
-  NotificationService::current()->Notify(
-      NOTIFICATION_WEB_CONTENTS_CONNECTED,
-      Source<WebContents>(this),
-      NotificationService::NoDetails());
 
   bool was_crashed = IsCrashed();
   SetIsCrashed(base::TERMINATION_STATUS_STILL_RUNNING, 0);
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc
index dddd81a..cd037f8 100644
--- a/content/browser/web_contents/web_contents_view_android.cc
+++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -12,6 +12,7 @@
 #include "content/browser/android/content_view_core.h"
 #include "content/browser/android/gesture_listener_manager.h"
 #include "content/browser/android/select_popup.h"
+#include "content/browser/android/selection_popup_controller.h"
 #include "content/browser/frame_host/interstitial_page_impl.h"
 #include "content/browser/renderer_host/display_util.h"
 #include "content/browser/renderer_host/render_view_host_factory.h"
@@ -350,8 +351,8 @@
     return;
   }
 
-  if (content_view_core_)
-    content_view_core_->HidePopupsAndPreserveSelection();
+  if (selection_popup_controller_)
+    selection_popup_controller_->HidePopupsAndPreserveSelection();
 }
 
 void WebContentsViewAndroid::UpdateDragCursor(blink::WebDragOperation op) {
diff --git a/content/browser/web_contents/web_contents_view_android.h b/content/browser/web_contents/web_contents_view_android.h
index 2c2a72b..4466d290 100644
--- a/content/browser/web_contents/web_contents_view_android.h
+++ b/content/browser/web_contents/web_contents_view_android.h
@@ -22,6 +22,7 @@
 class ContentViewCore;
 class RenderWidgetHostViewAndroid;
 class SelectPopup;
+class SelectionPopupController;
 class SynchronousCompositorClient;
 class WebContentsImpl;
 
@@ -46,6 +47,10 @@
     synchronous_compositor_client_ = client;
   }
 
+  void set_selection_popup_controller(SelectionPopupController* controller) {
+    selection_popup_controller_ = controller;
+  }
+
   SynchronousCompositorClient* synchronous_compositor_client() const {
     return synchronous_compositor_client_;
   }
@@ -145,6 +150,8 @@
   // Interface used to get notified of events from the synchronous compositor.
   SynchronousCompositorClient* synchronous_compositor_client_;
 
+  SelectionPopupController* selection_popup_controller_ = nullptr;
+
   // Show/hide popup UI for <select> tag.
   std::unique_ptr<SelectPopup> select_popup_;
 
diff --git a/content/child/BUILD.gn b/content/child/BUILD.gn
index 79dde2fc..30ae3d82 100644
--- a/content/child/BUILD.gn
+++ b/content/child/BUILD.gn
@@ -107,7 +107,7 @@
     "//media",
     "//media/blink",
     "//mojo/common",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//net",
     "//services/device/public/cpp:device_features",
     "//services/device/public/cpp/power_monitor",
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 0dde314c..2683038f 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -360,7 +360,7 @@
     "//media/midi",
     "//media/midi:mojo",
     "//mojo/common:common_base",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//net",
     "//ppapi/features",
     "//sandbox",
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
index 6f9a671..5099f20 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
@@ -475,10 +475,8 @@
         PopupController.hideAll(mWebContents);
     }
 
-    @CalledByNative
     private void hidePopupsAndPreserveSelection() {
-        getSelectionPopupController().destroyActionModeAndKeepSelection();
-        PopupController.hideAll(mWebContents);
+        getSelectionPopupController().hidePopupsAndPreserveSelection();
     }
 
     private void resetGestureDetection() {
diff --git a/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java b/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java
index 40cf354b..d726a89 100644
--- a/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java
@@ -1397,6 +1397,12 @@
         }
     }
 
+    @CalledByNative
+    public void hidePopupsAndPreserveSelection() {
+        destroyActionModeAndKeepSelection();
+        getPopupController().hideAllPopups();
+    }
+
     public void destroyActionModeAndUnselect() {
         mUnselectAllOnDismiss = true;
         finishActionMode();
diff --git a/content/public/browser/notification_types.h b/content/public/browser/notification_types.h
index 1a68aad..8fa3bee 100644
--- a/content/public/browser/notification_types.h
+++ b/content/public/browser/notification_types.h
@@ -5,12 +5,17 @@
 #ifndef CONTENT_PUBLIC_BROWSER_NOTIFICATION_TYPES_H_
 #define CONTENT_PUBLIC_BROWSER_NOTIFICATION_TYPES_H_
 
-// This file describes various types used to describe and filter notifications
-// that pass through the NotificationService.
-//
-// Only notifications that are fired from the content module should be here. We
-// should never have a notification that is fired by the embedder and listened
-// to by content.
+// **
+// ** NOTICE
+// **
+// ** The notification system is deprecated, obsolete, and is slowly being
+// ** removed. See https://crbug.com/268984 and https://crbug.com/170921.
+// **
+// ** Please don't add any new notification types, and please help migrate
+// ** existing uses of the notification types below to use the Observer and
+// ** Callback patterns.
+// **
+
 namespace content {
 
 enum NotificationType {
@@ -67,14 +72,6 @@
 
   // WebContents ---------------------------------------------------------------
 
-  // This notification is sent when a render view host has connected to a
-  // renderer process. The source is a Source<WebContents> with a pointer to
-  // the WebContents.  A WEB_CONTENTS_DISCONNECTED notification is
-  // guaranteed before the source pointer becomes junk.  No details are
-  // expected.
-  // DEPRECATED: Use WebContentsObserver::RenderViewReady()
-  NOTIFICATION_WEB_CONTENTS_CONNECTED,
-
   // This message is sent after a WebContents is disconnected from the
   // renderer process.  The source is a Source<WebContents> with a pointer to
   // the WebContents (the pointer is usable).  No details are expected.
@@ -145,4 +142,15 @@
 
 }  // namespace content
 
+// **
+// ** NOTICE
+// **
+// ** The notification system is deprecated, obsolete, and is slowly being
+// ** removed. See https://crbug.com/268984 and https://crbug.com/170921.
+// **
+// ** Please don't add any new notification types, and please help migrate
+// ** existing uses of the notification types below to use the Observer and
+// ** Callback patterns.
+// **
+
 #endif  // CONTENT_PUBLIC_BROWSER_NOTIFICATION_TYPES_H_
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn
index 8b8f389..51ce769 100644
--- a/content/public/common/BUILD.gn
+++ b/content/public/common/BUILD.gn
@@ -259,7 +259,7 @@
     "//content/common",
     "//ipc",
     "//media/capture:capture_base",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/bindings",
     "//net",
     "//services/network:network_service",
diff --git a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc
index 5c688e1..2ac4235 100644
--- a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc
+++ b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc
@@ -89,6 +89,11 @@
   DCHECK(main_thread_task_runner_);
   DCHECK(gpu_channel_host_);
 
+  task_runner->PostTask(
+      FROM_HERE,
+      base::BindOnce(&GpuVideoAcceleratorFactoriesImpl::BindContextToTaskRunner,
+                     base::Unretained(this)));
+
   task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&GpuVideoAcceleratorFactoriesImpl::
@@ -98,17 +103,30 @@
 
 GpuVideoAcceleratorFactoriesImpl::~GpuVideoAcceleratorFactoriesImpl() {}
 
+void GpuVideoAcceleratorFactoriesImpl::BindContextToTaskRunner() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(context_provider_);
+  if (context_provider_->BindToCurrentThread() !=
+      gpu::ContextResult::kSuccess) {
+    context_provider_ = nullptr;
+    main_thread_task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            &GpuVideoAcceleratorFactoriesImpl::ReleaseContextProvider,
+            base::Unretained(this)));
+  }
+}
+
 bool GpuVideoAcceleratorFactoriesImpl::CheckContextLost() {
   DCHECK(task_runner_->BelongsToCurrentThread());
   if (context_provider_) {
     bool release_context_provider = false;
-    {
-      viz::ContextProvider::ScopedContextLock lock(context_provider_);
-      if (lock.ContextGL()->GetGraphicsResetStatusKHR() != GL_NO_ERROR) {
-        context_provider_ = nullptr;
-        release_context_provider = true;
-      }
+    if (context_provider_->ContextGL()->GetGraphicsResetStatusKHR() !=
+        GL_NO_ERROR) {
+      context_provider_ = nullptr;
+      release_context_provider = true;
     }
+
     if (release_context_provider) {
       // Drop the reference on the main thread.
       main_thread_task_runner_->PostTask(
@@ -190,8 +208,7 @@
 
   if (CheckContextLost())
     return false;
-  viz::ContextProvider::ScopedContextLock lock(context_provider_);
-  gpu::gles2::GLES2Interface* gles2 = lock.ContextGL();
+  gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
   texture_ids->resize(count);
   texture_mailboxes->resize(count);
   gles2->GenTextures(count, &texture_ids->at(0));
@@ -226,17 +243,14 @@
   if (CheckContextLost())
     return;
 
-  viz::ContextProvider::ScopedContextLock lock(context_provider_);
-  gpu::gles2::GLES2Interface* gles2 = lock.ContextGL();
+  gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
   gles2->DeleteTextures(1, &texture_id);
   DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
 }
 
 gpu::SyncToken GpuVideoAcceleratorFactoriesImpl::CreateSyncToken() {
-  viz::ContextProvider::ScopedContextLock lock(context_provider_);
-  gpu::gles2::GLES2Interface* gl = lock.ContextGL();
   gpu::SyncToken sync_token;
-  gl->GenSyncTokenCHROMIUM(sync_token.GetData());
+  context_provider_->ContextGL()->GenSyncTokenCHROMIUM(sync_token.GetData());
   return sync_token;
 }
 
@@ -246,8 +260,7 @@
   if (CheckContextLost())
     return;
 
-  viz::ContextProvider::ScopedContextLock lock(context_provider_);
-  gpu::gles2::GLES2Interface* gles2 = lock.ContextGL();
+  gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
   gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
 
   // Callers expect the WaitSyncToken to affect the next IPCs. Make sure to
@@ -260,9 +273,7 @@
   if (CheckContextLost())
     return;
 
-  viz::ContextProvider::ScopedContextLock lock(context_provider_);
-  gpu::gles2::GLES2Interface* gles2 = lock.ContextGL();
-  gles2->ShallowFlushCHROMIUM();
+  context_provider_->ContextGL()->ShallowFlushCHROMIUM();
 }
 
 std::unique_ptr<gfx::GpuMemoryBuffer>
@@ -291,7 +302,6 @@
   DCHECK(task_runner_->BelongsToCurrentThread());
   if (CheckContextLost())
     return media::GpuVideoAcceleratorFactories::OutputFormat::UNDEFINED;
-  viz::ContextProvider::ScopedContextLock lock(context_provider_);
   auto capabilities = context_provider_->ContextCapabilities();
   if (bit_depth > 8) {
     // If high bit depth rendering is enabled, bail here, otherwise try and use
@@ -329,24 +339,8 @@
   return media::GpuVideoAcceleratorFactories::OutputFormat::UNDEFINED;
 }
 
-namespace {
-class ScopedGLContextLockImpl
-    : public media::GpuVideoAcceleratorFactories::ScopedGLContextLock {
- public:
-  ScopedGLContextLockImpl(viz::ContextProvider* context_provider)
-      : lock_(context_provider) {}
-  gpu::gles2::GLES2Interface* ContextGL() override { return lock_.ContextGL(); }
-
- private:
-  viz::ContextProvider::ScopedContextLock lock_;
-};
-}  // namespace
-
-std::unique_ptr<media::GpuVideoAcceleratorFactories::ScopedGLContextLock>
-GpuVideoAcceleratorFactoriesImpl::GetGLContextLock() {
-  if (CheckContextLost())
-    return nullptr;
-  return std::make_unique<ScopedGLContextLockImpl>(context_provider_);
+gpu::gles2::GLES2Interface* GpuVideoAcceleratorFactoriesImpl::ContextGL() {
+  return CheckContextLost() ? nullptr : context_provider_->ContextGL();
 }
 
 std::unique_ptr<base::SharedMemory>
diff --git a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h
index c3d7209d..c4a71be4 100644
--- a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h
+++ b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h
@@ -46,6 +46,8 @@
 // The GpuVideoAcceleratorFactoriesImpl can be constructed on any thread,
 // but subsequent calls to all public methods of the class must be called from
 // the |task_runner_|, as provided during construction.
+// |context_provider| should not support locking and will be bound to
+// |task_runner_| where all the operations on the context should also happen.
 class CONTENT_EXPORT GpuVideoAcceleratorFactoriesImpl
     : public media::GpuVideoAcceleratorFactories {
  public:
@@ -89,8 +91,9 @@
   bool ShouldUseGpuMemoryBuffersForVideoFrames() const override;
   unsigned ImageTextureTarget(gfx::BufferFormat format) override;
   OutputFormat VideoFrameOutputFormat(size_t bit_depth) override;
-  std::unique_ptr<media::GpuVideoAcceleratorFactories::ScopedGLContextLock>
-  GetGLContextLock() override;
+
+  gpu::gles2::GLES2Interface* ContextGL() override;
+  void BindContextToTaskRunner();
   bool CheckContextLost();
   std::unique_ptr<base::SharedMemory> CreateSharedMemory(size_t size) override;
   scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() override;
diff --git a/content/renderer/media/media_factory.cc b/content/renderer/media/media_factory.cc
index 1c0d456..e7a4ba3 100644
--- a/content/renderer/media/media_factory.cc
+++ b/content/renderer/media/media_factory.cc
@@ -350,11 +350,11 @@
 #if defined(OS_ANDROID)
   DCHECK(remote_interfaces_);
 
-  // The only MojoRendererService that is registered at the RenderFrameHost
-  // level uses the MediaPlayerRenderer as its underlying media::Renderer.
   auto mojo_media_player_renderer_factory =
       std::make_unique<media::MojoRendererFactory>(
-          media::MojoRendererFactory::GetGpuFactoriesCB(), remote_interfaces_);
+          media::mojom::HostedRendererType::kMediaPlayer,
+          media::MojoRendererFactory::GetGpuFactoriesCB(),
+          GetMediaInterfaceFactory());
 
   // Always give |factory_selector| a MediaPlayerRendererClient factory. WMPI
   // might fallback to it if the final redirected URL is an HLS url.
@@ -384,6 +384,7 @@
     factory_selector->AddFactory(
         media::RendererFactorySelector::FactoryType::MOJO,
         std::make_unique<media::MojoRendererFactory>(
+            media::mojom::HostedRendererType::kDefault,
             base::Bind(&RenderThreadImpl::GetGpuFactories,
                        base::Unretained(render_thread)),
             GetMediaInterfaceFactory()));
diff --git a/content/renderer/media/media_interface_factory.cc b/content/renderer/media/media_interface_factory.cc
index f2ea09f..77c7287 100644
--- a/content/renderer/media/media_interface_factory.cc
+++ b/content/renderer/media/media_interface_factory.cc
@@ -52,18 +52,19 @@
 }
 
 void MediaInterfaceFactory::CreateRenderer(
-    const std::string& audio_device_id,
+    media::mojom::HostedRendererType type,
+    const std::string& type_specific_id,
     media::mojom::RendererRequest request) {
   if (!task_runner_->BelongsToCurrentThread()) {
     task_runner_->PostTask(
         FROM_HERE,
-        base::BindOnce(&MediaInterfaceFactory::CreateRenderer, weak_this_,
-                       audio_device_id, std::move(request)));
+        base::BindOnce(&MediaInterfaceFactory::CreateRenderer, weak_this_, type,
+                       type_specific_id, std::move(request)));
     return;
   }
 
   DVLOG(1) << __func__;
-  GetMediaInterfaceFactory()->CreateRenderer(audio_device_id,
+  GetMediaInterfaceFactory()->CreateRenderer(type, type_specific_id,
                                              std::move(request));
 }
 
diff --git a/content/renderer/media/media_interface_factory.h b/content/renderer/media/media_interface_factory.h
index 02cd30e..ee4a33d 100644
--- a/content/renderer/media/media_interface_factory.h
+++ b/content/renderer/media/media_interface_factory.h
@@ -32,7 +32,8 @@
   // media::mojom::InterfaceFactory implementation.
   void CreateAudioDecoder(media::mojom::AudioDecoderRequest request) final;
   void CreateVideoDecoder(media::mojom::VideoDecoderRequest request) final;
-  void CreateRenderer(const std::string& audio_device_id,
+  void CreateRenderer(media::mojom::HostedRendererType type,
+                      const std::string& type_specific_id,
                       media::mojom::RendererRequest request) final;
   void CreateCdm(const std::string& key_system,
                  media::mojom::ContentDecryptionModuleRequest request) final;
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
index 087e554..97d30e5 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
@@ -53,7 +53,6 @@
 #include "crypto/openssl_util.h"
 #include "jingle/glue/thread_wrapper.h"
 #include "media/base/media_permission.h"
-#include "media/filters/ffmpeg_glue.h"
 #include "media/media_features.h"
 #include "media/video/gpu_video_accelerator_factories.h"
 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
@@ -160,12 +159,8 @@
 
 #if BUILDFLAG(RTC_USE_H264) && BUILDFLAG(ENABLE_FFMPEG_VIDEO_DECODERS)
   // Building /w |rtc_use_h264|, is the corresponding run-time feature enabled?
-  if (base::FeatureList::IsEnabled(kWebRtcH264WithOpenH264FFmpeg)) {
-    // |H264DecoderImpl| may be used which depends on FFmpeg, therefore we need
-    // to initialize FFmpeg before going further.
-    media::FFmpegGlue::InitializeFFmpeg();
-  } else {
-    // Feature is to be disabled, no need to make sure FFmpeg is initialized.
+  if (!base::FeatureList::IsEnabled(kWebRtcH264WithOpenH264FFmpeg)) {
+    // Feature is to be disabled.
     webrtc::DisableRtcUseH264();
   }
 #else
diff --git a/content/renderer/pepper/pepper_graphics_2d_host.cc b/content/renderer/pepper/pepper_graphics_2d_host.cc
index 2dc08d2..358bf3d 100644
--- a/content/renderer/pepper/pepper_graphics_2d_host.cc
+++ b/content/renderer/pepper/pepper_graphics_2d_host.cc
@@ -20,6 +20,7 @@
 #include "components/viz/client/client_shared_bitmap_manager.h"
 #include "components/viz/common/gpu/context_provider.h"
 #include "components/viz/common/quads/shared_bitmap.h"
+#include "components/viz/common/resources/resource_sizes.h"
 #include "content/public/renderer/render_thread.h"
 #include "content/public/renderer/renderer_ppapi_host.h"
 #include "content/renderer/pepper/gfx_conversion.h"
@@ -766,9 +767,9 @@
   if (!shared_bitmap)
     return false;
   void* src = image_data_->Map();
-  memcpy(
-      shared_bitmap->pixels(), src,
-      viz::SharedBitmap::CheckedSizeInBytes(pixel_image_size, viz::RGBA_8888));
+  memcpy(shared_bitmap->pixels(), src,
+         viz::ResourceSizes::CheckedSizeInBytes<size_t>(pixel_image_size,
+                                                        viz::RGBA_8888));
   image_data_->Unmap();
 
   *transferable_resource = viz::TransferableResource::MakeSoftware(
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index d730c8d9..278de05 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1549,23 +1549,14 @@
   DCHECK(IsMainThread());
 
   if (!gpu_factories_.empty()) {
-    scoped_refptr<ui::ContextProviderCommandBuffer> shared_context_provider =
-        gpu_factories_.back()->ContextProviderMainThread();
-    if (shared_context_provider) {
-      viz::ContextProvider::ScopedContextLock lock(
-          shared_context_provider.get());
-      if (lock.ContextGL()->GetGraphicsResetStatusKHR() == GL_NO_ERROR)
-        return gpu_factories_.back().get();
+    if (gpu_factories_.back()->ContextProviderMainThread())
+      return gpu_factories_.back().get();
 
-      scoped_refptr<base::SingleThreadTaskRunner> media_task_runner =
-          GetMediaThreadTaskRunner();
-      media_task_runner->PostTask(
-          FROM_HERE,
-          base::BindOnce(
-              base::IgnoreResult(
-                  &GpuVideoAcceleratorFactoriesImpl::CheckContextLost),
-              base::Unretained(gpu_factories_.back().get())));
-    }
+    GetMediaThreadTaskRunner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(base::IgnoreResult(
+                           &GpuVideoAcceleratorFactoriesImpl::CheckContextLost),
+                       base::Unretained(gpu_factories_.back().get())));
   }
 
   const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
@@ -1577,7 +1568,7 @@
   // This context is only used to create textures and mailbox them, so
   // use lower limits than the default.
   gpu::SharedMemoryLimits limits = gpu::SharedMemoryLimits::ForMailboxContext();
-  bool support_locking = true;
+  bool support_locking = false;
   bool support_gles2_interface = true;
   bool support_raster_interface = false;
   bool support_oop_rasterization = false;
@@ -1587,12 +1578,7 @@
           support_locking, support_gles2_interface, support_raster_interface,
           support_oop_rasterization, ui::command_buffer_metrics::MEDIA_CONTEXT,
           kGpuStreamIdMedia, kGpuStreamPriorityMedia);
-  auto result = media_context_provider->BindToCurrentThread();
-  if (result != gpu::ContextResult::kSuccess)
-    return nullptr;
 
-  scoped_refptr<base::SingleThreadTaskRunner> media_task_runner =
-      GetMediaThreadTaskRunner();
   const bool enable_video_accelerator =
       !cmd_line->HasSwitch(switches::kDisableAcceleratedVideoDecode) &&
       (gpu_channel_host->gpu_feature_info()
@@ -1615,7 +1601,7 @@
 
   gpu_factories_.push_back(GpuVideoAcceleratorFactoriesImpl::Create(
       std::move(gpu_channel_host), base::ThreadTaskRunnerHandle::Get(),
-      media_task_runner, std::move(media_context_provider),
+      GetMediaThreadTaskRunner(), std::move(media_context_provider),
       enable_gpu_memory_buffer_video_frames, enable_video_accelerator,
       vea_provider.PassInterface()));
   gpu_factories_.back()->SetRenderingColorSpace(rendering_color_space_);
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
index 93c9ffa..da726817 100644
--- a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/child/scoped_child_process_reference.h"
 #include "content/common/service_worker/service_worker_utils.h"
@@ -70,6 +71,13 @@
       io_thread_runner_);
   client->set_blink_initialized_time(blink_initialized_time_);
   client->set_start_worker_received_time(base::TimeTicks::Now());
+  // Record UMA to indicate StartWorker is received on renderer.
+  StartWorkerHistogramEnum metric =
+      params->is_installed ? StartWorkerHistogramEnum::RECEIVED_ON_INSTALLED
+                           : StartWorkerHistogramEnum::RECEIVED_ON_UNINSTALLED;
+  UMA_HISTOGRAM_ENUMERATION(
+      "ServiceWorker.EmbeddedWorkerInstanceClient.StartWorker", metric,
+      StartWorkerHistogramEnum::NUM_TYPES);
   wrapper_ = StartWorkerContext(std::move(params), std::move(client),
                                 std::move(interface_provider));
 }
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.h b/content/renderer/service_worker/embedded_worker_instance_client_impl.h
index 6f1dad2..b66b873 100644
--- a/content/renderer/service_worker/embedded_worker_instance_client_impl.h
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.h
@@ -45,6 +45,13 @@
 class EmbeddedWorkerInstanceClientImpl
     : public mojom::EmbeddedWorkerInstanceClient {
  public:
+  // Enum for UMA to record when StartWorker is received.
+  enum class StartWorkerHistogramEnum {
+    RECEIVED_ON_INSTALLED = 0,
+    RECEIVED_ON_UNINSTALLED = 1,
+    NUM_TYPES
+  };
+
   // Creates a new EmbeddedWorkerInstanceClientImpl instance bound to
   // |request|. The instance destroys itself when needed, see the class
   // documentation.
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index 9b40d4d..affe355 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -60,6 +60,8 @@
     "browser/layout_test/blink_test_controller.h",
     "browser/layout_test/devtools_protocol_test_bindings.cc",
     "browser/layout_test/devtools_protocol_test_bindings.h",
+    "browser/layout_test/fake_bluetooth_chooser.cc",
+    "browser/layout_test/fake_bluetooth_chooser.h",
     "browser/layout_test/layout_test_bluetooth_adapter_provider.cc",
     "browser/layout_test/layout_test_bluetooth_adapter_provider.h",
     "browser/layout_test/layout_test_bluetooth_chooser_factory.cc",
@@ -816,6 +818,7 @@
 mojom("mojo_bindings") {
   sources = [
     "common/layout_test.mojom",
+    "common/layout_test/fake_bluetooth_chooser.mojom",
     "common/layout_test/layout_test_bluetooth_fake_adapter_setter.mojom",
     "common/power_monitor_test.mojom",
   ]
diff --git a/content/shell/browser/content_shell_browser_manifest_overlay.json b/content/shell/browser/content_shell_browser_manifest_overlay.json
index b0a6891a..e3cfeefa 100644
--- a/content/shell/browser/content_shell_browser_manifest_overlay.json
+++ b/content/shell/browser/content_shell_browser_manifest_overlay.json
@@ -6,6 +6,7 @@
         "renderer": [
           "content::mojom::LayoutTestBluetoothFakeAdapterSetter",
           "content::mojom::MojoLayoutTestHelper",
+          "content::mojom::FakeBluetoothChooser",
           "bluetooth::mojom::FakeBluetooth"
         ]
       },
diff --git a/content/shell/browser/layout_test/blink_test_controller.cc b/content/shell/browser/layout_test/blink_test_controller.cc
index 07c5af44..4a11137d 100644
--- a/content/shell/browser/layout_test/blink_test_controller.cc
+++ b/content/shell/browser/layout_test/blink_test_controller.cc
@@ -53,6 +53,7 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/test/layouttest_support.h"
 #include "content/shell/browser/layout_test/devtools_protocol_test_bindings.h"
+#include "content/shell/browser/layout_test/fake_bluetooth_chooser.h"
 #include "content/shell/browser/layout_test/layout_test_bluetooth_chooser_factory.h"
 #include "content/shell/browser/layout_test/layout_test_content_browser_client.h"
 #include "content/shell/browser/layout_test/layout_test_devtools_bindings.h"
@@ -553,10 +554,18 @@
 std::unique_ptr<BluetoothChooser> BlinkTestController::RunBluetoothChooser(
     RenderFrameHost* frame,
     const BluetoothChooser::EventHandler& event_handler) {
+  // TODO(https://crbug.com/509038): Remove |bluetooth_chooser_factory_| once
+  // all of the Web Bluetooth tests are migrated to external/wpt/.
   if (bluetooth_chooser_factory_) {
     return bluetooth_chooser_factory_->RunBluetoothChooser(frame,
                                                            event_handler);
   }
+  auto next_fake_bluetooth_chooser =
+      LayoutTestContentBrowserClient::Get()->GetNextFakeBluetoothChooser();
+  if (next_fake_bluetooth_chooser) {
+    next_fake_bluetooth_chooser->SetEventHandler(event_handler);
+    return next_fake_bluetooth_chooser;
+  }
   return std::make_unique<LayoutTestFirstDeviceBluetoothChooser>(event_handler);
 }
 
diff --git a/content/shell/browser/layout_test/fake_bluetooth_chooser.cc b/content/shell/browser/layout_test/fake_bluetooth_chooser.cc
new file mode 100644
index 0000000..963e038e
--- /dev/null
+++ b/content/shell/browser/layout_test/fake_bluetooth_chooser.cc
@@ -0,0 +1,86 @@
+// Copyright 2018 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/shell/browser/layout_test/fake_bluetooth_chooser.h"
+
+#include <string>
+#include <utility>
+
+#include "content/public/browser/bluetooth_chooser.h"
+#include "content/shell/common/layout_test/fake_bluetooth_chooser.mojom.h"
+
+namespace content {
+
+FakeBluetoothChooser::~FakeBluetoothChooser() = default;
+
+// static
+std::unique_ptr<FakeBluetoothChooser> FakeBluetoothChooser::Create(
+    mojom::FakeBluetoothChooserRequest request) {
+  return std::unique_ptr<FakeBluetoothChooser>(
+      new FakeBluetoothChooser(std::move(request)));
+}
+
+void FakeBluetoothChooser::SetEventHandler(const EventHandler& event_handler) {
+  event_handler_ = event_handler;
+}
+
+// mojom::FakeBluetoothChooser overrides
+
+void FakeBluetoothChooser::WaitForEvents(uint32_t num_of_events,
+                                         WaitForEventsCallback callback) {
+  // TODO(https://crbug.com/719826): Implement this function according to the
+  // Web Bluetooth Test Scanning design document.
+  // https://docs.google.com/document/d/1XFl_4ZAgO8ddM6U53A9AfUuZeWgJnlYD5wtbXqEpzeg
+  NOTREACHED();
+}
+
+void FakeBluetoothChooser::SelectPeripheral(
+    const std::string& peripheral_address,
+    SelectPeripheralCallback callback) {
+  // TODO(https://crbug.com/719826): Record the event and send a
+  // BluetoothChooser::SELECTED event to |event_handler_|.
+  NOTREACHED();
+}
+
+void FakeBluetoothChooser::Cancel(CancelCallback callback) {
+  // TODO(https://crbug.com/719826): Record the event and send a
+  // BluetoothChooser::CANCELLED event to |event_handler_|.
+  NOTREACHED();
+}
+
+void FakeBluetoothChooser::Rescan(RescanCallback callback) {
+  // TODO(https://crbug.com/719826): Record the event and send a
+  // BluetoothChooser::RESCAN event to |event_handler_|.
+  NOTREACHED();
+}
+
+// BluetoothChooser overrides
+
+void FakeBluetoothChooser::SetAdapterPresence(AdapterPresence presence) {
+  // TODO(https://crbug.com/719826): Record the event.
+  NOTREACHED();
+}
+
+void FakeBluetoothChooser::ShowDiscoveryState(DiscoveryState state) {
+  // TODO(https://crbug.com/719826): Record the event.
+  NOTREACHED();
+}
+
+void FakeBluetoothChooser::AddOrUpdateDevice(const std::string& device_id,
+                                             bool should_update_name,
+                                             const base::string16& device_name,
+                                             bool is_gatt_connected,
+                                             bool is_paired,
+                                             int signal_strength_level) {
+  // TODO(https://crbug.com/719826): Record the event.
+  NOTREACHED();
+}
+
+// private
+
+FakeBluetoothChooser::FakeBluetoothChooser(
+    mojom::FakeBluetoothChooserRequest request)
+    : binding_(this, std::move(request)) {}
+
+}  // namespace content
diff --git a/content/shell/browser/layout_test/fake_bluetooth_chooser.h b/content/shell/browser/layout_test/fake_bluetooth_chooser.h
new file mode 100644
index 0000000..867490e
--- /dev/null
+++ b/content/shell/browser/layout_test/fake_bluetooth_chooser.h
@@ -0,0 +1,77 @@
+// Copyright 2018 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_SHELL_BROWSER_LAYOUT_TEST_FAKE_BLUETOOTH_CHOOSER_H_
+#define CONTENT_SHELL_BROWSER_LAYOUT_TEST_FAKE_BLUETOOTH_CHOOSER_H_
+
+#include <memory>
+
+#include "content/public/browser/bluetooth_chooser.h"
+#include "content/shell/common/layout_test/fake_bluetooth_chooser.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace content {
+
+// Implementation of FakeBluetoothChooser in
+// src/content/shell/common/layout_test/fake_bluetooth_chooser.mojom
+// to provide a method of controlling the Bluetooth chooser during a test.
+// Serves as a Bluetooth chooser factory for choosers that can be manually
+// controlled through the Mojo API. Only one instance of this class will exist
+// while the chooser is active.
+//
+// The implementation details for FakeBluetoothChooser can be found in the Web
+// Bluetooth Test Scanning design document.
+// https://docs.google.com/document/d/1XFl_4ZAgO8ddM6U53A9AfUuZeWgJnlYD5wtbXqEpzeg
+//
+// Intended to only be used through the FakeBluetoothChooser Mojo interface.
+class FakeBluetoothChooser : public mojom::FakeBluetoothChooser,
+                             public BluetoothChooser {
+ public:
+  ~FakeBluetoothChooser() override;
+
+  // LayoutTestContentBrowserClient will create an instance of this class when a
+  // request is bound. It will maintain ownership of the instance temporarily
+  // until the chooser is opened. When the chooser is opened, ownership of this
+  // instance will shift to the caller of
+  // WebContentsDelegate::RunBluetoothChooser.
+  static std::unique_ptr<FakeBluetoothChooser> Create(
+      mojom::FakeBluetoothChooserRequest request);
+
+  // Sets the EventHandler that will handle events produced by the chooser.
+  void SetEventHandler(const EventHandler& event_handler);
+
+  // mojom::FakeBluetoothChooser overrides:
+
+  void WaitForEvents(uint32_t num_of_events,
+                     WaitForEventsCallback callback) override;
+  void SelectPeripheral(const std::string& peripheral_address,
+                        SelectPeripheralCallback callback) override;
+  void Cancel(CancelCallback callback) override;
+  void Rescan(RescanCallback callback) override;
+
+  // BluetoothChooser overrides:
+
+  void SetAdapterPresence(AdapterPresence presence) override;
+  void ShowDiscoveryState(DiscoveryState state) override;
+  void AddOrUpdateDevice(const std::string& device_id,
+                         bool should_update_name,
+                         const base::string16& device_name,
+                         bool is_gatt_connected,
+                         bool is_paired,
+                         int signal_strength_level) override;
+
+ private:
+  explicit FakeBluetoothChooser(mojom::FakeBluetoothChooserRequest request);
+
+  // Stores the callback function that handles chooser events.
+  EventHandler event_handler_;
+
+  mojo::Binding<mojom::FakeBluetoothChooser> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeBluetoothChooser);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_LAYOUT_TEST_FAKE_BLUETOOTH_CHOOSER_H_
diff --git a/content/shell/browser/layout_test/layout_test_content_browser_client.cc b/content/shell/browser/layout_test/layout_test_content_browser_client.cc
index b25c2dc..edf9f389 100644
--- a/content/shell/browser/layout_test/layout_test_content_browser_client.cc
+++ b/content/shell/browser/layout_test/layout_test_content_browser_client.cc
@@ -14,6 +14,7 @@
 #include "content/public/browser/resource_dispatcher_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/shell/browser/layout_test/blink_test_controller.h"
+#include "content/shell/browser/layout_test/fake_bluetooth_chooser.h"
 #include "content/shell/browser/layout_test/layout_test_bluetooth_fake_adapter_setter_impl.h"
 #include "content/shell/browser/layout_test/layout_test_browser_context.h"
 #include "content/shell/browser/layout_test/layout_test_browser_main_parts.h"
@@ -65,6 +66,11 @@
   block_popups_ = block_popups;
 }
 
+std::unique_ptr<FakeBluetoothChooser>
+LayoutTestContentBrowserClient::GetNextFakeBluetoothChooser() {
+  return std::move(next_fake_bluetooth_chooser_);
+}
+
 LayoutTestNotificationManager*
 LayoutTestContentBrowserClient::GetLayoutTestNotificationManager() {
   return layout_test_notification_manager_.get();
@@ -93,12 +99,21 @@
       content::BrowserThread::GetTaskRunnerForThread(
           content::BrowserThread::UI);
   registry->AddInterface(
-      base::Bind(&LayoutTestBluetoothFakeAdapterSetterImpl::Create),
+      base::BindRepeating(&LayoutTestBluetoothFakeAdapterSetterImpl::Create),
       ui_task_runner);
 
-  registry->AddInterface(base::Bind(&bluetooth::FakeBluetooth::Create),
+  registry->AddInterface(base::BindRepeating(&bluetooth::FakeBluetooth::Create),
                          ui_task_runner);
-  registry->AddInterface(base::Bind(&MojoLayoutTestHelper::Create));
+  // This class outlives |render_process_host|, which owns |registry|. Since
+  // CreateFakeBluetoothChooser will not be called after |registry| is deleted
+  // and |registry| is outlived by this class, it is safe to use
+  // base::Unretained.
+  registry->AddInterface(
+      base::BindRepeating(
+          &LayoutTestContentBrowserClient::CreateFakeBluetoothChooser,
+          base::Unretained(this)),
+      ui_task_runner);
+  registry->AddInterface(base::BindRepeating(&MojoLayoutTestHelper::Create));
 }
 
 void LayoutTestContentBrowserClient::OverrideWebkitPrefs(
@@ -201,4 +216,12 @@
   return nullptr;
 }
 
+// private
+void LayoutTestContentBrowserClient::CreateFakeBluetoothChooser(
+    mojom::FakeBluetoothChooserRequest request) {
+  DCHECK(!next_fake_bluetooth_chooser_);
+  next_fake_bluetooth_chooser_ =
+      FakeBluetoothChooser::Create(std::move(request));
+}
+
 }  // namespace content
diff --git a/content/shell/browser/layout_test/layout_test_content_browser_client.h b/content/shell/browser/layout_test/layout_test_content_browser_client.h
index bfaec7c..80a61cfd 100644
--- a/content/shell/browser/layout_test/layout_test_content_browser_client.h
+++ b/content/shell/browser/layout_test/layout_test_content_browser_client.h
@@ -6,9 +6,11 @@
 #define CONTENT_SHELL_BROWSER_LAYOUT_TEST_LAYOUT_TEST_CONTENT_BROWSER_CLIENT_H_
 
 #include "content/shell/browser/shell_content_browser_client.h"
+#include "content/shell/common/layout_test/fake_bluetooth_chooser.mojom.h"
 
 namespace content {
 
+class FakeBluetoothChooser;
 class LayoutTestBrowserContext;
 class LayoutTestNotificationManager;
 
@@ -23,6 +25,9 @@
   LayoutTestBrowserContext* GetLayoutTestBrowserContext();
   void SetPopupBlockingEnabled(bool block_popups_);
 
+  // Retrieves the last created FakeBluetoothChooser instance.
+  std::unique_ptr<FakeBluetoothChooser> GetNextFakeBluetoothChooser();
+
   // Implements the PlatformNotificationService interface.
   LayoutTestNotificationManager* GetLayoutTestNotificationManager();
 
@@ -77,9 +82,16 @@
           auth_required_callback) override;
 
  private:
+  // Creates and stores a FakeBluetoothChooser instance.
+  void CreateFakeBluetoothChooser(mojom::FakeBluetoothChooserRequest request);
+
   std::unique_ptr<LayoutTestNotificationManager>
       layout_test_notification_manager_;
   bool block_popups_ = false;
+
+  // Stores the next instance of FakeBluetoothChooser that is to be returned
+  // when GetNextFakeBluetoothChooser is called.
+  std::unique_ptr<FakeBluetoothChooser> next_fake_bluetooth_chooser_;
 };
 
 }  // content
diff --git a/content/shell/common/layout_test/OWNERS b/content/shell/common/layout_test/OWNERS
index 42444bc..ef88cc7 100644
--- a/content/shell/common/layout_test/OWNERS
+++ b/content/shell/common/layout_test/OWNERS
@@ -1,2 +1,4 @@
 per-file *_messages*.h=set noparent
 per-file *_messages*.h=file://ipc/SECURITY_OWNERS
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/content/shell/common/layout_test/fake_bluetooth_chooser.mojom b/content/shell/common/layout_test/fake_bluetooth_chooser.mojom
new file mode 100644
index 0000000..7caf2e2
--- /dev/null
+++ b/content/shell/common/layout_test/fake_bluetooth_chooser.mojom
@@ -0,0 +1,68 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module content.mojom;
+
+// This interface is being developed to support Web Platform Tests for Web
+// Bluetooth.
+// https://docs.google.com/document/d/1Nhv_oVDCodd1pEH_jj9k8gF4rPGb_84VYaZ9IG8M_WY
+//
+// These interfaces are not intended to be used directly.
+// `web-bluetooth-test.js` makes the Fake Bluetooth interface easier to work
+// with.
+// *   Calls are synchronous.
+// *   IDs are cached.
+//
+// If another C++ client intends to use FakeBluetooth a C++ wrapper similar to
+// `web-bluetooth-test.js` should be created.
+//
+// The implementation details of FakeBluetoothChooser can be found in the Web
+// Bluetooth Test Scanning design document.
+// https://docs.google.com/document/d/1XFl_4ZAgO8ddM6U53A9AfUuZeWgJnlYD5wtbXqEpzeg
+
+// Indicates the types of Bluetooth chooser events.
+enum ChooserEventType {
+  CHOOSER_OPENED,
+  SCAN_STARTED,
+  DEVICE_UPDATE,
+  ADAPTER_REMOVED,
+  ADAPTER_DISABLED,
+  ADAPTER_ENABLED,
+  DISCOVERY_FAILED_TO_START,
+  DISCOVERING,
+  DISCOVERY_IDLE,
+  ADD_DEVICE,
+};
+
+// FakeBluetoothChooser allows clients to control the global state of the
+// Bluetooth chooser during a layout test.
+interface FakeBluetoothChooser {
+  // Waits until at least |num_of_events| have been recorded before returning
+  // |num_of_events| FakeBluetoothChooserEvents.
+  WaitForEvents(
+      uint32 num_of_events) => (array<FakeBluetoothChooserEvent> events);
+
+  // Simulates a user selecting the given |peripheral_address| in the Bluetooth
+  // chooser.
+  SelectPeripheral(string peripheral_address) => ();
+
+  // Calls the event handler function with the CANCELLED event.
+  Cancel() => ();
+
+  // Calls the event handler function with the RESCAN event.
+  Rescan() => ();
+};
+
+// FakeBluetoothChooserEvent describes the type of chooser event that has been
+// produced by the FakeBluetoothChooser.
+struct FakeBluetoothChooserEvent {
+  ChooserEventType type;
+
+  // Describes the origin the chooser is currently displaying.
+  // This field will be used by the |CHOOSER_OPENED| event type.
+  string? origin;
+
+  // Describes the MAC address of the Bluetooth device.
+  string? peripheral_address;
+};
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index fac859d..3d34909 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -322,7 +322,7 @@
     "//media",
     "//media/capture",
     "//media/capture/mojom:image_capture",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//net:test_support",
     "//services/device/public/mojom",
 
@@ -893,7 +893,7 @@
     "//ipc",
     "//ipc:test_support",
     "//media:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/bindings",
     "//net:test_support",
     "//ppapi/features",
@@ -1702,7 +1702,7 @@
     "//media/capture",
     "//media/midi:midi",
     "//media/midi:mojo",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/test_support:test_utils",
     "//net:extras",
diff --git a/device/BUILD.gn b/device/BUILD.gn
index 3cd79a8..d021dfa 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -103,7 +103,7 @@
     "//device/gamepad/public/mojom:gamepad_mojom_traits_test",
     "//device/geolocation:unittests",
     "//mojo/common",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/bindings",
     "//net",
     "//testing/gmock",
diff --git a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
index 6f147a27..8f92a3c 100644
--- a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
@@ -1383,7 +1383,9 @@
 
   // The adapter is already discovering.
   if (num_discovery_sessions_ > 0) {
-    DCHECK(IsDiscovering());
+    // DCHECK(IsDiscovering()) is removed due to BlueZ bug
+    // (https://crbug.com/822104).
+    // TODO(sonnysasaka): Put it back here when BlueZ bug is fixed.
     DCHECK(!discovery_request_pending_);
     num_discovery_sessions_++;
     SetDiscoveryFilter(BluetoothDiscoveryFilter::Merge(
diff --git a/device/geolocation/BUILD.gn b/device/geolocation/BUILD.gn
index 936039e..6046c65 100644
--- a/device/geolocation/BUILD.gn
+++ b/device/geolocation/BUILD.gn
@@ -59,7 +59,7 @@
 
   deps = [
     "//base",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/bindings",
     "//net",
     "//ui/gfx",
diff --git a/docs/process/merge_request.md b/docs/process/merge_request.md
index 454322f..9ee67df5c 100644
--- a/docs/process/merge_request.md
+++ b/docs/process/merge_request.md
@@ -63,9 +63,13 @@
 
 **Phase 2: First Four Weeks of Beta Rollout**
 
-During the first four weeks of Beta, merges should only be requested if
-the bug is considered either release blocking or
-considered a high-impact regression.
+During the first four weeks of Beta, merges should only be requested if:
+
+* The bug is considered either release blocking or
+  considered a high-impact regression
+* The merge is related to a feature which (1) is entirely gated behind
+  a flag and (2) does not change user functionality in a substantial way
+  (e.g. minor tweaks and metrics code are OK, workflow changes are not)
 
 Security bugs should be consulted with
 [chrome-security@google.com](chrome-security@google.com) to
diff --git a/docs/user_handle_mapping.md b/docs/user_handle_mapping.md
index 9c07ca38..2918c2d 100644
--- a/docs/user_handle_mapping.md
+++ b/docs/user_handle_mapping.md
@@ -63,6 +63,7 @@
 | levin             | dave\_levin     | levin           |
 | lfg               | lfg\_           | lfg             |
 | littledan         | littledan       | dehrenberg      |
+| loonybear         | loonybear       | lunalu          |
 | luken             | luken_chromium  | luken           |
 | mark              | markmentovai    | mmentovai       |
 | mbarbella         | mbarbella       | mbarbella       |
diff --git a/extensions/browser/notification_types.h b/extensions/browser/notification_types.h
index fe72081..4babc9a6 100644
--- a/extensions/browser/notification_types.h
+++ b/extensions/browser/notification_types.h
@@ -14,6 +14,17 @@
 #error "Extensions must be enabled"
 #endif
 
+// **
+// ** NOTICE
+// **
+// ** The notification system is deprecated, obsolete, and is slowly being
+// ** removed. See https://crbug.com/268984 and https://crbug.com/411569.
+// **
+// ** Please don't add any new notification types, and please help migrate
+// ** existing uses of the notification types below to use the Observer and
+// ** Callback patterns.
+// **
+
 namespace extensions {
 
 // Only notifications fired by the extensions module should be here. The
@@ -176,6 +187,17 @@
   std::string accelerator;
 };
 
+// **
+// ** NOTICE
+// **
+// ** The notification system is deprecated, obsolete, and is slowly being
+// ** removed. See https://crbug.com/268984 and https://crbug.com/411569.
+// **
+// ** Please don't add any new notification types, and please help migrate
+// ** existing uses of the notification types below to use the Observer and
+// ** Callback patterns.
+// **
+
 }  // namespace extensions
 
 #endif  // EXTENSIONS_BROWSER_NOTIFICATION_TYPES_H_
diff --git a/extensions/common/api/system_display.idl b/extensions/common/api/system_display.idl
index 7cd761f..4700adf 100644
--- a/extensions/common/api/system_display.idl
+++ b/extensions/common/api/system_display.idl
@@ -111,6 +111,21 @@
     long offset;
   };
 
+  // EDID extracted parameters. Field description refers to "VESA ENHANCED
+  // EXTENDED DISPLAY IDENTIFICATION DATA STANDARD (Defines EDID Structure
+  // Version 1, Revision 4)" Release A, Revision 2 September 25, 2006.
+  // https://www.vesa.org/vesa-standards
+  dictionary Edid {
+    // 3 character manufacturer code. See Sec. 3.4.1 page 21. Required in v1.4.
+    DOMString manufacturerId;
+
+    // 2 byte manufacturer-assigned code, Sec. 3.4.2 page 21. Required in v1.4.
+    DOMString productId;
+
+    // Year of manufacturer, Sec. 3.4.4 page 22. Required in v1.4.
+    long yearOfManufacture;
+  };
+
   dictionary DisplayUnitInfo {
     // The unique identifier of the display.
     DOMString id;
@@ -118,6 +133,9 @@
     // The user-friendly name (e.g. "HP LCD monitor").
     DOMString name;
 
+    // NOTE: This is only available to Chrome OS Kiosk apps and Web UI.
+    Edid? edid;
+
     // Chrome OS only. Identifier of the display that is being mirrored if
     // mirroring is enabled, otherwise empty. This will be set for all displays
     // (including the display being mirrored).
diff --git a/google_apis/gaia/fake_gaia.cc b/google_apis/gaia/fake_gaia.cc
index 5c130de..1e76b22 100644
--- a/google_apis/gaia/fake_gaia.cc
+++ b/google_apis/gaia/fake_gaia.cc
@@ -149,6 +149,7 @@
   maybe_update_field(&MergeSessionParams::auth_code);
   maybe_update_field(&MergeSessionParams::refresh_token);
   maybe_update_field(&MergeSessionParams::access_token);
+  maybe_update_field(&MergeSessionParams::id_token);
   maybe_update_field(&MergeSessionParams::gaia_uber_token);
   maybe_update_field(&MergeSessionParams::session_sid_cookie);
   maybe_update_field(&MergeSessionParams::session_lsid_cookie);
@@ -709,6 +710,8 @@
           device_id;
     response_dict.SetString("access_token",
                             merge_session_params_.access_token);
+    if (!merge_session_params_.id_token.empty())
+      response_dict.SetString("id_token", merge_session_params_.id_token);
     response_dict.SetInteger("expires_in", 3600);
     FormatJSONResponse(response_dict, http_response);
     return;
diff --git a/google_apis/gaia/fake_gaia.h b/google_apis/gaia/fake_gaia.h
index 9909539..fbb5ff9f 100644
--- a/google_apis/gaia/fake_gaia.h
+++ b/google_apis/gaia/fake_gaia.h
@@ -67,10 +67,11 @@
     // auth_code cookie value response for /o/oauth2/programmatic_auth call.
     std::string auth_code;
 
-    // OAuth2 refresh and access token generated by /oauth2/v4/token call
+    // OAuth2 refresh access and id token generated by /oauth2/v4/token call
     // with "...&grant_type=authorization_code".
     std::string refresh_token;
     std::string access_token;
+    std::string id_token;
 
     // Uber token response from /OAuthLogin call.
     std::string gaia_uber_token;
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index 109eb54..a93fa0c 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -440,7 +440,7 @@
     "//gpu/ipc/common:gpu_preferences_util",
     "//gpu/ipc/common:test_interfaces",
     "//gpu/ipc/host",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/bindings",
     "//net:test_support",
     "//testing/gmock",
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index 942f5857..4568677 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -226,7 +226,7 @@
     "//ios/third_party/material_roboto_font_loader_ios",
     "//ios/web",
     "//ios/web/public/app",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//net",
     "//skia",
     "//ui/base",
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 2f3e35a..ccd4fc9 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -248,6 +248,7 @@
     "//net",
     "//net:test_support",
     "//testing/gtest",
+    "//third_party/ocmock",
     "//url",
   ]
 }
diff --git a/ios/chrome/browser/download/BUILD.gn b/ios/chrome/browser/download/BUILD.gn
index da58770..4853e17 100644
--- a/ios/chrome/browser/download/BUILD.gn
+++ b/ios/chrome/browser/download/BUILD.gn
@@ -10,6 +10,8 @@
     "browser_download_service_factory.mm",
     "download_directory_util.cc",
     "download_directory_util.h",
+    "download_manager_metric_names.cc",
+    "download_manager_metric_names.h",
     "download_manager_tab_helper.h",
     "download_manager_tab_helper.mm",
     "download_manager_tab_helper_delegate.h",
diff --git a/ios/chrome/browser/download/download_manager_metric_names.cc b/ios/chrome/browser/download/download_manager_metric_names.cc
new file mode 100644
index 0000000..b8b99203
--- /dev/null
+++ b/ios/chrome/browser/download/download_manager_metric_names.cc
@@ -0,0 +1,8 @@
+// Copyright 2018 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 "ios/chrome/browser/download/download_manager_metric_names.h"
+
+const char kDownloadManagerGoogleDriveInstalled[] =
+    "MobileDownloadFileUIInstallGoogleDrive";
diff --git a/ios/chrome/browser/download/download_manager_metric_names.h b/ios/chrome/browser/download/download_manager_metric_names.h
new file mode 100644
index 0000000..71686fe9
--- /dev/null
+++ b/ios/chrome/browser/download/download_manager_metric_names.h
@@ -0,0 +1,12 @@
+// Copyright 2018 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 IOS_CHROME_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_METRIC_NAMES_H_
+#define IOS_CHROME_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_METRIC_NAMES_H_
+
+// MobileDownloadFileUIInstallGoogleDrive UMA action. Logged when Google Drive
+// app is installed after presenting Store Kit dialog from the Download Manager.
+extern const char kDownloadManagerGoogleDriveInstalled[];
+
+#endif  // IOS_CHROME_BROWSER_DOWNLOAD_DOWNLOAD_MANAGER_METRIC_NAMES_H_
diff --git a/ios/chrome/browser/installation_notifier.mm b/ios/chrome/browser/installation_notifier.mm
index d68fc922..701aa62 100644
--- a/ios/chrome/browser/installation_notifier.mm
+++ b/ios/chrome/browser/installation_notifier.mm
@@ -59,9 +59,6 @@
 @interface InstallationNotifier (Testing)
 // Sets the dispatcher.
 - (void)setDispatcher:(id<DispatcherProtocol>)dispatcher;
-// Sets the UIApplication used to determine if a scheme can be opened by an
-// application.
-- (void)setSharedApplication:(UIApplication*)sharedApplication;
 @end
 
 @implementation InstallationNotifier {
@@ -89,7 +86,6 @@
     _dispatcher = [[DefaultDispatcher alloc] init];
     _installedAppObservers = [[NSMutableDictionary alloc] init];
     _notificationCenter = [NSNotificationCenter defaultCenter];
-    sharedApplication_ = [UIApplication sharedApplication];
     _backoffEntry.reset(new net::BackoffEntry([self backOffPolicy]));
   }
   return self;
@@ -186,7 +182,7 @@
     DCHECK([observers count] > 0);
     NSURL* testSchemeURL =
         [NSURL URLWithString:[NSString stringWithFormat:@"%@:", scheme]];
-    if ([sharedApplication_ canOpenURL:testSchemeURL]) {
+    if ([[UIApplication sharedApplication] canOpenURL:testSchemeURL]) {
       [_notificationCenter postNotificationName:scheme object:self];
       for (id weakReferenceToObserver in observers) {
         id observer = [weakReferenceToObserver nonretainedObjectValue];
@@ -216,11 +212,8 @@
   _dispatcher = dispatcher;
 }
 
-- (void)setSharedApplication:(id)sharedApplication {
-  // Verify that the test application object responds to all the selectors that
-  // will be called on it.
-  CHECK([sharedApplication respondsToSelector:@selector(canOpenURL:)]);
-  sharedApplication_ = (UIApplication*)sharedApplication;
+- (void)resetDispatcher {
+  _dispatcher = [[DefaultDispatcher alloc] init];
 }
 
 @end
diff --git a/ios/chrome/browser/installation_notifier_unittest.mm b/ios/chrome/browser/installation_notifier_unittest.mm
index 226621a8..e330fd2d 100644
--- a/ios/chrome/browser/installation_notifier_unittest.mm
+++ b/ios/chrome/browser/installation_notifier_unittest.mm
@@ -13,6 +13,7 @@
 #include "ios/web/public/test/test_web_thread.h"
 #include "net/base/backoff_entry.h"
 #include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -78,27 +79,9 @@
 
 @end
 
-@interface MockUIApplication : NSObject
-// Mocks UIApplication's canOpenURL.
-@end
-
-@implementation MockUIApplication {
-  BOOL canOpen_;
-}
-
-- (void)setCanOpenURL:(BOOL)canOpen {
-  canOpen_ = canOpen;
-}
-
-- (BOOL)canOpenURL:(NSURL*)url {
-  return canOpen_;
-}
-
-@end
-
 @interface InstallationNotifier (Testing)
 - (void)setDispatcher:(id<DispatcherProtocol>)dispatcher;
-- (void)setSharedApplication:(id)sharedApplication;
+- (void)resetDispatcher;
 - (void)dispatchInstallationNotifierBlock;
 - (void)registerForInstallationNotifications:(id)observer
                                 withSelector:(SEL)notificationSelector
@@ -120,12 +103,16 @@
     dispatcher_ = dispatcher;
     notificationReceiver1_ = ([[MockNotificationReceiver alloc] init]);
     notificationReceiver2_ = ([[MockNotificationReceiver alloc] init]);
-    sharedApplication_ = [[MockUIApplication alloc] init];
-    [installationNotifier_ setSharedApplication:sharedApplication_];
+    application_ = OCMClassMock([UIApplication class]);
+    OCMStub([application_ sharedApplication]).andReturn(application_);
     [installationNotifier_ setDispatcher:dispatcher_];
     histogramTester_.reset(new base::HistogramTester());
   }
 
+  ~InstallationNotifierTest() override {
+    [installationNotifier_ resetDispatcher];
+  }
+
   void VerifyHistogramValidity(int expectedYes, int expectedNo) {
     histogramTester_->ExpectTotalCount("NativeAppLauncher.InstallationDetected",
                                        expectedYes + expectedNo);
@@ -154,12 +141,12 @@
   __weak FakeDispatcher* dispatcher_;
   MockNotificationReceiver* notificationReceiver1_;
   MockNotificationReceiver* notificationReceiver2_;
-  MockUIApplication* sharedApplication_;
+  id application_;
   std::unique_ptr<base::HistogramTester> histogramTester_;
 };
 
 TEST_F(InstallationNotifierTest, RegisterWithAppAlreadyInstalled) {
-  [sharedApplication_ setCanOpenURL:YES];
+  OCMStub([application_ canOpenURL:[OCMArg any]]).andReturn(YES);
   [installationNotifier_
       registerForInstallationNotifications:notificationReceiver1_
                               withSelector:@selector(receivedNotification)
@@ -174,11 +161,11 @@
 }
 
 TEST_F(InstallationNotifierTest, RegisterWithAppInstalledAfterSomeTime) {
-  [sharedApplication_ setCanOpenURL:NO];
-  [dispatcher_ executeAfter:10
-                      block:^{
-                        [sharedApplication_ setCanOpenURL:YES];
-                      }];
+  [dispatcher_
+      executeAfter:10
+             block:^{
+               OCMStub([application_ canOpenURL:[OCMArg any]]).andReturn(YES);
+             }];
   [installationNotifier_
       registerForInstallationNotifications:notificationReceiver1_
                               withSelector:@selector(receivedNotification)
@@ -188,11 +175,11 @@
 }
 
 TEST_F(InstallationNotifierTest, RegisterForTwoInstallations) {
-  [sharedApplication_ setCanOpenURL:NO];
-  [dispatcher_ executeAfter:10
-                      block:^{
-                        [sharedApplication_ setCanOpenURL:YES];
-                      }];
+  [dispatcher_
+      executeAfter:10
+             block:^{
+               OCMStub([application_ canOpenURL:[OCMArg any]]).andReturn(YES);
+             }];
   [installationNotifier_
       registerForInstallationNotifications:notificationReceiver1_
                               withSelector:@selector(receivedNotification)
@@ -215,7 +202,7 @@
 }
 
 TEST_F(InstallationNotifierTest, RegisterAndThenUnregister) {
-  [sharedApplication_ setCanOpenURL:NO];
+  OCMStub([application_ canOpenURL:[OCMArg any]]).andReturn(NO);
   [dispatcher_ executeAfter:10
                       block:^{
                         [installationNotifier_
@@ -230,7 +217,7 @@
 }
 
 TEST_F(InstallationNotifierTest, TestExponentialBackoff) {
-  [sharedApplication_ setCanOpenURL:NO];
+  OCMStub([application_ canOpenURL:[OCMArg any]]).andReturn(NO);
   // Making sure that delay is multiplied by |multiplyFactor| every time.
   [dispatcher_ executeAfter:0
                       block:^{
diff --git a/ios/chrome/browser/ui/download/BUILD.gn b/ios/chrome/browser/ui/download/BUILD.gn
index c0c8813e..4914a11 100644
--- a/ios/chrome/browser/ui/download/BUILD.gn
+++ b/ios/chrome/browser/ui/download/BUILD.gn
@@ -79,6 +79,7 @@
     "//ios/chrome/browser/ui:ui_util",
     "//ios/chrome/browser/web:test_support",
     "//ios/chrome/test:test_support",
+    "//ios/chrome/test/app:test_support",
     "//ios/chrome/test/fakes",
     "//ios/testing:ios_test_support",
     "//ios/web/public/test",
diff --git a/ios/chrome/browser/ui/download/download_manager_coordinator.mm b/ios/chrome/browser/ui/download/download_manager_coordinator.mm
index 3705f5f..e3a0478 100644
--- a/ios/chrome/browser/ui/download/download_manager_coordinator.mm
+++ b/ios/chrome/browser/ui/download/download_manager_coordinator.mm
@@ -7,10 +7,14 @@
 #include <memory>
 
 #import "base/logging.h"
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/strings/grit/components_strings.h"
+#include "ios/chrome/browser/download/download_manager_metric_names.h"
 #import "ios/chrome/browser/download/download_manager_tab_helper.h"
 #import "ios/chrome/browser/download/google_drive_app_util.h"
+#import "ios/chrome/browser/installation_notifier.h"
 #import "ios/chrome/browser/store_kit/store_kit_coordinator.h"
 #import "ios/chrome/browser/ui/download/download_manager_mediator.h"
 #import "ios/chrome/browser/ui/download/download_manager_view_controller.h"
@@ -45,6 +49,10 @@
 @synthesize animatesPresentation = _animatesPresentation;
 @synthesize downloadTask = _downloadTask;
 
+- (void)dealloc {
+  [[InstallationNotifier sharedInstance] unregisterForNotifications:self];
+}
+
 - (void)start {
   DCHECK(self.presenter);
 
@@ -171,6 +179,11 @@
   }
   [_storeKitCoordinator start];
   [controller setInstallDriveButtonVisible:NO animated:YES];
+
+  [[InstallationNotifier sharedInstance]
+      registerForInstallationNotifications:self
+                              withSelector:@selector(didInstallGoogleDriveApp)
+                                 forScheme:kGoogleDriveAppURLScheme];
 }
 
 - (void)downloadManagerViewControllerDidStartDownload:
@@ -236,4 +249,10 @@
                                       completion:nil];
 }
 
+// Called when Google Drive app is installed after starting StoreKitCoordinator.
+- (void)didInstallGoogleDriveApp {
+  base::RecordAction(
+      base::UserMetricsAction(kDownloadManagerGoogleDriveInstalled));
+}
+
 @end
diff --git a/ios/chrome/browser/ui/download/download_manager_coordinator_unittest.mm b/ios/chrome/browser/ui/download/download_manager_coordinator_unittest.mm
index 7d74fd62..65e496f 100644
--- a/ios/chrome/browser/ui/download/download_manager_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/download/download_manager_coordinator_unittest.mm
@@ -11,8 +11,11 @@
 #include "base/mac/foundation_util.h"
 #include "base/run_loop.h"
 #include "base/strings/sys_string_conversions.h"
+#include "base/test/user_action_tester.h"
 #include "ios/chrome/browser/download/download_directory_util.h"
+#include "ios/chrome/browser/download/download_manager_metric_names.h"
 #import "ios/chrome/browser/download/download_manager_tab_helper.h"
+#import "ios/chrome/browser/download/google_drive_app_util.h"
 #import "ios/chrome/browser/ui/download/download_manager_view_controller.h"
 #import "ios/chrome/test/fakes/fake_contained_presenter.h"
 #import "ios/chrome/test/fakes/fake_document_interaction_controller.h"
@@ -78,15 +81,22 @@
   }
   ~DownloadManagerCoordinatorTest() override {
     [document_interaction_controller_class_ stopMocking];
+    [application_ stopMocking];
   }
 
+  web::TestWebThreadBundle thread_bundle_;
   FakeContainedPresenter* presenter_;
   UIViewController* base_view_controller_;
   ScopedKeyWindow scoped_key_window_;
   web::TestWebState web_state_;
   id document_interaction_controller_class_;
   StubTabHelper tab_helper_;
+  // Application can be lazily created by tests, but it has to be OCMock.
+  // Destructor will call -stopMocking on this object to make sure that
+  // UIApplication is not mocked after these test finish running.
+  id application_;
   DownloadManagerCoordinator* coordinator_;
+  base::UserActionTester user_action_tester_;
 };
 
 // Tests starting the coordinator. Verifies that view controller is presented
@@ -274,8 +284,11 @@
   DownloadManagerViewController* viewController =
       base_view_controller_.childViewControllers.firstObject;
   ASSERT_EQ([DownloadManagerViewController class], [viewController class]);
-  [viewController.delegate
-      downloadManagerViewControllerDidClose:viewController];
+  @autoreleasepool {
+    // This call will retain coordinator, which should outlive thread bundle.
+    [viewController.delegate
+        downloadManagerViewControllerDidClose:viewController];
+  }
 
   // Verify that child view controller is removed, download task is set to null
   // and download task is cancelled.
@@ -305,9 +318,11 @@
   // button changes it's alpha.
   ASSERT_EQ(1.0f, viewController.installDriveButton.superview.alpha);
 
-  [viewController.delegate
-      installDriveForDownloadManagerViewController:viewController];
-
+  @autoreleasepool {
+    // This call will retain coordinator, which should outlive thread bundle.
+    [viewController.delegate
+        installDriveForDownloadManagerViewController:viewController];
+  }
   // Verify that Store Kit dialog was presented.
   EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^{
     return [base_view_controller_.presentedViewController class] ==
@@ -319,14 +334,27 @@
     return viewController.installDriveButton.superview.alpha == 0.0f;
   }));
 
+  // Simulate Google Drive app installation and verify that expected user action
+  // has been recorded.
+  ASSERT_EQ(0, user_action_tester_.GetActionCount(
+                   kDownloadManagerGoogleDriveInstalled));
+  // SKStoreProductViewController uses UIApplication, so it's not possible to
+  // install the mock before the test run.
+  application_ = OCMClassMock([UIApplication class]);
+  OCMStub([application_ sharedApplication]).andReturn(application_);
+  OCMStub([application_ canOpenURL:GetGoogleDriveAppUrl()]).andReturn(YES);
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(testing::kWaitForActionTimeout, ^{
+    base::RunLoop().RunUntilIdle();
+    return user_action_tester_.GetActionCount(
+               kDownloadManagerGoogleDriveInstalled) == 1;
+  }));
+
   // Stop to avoid holding a dangling pointer to destroyed task.
   [coordinator_ stop];
 }
 
 // Tests presenting Open In... menu.
 TEST_F(DownloadManagerCoordinatorTest, OpenIn) {
-  web::TestWebThreadBundle thread_bundle;
-
   web::FakeDownloadTask task(GURL(kTestUrl), kTestMimeType);
   task.SetSuggestedFilename(base::SysNSStringToUTF16(kTestSuggestedFileName));
   coordinator_.downloadTask = &task;
@@ -357,8 +385,11 @@
   UIView* view = [[UIView alloc] init];
   [view addLayoutGuide:guide];
   ASSERT_FALSE(document_interaction_controller.presentedOpenInMenu);
-  [viewController.delegate downloadManagerViewController:viewController
-                        presentOpenInMenuWithLayoutGuide:guide];
+  @autoreleasepool {
+    // This call will retain coordinator, which should outlive thread bundle.
+    [viewController.delegate downloadManagerViewController:viewController
+                          presentOpenInMenuWithLayoutGuide:guide];
+  }
   ASSERT_TRUE(document_interaction_controller.presentedOpenInMenu);
   ASSERT_TRUE(CGRectEqualToRect(
       CGRectZero, document_interaction_controller.presentedOpenInMenu.rect));
@@ -378,9 +409,11 @@
   DownloadManagerViewController* viewController =
       base_view_controller_.childViewControllers.firstObject;
   ASSERT_EQ([DownloadManagerViewController class], [viewController class]);
-  [viewController.delegate
-      downloadManagerViewControllerDidClose:viewController];
-
+  @autoreleasepool {
+    // This call will retain coordinator, which should outlive thread bundle.
+    [viewController.delegate
+        downloadManagerViewControllerDidClose:viewController];
+  }
   // Verify that UIAlert is presented.
   ASSERT_TRUE([base_view_controller_.presentedViewController
       isKindOfClass:[UIAlertController class]]);
@@ -428,8 +461,6 @@
 // Tests starting the download. Verifies that download task is started and its
 // file writer is configured to write into download directory.
 TEST_F(DownloadManagerCoordinatorTest, StartDownload) {
-  web::TestWebThreadBundle thread_bundle;
-
   web::FakeDownloadTask task(GURL(kTestUrl), kTestMimeType);
   task.SetSuggestedFilename(base::SysNSStringToUTF16(kTestSuggestedFileName));
   web::DownloadTask* task_ptr = &task;
@@ -439,8 +470,11 @@
   DownloadManagerViewController* viewController =
       base_view_controller_.childViewControllers.firstObject;
   ASSERT_EQ([DownloadManagerViewController class], [viewController class]);
-  [viewController.delegate
-      downloadManagerViewControllerDidStartDownload:viewController];
+  @autoreleasepool {
+    // This call will retain coordinator, which should outlive thread bundle.
+    [viewController.delegate
+        downloadManagerViewControllerDidStartDownload:viewController];
+  }
 
   // Starting download is async for model.
   ASSERT_TRUE(WaitUntilConditionOrTimeout(testing::kWaitForDownloadTimeout, ^{
diff --git a/ios/chrome/browser/ui/main/browser_view_wrangler_unittest.mm b/ios/chrome/browser/ui/main/browser_view_wrangler_unittest.mm
index 08332fe5..27e6d86a 100644
--- a/ios/chrome/browser/ui/main/browser_view_wrangler_unittest.mm
+++ b/ios/chrome/browser/ui/main/browser_view_wrangler_unittest.mm
@@ -30,30 +30,33 @@
 };
 
 TEST_F(BrowserViewWranglerTest, TestInitNilObserver) {
-  BrowserViewWrangler* wrangler = [[BrowserViewWrangler alloc]
-            initWithBrowserState:chrome_browser_state_.get()
+  // |thread_bundle_| must outlive all objects created by BVC, because those
+  // objects may rely on threading API in dealloc.
+  @autoreleasepool {
+    BrowserViewWrangler* wrangler = [[BrowserViewWrangler alloc]
+              initWithBrowserState:chrome_browser_state_.get()
 
-                tabModelObserver:nil
-      applicationCommandEndpoint:(id<ApplicationCommands>)nil];
+                  tabModelObserver:nil
+        applicationCommandEndpoint:(id<ApplicationCommands>)nil];
+    // Test that BVC and tab model are created on demand.
+    BrowserViewController* bvc = [wrangler mainBVC];
+    EXPECT_NE(bvc, nil);
 
-  // Test that BVC and tab model are created on demand.
-  BrowserViewController* bvc = [wrangler mainBVC];
-  EXPECT_NE(bvc, nil);
+    TabModel* tabModel = [wrangler mainTabModel];
+    EXPECT_NE(tabModel, nil);
 
-  TabModel* tabModel = [wrangler mainTabModel];
-  EXPECT_NE(tabModel, nil);
+    // Test that once created the BVC and tab model aren't re-created.
+    EXPECT_EQ(bvc, [wrangler mainBVC]);
+    EXPECT_EQ(tabModel, [wrangler mainTabModel]);
 
-  // Test that once created the BVC and tab model aren't re-created.
-  EXPECT_EQ(bvc, [wrangler mainBVC]);
-  EXPECT_EQ(tabModel, [wrangler mainTabModel]);
+    // Test that the OTR objects are (a) OTR and (b) not the same as the non-OTR
+    // objects.
+    EXPECT_NE(bvc, [wrangler otrBVC]);
+    EXPECT_NE(tabModel, [wrangler otrTabModel]);
+    EXPECT_TRUE([wrangler otrTabModel].browserState->IsOffTheRecord());
 
-  // Test that the OTR objects are (a) OTR and (b) not the same as the non-OTR
-  // objects.
-  EXPECT_NE(bvc, [wrangler otrBVC]);
-  EXPECT_NE(tabModel, [wrangler otrTabModel]);
-  EXPECT_TRUE([wrangler otrTabModel].browserState->IsOffTheRecord());
-
-  [wrangler shutdown];
+    [wrangler shutdown];
+  }
 }
 
 }  // namespace
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
index 5f332d9..fc8ebac 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
@@ -96,6 +96,8 @@
 // Handles displaying the context menu for all form factors.
 @property(nonatomic, strong) ContextMenuCoordinator* contextMenuCoordinator;
 @property(nonatomic, strong) SigninPromoViewMediator* signinPromoViewMediator;
+// The sectionIdentifier for the last tapped header, 0 if no header was tapped.
+@property(nonatomic, assign) NSInteger lastTappedHeaderSectionIdentifier;
 @end
 
 @implementation RecentTabsTableViewController : ChromeTableViewController
@@ -104,6 +106,8 @@
 @synthesize delegate = delegate_;
 @synthesize dispatcher = _dispatcher;
 @synthesize handsetCommandHandler = _handsetCommandHandler;
+@synthesize lastTappedHeaderSectionIdentifier =
+    _lastTappedHeaderSectionIdentifier;
 @synthesize loader = _loader;
 @synthesize sessionState = _sessionState;
 @synthesize signinPromoViewMediator = _signinPromoViewMediator;
@@ -116,6 +120,7 @@
   if (self) {
     _sessionState = SessionsSyncUserState::USER_SIGNED_OUT;
     _syncedSessions.reset(new synced_sessions::SyncedSessions());
+    _lastTappedHeaderSectionIdentifier = 0;
   }
   return self;
 }
@@ -134,12 +139,19 @@
   self.tableView.rowHeight = UITableViewAutomaticDimension;
   self.tableView.estimatedSectionHeaderHeight = kEstimatedRowHeight;
   self.tableView.sectionFooterHeight = 0.0;
+  // Gesture recognizer for long press context menu on Session Headers.
   UILongPressGestureRecognizer* longPress =
       [[UILongPressGestureRecognizer alloc]
           initWithTarget:self
                   action:@selector(handleLongPress:)];
   longPress.delegate = self;
   [self.tableView addGestureRecognizer:longPress];
+  // Gesture recognizer for header collapsing/expanding.
+  UITapGestureRecognizer* tapGesture =
+      [[UITapGestureRecognizer alloc] initWithTarget:self
+                                              action:@selector(handleTap:)];
+  tapGesture.delegate = self;
+  [self.tableView addGestureRecognizer:tapGesture];
 }
 
 #pragma mark - TableViewModel
@@ -166,6 +178,8 @@
 
   // Recently Closed Section.
   [model addSectionWithIdentifier:SectionIdentifierRecentlyClosedTabs];
+  [model setSectionIdentifier:SectionIdentifierRecentlyClosedTabs
+                 collapsedKey:kRecentlyClosedCollapsedKey];
   TableViewTextHeaderFooterItem* header = [[TableViewTextHeaderFooterItem alloc]
       initWithType:ItemTypeRecentlyClosedHeader];
   header.text = l10n_util::GetNSString(IDS_IOS_RECENT_TABS_RECENTLY_CLOSED);
@@ -271,6 +285,9 @@
         _syncedSessions->GetSession(i);
     NSInteger sessionIdentifier = [self sectionIdentifierForSession:session];
     [model addSectionWithIdentifier:sessionIdentifier];
+    NSString* sessionCollapsedKey = base::SysUTF8ToNSString(session->tag);
+    [model setSectionIdentifier:sessionIdentifier
+                   collapsedKey:sessionCollapsedKey];
     TableViewTextHeaderFooterItem* header =
         [[TableViewTextHeaderFooterItem alloc]
             initWithType:ItemTypeSessionHeader];
@@ -305,18 +322,24 @@
 // Needs to be called inside a [UITableView beginUpdates] block on iOS10, or
 // performBatchUpdates on iOS11+.
 - (void)removeSessionSections {
-  // Get the numberOfSessionSections from |self.tableViewModel|, since
-  // |_syncedSessions| has been updated by now.
-  int numberOfSessionSections =
-      [self.tableViewModel numberOfSections] - kNumberOfSectionsBeforeSessions;
-  for (int i = 0; i < numberOfSessionSections; i++) {
-    [self.tableView
-          deleteSections:[NSIndexSet
-                             indexSetWithIndex:i +
-                                               kNumberOfSectionsBeforeSessions]
-        withRowAnimation:UITableViewRowAnimationNone];
-    [self.tableViewModel
-        removeSectionWithIdentifier:i + kFirstSessionSectionIdentifier];
+  // |_syncedSessions| has been updated by now, that means that
+  // |self.tableViewModel| does not reflect |_syncedSessions| data. A
+  // SectionIdentifier could've been deleted previously, do not rely on these
+  // being in sequential order at this point.
+  NSInteger sectionIdentifierToRemove = kFirstSessionSectionIdentifier;
+  NSInteger sectionToDelete = kNumberOfSectionsBeforeSessions;
+  while ([self.tableViewModel numberOfSections] >
+         kNumberOfSectionsBeforeSessions) {
+    if ([self.tableViewModel
+            hasSectionForSectionIdentifier:sectionIdentifierToRemove]) {
+      [self.tableView
+            deleteSections:[NSIndexSet indexSetWithIndex:sectionToDelete]
+          withRowAnimation:UITableViewRowAnimationNone];
+      sectionToDelete++;
+      [self.tableViewModel
+          removeSectionWithIdentifier:sectionIdentifierToRemove];
+    }
+    sectionIdentifierToRemove++;
   }
 }
 
@@ -355,6 +378,8 @@
 - (void)addOtherDevicesSectionHeader {
   TableViewModel* model = self.tableViewModel;
   [model addSectionWithIdentifier:SectionIdentifierOtherDevices];
+  [model setSectionIdentifier:SectionIdentifierOtherDevices
+                 collapsedKey:kOtherDeviceCollapsedKey];
   TableViewTextHeaderFooterItem* header = [[TableViewTextHeaderFooterItem alloc]
       initWithType:ItemTypeRecentlyClosedHeader];
   header.text = l10n_util::GetNSString(IDS_IOS_RECENT_TABS_OTHER_DEVICES);
@@ -605,6 +630,10 @@
       [self indexOfSessionForTabAtIndexPath:indexPath]);
 }
 
+- (synced_sessions::DistantSession const*)sessionForSection:(NSInteger)section {
+  return _syncedSessions->GetSession(section - kNumberOfSectionsBeforeSessions);
+}
+
 - (synced_sessions::DistantTab const*)distantTabAtIndexPath:
     (NSIndexPath*)indexPath {
   DCHECK_EQ([self.tableViewModel itemTypeForIndexPath:indexPath],
@@ -705,34 +734,48 @@
   [self.handsetCommandHandler dismissRecentTabsWithCompletion:openHistory];
 }
 
-#pragma mark - Collapse sections
+#pragma mark - Collapse/Expand sections
 
-- (void)toggleExpansionOfSection:(NSInteger)sectionIndex {
-  // TO IMPLEMENT!
+- (void)handleTap:(UITapGestureRecognizer*)tapGesture {
+  DCHECK_EQ(self.tableView, tapGesture.view);
+  if (tapGesture.state == UIGestureRecognizerStateEnded) {
+    [self toggleExpansionOfSectionIdentifier:
+              self.lastTappedHeaderSectionIdentifier];
+  }
 }
 
-- (void)setSection:(NSString*)sectionKey collapsed:(BOOL)collapsed {
-  // TODO(crbug.com/419346): Store in the browser state preference instead of
-  // NSUserDefaults.
-  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
-  NSDictionary* collapsedSections =
-      [defaults dictionaryForKey:kCollapsedSectionsKey];
-  NSMutableDictionary* newCollapsedSessions =
-      [NSMutableDictionary dictionaryWithDictionary:collapsedSections];
-  NSNumber* value = [NSNumber numberWithBool:collapsed];
-  [newCollapsedSessions setValue:value forKey:sectionKey];
-  [defaults setObject:newCollapsedSessions forKey:kCollapsedSectionsKey];
-}
+- (void)toggleExpansionOfSectionIdentifier:(NSInteger)sectionIdentifier {
+  NSMutableArray* cellIndexPathsToDeleteOrInsert = [NSMutableArray array];
+  NSInteger sectionIndex =
+      [self.tableViewModel sectionForSectionIdentifier:sectionIdentifier];
+  NSArray* items =
+      [self.tableViewModel itemsInSectionWithIdentifier:sectionIdentifier];
+  for (NSUInteger i = 0; i < [items count]; i++) {
+    NSIndexPath* tabIndexPath =
+        [NSIndexPath indexPathForRow:i inSection:sectionIndex];
+    [cellIndexPathsToDeleteOrInsert addObject:tabIndexPath];
+  }
 
-- (BOOL)sectionIsCollapsed:(NSString*)sectionKey {
-  // TODO(crbug.com/419346): Store in the profile's preference instead of the
-  // NSUserDefaults.
-  DCHECK(sectionKey);
-  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
-  NSDictionary* collapsedSessions =
-      [defaults dictionaryForKey:kCollapsedSectionsKey];
-  NSNumber* value = (NSNumber*)[collapsedSessions valueForKey:sectionKey];
-  return [value boolValue];
+  void (^tableUpdates)(void) = ^{
+    if ([self.tableViewModel sectionIsCollapsed:sectionIdentifier]) {
+      [self.tableViewModel setSection:sectionIdentifier collapsed:NO];
+      [self.tableView insertRowsAtIndexPaths:cellIndexPathsToDeleteOrInsert
+                            withRowAnimation:UITableViewRowAnimationFade];
+    } else {
+      [self.tableViewModel setSection:sectionIdentifier collapsed:YES];
+      [self.tableView deleteRowsAtIndexPaths:cellIndexPathsToDeleteOrInsert
+                            withRowAnimation:UITableViewRowAnimationFade];
+    }
+  };
+
+  // If iOS11+ use performBatchUpdates: instead of beginUpdates/endUpdates.
+  if (@available(iOS 11, *)) {
+    [self.tableView performBatchUpdates:tableUpdates completion:nil];
+  } else {
+    [self.tableView beginUpdates];
+    tableUpdates();
+    [self.tableView endUpdates];
+  }
 }
 
 #pragma mark - Long press and context menus
@@ -740,16 +783,9 @@
 - (void)handleLongPress:(UILongPressGestureRecognizer*)longPressGesture {
   DCHECK_EQ(self.tableView, longPressGesture.view);
   if (longPressGesture.state == UIGestureRecognizerStateBegan) {
-    CGPoint point = [longPressGesture locationInView:self.tableView];
-    NSIndexPath* indexPath = [self.tableView indexPathForRowAtPoint:point];
-    if (!indexPath)
-      return;
-    DCHECK_LE(indexPath.section,
-              [self numberOfSectionsInTableView:self.tableView]);
-
-    NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:indexPath];
-    if ([self isSessionSectionIdentifier:itemType]) {
-      NOTREACHED();
+    NSInteger sectionIdentifier = self.lastTappedHeaderSectionIdentifier;
+    if (![self isSessionSectionIdentifier:sectionIdentifier]) {
+      // Only handle LongPress for SessionHeaders.
       return;
     }
 
@@ -777,7 +813,8 @@
     [self.contextMenuCoordinator
         addItemWithTitle:openAllButtonLabel
                   action:^{
-                    [weakSelf openTabsFromSessionAtIndexPath:indexPath];
+                    [weakSelf
+                        openTabsFromSessionSectionIdentifier:sectionIdentifier];
                   }];
 
     // "Hide for now" button.
@@ -786,18 +823,19 @@
     [self.contextMenuCoordinator
         addItemWithTitle:hideButtonLabel
                   action:^{
-                    [weakSelf removeSessionAtIndexPath:indexPath];
+                    [weakSelf removeSessionAtSessionSectionIdentifier:
+                                  sectionIdentifier];
                   }];
 
     [self.contextMenuCoordinator start];
   }
 }
 
-- (void)openTabsFromSessionAtIndexPath:(NSIndexPath*)indexPath {
-  // TO-ADAPT.
-  return;
+- (void)openTabsFromSessionSectionIdentifier:(NSInteger)sectionIdentifier {
+  NSInteger section =
+      [self.tableViewModel sectionForSectionIdentifier:sectionIdentifier];
   synced_sessions::DistantSession const* session =
-      [self sessionForTabAtIndexPath:indexPath];
+      [self sessionForSection:section];
   [self dismissRecentTabsModal];
   for (auto const& tab : session->tabs) {
     [self.loader webPageOrderedOpen:tab->virtual_url
@@ -807,29 +845,45 @@
   }
 }
 
-- (void)removeSessionAtIndexPath:(NSIndexPath*)indexPath {
-  // TO-ADAPT.
-  return;
-  DCHECK([self
-      isSessionSectionIdentifier:
-          [self.tableViewModel sectionIdentifierForSection:indexPath.section]]);
+- (void)removeSessionAtSessionSectionIdentifier:(NSInteger)sectionIdentifier {
+  DCHECK([self isSessionSectionIdentifier:sectionIdentifier]);
+  NSInteger section =
+      [self.tableViewModel sectionForSectionIdentifier:sectionIdentifier];
   synced_sessions::DistantSession const* session =
-      [self sessionForTabAtIndexPath:indexPath];
+      [self sessionForSection:section];
   std::string sessionTagCopy = session->tag;
   syncer::SyncService* syncService =
       IOSChromeProfileSyncServiceFactory::GetForBrowserState(self.browserState);
   sync_sessions::OpenTabsUIDelegate* openTabs =
       syncService->GetOpenTabsUIDelegate();
-  _syncedSessions->EraseSession(
-      [self indexOfSessionForTabAtIndexPath:indexPath]);
-  [self.tableView
-        deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section]
-      withRowAnimation:UITableViewRowAnimationLeft];
-  // Use dispatch_async to give the action sheet a chance to cleanup before
-  // replacing its parent view.
-  dispatch_async(dispatch_get_main_queue(), ^{
+
+  [self.tableViewModel removeSectionWithIdentifier:sectionIdentifier];
+  _syncedSessions->EraseSession(sectionIdentifier -
+                                kFirstSessionSectionIdentifier);
+
+  void (^tableUpdates)(void) = ^{
+    [self.tableView
+          deleteSections:[NSIndexSet
+                             indexSetWithIndex:sectionIdentifier -
+                                               kSectionIdentifierEnumZero]
+        withRowAnimation:UITableViewRowAnimationLeft];
+  };
+
+  // If iOS11+ use performBatchUpdates: instead of beginUpdates/endUpdates.
+  if (@available(iOS 11, *)) {
+    [self.tableView performBatchUpdates:tableUpdates
+                             completion:^(BOOL) {
+                               openTabs->DeleteForeignSession(sessionTagCopy);
+                             }];
+  } else {
+    [self.tableView beginUpdates];
+    tableUpdates();
+    // DeleteForeignSession will cause |self refreshUserState:| to be called,
+    // thus refreshing the TableView, running this inside the updates block will
+    // make sure that the tableView animations are performed in order.
     openTabs->DeleteForeignSession(sessionTagCopy);
-  });
+    [self.tableView endUpdates];
+  }
 }
 
 #pragma mark - UIGestureRecognizerDelegate
@@ -842,8 +896,8 @@
     NSInteger itemType =
         [self.tableViewModel sectionIdentifierForSection:section];
     if (CGRectContainsPoint([self.tableView rectForHeaderInSection:section],
-                            point) &&
-        [self isSessionSectionIdentifier:itemType]) {
+                            point)) {
+      self.lastTappedHeaderSectionIdentifier = itemType;
       return YES;
     }
   }
@@ -856,7 +910,7 @@
             (SigninPromoViewConfigurator*)configurator
                              identityChanged:(BOOL)identityChanged {
   DCHECK(self.signinPromoViewMediator);
-  if ([self sectionIsCollapsed:kOtherDeviceCollapsedKey])
+  if ([self.tableViewModel sectionIsCollapsed:SectionIdentifierOtherDevices])
     return;
   NSIndexPath* indexPath =
       [self.tableViewModel indexPathForItemType:ItemTypeOtherDevicesSigninPromo
diff --git a/ios/chrome/browser/ui/settings/sync_utils/sync_fake_server_egtest.mm b/ios/chrome/browser/ui/settings/sync_utils/sync_fake_server_egtest.mm
index a11d161..b554ec4f 100644
--- a/ios/chrome/browser/ui/settings/sync_utils/sync_fake_server_egtest.mm
+++ b/ios/chrome/browser/ui/settings/sync_utils/sync_fake_server_egtest.mm
@@ -131,9 +131,8 @@
 
 // Tests that a bookmark added on the client (before Sync is enabled) is
 // uploaded to the Sync server once Sync is turned on.
-// TODO(crbug.com/814990): Reenable the simulator test.
-// TODO(crbug.com/821490): Reenable the device test.
-- (void)FLAKY_testSyncUploadBookmarkOnFirstSync {
+// TODO(crbug.com/821490): Reenable the test.
+- (void)DISABLED_testSyncUploadBookmarkOnFirstSync {
   [self addBookmark:GURL("https://www.foo.com") withTitle:@"foo"];
 
   // Sign in to sync, after a bookmark has been added.
@@ -148,9 +147,8 @@
 }
 
 // Tests that a bookmark added on the client is uploaded to the Sync server.
-// TODO(crbug.com/814990): Reenable the simulator test.
-// TODO(crbug.com/821490): Reenable the device test.
-- (void)FLAKY_testSyncUploadBookmark {
+// TODO(crbug.com/821490): Reenable the test.
+- (void)DISABLED_testSyncUploadBookmark {
   ChromeIdentity* identity = [SigninEarlGreyUtils fakeIdentity1];
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()->AddIdentity(
       identity);
@@ -164,9 +162,8 @@
 
 // Tests that a bookmark injected in the FakeServer is synced down to the
 // client.
-// TODO(crbug.com/814990): Reenable the simulator test.
-// TODO(crbug.com/821490): Reenable the device test.
-- (void)FLAKY_testSyncDownloadBookmark {
+// TODO(crbug.com/821490): Reenable the test.
+- (void)DISABLED_testSyncDownloadBookmark {
   [[self class] assertBookmarksWithTitle:@"hoo" expectedCount:0];
   chrome_test_util::InjectBookmarkOnFakeSyncServer("http://www.hoo.com", "hoo");
 
@@ -268,14 +265,8 @@
 }
 
 // Tests that autofill profile injected in FakeServer gets synced to client.
-// TODO(crbug.com/821490): Reenable the device test.
-#if TARGET_IPHONE_SIMULATOR
-#define MAYBE_testSyncDownloadAutofillProfile testSyncDownloadAutofillProfile
-#else
-#define MAYBE_testSyncDownloadAutofillProfile \
-  FLAKY_testSyncDownloadAutofillProfile
-#endif
-- (void)MAYBE_testSyncDownloadAutofillProfile {
+// TODO(crbug.com/821490): Reenable the test.
+- (void)DISABLED_testSyncDownloadAutofillProfile {
   const std::string kGuid = "2340E83B-5BEE-4560-8F95-5914EF7F539E";
   const std::string kFullName = "Peter Pan";
   GREYAssertFalse(chrome_test_util::IsAutofillProfilePresent(kGuid, kFullName),
@@ -300,9 +291,8 @@
 
 // Test that update to autofill profile injected in FakeServer gets synced to
 // client.
-// TODO(crbug.com/814990): Reenable the simulator test.
-// TODO(crbug.com/821490): Reenable the device test.
-- (void)FLAKY_testSyncUpdateAutofillProfile {
+// TODO(crbug.com/821490): Reenable the test.
+- (void)DISABLED_testSyncUpdateAutofillProfile {
   const std::string kGuid = "2340E83B-5BEE-4560-8F95-5914EF7F539E";
   const std::string kFullName = "Peter Pan";
   const std::string kUpdatedFullName = "Roger Rabbit";
@@ -346,9 +336,8 @@
 
 // Test that autofill profile deleted from FakeServer gets deleted from client
 // as well.
-// TODO(crbug.com/814990): Reenable the simulator test.
-// TODO(crbug.com/821490): Reenable the device test.
-- (void)FLAKY_testSyncDeleteAutofillProfile {
+// TODO(crbug.com/821490): Reenable the test.
+- (void)DISABLED_testSyncDeleteAutofillProfile {
   const std::string kGuid = "2340E83B-5BEE-4560-8F95-5914EF7F539E";
   const std::string kFullName = "Peter Pan";
   GREYAssertFalse(chrome_test_util::IsAutofillProfilePresent(kGuid, kFullName),
@@ -382,9 +371,8 @@
 
 // Tests that tabs opened on this client are committed to the Sync server and
 // that the created sessions entities are correct.
-// TODO(crbug.com/814990): Reenable the simulator test.
-// TODO(crbug.com/821490): Reenable the device test.
-- (void)FLAKY_testSyncUploadOpenTabs {
+// TODO(crbug.com/821490): Reenable the test.
+- (void)DISABLED_testSyncUploadOpenTabs {
   // Create map of canned responses and set up the test HTML server.
   const GURL URL1 = web::test::HttpServer::MakeUrl("http://page1");
   const GURL URL2 = web::test::HttpServer::MakeUrl("http://page2");
@@ -418,9 +406,8 @@
 
 // Tests that a typed URL (after Sync is enabled) is uploaded to the Sync
 // server.
-// TODO(crbug.com/814990): Reenable the simulator test.
-// TODO(crbug.com/821490): Reenable the device test.
-- (void)FLAKY_testSyncTypedURLUpload {
+// TODO(crbug.com/821490): Reenable the test.
+- (void)DISABLED_testSyncTypedURLUpload {
   const GURL mockURL("http://not-a-real-site/");
 
   GREYAssertTrue(chrome_test_util::ClearBrowsingHistory(),
@@ -459,9 +446,8 @@
 }
 
 // Tests that typed url is downloaded from sync server.
-// TODO(crbug.com/814990): Reenable the simulator test.
-// TODO(crbug.com/821490): Reenable the device test.
-- (void)FLAKY_testSyncTypedUrlDownload {
+// TODO(crbug.com/821490): Reenable the test.
+- (void)DISABLED_testSyncTypedUrlDownload {
   const GURL mockURL("http://not-a-real-site/");
 
   GREYAssertTrue(chrome_test_util::ClearBrowsingHistory(),
@@ -498,9 +484,8 @@
 
 // Tests that when typed url is deleted on the client, sync the change gets
 // propagated to server.
-// TODO(crbug.com/814990): Reenable the simulator test.
-// TODO(crbug.com/821490): Reenable the device test.
-- (void)FLAKY_testSyncTypedURLDeleteFromClient {
+// TODO(crbug.com/821490): Reenable the test.
+- (void)DISABLED_testSyncTypedURLDeleteFromClient {
   const GURL mockURL("http://not-a-real-site/");
 
   GREYAssertTrue(chrome_test_util::ClearBrowsingHistory(),
@@ -548,9 +533,8 @@
 
 // Test that typed url is deleted from client after server sends tombstone for
 // that typed url.
-// TODO(crbug.com/814990): Reenable the simulator test.
-// TODO(crbug.com/821490): Reenable the device test.
-- (void)FLAKY_testSyncTypedURLDeleteFromServer {
+// TODO(crbug.com/821490): Reenable the test.
+- (void)DISABLED_testSyncTypedURLDeleteFromServer {
   const GURL mockURL("http://not-a-real-site/");
 
   GREYAssertTrue(chrome_test_util::ClearBrowsingHistory(),
diff --git a/ios/chrome/browser/ui/tab_grid/grid_cell.mm b/ios/chrome/browser/ui/tab_grid/grid_cell.mm
index 49cc058..1bdd3b5 100644
--- a/ios/chrome/browser/ui/tab_grid/grid_cell.mm
+++ b/ios/chrome/browser/ui/tab_grid/grid_cell.mm
@@ -27,7 +27,6 @@
 @interface GridCell ()
 // Visual components of the cell.
 @property(nonatomic, weak) UIView* topBar;
-@property(nonatomic, weak) UIView* line;
 @property(nonatomic, weak) UIImageView* iconView;
 @property(nonatomic, weak) TopAlignedImageView* snapshotView;
 @property(nonatomic, weak) UILabel* titleLabel;
@@ -45,7 +44,6 @@
 @synthesize title = _title;
 // Private properties.
 @synthesize topBar = _topBar;
-@synthesize line = _line;
 @synthesize iconView = _iconView;
 @synthesize snapshotView = _snapshotView;
 @synthesize titleLabel = _titleLabel;
@@ -62,15 +60,11 @@
     contentView.layer.cornerRadius = 11.0f;
     contentView.layer.masksToBounds = YES;
     UIView* topBar = [self setupTopBar];
-    UIView* line = [[UIView alloc] init];
-    line.translatesAutoresizingMaskIntoConstraints = NO;
     TopAlignedImageView* snapshotView = [[TopAlignedImageView alloc] init];
     snapshotView.translatesAutoresizingMaskIntoConstraints = NO;
     [contentView addSubview:topBar];
-    [contentView addSubview:line];
     [contentView addSubview:snapshotView];
     _topBar = topBar;
-    _line = line;
     _snapshotView = snapshotView;
     NSArray* constraints = @[
       [topBar.topAnchor constraintEqualToAnchor:contentView.topAnchor],
@@ -78,11 +72,7 @@
       [topBar.trailingAnchor
           constraintEqualToAnchor:contentView.trailingAnchor],
       [topBar.heightAnchor constraintEqualToConstant:kTopBarHeight],
-      [line.topAnchor constraintEqualToAnchor:topBar.bottomAnchor],
-      [line.leadingAnchor constraintEqualToAnchor:contentView.leadingAnchor],
-      [line.trailingAnchor constraintEqualToAnchor:contentView.trailingAnchor],
-      [line.heightAnchor constraintEqualToConstant:0.5f],
-      [snapshotView.topAnchor constraintEqualToAnchor:line.bottomAnchor],
+      [snapshotView.topAnchor constraintEqualToAnchor:topBar.bottomAnchor],
       [snapshotView.leadingAnchor
           constraintEqualToAnchor:contentView.leadingAnchor],
       [snapshotView.trailingAnchor
@@ -125,33 +115,27 @@
 - (void)setTheme:(GridTheme)theme {
   if (_theme == theme)
     return;
+  self.iconView.backgroundColor = UIColorFromRGB(kGridCellIconBackgroundColor);
+  self.snapshotView.backgroundColor =
+      UIColorFromRGB(kGridCellSnapshotBackgroundColor);
   switch (theme) {
     case GridThemeLight:
-      self.topBar.backgroundColor = [UIColor whiteColor];
-      self.iconView.backgroundColor = [UIColor colorWithWhite:0.9f alpha:1.0f];
-      self.titleLabel.textColor = [UIColor blackColor];
-      self.line.backgroundColor = [UIColor colorWithWhite:0.6f alpha:1.0f];
-      self.snapshotView.backgroundColor = [UIColor whiteColor];
+      self.topBar.backgroundColor =
+          UIColorFromRGB(kGridLightThemeCellHeaderColor);
+      self.titleLabel.textColor = UIColorFromRGB(kGridLightThemeCellTitleColor);
       self.closeButton.tintColor =
           UIColorFromRGB(kGridLightThemeCellCloseButtonTintColor);
-      self.tintColor =
-          [UIColor colorWithRed:0.0 green:122.0 / 255.0 blue:1.0 alpha:1.0];
-      self.border.layer.borderColor = self.tintColor.CGColor;
+      self.border.layer.borderColor =
+          UIColorFromRGB(kGridLightThemeCellSelectionColor).CGColor;
       break;
     case GridThemeDark:
-      self.topBar.backgroundColor = [UIColor colorWithWhite:0.2f alpha:1.0f];
-      self.iconView.backgroundColor = [UIColor colorWithWhite:0.9f alpha:1.0f];
-      self.titleLabel.textColor = [UIColor whiteColor];
-      self.line.backgroundColor = [UIColor colorWithWhite:0.2f alpha:1.0f];
-      self.snapshotView.backgroundColor =
-          [UIColor colorWithWhite:0.4f alpha:1.0f];
+      self.topBar.backgroundColor =
+          UIColorFromRGB(kGridDarkThemeCellHeaderColor);
+      self.titleLabel.textColor = UIColorFromRGB(kGridDarkThemeCellTitleColor);
       self.closeButton.tintColor =
           UIColorFromRGB(kGridDarkThemeCellCloseButtonTintColor);
-      self.tintColor = [UIColor colorWithWhite:0.9f alpha:1.0f];
-      self.border.layer.borderColor = self.tintColor.CGColor;
-      break;
-    default:
-      NOTREACHED() << "Invalid GridTheme.";
+      self.border.layer.borderColor =
+          UIColorFromRGB(kGridDarkThemeCellSelectionColor).CGColor;
       break;
   }
   _theme = theme;
diff --git a/ios/chrome/browser/ui/tab_grid/grid_constants.h b/ios/chrome/browser/ui/tab_grid/grid_constants.h
index 4cb27a8..049e310 100644
--- a/ios/chrome/browser/ui/tab_grid/grid_constants.h
+++ b/ios/chrome/browser/ui/tab_grid/grid_constants.h
@@ -21,7 +21,18 @@
 // uikit_ui_util.h
 
 // GridCell styling.
+// Common colors.
+extern const CGFloat kGridCellIconBackgroundColor;
+extern const CGFloat kGridCellSnapshotBackgroundColor;
+// Light theme colors.
+extern const CGFloat kGridLightThemeCellTitleColor;
+extern const CGFloat kGridLightThemeCellHeaderColor;
+extern const CGFloat kGridLightThemeCellSelectionColor;
 extern const CGFloat kGridLightThemeCellCloseButtonTintColor;
+// Dark theme colors.
+extern const CGFloat kGridDarkThemeCellTitleColor;
+extern const CGFloat kGridDarkThemeCellHeaderColor;
+extern const CGFloat kGridDarkThemeCellSelectionColor;
 extern const CGFloat kGridDarkThemeCellCloseButtonTintColor;
 
 #endif  // IOS_CHROME_BROWSER_UI_TAB_GRID_GRID_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/tab_grid/grid_constants.mm b/ios/chrome/browser/ui/tab_grid/grid_constants.mm
index 967a708f..c59e74c3 100644
--- a/ios/chrome/browser/ui/tab_grid/grid_constants.mm
+++ b/ios/chrome/browser/ui/tab_grid/grid_constants.mm
@@ -16,5 +16,16 @@
     @"GridCellCloseButtonIdentifier";
 
 // GridCell styling.
+// Common colors.
+const CGFloat kGridCellIconBackgroundColor = 0xF1F3F4;
+const CGFloat kGridCellSnapshotBackgroundColor = 0xE8EAED;
+// Light theme colors.
+const CGFloat kGridLightThemeCellTitleColor = 0x000000;
+const CGFloat kGridLightThemeCellHeaderColor = 0xF8F9FA;
+const CGFloat kGridLightThemeCellSelectionColor = 0x1A73E8;
 const CGFloat kGridLightThemeCellCloseButtonTintColor = 0x3C4043;
+// Dark theme colors.
+const CGFloat kGridDarkThemeCellTitleColor = 0xFFFFFF;
+const CGFloat kGridDarkThemeCellHeaderColor = 0x5F6368;
+const CGFloat kGridDarkThemeCellSelectionColor = 0x9AA0A6;
 const CGFloat kGridDarkThemeCellCloseButtonTintColor = 0xFFFFFF;
diff --git a/ios/chrome/browser/ui/tab_grid/grid_theme.h b/ios/chrome/browser/ui/tab_grid/grid_theme.h
index 1c0295d6..df91777 100644
--- a/ios/chrome/browser/ui/tab_grid/grid_theme.h
+++ b/ios/chrome/browser/ui/tab_grid/grid_theme.h
@@ -7,8 +7,7 @@
 
 // Theme describing the look of the grid.
 typedef NS_ENUM(NSUInteger, GridTheme) {
-  GridThemeInvalid = 0,
-  GridThemeLight,
+  GridThemeLight = 1,
   GridThemeDark,
 };
 
diff --git a/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button.imageset/new_tab_toolbar_button.png b/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button.imageset/new_tab_toolbar_button.png
index faa0657c..98c8858 100644
--- a/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button.imageset/new_tab_toolbar_button.png
+++ b/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button.imageset/new_tab_toolbar_button.png
Binary files differ
diff --git a/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button.imageset/new_tab_toolbar_button@2x.png b/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button.imageset/new_tab_toolbar_button@2x.png
index f23c6cb..fb0dc2a 100644
--- a/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button.imageset/new_tab_toolbar_button@2x.png
+++ b/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button.imageset/new_tab_toolbar_button@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button.imageset/new_tab_toolbar_button@3x.png b/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button.imageset/new_tab_toolbar_button@3x.png
index 83278aad..357df3b7 100644
--- a/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button.imageset/new_tab_toolbar_button@3x.png
+++ b/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button.imageset/new_tab_toolbar_button@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button_incognito.imageset/new_tab_toolbar_button_incognito.png b/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button_incognito.imageset/new_tab_toolbar_button_incognito.png
index 5c919d6..13f3e8f 100644
--- a/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button_incognito.imageset/new_tab_toolbar_button_incognito.png
+++ b/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button_incognito.imageset/new_tab_toolbar_button_incognito.png
Binary files differ
diff --git a/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button_incognito.imageset/new_tab_toolbar_button_incognito@2x.png b/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button_incognito.imageset/new_tab_toolbar_button_incognito@2x.png
index a880f19..f6d2c2f 100644
--- a/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button_incognito.imageset/new_tab_toolbar_button_incognito@2x.png
+++ b/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button_incognito.imageset/new_tab_toolbar_button_incognito@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button_incognito.imageset/new_tab_toolbar_button_incognito@3x.png b/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button_incognito.imageset/new_tab_toolbar_button_incognito@3x.png
index 048063b..64a811cb 100644
--- a/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button_incognito.imageset/new_tab_toolbar_button_incognito@3x.png
+++ b/ios/chrome/browser/ui/tab_grid/resources/new_tab_toolbar_button_incognito.imageset/new_tab_toolbar_button_incognito@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/table_view/BUILD.gn b/ios/chrome/browser/ui/table_view/BUILD.gn
index 0c00a6d..a145f6eb 100644
--- a/ios/chrome/browser/ui/table_view/BUILD.gn
+++ b/ios/chrome/browser/ui/table_view/BUILD.gn
@@ -14,6 +14,7 @@
   ]
   deps = [
     ":styler",
+    "//base",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/ui/list_model",
     "//ui/base",
@@ -36,6 +37,7 @@
   testonly = true
   sources = [
     "chrome_table_view_controller_unittest.mm",
+    "table_view_model_unittest.mm",
   ]
   deps = [
     ":table_view",
diff --git a/ios/chrome/browser/ui/table_view/table_view_model.h b/ios/chrome/browser/ui/table_view/table_view_model.h
index e978112..0f8a0b1 100644
--- a/ios/chrome/browser/ui/table_view/table_view_model.h
+++ b/ios/chrome/browser/ui/table_view/table_view_model.h
@@ -11,9 +11,27 @@
 #import "ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_item.h"
 
+// Key for saving collapsed state in the UserDefaults.
+extern NSString* const kTableViewModelCollapsedKey;
+
 // TableViewModel acts as a model class for table view controllers.
-@interface TableViewModel<__covariant ObjectType : TableViewItem*>
-    : ListModel<ObjectType, TableViewHeaderFooterItem*>
+@interface TableViewModel<__covariant ObjectType : TableViewItem*> :
+    ListModel<ObjectType, TableViewHeaderFooterItem*>
+
+// Sets an existing |sectionIdentifier| |collapsedKey| to be used when
+// collapsing or expanding a section. |collapsedKey| is a unique identifier for
+// each section that will be used for persisting information about the collapsed
+// state of a section. A |collapsedKey| its only needed when
+// collapsing/expanding sections. You can't collapse/expand any sections without
+// a |collapsedKey|.
+- (void)setSectionIdentifier:(NSInteger)sectionIdentifier
+                collapsedKey:(NSString*)collapsedKey;
+// Sets the state of an existing |sectionIdentifier| to |collapsed|. A
+// collapsedKey has to be previously set or this method will DCHECK().
+- (void)setSection:(NSInteger)sectionIdentifier collapsed:(BOOL)collapsed;
+// Returns YES if |sectionIdentifier| is collapsed. If not collapsedKey has been
+// set it will also return NO.
+- (BOOL)sectionIsCollapsed:(NSInteger)sectionIdentifier;
 
 @end
 
diff --git a/ios/chrome/browser/ui/table_view/table_view_model.mm b/ios/chrome/browser/ui/table_view/table_view_model.mm
index 45549a99..a68d2d5 100644
--- a/ios/chrome/browser/ui/table_view/table_view_model.mm
+++ b/ios/chrome/browser/ui/table_view/table_view_model.mm
@@ -4,9 +4,84 @@
 
 #import "ios/chrome/browser/ui/table_view/table_view_model.h"
 
+#include "base/logging.h"
+
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
+NSString* const kTableViewModelCollapsedKey =
+    @"ChromeTableViewModelCollapsedSections";
+
+@interface TableViewModel ()
+@property(strong, nonatomic) NSMutableDictionary* collapsedKeys;
+@end
+
 @implementation TableViewModel
+@synthesize collapsedKeys = _collapsedKeys;
+
+#pragma mark - UITableViewDataSource
+
+// Override numberOfItemsInSection to return 0 if the section is collapsed.
+- (NSInteger)numberOfItemsInSection:(NSInteger)section {
+  DCHECK_LT(section, [self numberOfSections]);
+  NSInteger sectionIdentifier = [self sectionIdentifierForSection:section];
+  // Check if the sectionType is collapsed. If sectionType is collapsed
+  // return 0.
+  if ([self sectionIsCollapsed:sectionIdentifier]) {
+    return 0;
+  } else {
+    return [super numberOfItemsInSection:section];
+  }
+}
+
+#pragma mark - Collapsing methods.
+
+- (void)setSectionIdentifier:(NSInteger)sectionIdentifier
+                collapsedKey:(NSString*)collapsedKey {
+  // Check that the sectionIdentifier exists.
+  DCHECK([self hasSectionForSectionIdentifier:sectionIdentifier]);
+  // Check that the collapsedKey is not being used already.
+  DCHECK(![self.collapsedKeys objectForKey:collapsedKey]);
+  [self.collapsedKeys setObject:collapsedKey forKey:@(sectionIdentifier)];
+}
+
+- (void)setSection:(NSInteger)sectionIdentifier collapsed:(BOOL)collapsed {
+  // TODO(crbug.com/419346): Store in the browser state preference instead of
+  // NSUserDefaults.
+  DCHECK([self hasSectionForSectionIdentifier:sectionIdentifier]);
+  NSString* sectionKey = [self.collapsedKeys objectForKey:@(sectionIdentifier)];
+  DCHECK(sectionKey);
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  NSDictionary* collapsedSections =
+      [defaults dictionaryForKey:kTableViewModelCollapsedKey];
+  NSMutableDictionary* newCollapsedSection =
+      [NSMutableDictionary dictionaryWithDictionary:collapsedSections];
+  NSNumber* value = [NSNumber numberWithBool:collapsed];
+  [newCollapsedSection setValue:value forKey:sectionKey];
+  [defaults setObject:newCollapsedSection forKey:kTableViewModelCollapsedKey];
+}
+
+- (BOOL)sectionIsCollapsed:(NSInteger)sectionIdentifier {
+  // TODO(crbug.com/419346): Store in the profile's preference instead of the
+  // NSUserDefaults.
+  DCHECK([self hasSectionForSectionIdentifier:sectionIdentifier]);
+  NSString* sectionKey = [self.collapsedKeys objectForKey:@(sectionIdentifier)];
+  if (!sectionKey)
+    return NO;
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  NSDictionary* collapsedSections =
+      [defaults dictionaryForKey:kTableViewModelCollapsedKey];
+  NSNumber* value = (NSNumber*)[collapsedSections valueForKey:sectionKey];
+  return [value boolValue];
+}
+
+// |self.collapsedKeys| lazy instantiation.
+- (NSMutableDictionary*)collapsedKeys {
+  if (!_collapsedKeys) {
+    _collapsedKeys = [[NSMutableDictionary alloc] init];
+  }
+  return _collapsedKeys;
+}
+
 @end
diff --git a/ios/chrome/browser/ui/table_view/table_view_model_unittest.mm b/ios/chrome/browser/ui/table_view/table_view_model_unittest.mm
new file mode 100644
index 0000000..c47109f
--- /dev/null
+++ b/ios/chrome/browser/ui/table_view/table_view_model_unittest.mm
@@ -0,0 +1,171 @@
+// Copyright 2018 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 "ios/chrome/browser/ui/table_view/table_view_model.h"
+
+#import "ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.h"
+#import "ios/chrome/browser/ui/table_view/cells/table_view_item.h"
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+typedef NS_ENUM(NSInteger, SectionIdentifier) {
+  SectionIdentifierFoo = kSectionIdentifierEnumZero,
+  SectionIdentifierBar,
+};
+
+typedef NS_ENUM(NSInteger, ItemType) {
+  ItemTypeFooBar = kItemTypeEnumZero,
+};
+
+class TableViewModelTest : public PlatformTest {
+ protected:
+  TableViewModelTest() {
+    // Need to clean up NSUserDefaults before and after each test.
+    NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+    [defaults setObject:nil forKey:kTableViewModelCollapsedKey];
+
+    model = [[TableViewModel alloc] init];
+
+    [model addSectionWithIdentifier:SectionIdentifierFoo];
+    [model setSectionIdentifier:SectionIdentifierFoo collapsedKey:@"FooKey"];
+    TableViewHeaderFooterItem* header =
+        [[TableViewHeaderFooterItem alloc] initWithType:ItemTypeFooBar];
+    TableViewItem* item = [[TableViewItem alloc] initWithType:ItemTypeFooBar];
+    [model setHeader:header forSectionWithIdentifier:SectionIdentifierFoo];
+    [model addItem:item toSectionWithIdentifier:SectionIdentifierFoo];
+
+    [model addSectionWithIdentifier:SectionIdentifierBar];
+    [model setSectionIdentifier:SectionIdentifierBar collapsedKey:@"BarKey"];
+    header = [[TableViewHeaderFooterItem alloc] initWithType:ItemTypeFooBar];
+    item = [[TableViewItem alloc] initWithType:ItemTypeFooBar];
+    [model setHeader:header forSectionWithIdentifier:SectionIdentifierBar];
+    [model addItem:item toSectionWithIdentifier:SectionIdentifierBar];
+  }
+
+  ~TableViewModelTest() override {
+    NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+    [defaults setObject:nil forKey:kTableViewModelCollapsedKey];
+  }
+
+  TableViewModel* model;
+};
+
+// Tests the default collapsed value is NO.
+TEST_F(TableViewModelTest, DefaultCollapsedSectionValue) {
+  EXPECT_FALSE([model sectionIsCollapsed:SectionIdentifierFoo]);
+  EXPECT_FALSE([model sectionIsCollapsed:SectionIdentifierBar]);
+}
+
+// Collapses all sections.
+TEST_F(TableViewModelTest, SetAllCollapsed) {
+  [model setSection:SectionIdentifierFoo collapsed:YES];
+  [model setSection:SectionIdentifierBar collapsed:YES];
+
+  EXPECT_TRUE([model sectionIsCollapsed:SectionIdentifierFoo]);
+  EXPECT_TRUE([model sectionIsCollapsed:SectionIdentifierBar]);
+
+  [model setSection:SectionIdentifierFoo collapsed:NO];
+  [model setSection:SectionIdentifierBar collapsed:NO];
+
+  EXPECT_FALSE([model sectionIsCollapsed:SectionIdentifierFoo]);
+  EXPECT_FALSE([model sectionIsCollapsed:SectionIdentifierBar]);
+}
+
+// Collapses just one section at the time.
+TEST_F(TableViewModelTest, SetSomeCollapsed) {
+  [model setSection:SectionIdentifierFoo collapsed:NO];
+  [model setSection:SectionIdentifierBar collapsed:YES];
+
+  EXPECT_FALSE([model sectionIsCollapsed:SectionIdentifierFoo]);
+  EXPECT_TRUE([model sectionIsCollapsed:SectionIdentifierBar]);
+
+  [model setSection:SectionIdentifierFoo collapsed:YES];
+  [model setSection:SectionIdentifierBar collapsed:NO];
+
+  EXPECT_TRUE([model sectionIsCollapsed:SectionIdentifierFoo]);
+  EXPECT_FALSE([model sectionIsCollapsed:SectionIdentifierBar]);
+}
+
+// Removes a collapsed section.
+TEST_F(TableViewModelTest, RemoveCollapsedSection) {
+  [model setSection:SectionIdentifierFoo collapsed:NO];
+  [model setSection:SectionIdentifierBar collapsed:YES];
+
+  EXPECT_FALSE([model sectionIsCollapsed:SectionIdentifierFoo]);
+  EXPECT_TRUE([model sectionIsCollapsed:SectionIdentifierBar]);
+
+  EXPECT_EQ(2, [model numberOfSections]);
+  [model removeSectionWithIdentifier:SectionIdentifierBar];
+  EXPECT_EQ(1, [model numberOfSections]);
+
+  EXPECT_FALSE([model sectionIsCollapsed:SectionIdentifierFoo]);
+}
+
+// Removes a collapsed section, then re-adds it, it should still be collapsed.
+TEST_F(TableViewModelTest, RemoveReaddCollapsedSection) {
+  [model setSection:SectionIdentifierFoo collapsed:NO];
+  [model setSection:SectionIdentifierBar collapsed:YES];
+
+  EXPECT_FALSE([model sectionIsCollapsed:SectionIdentifierFoo]);
+  EXPECT_TRUE([model sectionIsCollapsed:SectionIdentifierBar]);
+
+  EXPECT_EQ(2, [model numberOfSections]);
+  [model removeSectionWithIdentifier:SectionIdentifierBar];
+  EXPECT_EQ(1, [model numberOfSections]);
+
+  EXPECT_FALSE([model sectionIsCollapsed:SectionIdentifierFoo]);
+
+  [model addSectionWithIdentifier:SectionIdentifierBar];
+  // Use the same Key as the previously removed section.
+  [model setSectionIdentifier:SectionIdentifierBar collapsedKey:@"BarKey"];
+  TableViewHeaderFooterItem* header =
+      [[TableViewHeaderFooterItem alloc] initWithType:ItemTypeFooBar];
+  TableViewItem* item = [[TableViewItem alloc] initWithType:ItemTypeFooBar];
+  [model setHeader:header forSectionWithIdentifier:SectionIdentifierBar];
+  [model addItem:item toSectionWithIdentifier:SectionIdentifierBar];
+
+  EXPECT_EQ(2, [model numberOfSections]);
+  EXPECT_TRUE([model sectionIsCollapsed:SectionIdentifierBar]);
+  EXPECT_FALSE([model sectionIsCollapsed:SectionIdentifierFoo]);
+}
+
+// Test Collapsed persistance.
+TEST_F(TableViewModelTest, PersistCollapsedSections) {
+  [model setSection:SectionIdentifierFoo collapsed:NO];
+  [model setSection:SectionIdentifierBar collapsed:YES];
+
+  EXPECT_FALSE([model sectionIsCollapsed:SectionIdentifierFoo]);
+  EXPECT_TRUE([model sectionIsCollapsed:SectionIdentifierBar]);
+
+  TableViewModel* anotherModel = [[TableViewModel alloc] init];
+
+  [anotherModel addSectionWithIdentifier:SectionIdentifierFoo];
+  [anotherModel setSectionIdentifier:SectionIdentifierFoo
+                        collapsedKey:@"FooKey"];
+  TableViewHeaderFooterItem* header =
+      [[TableViewHeaderFooterItem alloc] initWithType:ItemTypeFooBar];
+  TableViewItem* item = [[TableViewItem alloc] initWithType:ItemTypeFooBar];
+  [anotherModel setHeader:header forSectionWithIdentifier:SectionIdentifierFoo];
+  [anotherModel addItem:item toSectionWithIdentifier:SectionIdentifierFoo];
+
+  [anotherModel addSectionWithIdentifier:SectionIdentifierBar];
+  [anotherModel setSectionIdentifier:SectionIdentifierBar
+                        collapsedKey:@"BarKey"];
+  header = [[TableViewHeaderFooterItem alloc] initWithType:ItemTypeFooBar];
+  item = [[TableViewItem alloc] initWithType:ItemTypeFooBar];
+  [anotherModel setHeader:header forSectionWithIdentifier:SectionIdentifierBar];
+  [anotherModel addItem:item toSectionWithIdentifier:SectionIdentifierBar];
+
+  // Since the Keys are the same as the previous model it should have preserved
+  // its collapsed values.
+  EXPECT_FALSE([model sectionIsCollapsed:SectionIdentifierFoo]);
+  EXPECT_TRUE([model sectionIsCollapsed:SectionIdentifierBar]);
+}
+
+}  // namespace
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index 5532bac..c1165f95 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -88,7 +88,7 @@
     ":test_support",
     "//base",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
   ]
 }
 
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 814e5904..ead43b8 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -135,7 +135,7 @@
     "//base/test:test_support",
     "//ios/web/public/test",
     "//ios/web/public/test/http_server",
-    "//mojo/edk/system",
+    "//mojo/edk",
   ]
 }
 
@@ -554,7 +554,7 @@
     "//ios/web/test:resources",
     "//ios/web/test:test_constants",
     "//ios/web/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//net:test_support",
     "//services/network/public/cpp",
     "//services/service_manager/public/cpp",
diff --git a/ios/web/app/BUILD.gn b/ios/web/app/BUILD.gn
index 10b9705..8c8f41b 100644
--- a/ios/web/app/BUILD.gn
+++ b/ios/web/app/BUILD.gn
@@ -20,7 +20,7 @@
     "//crypto",
     "//ios/web",
     "//ios/web/public/global_state",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//net",
     "//ui/base",
     "//ui/gfx",
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn
index 1dabafb..b0588793 100644
--- a/ios/web_view/BUILD.gn
+++ b/ios/web_view/BUILD.gn
@@ -255,6 +255,11 @@
   }
 }
 
+ios_web_view_test_sources = [
+  "internal/translate/fake_web_view_translate_client.h",
+  "internal/translate/fake_web_view_translate_client.mm",
+]
+
 test("ios_web_view_unittests") {
   testonly = true
   sources = [
@@ -269,6 +274,7 @@
     "internal/web_view_web_client_unittest.mm",
   ]
   sources += ios_web_view_sources
+  sources += ios_web_view_test_sources
 
   deps = [
     "test:test_support",
diff --git a/ios/web_view/internal/translate/cwv_translation_controller_unittest.mm b/ios/web_view/internal/translate/cwv_translation_controller_unittest.mm
index 309579b5..82de2cd 100644
--- a/ios/web_view/internal/translate/cwv_translation_controller_unittest.mm
+++ b/ios/web_view/internal/translate/cwv_translation_controller_unittest.mm
@@ -15,7 +15,7 @@
 #import "ios/web/public/test/fakes/test_web_state.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
 #import "ios/web_view/internal/translate/cwv_translation_language_internal.h"
-#import "ios/web_view/internal/translate/web_view_translate_client.h"
+#import "ios/web_view/internal/translate/fake_web_view_translate_client.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
 #import "ios/web_view/public/cwv_translation_controller_delegate.h"
 #import "ios/web_view/public/cwv_translation_policy.h"
@@ -46,10 +46,10 @@
     CRWTestJSInjectionReceiver* injection_receiver =
         [[CRWTestJSInjectionReceiver alloc] init];
     web_state_.SetJSInjectionReceiver(injection_receiver);
-    WebViewTranslateClient::CreateForWebState(&web_state_);
-    translate_client_ = WebViewTranslateClient::FromWebState(&web_state_);
+    translate_client_ = std::make_unique<FakeWebViewTranslateClient>(
+        &web_state_, /*page_lang=*/"en");
     translation_controller_ = [[CWVTranslationController alloc]
-        initWithTranslateClient:translate_client_];
+        initWithTranslateClient:translate_client_.get()];
     translate_prefs_ = translate_client_->GetTranslatePrefs();
     translate_prefs_->ResetToDefaults();
   }
@@ -67,8 +67,8 @@
 
   web::TestWebThreadBundle web_thread_bundle_;
   WebViewBrowserState browser_state_;
+  std::unique_ptr<FakeWebViewTranslateClient> translate_client_;
   web::TestWebState web_state_;
-  WebViewTranslateClient* translate_client_;
   CWVTranslationController* translation_controller_;
   std::unique_ptr<translate::TranslatePrefs> translate_prefs_;
 };
@@ -175,4 +175,28 @@
   EXPECT_NSEQ(nil, policy.language);
 }
 
+// Tests CWVTranslationController translate page and revert methods.
+TEST_F(CWVTranslationControllerTest, TranslatePageAndRevert) {
+  NSArray* langs = translation_controller_.supportedLanguages.allObjects;
+  CWVTranslationLanguage* from_lang = langs.firstObject;
+  CWVTranslationLanguage* to_lang = langs.lastObject;
+  std::string from_code = base::SysNSStringToUTF8(from_lang.languageCode);
+  std::string to_code = base::SysNSStringToUTF8(to_lang.languageCode);
+
+  [translation_controller_ translatePageFromLanguage:from_lang
+                                          toLanguage:to_lang
+                                       userInitiated:YES];
+  EXPECT_EQ(to_code, translate_client_->GetCurrentLang());
+
+  TranslatePageInvocation invocation =
+      translate_client_->GetLastTraslatePageInvocation();
+  EXPECT_EQ(from_code, invocation.source_lang);
+  EXPECT_EQ(to_code, invocation.target_lang);
+  EXPECT_TRUE(invocation.triggered_from_menu);
+
+  [translation_controller_ revertTranslation];
+  EXPECT_EQ(translate_client_->GetPageLang(),
+            translate_client_->GetCurrentLang());
+}
+
 }  // namespace ios_web_view
diff --git a/ios/web_view/internal/translate/fake_web_view_translate_client.h b/ios/web_view/internal/translate/fake_web_view_translate_client.h
new file mode 100644
index 0000000..e921ed6c
--- /dev/null
+++ b/ios/web_view/internal/translate/fake_web_view_translate_client.h
@@ -0,0 +1,50 @@
+// Copyright 2018 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 IOS_WEB_VIEW_INTERNAL_TRANSLATE_FAKE_WEB_VIEW_TRANSLATE_CLIENT_H_
+#define IOS_WEB_VIEW_INTERNAL_TRANSLATE_FAKE_WEB_VIEW_TRANSLATE_CLIENT_H_
+
+#include <string>
+
+#import "ios/web_view/internal/translate/web_view_translate_client.h"
+
+namespace ios_web_view {
+
+// Contains the list of parameters passed to |TranslatePage|.
+struct TranslatePageInvocation {
+  std::string source_lang;
+  std::string target_lang;
+  bool triggered_from_menu;
+};
+
+// Fake translate client used in unit tests.
+class FakeWebViewTranslateClient : public WebViewTranslateClient {
+ public:
+  // |page_lang| The original language of the page.
+  explicit FakeWebViewTranslateClient(web::WebState* web_state,
+                                      std::string page_lang);
+  ~FakeWebViewTranslateClient() override;
+
+  // WebViewTranslateClient implementation.
+  void TranslatePage(const std::string& source_lang,
+                     const std::string& target_lang,
+                     bool triggered_from_menu) override;
+  void RevertTranslation() override;
+
+  // Getters for ivars used for testing.
+  std::string GetPageLang() { return page_lang_; }
+  std::string GetCurrentLang() { return current_lang_; }
+  TranslatePageInvocation GetLastTraslatePageInvocation() {
+    return last_translate_page_invocation_;
+  }
+
+ private:
+  std::string page_lang_;
+  TranslatePageInvocation last_translate_page_invocation_;
+  std::string current_lang_;
+};
+
+}  // namespace ios_web_view
+
+#endif  // IOS_WEB_VIEW_INTERNAL_TRANSLATE_FAKE_WEB_VIEW_TRANSLATE_CLIENT_H_
diff --git a/ios/web_view/internal/translate/fake_web_view_translate_client.mm b/ios/web_view/internal/translate/fake_web_view_translate_client.mm
new file mode 100644
index 0000000..938787a
--- /dev/null
+++ b/ios/web_view/internal/translate/fake_web_view_translate_client.mm
@@ -0,0 +1,34 @@
+// Copyright 2018 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 "ios/web_view/internal/translate/fake_web_view_translate_client.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace ios_web_view {
+
+FakeWebViewTranslateClient::FakeWebViewTranslateClient(web::WebState* web_state,
+                                                       std::string page_lang)
+    : WebViewTranslateClient(web_state),
+      page_lang_(page_lang),
+      current_lang_(page_lang){};
+
+FakeWebViewTranslateClient::~FakeWebViewTranslateClient(){};
+
+void FakeWebViewTranslateClient::TranslatePage(const std::string& source_lang,
+                                               const std::string& target_lang,
+                                               bool triggered_from_menu) {
+  last_translate_page_invocation_.source_lang = source_lang;
+  last_translate_page_invocation_.target_lang = target_lang;
+  last_translate_page_invocation_.triggered_from_menu = triggered_from_menu;
+  current_lang_ = target_lang;
+}
+
+void FakeWebViewTranslateClient::RevertTranslation() {
+  current_lang_ = page_lang_;
+}
+
+}  // namespace ios_web_view
diff --git a/ios/web_view/internal/translate/web_view_translate_client.h b/ios/web_view/internal/translate/web_view_translate_client.h
index 7f36adf..660a9e4 100644
--- a/ios/web_view/internal/translate/web_view_translate_client.h
+++ b/ios/web_view/internal/translate/web_view_translate_client.h
@@ -52,13 +52,15 @@
   }
 
   // Performs translation from |source_lang| to |target_lang|.
-  // |trigged_from_menu| indicates if a direct result of user interaction.
-  void TranslatePage(const std::string& source_lang,
-                     const std::string& target_lang,
-                     bool triggered_from_menu);
+  // |trigged_from_menu| indicates if a direct result of user.
+  // Marked virtual to allow for testing.
+  virtual void TranslatePage(const std::string& source_lang,
+                             const std::string& target_lang,
+                             bool triggered_from_menu);
 
   // Reverts previous translations back to original language.
-  void RevertTranslation();
+  // Marked virtual to allow for testing.
+  virtual void RevertTranslation();
 
   // TranslateClient implementation.
   translate::IOSTranslateDriver* GetTranslateDriver() override;
@@ -80,12 +82,13 @@
   bool IsTranslatableURL(const GURL& url) override;
   void ShowReportLanguageDetectionErrorUI(const GURL& report_url) override;
 
- private:
-  friend class web::WebStateUserData<WebViewTranslateClient>;
-
+ protected:
   // The lifetime of WebViewTranslateClient is managed by WebStateUserData.
   explicit WebViewTranslateClient(web::WebState* web_state);
 
+ private:
+  friend class web::WebStateUserData<WebViewTranslateClient>;
+
   // web::WebStateObserver implementation.
   void WebStateDestroyed(web::WebState* web_state) override;
 
diff --git a/ipc/BUILD.gn b/ipc/BUILD.gn
index d2ca944..0d9d726 100644
--- a/ipc/BUILD.gn
+++ b/ipc/BUILD.gn
@@ -218,7 +218,7 @@
     deps = [
       "//base",
       "//base/test:test_support",
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//mojo/edk/test:test_support",
     ]
   }
@@ -262,7 +262,7 @@
       "//base:i18n",
       "//base/test:test_support",
       "//crypto",
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//mojo/edk/test:test_support",
       "//testing/gtest",
     ]
@@ -301,7 +301,7 @@
       "//base",
       "//base:i18n",
       "//base/test:test_support",
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//mojo/edk/test:test_support",
       "//mojo/edk/test:test_support_impl",
       "//testing/gtest",
diff --git a/mash/BUILD.gn b/mash/BUILD.gn
index 415a893..084d684 100644
--- a/mash/BUILD.gn
+++ b/mash/BUILD.gn
@@ -104,7 +104,7 @@
       "//cc",
       "//cc:test_support",
       "//components/viz/service",
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//services/catalog:lib",
       "//ui/aura",
       "//ui/base",
diff --git a/mash/runner/BUILD.gn b/mash/runner/BUILD.gn
index c4c4f16..4a823fe 100644
--- a/mash/runner/BUILD.gn
+++ b/mash/runner/BUILD.gn
@@ -14,7 +14,7 @@
     "//base:i18n",
     "//base/test:test_support",
     "//build/config:exe_and_shlib_deps",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//services/service_manager",
     "//services/service_manager/runner:init",
     "//services/service_manager/standalone",
diff --git a/media/blink/BUILD.gn b/media/blink/BUILD.gn
index 21a9ddb..d566b47 100644
--- a/media/blink/BUILD.gn
+++ b/media/blink/BUILD.gn
@@ -115,7 +115,7 @@
     "//media:test_support",
     "//media/mojo/interfaces",
     "//media/mojo/services",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//net",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/media/capture/BUILD.gn b/media/capture/BUILD.gn
index c15e91a..7b06c3a 100644
--- a/media/capture/BUILD.gn
+++ b/media/capture/BUILD.gn
@@ -238,7 +238,7 @@
     deps += [
       "//chromeos:chromeos",
       "//media/capture/video/chromeos/mojo:arc_camera3",
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//third_party/libsync",
     ]
   }
@@ -292,7 +292,7 @@
     "//media:test_support",
     "//media/capture/mojom:image_capture",
     "//media/capture/mojom:image_capture_types",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//testing/gmock",
     "//testing/gtest",
     "//ui/gfx:test_support",
@@ -340,7 +340,7 @@
     deps += [
       "//chromeos:chromeos",
       "//media/capture/video/chromeos/mojo:arc_camera3",
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//third_party/libdrm",
       "//third_party/libsync",
       "//third_party/minigbm",
diff --git a/media/cast/net/udp_socket_client_unittest.cc b/media/cast/net/udp_socket_client_unittest.cc
index c1b00df..f2ae68b 100644
--- a/media/cast/net/udp_socket_client_unittest.cc
+++ b/media/cast/net/udp_socket_client_unittest.cc
@@ -126,6 +126,7 @@
   void SetNetworkConditions(
       const std::string& profile_id,
       network::mojom::NetworkConditionsPtr conditions) override {}
+  void SetAcceptLanguage(const std::string& new_accept_language) override {}
   void AddHSTSForTesting(const std::string& host,
                          base::Time expiry,
                          bool include_subdomains,
diff --git a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
index e60494e..a69a9dd 100644
--- a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
+++ b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
@@ -38,14 +38,6 @@
 #include "media/cdm/library_cdm/clear_key_cdm/ffmpeg_cdm_audio_decoder.h"
 #include "media/cdm/library_cdm/clear_key_cdm/ffmpeg_cdm_video_decoder.h"
 
-// Include FFmpeg avformat.h for av_register_all().
-extern "C" {
-// Temporarily disable possible loss of data warning.
-MSVC_PUSH_DISABLE_WARNING(4244);
-#include <libavformat/avformat.h>
-MSVC_POP_WARNING();
-}  // extern "C"
-
 #if !defined COMPONENT_BUILD
 static base::AtExitManager g_at_exit_manager;
 #endif
@@ -234,7 +226,6 @@
   DVLOG(1) << __func__;
 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER)
   media::InitializeMediaLibrary();
-  av_register_all();
 #endif  // CLEAR_KEY_CDM_USE_FFMPEG_DECODER
 
   g_is_cdm_module_initialized = true;
diff --git a/media/ffmpeg/ffmpeg_common_unittest.cc b/media/ffmpeg/ffmpeg_common_unittest.cc
index c221685..84466d81 100644
--- a/media/ffmpeg/ffmpeg_common_unittest.cc
+++ b/media/ffmpeg/ffmpeg_common_unittest.cc
@@ -25,9 +25,7 @@
 
 class FFmpegCommonTest : public testing::Test {
  public:
-  FFmpegCommonTest() {
-    FFmpegGlue::InitializeFFmpeg();
-  }
+  FFmpegCommonTest() {}
   ~FFmpegCommonTest() override = default;
 };
 
diff --git a/media/filters/ffmpeg_audio_decoder.cc b/media/filters/ffmpeg_audio_decoder.cc
index 3be4495..6b0d7bb6 100644
--- a/media/filters/ffmpeg_audio_decoder.cc
+++ b/media/filters/ffmpeg_audio_decoder.cc
@@ -80,8 +80,6 @@
     return;
   }
 
-  FFmpegGlue::InitializeFFmpeg();
-
   if (!ConfigureDecoder(config)) {
     av_sample_format_ = 0;
     bound_init_cb.Run(false);
diff --git a/media/filters/ffmpeg_glue.cc b/media/filters/ffmpeg_glue.cc
index 9fe7949..2adbc7020 100644
--- a/media/filters/ffmpeg_glue.cc
+++ b/media/filters/ffmpeg_glue.cc
@@ -63,13 +63,7 @@
   return new_offset;
 }
 
-void FFmpegGlue::InitializeFFmpeg() {
-  av_register_all();
-}
-
 FFmpegGlue::FFmpegGlue(FFmpegURLProtocol* protocol) {
-  InitializeFFmpeg();
-
   // Initialize an AVIOContext using our custom read and seek operations.  Don't
   // keep pointers to the buffer since FFmpeg may reallocate it on the fly.  It
   // will be cleaned up
diff --git a/media/filters/ffmpeg_glue.h b/media/filters/ffmpeg_glue.h
index 48a7c51..be55fb2f 100644
--- a/media/filters/ffmpeg_glue.h
+++ b/media/filters/ffmpeg_glue.h
@@ -17,10 +17,6 @@
 //
 // The glue in turn processes those read and seek requests using the
 // FFmpegURLProtocol provided during construction.
-//
-// FFmpegGlue is also responsible for initializing FFmpeg, which is done once
-// per process.  Initialization includes: turning off log messages, registering
-// a lock manager, and finally registering all demuxers and codecs.
 
 #ifndef MEDIA_FILTERS_FFMPEG_GLUE_H_
 #define MEDIA_FILTERS_FFMPEG_GLUE_H_
@@ -63,8 +59,6 @@
 
 class MEDIA_EXPORT FFmpegGlue {
  public:
-  static void InitializeFFmpeg();
-
   // See file documentation for usage.  |protocol| must outlive FFmpegGlue.
   explicit FFmpegGlue(FFmpegURLProtocol* protocol);
   ~FFmpegGlue();
diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc
index 077ed78..73f1a60 100644
--- a/media/filters/ffmpeg_video_decoder.cc
+++ b/media/filters/ffmpeg_video_decoder.cc
@@ -28,7 +28,6 @@
 #include "media/base/video_util.h"
 #include "media/ffmpeg/ffmpeg_common.h"
 #include "media/ffmpeg/ffmpeg_decoding_loop.h"
-#include "media/filters/ffmpeg_glue.h"
 
 namespace media {
 
@@ -111,7 +110,6 @@
 
 // static
 bool FFmpegVideoDecoder::IsCodecSupported(VideoCodec codec) {
-  FFmpegGlue::InitializeFFmpeg();
   return avcodec_find_decoder(VideoCodecToCodecID(codec)) != nullptr;
 }
 
@@ -243,8 +241,6 @@
     return;
   }
 
-  FFmpegGlue::InitializeFFmpeg();
-
   if (!ConfigureDecoder(config, low_delay)) {
     bound_init_cb.Run(false);
     return;
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc
index 80c161c..a3f3c6a 100644
--- a/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -29,7 +29,6 @@
 #include "media/base/video_frame.h"
 #include "media/base/video_util.h"
 #include "media/ffmpeg/ffmpeg_common.h"
-#include "media/filters/ffmpeg_glue.h"
 #include "media/filters/ffmpeg_video_decoder.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -63,8 +62,6 @@
       : decoder_(new FFmpegVideoDecoder(&media_log_)),
         decode_cb_(base::Bind(&FFmpegVideoDecoderTest::DecodeDone,
                               base::Unretained(this))) {
-    FFmpegGlue::InitializeFFmpeg();
-
     // Initialize various test buffers.
     frame_buffer_.reset(new uint8_t[kCodedSize.GetArea()]);
     end_of_stream_buffer_ = DecoderBuffer::CreateEOSBuffer();
diff --git a/media/gpu/video_encode_accelerator_unittest.cc b/media/gpu/video_encode_accelerator_unittest.cc
index f60fe22..369e7e7 100644
--- a/media/gpu/video_encode_accelerator_unittest.cc
+++ b/media/gpu/video_encode_accelerator_unittest.cc
@@ -43,7 +43,6 @@
 #include "media/base/test_data_util.h"
 #include "media/base/video_decoder.h"
 #include "media/base/video_frame.h"
-#include "media/filters/ffmpeg_glue.h"
 #include "media/filters/ffmpeg_video_decoder.h"
 #include "media/filters/ivf_parser.h"
 #include "media/gpu/features.h"
@@ -728,7 +727,6 @@
 void VideoFrameQualityValidator::Initialize(const gfx::Size& coded_size,
                                             const gfx::Rect& visible_size) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  FFmpegGlue::InitializeFFmpeg();
 
   gfx::Size natural_size(visible_size.size());
   // The default output format of ffmpeg video decoder is YV12.
diff --git a/media/mojo/clients/mojo_renderer_factory.cc b/media/mojo/clients/mojo_renderer_factory.cc
index 5c5fa3a..2601efde 100644
--- a/media/mojo/clients/mojo_renderer_factory.cc
+++ b/media/mojo/clients/mojo_renderer_factory.cc
@@ -8,7 +8,6 @@
 
 #include "base/single_thread_task_runner.h"
 #include "media/mojo/clients/mojo_renderer.h"
-#include "media/mojo/interfaces/interface_factory.mojom.h"
 #include "media/renderers/video_overlay_factory.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "services/service_manager/public/cpp/connect.h"
@@ -17,21 +16,13 @@
 namespace media {
 
 MojoRendererFactory::MojoRendererFactory(
+    mojom::HostedRendererType type,
     const GetGpuFactoriesCB& get_gpu_factories_cb,
     media::mojom::InterfaceFactory* interface_factory)
     : get_gpu_factories_cb_(get_gpu_factories_cb),
-      interface_factory_(interface_factory) {
+      interface_factory_(interface_factory),
+      hosted_renderer_type_(type) {
   DCHECK(interface_factory_);
-  DCHECK(!interface_provider_);
-}
-
-MojoRendererFactory::MojoRendererFactory(
-    const GetGpuFactoriesCB& get_gpu_factories_cb,
-    service_manager::InterfaceProvider* interface_provider)
-    : get_gpu_factories_cb_(get_gpu_factories_cb),
-      interface_provider_(interface_provider) {
-  DCHECK(interface_provider_);
-  DCHECK(!interface_factory_);
 }
 
 MojoRendererFactory::~MojoRendererFactory() = default;
@@ -61,10 +52,8 @@
   mojom::RendererPtr renderer_ptr;
 
   if (interface_factory_) {
-    interface_factory_->CreateRenderer(std::string(),
+    interface_factory_->CreateRenderer(hosted_renderer_type_, std::string(),
                                        mojo::MakeRequest(&renderer_ptr));
-  } else if (interface_provider_) {
-    interface_provider_->GetInterface(&renderer_ptr);
   } else {
     NOTREACHED();
   }
diff --git a/media/mojo/clients/mojo_renderer_factory.h b/media/mojo/clients/mojo_renderer_factory.h
index db6b2fe..f0fa1f33 100644
--- a/media/mojo/clients/mojo_renderer_factory.h
+++ b/media/mojo/clients/mojo_renderer_factory.h
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "media/base/renderer_factory.h"
+#include "media/mojo/interfaces/interface_factory.mojom.h"
 #include "media/mojo/interfaces/renderer.mojom.h"
 
 namespace service_manager {
@@ -17,10 +18,6 @@
 
 namespace media {
 
-namespace mojom {
-class InterfaceFactory;
-}
-
 class GpuVideoAcceleratorFactories;
 
 // The default factory class for creating MojoRenderer.
@@ -28,10 +25,9 @@
  public:
   using GetGpuFactoriesCB = base::Callback<GpuVideoAcceleratorFactories*()>;
 
-  MojoRendererFactory(const GetGpuFactoriesCB& get_gpu_factories_cb,
+  MojoRendererFactory(mojom::HostedRendererType type,
+                      const GetGpuFactoriesCB& get_gpu_factories_cb,
                       media::mojom::InterfaceFactory* interface_factory);
-  MojoRendererFactory(const GetGpuFactoriesCB& get_gpu_factories_cb,
-                      service_manager::InterfaceProvider* interface_provider);
 
   ~MojoRendererFactory() final;
 
@@ -51,7 +47,9 @@
   // InterfaceFactory or InterfaceProvider used to create or connect to remote
   // renderer.
   media::mojom::InterfaceFactory* interface_factory_ = nullptr;
-  service_manager::InterfaceProvider* interface_provider_ = nullptr;
+
+  // Underlying renderer type that will be hosted by the MojoRenderer.
+  mojom::HostedRendererType hosted_renderer_type_;
 
   DISALLOW_COPY_AND_ASSIGN(MojoRendererFactory);
 };
diff --git a/media/mojo/interfaces/interface_factory.mojom b/media/mojo/interfaces/interface_factory.mojom
index 3c8e3ee..b3101de 100644
--- a/media/mojo/interfaces/interface_factory.mojom
+++ b/media/mojo/interfaces/interface_factory.mojom
@@ -10,17 +10,37 @@
 import "media/mojo/interfaces/renderer.mojom";
 import "media/mojo/interfaces/video_decoder.mojom";
 
+// Defines the types of renderers that can be hosted by a mojo Renderer.
+enum HostedRendererType {
+  // media::DefaultRenderer: Used to offload normal rendering scenarios to a
+  // different process, for stability or performance reasons.
+  kDefault,
+
+  // content::MediaPlayerRenderer: Used to handle HLS videos on Android. Also
+  // used on older Android devices, that don't have platform decode support, and
+  // are better off using the native Android MediaPlayer.
+  [EnableIf=is_android]
+  kMediaPlayer,
+};
+
 // A factory for creating media mojo interfaces. Renderers can only access
 // ContentDecryptionModules created with the same factory.
 interface InterfaceFactory {
   CreateAudioDecoder(AudioDecoder& audio_decoder);
   CreateVideoDecoder(VideoDecoder& video_decoder);
 
-  // Creates a Renderer.
-  // The audio stream will be played on |audio_device_id|, which is defined in
-  // media/audio/audio_device_description.h. If |audio_device_id| is empty,
-  // kDefaultDeviceId will be used.
-  CreateRenderer(string audio_device_id, Renderer& renderer);
+  // Creates a Renderer, using |type| to choose which concrete media::Renderer
+  // implementation to host. Different values of |type| might affect how the
+  // request is ultimately routed (i.e. |type| will determine in which process
+  // the mojom::Renderer is created).
+  // |type_specific_id| represents a different kind of ID, based off of |type|.
+  // The usage of |type_specific_id| per |type| is defined as follows:
+  // - kDefault: represents an audio device ID, which is defined in
+  //   media/audio/audio_device_description.h.
+  //   If |type_specific_id| is empty, kDefaultDeviceId will be used.
+  // - kMediaPlayer: unused.
+  CreateRenderer(HostedRendererType type, string type_specific_id,
+                 Renderer& renderer);
 
   // Creates a CDM based on the |key_system| provided. A |key_system| is a
   // generic term for a decryption mechanism and/or content protection provider.
diff --git a/media/mojo/services/BUILD.gn b/media/mojo/services/BUILD.gn
index 969bfdd..5c96e4b 100644
--- a/media/mojo/services/BUILD.gn
+++ b/media/mojo/services/BUILD.gn
@@ -248,7 +248,7 @@
     "//components/ukm:test_support",
     "//media:test_support",
     "//media/mojo:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//services/metrics/public/cpp:ukm_builders",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/media/mojo/services/interface_factory_impl.cc b/media/mojo/services/interface_factory_impl.cc
index 97661aa6..7605682 100644
--- a/media/mojo/services/interface_factory_impl.cc
+++ b/media/mojo/services/interface_factory_impl.cc
@@ -97,17 +97,26 @@
 }
 
 void InterfaceFactoryImpl::CreateRenderer(
-    const std::string& audio_device_id,
+    media::mojom::HostedRendererType type,
+    const std::string& type_specific_id,
     mojo::InterfaceRequest<mojom::Renderer> request) {
 #if BUILDFLAG(ENABLE_MOJO_RENDERER)
   RendererFactory* renderer_factory = GetRendererFactory();
   if (!renderer_factory)
     return;
 
+  // Creation requests for non default renderers should have already been
+  // handled by now, in a different layer.
+  if (type != media::mojom::HostedRendererType::kDefault) {
+    DLOG(ERROR) << "Creation of specialized renderers is not supported.";
+    return;
+  }
+
   scoped_refptr<base::SingleThreadTaskRunner> task_runner(
       base::ThreadTaskRunnerHandle::Get());
   auto audio_sink =
-      mojo_media_client_->CreateAudioRendererSink(audio_device_id);
+      mojo_media_client_->CreateAudioRendererSink(type_specific_id);
+
   auto video_sink = mojo_media_client_->CreateVideoRendererSink(task_runner);
   // TODO(hubbe): Find out if gfx::ColorSpace() is correct for the
   // target_color_space.
diff --git a/media/mojo/services/interface_factory_impl.h b/media/mojo/services/interface_factory_impl.h
index 18f9f668..d441eb01 100644
--- a/media/mojo/services/interface_factory_impl.h
+++ b/media/mojo/services/interface_factory_impl.h
@@ -34,7 +34,8 @@
   // mojom::InterfaceFactory implementation.
   void CreateAudioDecoder(mojom::AudioDecoderRequest request) final;
   void CreateVideoDecoder(mojom::VideoDecoderRequest request) final;
-  void CreateRenderer(const std::string& audio_device_id,
+  void CreateRenderer(media::mojom::HostedRendererType type,
+                      const std::string& type_specific_id,
                       mojom::RendererRequest request) final;
   void CreateCdm(const std::string& key_system,
                  mojom::ContentDecryptionModuleRequest request) final;
diff --git a/media/mojo/services/media_service_unittest.cc b/media/mojo/services/media_service_unittest.cc
index 86ddb583..87860f8d 100644
--- a/media/mojo/services/media_service_unittest.cc
+++ b/media/mojo/services/media_service_unittest.cc
@@ -122,8 +122,9 @@
 
   void InitializeRenderer(const VideoDecoderConfig& video_config,
                           bool expected_result) {
-    interface_factory_->CreateRenderer(std::string(),
-                                       mojo::MakeRequest(&renderer_));
+    interface_factory_->CreateRenderer(
+        media::mojom::HostedRendererType::kDefault, std::string(),
+        mojo::MakeRequest(&renderer_));
 
     video_stream_.set_video_decoder_config(video_config);
 
diff --git a/media/mojo/services/mojo_renderer_service.cc b/media/mojo/services/mojo_renderer_service.cc
index cd093e6..7097a77d 100644
--- a/media/mojo/services/mojo_renderer_service.cc
+++ b/media/mojo/services/mojo_renderer_service.cc
@@ -39,7 +39,7 @@
     scoped_refptr<AudioRendererSink> audio_sink,
     std::unique_ptr<VideoRendererSink> video_sink,
     std::unique_ptr<media::Renderer> renderer,
-    InitiateSurfaceRequestCB initiate_surface_request_cb,
+    const InitiateSurfaceRequestCB& initiate_surface_request_cb,
     mojo::InterfaceRequest<mojom::Renderer> request) {
   MojoRendererService* service = new MojoRendererService(
       mojo_cdm_service_context, std::move(audio_sink), std::move(video_sink),
@@ -54,6 +54,16 @@
   return binding;
 }
 
+// static
+mojo::StrongBindingPtr<mojom::Renderer> MojoRendererService::Create(
+    std::unique_ptr<media::Renderer> renderer,
+    const InitiateSurfaceRequestCB& initiate_surface_request_cb,
+    mojo::InterfaceRequest<mojom::Renderer> request) {
+  return MojoRendererService::Create(
+      nullptr, nullptr, nullptr, std::move(renderer),
+      initiate_surface_request_cb, std::move(request));
+}
+
 MojoRendererService::MojoRendererService(
     MojoCdmServiceContext* mojo_cdm_service_context,
     scoped_refptr<AudioRendererSink> audio_sink,
diff --git a/media/mojo/services/mojo_renderer_service.h b/media/mojo/services/mojo_renderer_service.h
index add37ea1..8303d772 100644
--- a/media/mojo/services/mojo_renderer_service.h
+++ b/media/mojo/services/mojo_renderer_service.h
@@ -46,7 +46,20 @@
       scoped_refptr<AudioRendererSink> audio_sink,
       std::unique_ptr<VideoRendererSink> video_sink,
       std::unique_ptr<media::Renderer> renderer,
-      InitiateSurfaceRequestCB initiate_surface_request_cb,
+      const InitiateSurfaceRequestCB& initiate_surface_request_cb,
+      mojo::InterfaceRequest<mojom::Renderer> request);
+
+  // Helper function to bind MojoRendererService with a StrongBinding,
+  // which is safely accessible via the returned StrongBindingPtr.
+  // NOTE: Some media::Renderers don't need Audio/VideoRendererSinks, and don't
+  // support encrypted content. For example, MediaPlayerRenderer instead uses a
+  // StreamTextureWrapper, and FlingingRenderer does not need to render any
+  // video on the local device. This function serves the same purpose as the one
+  // above, but without forcing classes to define the forward declared
+  // AudioRendererSink, VideoRendererSink and MojoCdmServiceContext.
+  static mojo::StrongBindingPtr<mojom::Renderer> Create(
+      std::unique_ptr<media::Renderer> renderer,
+      const InitiateSurfaceRequestCB& initiate_surface_request_cb,
       mojo::InterfaceRequest<mojom::Renderer> request);
 
   // |mojo_cdm_service_context| can be used to find the CDM to support
diff --git a/media/renderers/video_overlay_factory.cc b/media/renderers/video_overlay_factory.cc
index 16fdd0f7..71057d8 100644
--- a/media/renderers/video_overlay_factory.cc
+++ b/media/renderers/video_overlay_factory.cc
@@ -21,16 +21,15 @@
     DCHECK(gpu_factories_);
     DCHECK(gpu_factories_->GetTaskRunner()->BelongsToCurrentThread());
 
-    std::unique_ptr<GpuVideoAcceleratorFactories::ScopedGLContextLock> lock(
-        gpu_factories_->GetGLContextLock());
-    if (lock) {
-      gpu::gles2::GLES2Interface* gl = lock->ContextGL();
-      gpu_memory_buffer_ = gpu_factories_->CreateGpuMemoryBuffer(
-          gfx::Size(1, 1), gfx::BufferFormat::RGBA_8888,
-          gfx::BufferUsage::SCANOUT);
-      if (gpu_memory_buffer_) {
-        image_id_ = gl->CreateImageCHROMIUM(
-            gpu_memory_buffer_->AsClientBuffer(), 1, 1, GL_RGBA);
+    gpu::gles2::GLES2Interface* gl = gpu_factories_->ContextGL();
+    if (!gl)
+      return;
+    gpu_memory_buffer_ = gpu_factories_->CreateGpuMemoryBuffer(
+        gfx::Size(1, 1), gfx::BufferFormat::RGBA_8888,
+        gfx::BufferUsage::SCANOUT);
+    if (gpu_memory_buffer_) {
+      image_id_ = gl->CreateImageCHROMIUM(gpu_memory_buffer_->AsClientBuffer(),
+                                          1, 1, GL_RGBA);
       }
       if (image_id_) {
         gl->GenTextures(1, &texture_id_);
@@ -42,22 +41,19 @@
 
         gl->GenSyncTokenCHROMIUM(sync_token_.GetData());
       }
-    }
   }
 
   ~Texture() {
     DCHECK(gpu_factories_->GetTaskRunner()->BelongsToCurrentThread());
 
     if (image_id_) {
-      std::unique_ptr<GpuVideoAcceleratorFactories::ScopedGLContextLock> lock(
-          gpu_factories_->GetGLContextLock());
-      if (lock) {
-        gpu::gles2::GLES2Interface* gl = lock->ContextGL();
-        gl->BindTexture(GL_TEXTURE_2D, texture_id_);
-        gl->ReleaseTexImage2DCHROMIUM(GL_TEXTURE_2D, image_id_);
-        gl->DeleteTextures(1, &texture_id_);
-        gl->DestroyImageCHROMIUM(image_id_);
-      }
+      gpu::gles2::GLES2Interface* gl = gpu_factories_->ContextGL();
+      if (!gl)
+        return;
+      gl->BindTexture(GL_TEXTURE_2D, texture_id_);
+      gl->ReleaseTexImage2DCHROMIUM(GL_TEXTURE_2D, image_id_);
+      gl->DeleteTextures(1, &texture_id_);
+      gl->DestroyImageCHROMIUM(image_id_);
     }
   }
 
diff --git a/media/test/BUILD.gn b/media/test/BUILD.gn
index d3c0f452..4badd3d 100644
--- a/media/test/BUILD.gn
+++ b/media/test/BUILD.gn
@@ -15,7 +15,7 @@
     "//base",
     "//base/test:test_support",
     "//media:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
   ]
 
   if (is_android) {
diff --git a/media/video/gpu_memory_buffer_video_frame_pool.cc b/media/video/gpu_memory_buffer_video_frame_pool.cc
index 7c719cc7..4c9a396 100644
--- a/media/video/gpu_memory_buffer_video_frame_pool.cc
+++ b/media/video/gpu_memory_buffer_video_frame_pool.cc
@@ -797,15 +797,13 @@
     BindAndCreateMailboxesHardwareFrameResources(
         const scoped_refptr<VideoFrame>& video_frame,
         FrameResources* frame_resources) {
-  std::unique_ptr<GpuVideoAcceleratorFactories::ScopedGLContextLock> lock(
-      gpu_factories_->GetGLContextLock());
-  if (!lock) {
+  gpu::gles2::GLES2Interface* gles2 = gpu_factories_->ContextGL();
+  if (!gles2) {
     frame_resources->MarkUnused(tick_clock_->NowTicks());
     std::move(frame_copy_requests_.front().frame_ready_cb).Run(video_frame);
     frame_copy_requests_.pop_front();
     return;
   }
-  gpu::gles2::GLES2Interface* gles2 = lock->ContextGL();
 
   const gfx::Size coded_size = CodedSize(video_frame, output_format_);
   gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes];
@@ -898,7 +896,6 @@
   frame->metadata()->SetBoolean(VideoFrameMetadata::READ_LOCK_FENCES_ENABLED,
                                 true);
 
-  lock.reset();  // Release the lock to avoid deadlocks.
   DCHECK(!frame_copy_requests_.empty());
   std::move(frame_copy_requests_.front().frame_ready_cb).Run(frame);
   frame_copy_requests_.pop_front();
@@ -963,12 +960,10 @@
   }
 
   // Create the resources.
-  std::unique_ptr<GpuVideoAcceleratorFactories::ScopedGLContextLock> lock(
-      gpu_factories_->GetGLContextLock());
-  if (!lock)
+  gpu::gles2::GLES2Interface* gles2 = gpu_factories_->ContextGL();
+  if (!gles2)
     return nullptr;
 
-  gpu::gles2::GLES2Interface* gles2 = lock->ContextGL();
   gles2->ActiveTexture(GL_TEXTURE0);
   FrameResources* frame_resources = new FrameResources(size);
   resources_pool_.push_back(frame_resources);
@@ -1007,11 +1002,9 @@
   // make sure that we won't execute this callback (use a weak pointer to
   // the old context).
 
-  std::unique_ptr<GpuVideoAcceleratorFactories::ScopedGLContextLock> lock(
-      gpu_factories->GetGLContextLock());
-  if (!lock)
+  gpu::gles2::GLES2Interface* gles2 = gpu_factories->ContextGL();
+  if (!gles2)
     return;
-  gpu::gles2::GLES2Interface* gles2 = lock->ContextGL();
 
   for (PlaneResource& plane_resource : frame_resources->plane_resources) {
     if (plane_resource.image_id)
diff --git a/media/video/gpu_video_accelerator_factories.h b/media/video/gpu_video_accelerator_factories.h
index ceab408..3d8065c 100644
--- a/media/video/gpu_video_accelerator_factories.h
+++ b/media/video/gpu_video_accelerator_factories.h
@@ -53,17 +53,6 @@
 //   loop.
 class MEDIA_EXPORT GpuVideoAcceleratorFactories {
  public:
-  class ScopedGLContextLock {
-   public:
-    ScopedGLContextLock() = default;
-    virtual ~ScopedGLContextLock() = default;
-
-    virtual gpu::gles2::GLES2Interface* ContextGL() = 0;
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(ScopedGLContextLock);
-  };
-
   enum class OutputFormat {
     UNDEFINED = 0,    // Unset state
     I420,             // 3 x R8 GMBs
@@ -121,7 +110,11 @@
   // video frames are enabled.
   virtual OutputFormat VideoFrameOutputFormat(size_t bit_depth) = 0;
 
-  virtual std::unique_ptr<ScopedGLContextLock> GetGLContextLock() = 0;
+  // Returns a GL Context that can be used on the task runner associated with
+  // the same instance of GpuVideoAcceleratorFactories.
+  // nullptr will be returned in cases where a context couldn't be created or
+  // the context was lost.
+  virtual gpu::gles2::GLES2Interface* ContextGL() = 0;
 
   // Allocate & return a shared memory segment.
   virtual std::unique_ptr<base::SharedMemory> CreateSharedMemory(
diff --git a/media/video/mock_gpu_video_accelerator_factories.cc b/media/video/mock_gpu_video_accelerator_factories.cc
index 9870eff..fadb1e23 100644
--- a/media/video/mock_gpu_video_accelerator_factories.cc
+++ b/media/video/mock_gpu_video_accelerator_factories.cc
@@ -130,25 +130,4 @@
   return GL_TEXTURE_2D;
 }
 
-namespace {
-class ScopedGLContextLockImpl
-    : public GpuVideoAcceleratorFactories::ScopedGLContextLock {
- public:
-  ScopedGLContextLockImpl(MockGpuVideoAcceleratorFactories* gpu_factories)
-      : gpu_factories_(gpu_factories) {}
-  gpu::gles2::GLES2Interface* ContextGL() override {
-    return gpu_factories_->GetGLES2Interface();
-  }
-
- private:
-  MockGpuVideoAcceleratorFactories* gpu_factories_;
-};
-}  // namespace
-
-std::unique_ptr<GpuVideoAcceleratorFactories::ScopedGLContextLock>
-MockGpuVideoAcceleratorFactories::GetGLContextLock() {
-  DCHECK(gles2_);
-  return std::make_unique<ScopedGLContextLockImpl>(this);
-}
-
 }  // namespace media
diff --git a/media/video/mock_gpu_video_accelerator_factories.h b/media/video/mock_gpu_video_accelerator_factories.h
index a95fd5c..d5fe8a5 100644
--- a/media/video/mock_gpu_video_accelerator_factories.h
+++ b/media/video/mock_gpu_video_accelerator_factories.h
@@ -68,7 +68,7 @@
     return video_frame_output_format_;
   };
 
-  std::unique_ptr<ScopedGLContextLock> GetGLContextLock() override;
+  gpu::gles2::GLES2Interface* ContextGL() override { return gles2_; }
 
   void SetVideoFrameOutputFormat(const OutputFormat video_frame_output_format) {
     video_frame_output_format_ = video_frame_output_format;
diff --git a/mojo/BUILD.gn b/mojo/BUILD.gn
index 664daace..fcc91bbf 100644
--- a/mojo/BUILD.gn
+++ b/mojo/BUILD.gn
@@ -61,7 +61,7 @@
     deps += [
       "//base",
       "//base/test:test_support",
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//mojo/edk/system:test_utils",
       "//testing/gtest",
     ]
diff --git a/mojo/android/BUILD.gn b/mojo/android/BUILD.gn
index f4932ff..223f859a 100644
--- a/mojo/android/BUILD.gn
+++ b/mojo/android/BUILD.gn
@@ -130,7 +130,7 @@
     "//base",
     "//base/test:test_support",
     "//build/config:exe_and_shlib_deps",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/bindings/tests:mojo_public_bindings_test_utils",
     "//mojo/public/cpp/test_support:test_utils",
   ]
diff --git a/mojo/edk/BUILD.gn b/mojo/edk/BUILD.gn
new file mode 100644
index 0000000..a5a2102
--- /dev/null
+++ b/mojo/edk/BUILD.gn
@@ -0,0 +1,113 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/nacl/config.gni")
+
+# Targets should depend on this if directly referencing the |mojo::edk|
+# namespace.
+component("edk") {
+  output_name = "mojo_edk"
+
+  public = [
+    "embedder/embedder.h",
+    "embedder/incoming_broker_client_invitation.h",
+    "embedder/outgoing_broker_client_invitation.h",
+    "embedder/peer_connection.h",
+  ]
+
+  sources = [
+    "embedder/embedder.cc",
+    "embedder/incoming_broker_client_invitation.cc",
+    "embedder/outgoing_broker_client_invitation.cc",
+    "embedder/peer_connection.cc",
+  ]
+
+  defines = [ "MOJO_SYSTEM_IMPL_IMPLEMENTATION" ]
+
+  deps = []
+  if (!is_nacl) {
+    deps += [ "//crypto" ]
+  }
+
+  public_deps = [
+    ":core",
+    "//mojo/public/cpp/system",
+  ]
+}
+
+# Bits of the EDK library which do not depend on public API linkage. It is
+# not allowed for this target or any of its transitive dependencies to depend
+# on anything under //mojo/public beyond strict C type definitions.
+source_set("core") {
+  visibility = [ ":edk" ]
+
+  public = [
+    "embedder/configuration.h",
+    "embedder/connection_params.h",
+    "embedder/embedder_internal.h",
+    "embedder/entrypoints.h",
+    "embedder/named_platform_channel_pair.h",
+    "embedder/named_platform_handle.h",
+    "embedder/named_platform_handle_utils.h",
+    "embedder/platform_channel_pair.h",
+    "embedder/platform_handle.h",
+    "embedder/platform_handle_utils.h",
+    "embedder/process_error_callback.h",
+    "embedder/scoped_ipc_support.h",
+    "embedder/scoped_platform_handle.h",
+    "embedder/transport_protocol.h",
+  ]
+
+  sources = [
+    "embedder/connection_params.cc",
+    "embedder/entrypoints.cc",
+    "embedder/named_platform_channel_pair_win.cc",
+    "embedder/named_platform_handle_utils_win.cc",
+    "embedder/platform_channel_pair.cc",
+    "embedder/platform_channel_pair_win.cc",
+    "embedder/platform_handle.cc",
+    "embedder/platform_handle_utils_win.cc",
+    "embedder/platform_shared_buffer.cc",
+    "embedder/scoped_ipc_support.cc",
+  ]
+
+  if (is_fuchsia) {
+    sources += [
+      "embedder/named_platform_handle_utils_fuchsia.cc",
+      "embedder/platform_channel_pair_fuchsia.cc",
+      "embedder/platform_handle_utils_fuchsia.cc",
+    ]
+  } else if (is_posix) {
+    public += [ "embedder/platform_channel_utils_posix.h" ]
+
+    sources += [
+      "embedder/platform_channel_pair_posix.cc",
+      "embedder/platform_channel_utils_posix.cc",
+      "embedder/platform_handle_utils_posix.cc",
+    ]
+
+    if (!is_nacl) {
+      sources += [ "embedder/named_platform_handle_utils_posix.cc" ]
+    }
+  }
+
+  if (is_nacl && !is_nacl_nonsfi) {
+    sources -= [ "embedder/platform_channel_utils_posix.cc" ]
+  }
+
+  defines = [ "MOJO_SYSTEM_IMPL_IMPLEMENTATION" ]
+
+  public_deps = [
+    "//base",
+    "//mojo/edk/system",
+    "//mojo/public/c/system:headers",
+  ]
+
+  deps = []
+  if (is_android) {
+    deps += [ "//third_party/ashmem" ]
+  }
+
+  allow_circular_includes_from = [ "//mojo/edk/system" ]
+}
diff --git a/mojo/edk/embedder/BUILD.gn b/mojo/edk/embedder/BUILD.gn
index fa60f2f7..3528cb32 100644
--- a/mojo/edk/embedder/BUILD.gn
+++ b/mojo/edk/embedder/BUILD.gn
@@ -2,142 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/config/nacl/config.gni")
-
-source_set("headers") {
-  sources = [
-    "configuration.h",
-    "connection_params.h",
-    "embedder.h",
-    "embedder_internal.h",
-    "incoming_broker_client_invitation.h",
-    "named_platform_channel_pair.h",
-    "named_platform_handle.h",
-    "named_platform_handle_utils.h",
-    "outgoing_broker_client_invitation.h",
-    "peer_connection.h",
-    "platform_channel_pair.h",
-    "platform_handle.h",
-    "platform_handle_utils.h",
-    "scoped_ipc_support.h",
-    "scoped_platform_handle.h",
-    "transport_protocol.h",
-  ]
-
-  public_deps = [
-    "//base",
-    "//mojo/public/cpp/system",
-  ]
-}
-
-source_set("embedder") {
-  # This isn't really a standalone target; it must be linked into the
-  # mojo_system_impl component.
-  visibility = [
-    "//mojo/edk/system",
-    "//components/nacl:nacl",
-  ]
-
-  sources = [
-    "configuration.h",
-    "connection_params.cc",
-    "embedder.cc",
-    "entrypoints.cc",
-    "entrypoints.h",
-    "incoming_broker_client_invitation.cc",
-    "outgoing_broker_client_invitation.cc",
-    "peer_connection.cc",
-    "scoped_ipc_support.cc",
-
-    # Test-only code:
-    # TODO(vtl): It's a little unfortunate that these end up in the same
-    # component as non-test-only code. In the static build, this code should
-    # hopefully be dead-stripped.
-    "test_embedder.cc",
-    "test_embedder.h",
-  ]
-
-  defines = [ "MOJO_SYSTEM_IMPL_IMPLEMENTATION" ]
-
-  deps = [
-    "//mojo/edk/system/ports",
-  ]
-
-  public_deps = [
-    ":headers",
-    ":platform",
-    "//base",
-    "//mojo/public/cpp/system",
-  ]
-
-  if (!is_nacl) {
-    deps += [ "//crypto" ]
-  }
-}
-
-source_set("platform") {
-  # This isn't really a standalone target; it must be linked into the
-  # mojo_system_impl component.
-  visibility = [
-    ":embedder",
-    "//mojo/edk/system",
-  ]
-
-  sources = [
-    "named_platform_channel_pair.h",
-    "named_platform_channel_pair_win.cc",
-    "named_platform_handle.h",
-    "named_platform_handle_utils.h",
-    "named_platform_handle_utils_win.cc",
-    "platform_channel_pair.cc",
-    "platform_channel_pair.h",
-    "platform_channel_pair_win.cc",
-    "platform_handle.cc",
-    "platform_handle.h",
-    "platform_handle_utils.h",
-    "platform_handle_utils_win.cc",
-    "platform_shared_buffer.cc",
-    "platform_shared_buffer.h",
-    "scoped_platform_handle.h",
-  ]
-
-  if (is_fuchsia) {
-    sources += [
-      "named_platform_handle_utils_fuchsia.cc",
-      "platform_channel_pair_fuchsia.cc",
-      "platform_handle_utils_fuchsia.cc",
-    ]
-  } else if (is_posix) {
-    sources += [
-      "platform_channel_pair_posix.cc",
-      "platform_channel_utils_posix.cc",
-      "platform_channel_utils_posix.h",
-      "platform_handle_utils_posix.cc",
-    ]
-    if (!is_nacl) {
-      sources += [ "named_platform_handle_utils_posix.cc" ]
-    }
-  }
-
-  if (is_nacl && !is_nacl_nonsfi) {
-    sources -= [ "platform_channel_utils_posix.cc" ]
-  }
-
-  defines = [ "MOJO_SYSTEM_IMPL_IMPLEMENTATION" ]
-
-  public_deps = [
-    "//mojo/public/cpp/system",
-  ]
-
-  deps = [
-    "//base",
-  ]
-
-  if (is_android) {
-    deps += [ "//third_party/ashmem" ]
-  }
-}
-
 source_set("embedder_unittests") {
   testonly = true
 
@@ -156,7 +20,7 @@
   deps = [
     "//base",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/edk/system:test_utils",
     "//mojo/edk/test:test_support",
     "//testing/gtest",
diff --git a/mojo/edk/embedder/README.md b/mojo/edk/embedder/README.md
index 83ed35c..30dd151 100644
--- a/mojo/edk/embedder/README.md
+++ b/mojo/edk/embedder/README.md
@@ -8,10 +8,9 @@
 The Mojo EDK is a (binary-unstable) API which enables a process to use Mojo both
 internally and for IPC to other Mojo-embedding processes.
 
-Using any of the API surface in `//mojo/edk/embedder` requires (somewhat
-confusingly) a direct dependency on the GN `//mojo/edk/system` target. Despite
-this fact, you should never reference any of the headers in `mojo/edk/system`
-directly, as everything there is considered to be an internal detail of the EDK.
+Using any of the API surface in `//mojo/edk/embedder` requires a direct
+dependency on the GN `//mojo/edk` target. Headers in `mojo/edk/system` are
+reserved for internal use by the EDK only.
 
 **NOTE:** Unless you are introducing a new binary entry point into the system
 (*e.g.,* a new executable with a new `main()` definition), you probably don't
diff --git a/mojo/edk/embedder/incoming_broker_client_invitation.cc b/mojo/edk/embedder/incoming_broker_client_invitation.cc
index 80a3a26..4bb7374 100644
--- a/mojo/edk/embedder/incoming_broker_client_invitation.cc
+++ b/mojo/edk/embedder/incoming_broker_client_invitation.cc
@@ -38,7 +38,8 @@
 
 ScopedMessagePipeHandle IncomingBrokerClientInvitation::ExtractMessagePipe(
     const std::string& name) {
-  return internal::g_core->ExtractMessagePipeFromInvitation(name);
+  return ScopedMessagePipeHandle(MessagePipeHandle(
+      internal::g_core->ExtractMessagePipeFromInvitation(name)));
 }
 
 IncomingBrokerClientInvitation::IncomingBrokerClientInvitation(
diff --git a/mojo/edk/embedder/outgoing_broker_client_invitation.cc b/mojo/edk/embedder/outgoing_broker_client_invitation.cc
index 718b8d2..f66a33e 100644
--- a/mojo/edk/embedder/outgoing_broker_client_invitation.cc
+++ b/mojo/edk/embedder/outgoing_broker_client_invitation.cc
@@ -28,8 +28,8 @@
     const std::string& name) {
   DCHECK(!sent_);
   ports::PortRef port;
-  ScopedMessagePipeHandle pipe =
-      internal::g_core->CreatePartialMessagePipe(&port);
+  ScopedMessagePipeHandle pipe = ScopedMessagePipeHandle(
+      MessagePipeHandle(internal::g_core->CreatePartialMessagePipe(&port)));
   attached_ports_.emplace_back(name, port);
   return pipe;
 }
@@ -42,8 +42,8 @@
   // a single entry.
   for (auto it = attached_ports_.begin(); it != attached_ports_.end(); ++it) {
     if (it->first == name) {
-      ScopedMessagePipeHandle pipe =
-          internal::g_core->CreatePartialMessagePipe(it->second);
+      ScopedMessagePipeHandle pipe = ScopedMessagePipeHandle(MessagePipeHandle(
+          internal::g_core->CreatePartialMessagePipe(it->second)));
       attached_ports_.erase(it);
       return pipe;
     }
diff --git a/mojo/edk/embedder/peer_connection.cc b/mojo/edk/embedder/peer_connection.cc
index 77b26488..a4139b5 100644
--- a/mojo/edk/embedder/peer_connection.cc
+++ b/mojo/edk/embedder/peer_connection.cc
@@ -22,7 +22,8 @@
   is_connected_ = true;
 
   ports::PortRef peer_port;
-  auto pipe = internal::g_core->CreatePartialMessagePipe(&peer_port);
+  auto pipe = ScopedMessagePipeHandle(MessagePipeHandle(
+      internal::g_core->CreatePartialMessagePipe(&peer_port)));
   connection_id_ =
       internal::g_core->ConnectToPeer(std::move(params), peer_port);
   return pipe;
diff --git a/mojo/edk/embedder/process_error_callback.h b/mojo/edk/embedder/process_error_callback.h
new file mode 100644
index 0000000..53234def
--- /dev/null
+++ b/mojo/edk/embedder/process_error_callback.h
@@ -0,0 +1,21 @@
+// Copyright 2018 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 MOJO_EDK_EMBEDDER_PROCESS_ERROR_CALLBACK_H_
+#define MOJO_EDK_EMBEDDER_PROCESS_ERROR_CALLBACK_H_
+
+#include <string>
+
+#include "base/callback.h"
+
+namespace mojo {
+namespace edk {
+
+using ProcessErrorCallback =
+    base::RepeatingCallback<void(const std::string& error)>;
+
+}  // namespace edk
+}  // namespace mojo
+
+#endif  // MOJO_EDK_EMBEDDER_PROCESS_ERROR_CALLBACK_H_
diff --git a/mojo/edk/embedder/scoped_ipc_support.cc b/mojo/edk/embedder/scoped_ipc_support.cc
index 03813bb..7d05f55 100644
--- a/mojo/edk/embedder/scoped_ipc_support.cc
+++ b/mojo/edk/embedder/scoped_ipc_support.cc
@@ -8,7 +8,6 @@
 #include "base/bind_helpers.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread_restrictions.h"
-#include "mojo/edk/embedder/embedder.h"
 #include "mojo/edk/embedder/embedder_internal.h"
 #include "mojo/edk/system/core.h"
 
diff --git a/mojo/edk/system/BUILD.gn b/mojo/edk/system/BUILD.gn
index 63bc3861..ad03c3ad 100644
--- a/mojo/edk/system/BUILD.gn
+++ b/mojo/edk/system/BUILD.gn
@@ -10,8 +10,10 @@
   import("//build/config/android/rules.gni")
 }
 
-component("system") {
-  output_name = "mojo_system_impl"
+source_set("system") {
+  # All sources in this target should really just be private sources in
+  # "//mojo/edk:core". Make sure that's the only target than can see this one.
+  visibility = [ "//mojo/edk:core" ]
 
   sources = [
     "atomic_flag.h",
@@ -89,11 +91,8 @@
   defines = [ "MOJO_SYSTEM_IMPL_IMPLEMENTATION" ]
 
   public_deps = [
-    "//mojo/edk/embedder",
-    "//mojo/edk/embedder:platform",
     "//mojo/edk/system/ports",
-    "//mojo/public/c/system",
-    "//mojo/public/cpp/system",
+    "//mojo/public/c/system:headers",
   ]
 
   deps = [
@@ -114,8 +113,6 @@
   if (is_android || target_os == "chromeos") {
     defines += [ "MOJO_EDK_LEGACY_PROTOCOL" ]
   }
-
-  allow_circular_includes_from = [ "//mojo/edk/embedder" ]
 }
 
 source_set("test_utils") {
@@ -169,8 +166,8 @@
     ":test_utils",
     "//base",
     "//base/test:test_support",
+    "//mojo/edk",
     "//mojo/edk/embedder:embedder_unittests",
-    "//mojo/edk/system",
     "//mojo/edk/system/ports:tests",
     "//mojo/edk/test:run_all_unittests",
     "//mojo/edk/test:test_support",
diff --git a/mojo/edk/system/broker_host.h b/mojo/edk/system/broker_host.h
index ccfbce8..3f1b7ce 100644
--- a/mojo/edk/system/broker_host.h
+++ b/mojo/edk/system/broker_host.h
@@ -12,7 +12,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/process/process_handle.h"
 #include "base/strings/string_piece.h"
-#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/process_error_callback.h"
 #include "mojo/edk/embedder/scoped_platform_handle.h"
 #include "mojo/edk/system/channel.h"
 
diff --git a/mojo/edk/system/core.cc b/mojo/edk/system/core.cc
index eaa6937..f5bcbcc 100644
--- a/mojo/edk/system/core.cc
+++ b/mojo/edk/system/core.cc
@@ -20,9 +20,9 @@
 #include "base/time/time.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "build/build_config.h"
-#include "mojo/edk/embedder/embedder.h"
 #include "mojo/edk/embedder/embedder_internal.h"
 #include "mojo/edk/embedder/platform_shared_buffer.h"
+#include "mojo/edk/embedder/process_error_callback.h"
 #include "mojo/edk/system/channel.h"
 #include "mojo/edk/system/configuration.h"
 #include "mojo/edk/system/data_pipe_consumer_dispatcher.h"
@@ -186,21 +186,18 @@
   default_process_error_callback_ = callback;
 }
 
-ScopedMessagePipeHandle Core::CreatePartialMessagePipe(ports::PortRef* peer) {
+MojoHandle Core::CreatePartialMessagePipe(ports::PortRef* peer) {
   RequestContext request_context;
   ports::PortRef local_port;
   GetNodeController()->node()->CreatePortPair(&local_port, peer);
-  MojoHandle handle = AddDispatcher(new MessagePipeDispatcher(
+  return AddDispatcher(new MessagePipeDispatcher(
       GetNodeController(), local_port, kUnknownPipeIdForDebug, 0));
-  return ScopedMessagePipeHandle(MessagePipeHandle(handle));
 }
 
-ScopedMessagePipeHandle Core::CreatePartialMessagePipe(
-    const ports::PortRef& port) {
+MojoHandle Core::CreatePartialMessagePipe(const ports::PortRef& port) {
   RequestContext request_context;
-  return ScopedMessagePipeHandle(
-      MessagePipeHandle(AddDispatcher(new MessagePipeDispatcher(
-          GetNodeController(), port, kUnknownPipeIdForDebug, 1))));
+  return AddDispatcher(new MessagePipeDispatcher(GetNodeController(), port,
+                                                 kUnknownPipeIdForDebug, 1));
 }
 
 void Core::SendBrokerClientInvitation(
@@ -382,15 +379,14 @@
   GetNodeController()->RequestShutdown(callback);
 }
 
-ScopedMessagePipeHandle Core::ExtractMessagePipeFromInvitation(
-    const std::string& name) {
+MojoHandle Core::ExtractMessagePipeFromInvitation(const std::string& name) {
   RequestContext request_context;
   ports::PortRef port0, port1;
   GetNodeController()->node()->CreatePortPair(&port0, &port1);
   MojoHandle handle = AddDispatcher(new MessagePipeDispatcher(
       GetNodeController(), port0, kUnknownPipeIdForDebug, 1));
   GetNodeController()->MergePortIntoInviter(name, port1);
-  return ScopedMessagePipeHandle(MessagePipeHandle(handle));
+  return handle;
 }
 
 MojoResult Core::SetProperty(MojoPropertyType type, const void* value) {
diff --git a/mojo/edk/system/core.h b/mojo/edk/system/core.h
index b8deb3c..6ac8cf6 100644
--- a/mojo/edk/system/core.h
+++ b/mojo/edk/system/core.h
@@ -28,7 +28,6 @@
 #include "mojo/public/c/system/platform_handle.h"
 #include "mojo/public/c/system/trap.h"
 #include "mojo/public/c/system/types.h"
-#include "mojo/public/cpp/system/message_pipe.h"
 
 namespace base {
 class PortProvider;
@@ -61,11 +60,11 @@
   //
   // The value returned in |*peer| may be passed along with a broker client
   // invitation. See SendBrokerClientInvitation() below.
-  ScopedMessagePipeHandle CreatePartialMessagePipe(ports::PortRef* peer);
+  MojoHandle CreatePartialMessagePipe(ports::PortRef* peer);
 
   // Like above but exchanges an existing ports::PortRef for a message pipe
   // handle which wraps it.
-  ScopedMessagePipeHandle CreatePartialMessagePipe(const ports::PortRef& port);
+  MojoHandle CreatePartialMessagePipe(const ports::PortRef& port);
 
   // Sends a broker client invitation to |target_process| over the connection
   // medium in |connection_params|. The other end of the connection medium in
@@ -90,8 +89,7 @@
   // Extracts a named message pipe endpoint from the broker client invitation
   // accepted by this process. Must only be called after
   // AcceptBrokerClientInvitation.
-  ScopedMessagePipeHandle ExtractMessagePipeFromInvitation(
-      const std::string& name);
+  MojoHandle ExtractMessagePipeFromInvitation(const std::string& name);
 
   // Called to connect to a peer process. This should be called only if there
   // is no common ancestor for the processes involved within this mojo system.
diff --git a/mojo/edk/system/handle_signals_state.h b/mojo/edk/system/handle_signals_state.h
index f241278..c8c5b5ea 100644
--- a/mojo/edk/system/handle_signals_state.h
+++ b/mojo/edk/system/handle_signals_state.h
@@ -5,9 +5,102 @@
 #ifndef MOJO_EDK_SYSTEM_HANDLE_SIGNALS_STATE_H_
 #define MOJO_EDK_SYSTEM_HANDLE_SIGNALS_STATE_H_
 
-#include "mojo/public/cpp/system/handle_signals_state.h"
+#include "mojo/edk/system/system_impl_export.h"
+#include "mojo/public/c/system/types.h"
 
-// TODO(rockot): Remove this header and use the C++ system library type
-// directly inside the EDK.
+namespace mojo {
+namespace edk {
+
+// A convenience wrapper around the MojoHandleSignalsState struct.
+//
+// NOTE: This is duplicated in the public C++ SDK to avoid circular
+// dependencies between the EDK and the public SDK.
+struct MOJO_SYSTEM_IMPL_EXPORT HandleSignalsState final
+    : public MojoHandleSignalsState {
+  HandleSignalsState() {
+    satisfied_signals = MOJO_HANDLE_SIGNAL_NONE;
+    satisfiable_signals = MOJO_HANDLE_SIGNAL_NONE;
+  }
+
+  HandleSignalsState(MojoHandleSignals satisfied,
+                     MojoHandleSignals satisfiable) {
+    satisfied_signals = satisfied;
+    satisfiable_signals = satisfiable;
+  }
+
+  bool operator==(const HandleSignalsState& other) const {
+    return satisfied_signals == other.satisfied_signals &&
+           satisfiable_signals == other.satisfiable_signals;
+  }
+
+  // TODO(rockot): Remove this in favor of operator==.
+  bool equals(const HandleSignalsState& other) const {
+    return satisfied_signals == other.satisfied_signals &&
+           satisfiable_signals == other.satisfiable_signals;
+  }
+
+  bool satisfies_any(MojoHandleSignals signals) const {
+    return !!(satisfied_signals & signals);
+  }
+
+  bool satisfies_all(MojoHandleSignals signals) const {
+    return (satisfied_signals & signals) == signals;
+  }
+
+  bool can_satisfy_any(MojoHandleSignals signals) const {
+    return !!(satisfiable_signals & signals);
+  }
+
+  // The handle is currently readable. May apply to a message pipe handle or
+  // data pipe consumer handle.
+  bool readable() const { return satisfies_any(MOJO_HANDLE_SIGNAL_READABLE); }
+
+  // The handle is currently writable. May apply to a message pipe handle or
+  // data pipe producer handle.
+  bool writable() const { return satisfies_any(MOJO_HANDLE_SIGNAL_WRITABLE); }
+
+  // The handle's peer is closed. May apply to any message pipe or data pipe
+  // handle.
+  bool peer_closed() const {
+    return satisfies_any(MOJO_HANDLE_SIGNAL_PEER_CLOSED);
+  }
+
+  // The handle's peer exists in a remote execution context (e.g. in another
+  // process.)
+  bool peer_remote() const {
+    return satisfies_any(MOJO_HANDLE_SIGNAL_PEER_REMOTE);
+  }
+
+  // The handle will never be |readable()| again.
+  bool never_readable() const {
+    return !can_satisfy_any(MOJO_HANDLE_SIGNAL_READABLE);
+  }
+
+  // The handle will never be |writable()| again.
+  bool never_writable() const {
+    return !can_satisfy_any(MOJO_HANDLE_SIGNAL_WRITABLE);
+  }
+
+  // The handle can never indicate |peer_closed()|. Never true for message pipe
+  // or data pipe handles (they can always signal peer closure), but always true
+  // for other types of handles (they have no peer.)
+  bool never_peer_closed() const {
+    return !can_satisfy_any(MOJO_HANDLE_SIGNAL_PEER_CLOSED);
+  }
+
+  // The handle will never indicate |peer_remote()| again. True iff the peer is
+  // known to be closed.
+  bool never_peer_remote() const {
+    return !can_satisfy_any(MOJO_HANDLE_SIGNAL_PEER_REMOTE);
+  }
+
+  // (Copy and assignment allowed.)
+};
+
+static_assert(sizeof(HandleSignalsState) == sizeof(MojoHandleSignalsState),
+              "HandleSignalsState should add no overhead");
+
+}  // namespace edk
+}  // namespace mojo
 
 #endif  // MOJO_EDK_SYSTEM_HANDLE_SIGNALS_STATE_H_
diff --git a/mojo/edk/system/node_channel.h b/mojo/edk/system/node_channel.h
index 657534f9..864ed1c 100644
--- a/mojo/edk/system/node_channel.h
+++ b/mojo/edk/system/node_channel.h
@@ -17,7 +17,7 @@
 #include "base/task_runner.h"
 #include "build/build_config.h"
 #include "mojo/edk/embedder/connection_params.h"
-#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/process_error_callback.h"
 #include "mojo/edk/embedder/scoped_platform_handle.h"
 #include "mojo/edk/system/channel.h"
 #include "mojo/edk/system/ports/name.h"
diff --git a/mojo/edk/system/node_controller.h b/mojo/edk/system/node_controller.h
index 1e929bb3..853442d 100644
--- a/mojo/edk/system/node_controller.h
+++ b/mojo/edk/system/node_controller.h
@@ -28,6 +28,7 @@
 #include "mojo/edk/system/ports/name.h"
 #include "mojo/edk/system/ports/node.h"
 #include "mojo/edk/system/ports/node_delegate.h"
+#include "mojo/edk/system/system_impl_export.h"
 
 namespace base {
 class PortProvider;
@@ -42,8 +43,8 @@
 
 // The owner of ports::Node which facilitates core EDK implementation. All
 // public interface methods are safe to call from any thread.
-class NodeController : public ports::NodeDelegate,
-                       public NodeChannel::Delegate {
+class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate,
+                                               public NodeChannel::Delegate {
  public:
   class PortObserver : public ports::UserData {
    public:
diff --git a/mojo/edk/system/ports/BUILD.gn b/mojo/edk/system/ports/BUILD.gn
index 42fd523..1a5ba79 100644
--- a/mojo/edk/system/ports/BUILD.gn
+++ b/mojo/edk/system/ports/BUILD.gn
@@ -4,7 +4,9 @@
 
 import("//testing/test.gni")
 
-source_set("ports") {
+component("ports") {
+  output_name = "mojo_edk_ports"
+
   sources = [
     "event.cc",
     "event.h",
@@ -27,6 +29,8 @@
     "user_message.h",
   ]
 
+  defines = [ "IS_MOJO_EDK_PORTS_IMPL" ]
+
   public_deps = [
     "//base",
   ]
diff --git a/mojo/edk/system/ports/event.h b/mojo/edk/system/ports/event.h
index 27dc4fdd..ab8a4d8 100644
--- a/mojo/edk/system/ports/event.h
+++ b/mojo/edk/system/ports/event.h
@@ -9,6 +9,7 @@
 
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "mojo/edk/system/ports/name.h"
@@ -24,7 +25,7 @@
 
 // A Event is the fundamental unit of operation and communication within and
 // between Nodes.
-class Event {
+class COMPONENT_EXPORT(MOJO_EDK_PORTS) Event {
  public:
   enum Type : uint32_t {
     // A user message event contains arbitrary user-specified payload data
@@ -102,7 +103,7 @@
   DISALLOW_COPY_AND_ASSIGN(Event);
 };
 
-class UserMessageEvent : public Event {
+class COMPONENT_EXPORT(MOJO_EDK_PORTS) UserMessageEvent : public Event {
  public:
   explicit UserMessageEvent(size_t num_ports);
   ~UserMessageEvent() override;
@@ -152,7 +153,7 @@
   DISALLOW_COPY_AND_ASSIGN(UserMessageEvent);
 };
 
-class PortAcceptedEvent : public Event {
+class COMPONENT_EXPORT(MOJO_EDK_PORTS) PortAcceptedEvent : public Event {
  public:
   explicit PortAcceptedEvent(const PortName& port_name);
   ~PortAcceptedEvent() override;
@@ -168,7 +169,7 @@
   DISALLOW_COPY_AND_ASSIGN(PortAcceptedEvent);
 };
 
-class ObserveProxyEvent : public Event {
+class COMPONENT_EXPORT(MOJO_EDK_PORTS) ObserveProxyEvent : public Event {
  public:
   ObserveProxyEvent(const PortName& port_name,
                     const NodeName& proxy_node_name,
@@ -203,7 +204,7 @@
   DISALLOW_COPY_AND_ASSIGN(ObserveProxyEvent);
 };
 
-class ObserveProxyAckEvent : public Event {
+class COMPONENT_EXPORT(MOJO_EDK_PORTS) ObserveProxyAckEvent : public Event {
  public:
   ObserveProxyAckEvent(const PortName& port_name, uint64_t last_sequence_num);
   ~ObserveProxyAckEvent() override;
@@ -224,7 +225,7 @@
   DISALLOW_COPY_AND_ASSIGN(ObserveProxyAckEvent);
 };
 
-class ObserveClosureEvent : public Event {
+class COMPONENT_EXPORT(MOJO_EDK_PORTS) ObserveClosureEvent : public Event {
  public:
   ObserveClosureEvent(const PortName& port_name, uint64_t last_sequence_num);
   ~ObserveClosureEvent() override;
@@ -248,7 +249,7 @@
   DISALLOW_COPY_AND_ASSIGN(ObserveClosureEvent);
 };
 
-class MergePortEvent : public Event {
+class COMPONENT_EXPORT(MOJO_EDK_PORTS) MergePortEvent : public Event {
  public:
   MergePortEvent(const PortName& port_name,
                  const PortName& new_port_name,
diff --git a/mojo/edk/system/ports/message_queue.h b/mojo/edk/system/ports/message_queue.h
index 3dc6226..829d2172 100644
--- a/mojo/edk/system/ports/message_queue.h
+++ b/mojo/edk/system/ports/message_queue.h
@@ -11,6 +11,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "mojo/edk/system/ports/event.h"
 
@@ -27,7 +28,7 @@
 // known sequence number and can indicate whether the next sequential message is
 // available. Thus the queue enforces message ordering for the consumer without
 // enforcing it for the producer (see AcceptMessage() below.)
-class MessageQueue {
+class COMPONENT_EXPORT(MOJO_EDK_PORTS) MessageQueue {
  public:
   explicit MessageQueue();
   explicit MessageQueue(uint64_t next_sequence_num);
diff --git a/mojo/edk/system/ports/name.h b/mojo/edk/system/ports/name.h
index 72e41b92..80d7ffc 100644
--- a/mojo/edk/system/ports/name.h
+++ b/mojo/edk/system/ports/name.h
@@ -10,13 +10,14 @@
 #include <ostream>
 #include <tuple>
 
+#include "base/component_export.h"
 #include "base/hash.h"
 
 namespace mojo {
 namespace edk {
 namespace ports {
 
-struct Name {
+struct COMPONENT_EXPORT(MOJO_EDK_PORTS) Name {
   Name(uint64_t v1, uint64_t v2) : v1(v1), v2(v2) {}
   uint64_t v1, v2;
 };
@@ -33,21 +34,22 @@
   return std::tie(a.v1, a.v2) < std::tie(b.v1, b.v2);
 }
 
+COMPONENT_EXPORT(MOJO_EDK_PORTS)
 std::ostream& operator<<(std::ostream& stream, const Name& name);
 
-struct PortName : Name {
+struct COMPONENT_EXPORT(MOJO_EDK_PORTS) PortName : Name {
   PortName() : Name(0, 0) {}
   PortName(uint64_t v1, uint64_t v2) : Name(v1, v2) {}
 };
 
-extern const PortName kInvalidPortName;
+extern COMPONENT_EXPORT(MOJO_EDK_PORTS) const PortName kInvalidPortName;
 
-struct NodeName : Name {
+struct COMPONENT_EXPORT(MOJO_EDK_PORTS) NodeName : Name {
   NodeName() : Name(0, 0) {}
   NodeName(uint64_t v1, uint64_t v2) : Name(v1, v2) {}
 };
 
-extern const NodeName kInvalidNodeName;
+extern COMPONENT_EXPORT(MOJO_EDK_PORTS) const NodeName kInvalidNodeName;
 
 }  // namespace ports
 }  // namespace edk
@@ -56,14 +58,14 @@
 namespace std {
 
 template <>
-struct hash<mojo::edk::ports::PortName> {
+struct COMPONENT_EXPORT(MOJO_EDK_PORTS) hash<mojo::edk::ports::PortName> {
   std::size_t operator()(const mojo::edk::ports::PortName& name) const {
     return base::HashInts64(name.v1, name.v2);
   }
 };
 
 template <>
-struct hash<mojo::edk::ports::NodeName> {
+struct COMPONENT_EXPORT(MOJO_EDK_PORTS) hash<mojo::edk::ports::NodeName> {
   std::size_t operator()(const mojo::edk::ports::NodeName& name) const {
     return base::HashInts64(name.v1, name.v2);
   }
diff --git a/mojo/edk/system/ports/node.h b/mojo/edk/system/ports/node.h
index 5bc8a12..ec4bbbc 100644
--- a/mojo/edk/system/ports/node.h
+++ b/mojo/edk/system/ports/node.h
@@ -11,6 +11,7 @@
 #include <queue>
 #include <unordered_map>
 
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
@@ -61,7 +62,7 @@
 // by Nodes to coordinate Port behavior and lifetime within and across Nodes.
 // See Event documentation for description of different types of events used by
 // a Node to coordinate behavior.
-class Node {
+class COMPONENT_EXPORT(MOJO_EDK_PORTS) Node {
  public:
   enum class ShutdownPolicy {
     DONT_ALLOW_LOCAL_PORTS,
diff --git a/mojo/edk/system/ports/port_ref.h b/mojo/edk/system/ports/port_ref.h
index dce317e..9bafe38 100644
--- a/mojo/edk/system/ports/port_ref.h
+++ b/mojo/edk/system/ports/port_ref.h
@@ -5,6 +5,7 @@
 #ifndef MOJO_EDK_SYSTEM_PORTS_PORT_REF_H_
 #define MOJO_EDK_SYSTEM_PORTS_PORT_REF_H_
 
+#include "base/component_export.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "mojo/edk/system/ports/name.h"
@@ -16,7 +17,7 @@
 class Port;
 class PortLocker;
 
-class PortRef {
+class COMPONENT_EXPORT(MOJO_EDK_PORTS) PortRef {
  public:
   ~PortRef();
   PortRef();
diff --git a/mojo/edk/system/ports/user_message.h b/mojo/edk/system/ports/user_message.h
index 435e203c..b4414b2 100644
--- a/mojo/edk/system/ports/user_message.h
+++ b/mojo/edk/system/ports/user_message.h
@@ -5,6 +5,7 @@
 #ifndef MOJO_EDK_SYSTEM_PORTS_USER_MESSAGE_H_
 #define MOJO_EDK_SYSTEM_PORTS_USER_MESSAGE_H_
 
+#include "base/component_export.h"
 #include "base/macros.h"
 
 namespace mojo {
@@ -21,7 +22,7 @@
 // |kUserMessageTypeInfo| and pass its address down to the UserMessage
 // constructor. The type of a UserMessage can then be dynamically inspected by
 // comparing |type_info()| to any subclass's |&kUserMessageTypeInfo|.
-class UserMessage {
+class COMPONENT_EXPORT(MOJO_EDK_PORTS) UserMessage {
  public:
   struct TypeInfo {};
 
diff --git a/mojo/edk/system/user_message_impl.cc b/mojo/edk/system/user_message_impl.cc
index 1d971e4..da361229 100644
--- a/mojo/edk/system/user_message_impl.cc
+++ b/mojo/edk/system/user_message_impl.cc
@@ -18,7 +18,7 @@
 #include "mojo/edk/system/ports/event.h"
 #include "mojo/edk/system/ports/message_filter.h"
 #include "mojo/edk/system/ports/node.h"
-#include "mojo/public/cpp/system/handle.h"
+#include "mojo/public/c/system/types.h"
 
 namespace mojo {
 namespace edk {
@@ -273,7 +273,7 @@
     if (result == MOJO_RESULT_OK) {
       for (auto handle : handles) {
         if (handle != MOJO_HANDLE_INVALID)
-          MojoClose(handle);
+          internal::g_core->Close(handle);
       }
     }
 
@@ -281,7 +281,7 @@
       internal::g_core->ReleaseDispatchersForTransit(
           pending_handle_attachments_, false);
       for (const auto& dispatcher : pending_handle_attachments_)
-        MojoClose(dispatcher.local_handle);
+        internal::g_core->Close(dispatcher.local_handle);
     }
   }
 }
diff --git a/mojo/edk/system/user_message_impl.h b/mojo/edk/system/user_message_impl.h
index 8fe3ed9b..dc974c31 100644
--- a/mojo/edk/system/user_message_impl.h
+++ b/mojo/edk/system/user_message_impl.h
@@ -21,7 +21,6 @@
 #include "mojo/edk/system/system_impl_export.h"
 #include "mojo/public/c/system/message_pipe.h"
 #include "mojo/public/c/system/types.h"
-#include "mojo/public/cpp/system/handle.h"
 
 namespace mojo {
 namespace edk {
diff --git a/mojo/edk/test/BUILD.gn b/mojo/edk/test/BUILD.gn
index 1b4f996..427492c 100644
--- a/mojo/edk/test/BUILD.gn
+++ b/mojo/edk/test/BUILD.gn
@@ -27,7 +27,7 @@
   deps = [
     "//base",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/system",
     "//testing/gtest",
   ]
@@ -44,7 +44,7 @@
     ":test_support_impl",
     "//base",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/c/test_support",
     "//testing/gtest",
   ]
@@ -60,7 +60,7 @@
     ":test_support_impl",
     "//base",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/edk/test:test_support",
     "//mojo/public/c/test_support",
   ]
diff --git a/mojo/public/c/system/BUILD.gn b/mojo/public/c/system/BUILD.gn
index bf4a3a5..4d8605b1 100644
--- a/mojo/public/c/system/BUILD.gn
+++ b/mojo/public/c/system/BUILD.gn
@@ -6,6 +6,18 @@
   output_name = "mojo_public_system"
 
   sources = [
+    "thunks.cc",
+  ]
+
+  defines = [ "MOJO_SYSTEM_IMPLEMENTATION" ]
+
+  public_deps = [
+    ":headers",
+  ]
+}
+
+source_set("headers") {
+  public = [
     "buffer.h",
     "core.h",
     "data_pipe.h",
@@ -14,24 +26,8 @@
     "message_pipe.h",
     "platform_handle.h",
     "system_export.h",
-    "thunks.cc",
     "thunks.h",
     "trap.h",
     "types.h",
   ]
-
-  defines = [ "MOJO_SYSTEM_IMPLEMENTATION" ]
-}
-
-# This should ONLY be depended upon directly by shared_library targets which
-# need to export the MojoSetSystemThunks symbol, like targets generated by the
-# mojo_native_application template in //services/service_manager/public/cpp/service.gni.
-source_set("set_thunks_for_app") {
-  sources = [
-    "set_thunks_for_app.cc",
-  ]
-
-  public_deps = [
-    ":system",
-  ]
 }
diff --git a/mojo/public/cpp/bindings/tests/BUILD.gn b/mojo/public/cpp/bindings/tests/BUILD.gn
index 4ab1ff1c..b54000d 100644
--- a/mojo/public/cpp/bindings/tests/BUILD.gn
+++ b/mojo/public/cpp/bindings/tests/BUILD.gn
@@ -50,7 +50,7 @@
   deps = [
     ":mojo_public_bindings_test_utils",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
     "//mojo/public/cpp/test_support:test_utils",
@@ -134,7 +134,7 @@
 
   deps = [
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/edk/test:test_support",
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
diff --git a/mojo/public/tools/fuzzers/BUILD.gn b/mojo/public/tools/fuzzers/BUILD.gn
index 12d1b9f0..2c8a68a 100644
--- a/mojo/public/tools/fuzzers/BUILD.gn
+++ b/mojo/public/tools/fuzzers/BUILD.gn
@@ -25,7 +25,7 @@
   ]
   deps = [
     ":fuzz_mojom",
-    "//mojo/edk/system",
+    "//mojo/edk",
   ]
   seed_corpus = "//mojo/public/tools/fuzzers/message_corpus"
 }
@@ -41,7 +41,7 @@
       ":fuzz_mojom",
       "//base",
       "//build/config:exe_and_shlib_deps",
-      "//mojo/edk/system",
+      "//mojo/edk",
     ]
   }
 }
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 61319eb..8de382a 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -5589,7 +5589,7 @@
     deps += [
       ":net_browser_services",
       ":net_utility_services",
-      "//mojo/edk/system",
+      "//mojo/edk",
     ]
   } else {
     sources -= [
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index 1460130..45a38a88 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -3156,12 +3156,16 @@
   if (!delete_object) {
     // The simplest way to re-initialize partial_ is to create a new object.
     partial_.reset(new PartialData());
-    if (partial_->Init(request_->extra_headers))
+
+    // Reset the range header to the original value (http://crbug.com/820599).
+    custom_request_->extra_headers.RemoveHeader(HttpRequestHeaders::kRange);
+    if (partial_->Init(initial_request_->extra_headers))
       partial_->SetHeaders(custom_request_->extra_headers);
     else
       partial_.reset();
   }
 }
+
 void HttpCache::Transaction::ResetNetworkTransaction() {
   SaveNetworkTransactionInfo(*network_trans_);
   network_trans_.reset();
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index 83c838d..690f67a 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -1977,6 +1977,91 @@
   EXPECT_EQ(1, cache.disk_cache()->create_count());
 }
 
+// Tests a full request and a simultaneous range request and the range request
+// dooms the entry created by the full request due to not being able to
+// conditionalize.
+TEST(HttpCache, RangeGET_ParallelValidationCouldntConditionalize) {
+  MockHttpCache cache;
+
+  MockTransaction mock_transaction(kSimpleGET_Transaction);
+  mock_transaction.url = kRangeGET_TransactionOK.url;
+  ScopedMockTransaction transaction(mock_transaction);
+
+  // Remove the cache-control and other headers so that the response cannot be
+  // conditionalized.
+  transaction.response_headers = "";
+
+  std::vector<std::unique_ptr<Context>> context_list;
+  const int kNumTransactions = 2;
+
+  for (int i = 0; i < kNumTransactions; ++i) {
+    context_list.push_back(std::make_unique<Context>());
+  }
+
+  // Let 1st transaction complete headers phase for no range and read some part
+  // of the response and write in the cache.
+  std::string first_read;
+  MockHttpRequest request1(transaction);
+  {
+    request1.url = GURL(kRangeGET_TransactionOK.url);
+    auto& c = context_list[0];
+    c->result = cache.CreateTransaction(&c->trans);
+    ASSERT_THAT(c->result, IsOk());
+    EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+
+    c->result =
+        c->trans->Start(&request1, c->callback.callback(), NetLogWithSource());
+    base::RunLoop().RunUntilIdle();
+
+    const int kBufferSize = 5;
+    scoped_refptr<IOBuffer> buffer(new IOBuffer(kBufferSize));
+    ReleaseBufferCompletionCallback cb(buffer.get());
+    c->result = c->trans->Read(buffer.get(), kBufferSize, cb.callback());
+    EXPECT_EQ(kBufferSize, cb.GetResult(c->result));
+
+    std::string data_read(buffer->data(), kBufferSize);
+    first_read = data_read;
+
+    EXPECT_EQ(LOAD_STATE_READING_RESPONSE, c->trans->GetLoadState());
+  }
+
+  // 2nd transaction requests a range.
+  ScopedMockTransaction range_transaction(kRangeGET_TransactionOK);
+  range_transaction.request_headers = "Range: bytes = 0-29\r\n" EXTRA_HEADER;
+  MockHttpRequest request2(range_transaction);
+  {
+    auto& c = context_list[1];
+    c->result = cache.CreateTransaction(&c->trans);
+    ASSERT_THAT(c->result, IsOk());
+    EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+
+    c->result =
+        c->trans->Start(&request2, c->callback.callback(), NetLogWithSource());
+    base::RunLoop().RunUntilIdle();
+
+    EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+  }
+
+  // The second request would have doomed the 1st entry and created a new entry.
+  EXPECT_EQ(2, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(2, cache.disk_cache()->create_count());
+
+  for (int i = 0; i < kNumTransactions; ++i) {
+    auto& c = context_list[i];
+    if (c->result == ERR_IO_PENDING)
+      c->result = c->callback.WaitForResult();
+
+    if (i == 0) {
+      ReadRemainingAndVerifyTransaction(c->trans.get(), first_read,
+                                        transaction);
+      continue;
+    }
+    range_transaction.data = "rg: 00-09 rg: 10-19 rg: 20-29 ";
+    ReadAndVerifyTransaction(c->trans.get(), range_transaction);
+  }
+}
+
 // Tests parallel validation on range requests with overlapping ranges.
 TEST(HttpCache, RangeGET_ParallelValidationOverlappingRanges) {
   MockHttpCache cache;
diff --git a/net/http/http_cache_writers.cc b/net/http/http_cache_writers.cc
index 6bf0074..1ab3fbbc 100644
--- a/net/http/http_cache_writers.cc
+++ b/net/http/http_cache_writers.cc
@@ -283,6 +283,11 @@
     return false;
   }
 
+  if (response_info_truncation_.headers->HasHeader("Content-Encoding")) {
+    should_keep_entry_ = false;
+    return false;
+  }
+
   int64_t content_length =
       response_info_truncation_.headers->GetContentLength();
   if (content_length >= 0 && content_length <= current_size)
diff --git a/net/http/http_cache_writers_unittest.cc b/net/http/http_cache_writers_unittest.cc
index c386a62..86a943b 100644
--- a/net/http/http_cache_writers_unittest.cc
+++ b/net/http/http_cache_writers_unittest.cc
@@ -106,7 +106,8 @@
 
   void CreateWritersAddTransaction(
       HttpCache::ParallelWritingPattern parallel_writing_pattern_ =
-          HttpCache::PARALLEL_WRITING_JOIN) {
+          HttpCache::PARALLEL_WRITING_JOIN,
+      bool content_encoding_present = false) {
     TestCompletionCallback callback;
 
     // Create and Start a mock network transaction.
@@ -116,6 +117,8 @@
                                NetLogWithSource());
     base::RunLoop().RunUntilIdle();
     response_info_ = *(network_transaction->GetResponseInfo());
+    if (content_encoding_present)
+      response_info_.headers->AddHeader("Content-Encoding: gzip");
 
     // Create a mock cache transaction.
     std::unique_ptr<TestHttpCacheTransaction> transaction =
@@ -188,6 +191,28 @@
     return OK;
   }
 
+  int ReadFewBytes(std::string* result) {
+    EXPECT_TRUE(transactions_.size() >= (size_t)1);
+    TestHttpCacheTransaction* transaction = transactions_.begin()->get();
+    TestCompletionCallback callback;
+
+    std::string content;
+    int rv = 0;
+    scoped_refptr<IOBuffer> buf(new IOBuffer(5));
+    rv = writers_->Read(buf.get(), 5, callback.callback(), transaction);
+    if (rv == ERR_IO_PENDING) {
+      rv = callback.WaitForResult();
+      base::RunLoop().RunUntilIdle();
+    }
+
+    if (rv > 0)
+      result->append(buf->data(), rv);
+    else if (rv < 0)
+      return rv;
+
+    return OK;
+  }
+
   void ReadVerifyTwoDifferentBufferLengths(
       const std::vector<int>& buffer_lengths) {
     EXPECT_EQ(2u, buffer_lengths.size());
@@ -782,4 +807,17 @@
   EXPECT_FALSE(ShouldKeepEntry());
 }
 
+// Tests that if content-encoding is set, the entry should not be marked as
+// truncated, since we should not be creating range requests for compressed
+// entries.
+TEST_F(WritersTest, ContentEncodingShouldNotTruncate) {
+  CreateWritersAddTransaction(HttpCache::PARALLEL_WRITING_JOIN,
+                              true /* content_encoding_present */);
+  std::string result;
+  ReadFewBytes(&result);
+
+  EXPECT_FALSE(ShouldTruncate());
+  EXPECT_FALSE(ShouldKeepEntry());
+}
+
 }  // namespace net
diff --git a/net/quic/core/quic_connection.cc b/net/quic/core/quic_connection.cc
index e9e93ae..51534aa 100644
--- a/net/quic/core/quic_connection.cc
+++ b/net/quic/core/quic_connection.cc
@@ -788,6 +788,11 @@
   if (send_alarm_->IsSet()) {
     send_alarm_->Cancel();
   }
+
+  if (LargestAcked(incoming_ack) > sent_packet_manager_.GetLargestObserved()) {
+    visitor_->OnForwardProgressConfirmed();
+  }
+
   largest_seen_packet_with_ack_ = last_header_.packet_number;
   sent_packet_manager_.OnIncomingAck(incoming_ack,
                                      time_of_last_received_packet_);
@@ -830,7 +835,9 @@
     return false;
   }
 
-  if (largest_acked < sent_packet_manager_.GetLargestObserved()) {
+  if (largest_acked > sent_packet_manager_.GetLargestObserved()) {
+    visitor_->OnForwardProgressConfirmed();
+  } else if (largest_acked < sent_packet_manager_.GetLargestObserved()) {
     QUIC_LOG(INFO) << ENDPOINT << "Peer's largest_observed packet decreased:"
                    << largest_acked << " vs "
                    << sent_packet_manager_.GetLargestObserved()
diff --git a/net/quic/core/quic_connection.h b/net/quic/core/quic_connection.h
index 4242e797..7e988fd 100644
--- a/net/quic/core/quic_connection.h
+++ b/net/quic/core/quic_connection.h
@@ -172,6 +172,10 @@
   // Called when a self address change is observed. Returns true if self address
   // change is allowed.
   virtual bool AllowSelfAddressChange() const = 0;
+
+  // Called when an ACK is received with a larger |largest_acked| than
+  // previously observed.
+  virtual void OnForwardProgressConfirmed() = 0;
 };
 
 // Interface which gets callbacks from the QuicConnection at interesting
diff --git a/net/quic/core/quic_connection_test.cc b/net/quic/core/quic_connection_test.cc
index 2d9524800..e489575 100644
--- a/net/quic/core/quic_connection_test.cc
+++ b/net/quic/core/quic_connection_test.cc
@@ -48,6 +48,7 @@
 using testing::AnyNumber;
 using testing::AtLeast;
 using testing::DoAll;
+using testing::Exactly;
 using testing::Ge;
 using testing::InSequence;
 using testing::Invoke;
@@ -801,6 +802,7 @@
         .WillRepeatedly(Return(false));
     EXPECT_CALL(visitor_, OnCongestionWindowChange(_)).Times(AnyNumber());
     EXPECT_CALL(visitor_, OnConnectivityProbeReceived(_, _)).Times(AnyNumber());
+    EXPECT_CALL(visitor_, OnForwardProgressConfirmed()).Times(AnyNumber());
 
     EXPECT_CALL(*loss_algorithm_, GetLossTimeout())
         .WillRepeatedly(Return(QuicTime::Zero()));
@@ -5970,6 +5972,44 @@
   ASSERT_EQ(1u, writer_->ping_frames().size());
 }
 
+TEST_P(QuicConnectionTest, OnForwardProgressConfirmed) {
+  EXPECT_CALL(visitor_, OnForwardProgressConfirmed()).Times(Exactly(0));
+  EXPECT_TRUE(connection_.connected());
+
+  const char data[] = "data";
+  size_t data_size = strlen(data);
+  QuicStreamOffset offset = 0;
+
+  // Send two packets.
+  connection_.SendStreamDataWithString(1, data, offset, NO_FIN);
+  offset += data_size;
+  connection_.SendStreamDataWithString(1, data, offset, NO_FIN);
+  offset += data_size;
+
+  // Ack packet 1. This increases the largest_acked to 1, so
+  // OnForwardProgressConfirmed() should be called
+  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+  EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
+  EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
+  EXPECT_CALL(visitor_, OnForwardProgressConfirmed());
+  QuicAckFrame frame = InitAckFrame({{1, 2}});
+  ProcessAckPacket(&frame);
+
+  // Ack packet 1 again. largest_acked remains at 1, so
+  // OnForwardProgressConfirmed() should not be called.
+  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+  frame = InitAckFrame({{1, 2}});
+  ProcessAckPacket(&frame);
+
+  // Ack packet 2. This increases the largest_acked to 2, so
+  // OnForwardProgressConfirmed() should be called.
+  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+  EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
+  EXPECT_CALL(visitor_, OnForwardProgressConfirmed());
+  frame = InitAckFrame({{2, 3}});
+  ProcessAckPacket(&frame);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/core/quic_session.cc b/net/quic/core/quic_session.cc
index 94b5d3d3..42db6722 100644
--- a/net/quic/core/quic_session.cc
+++ b/net/quic/core/quic_session.cc
@@ -219,6 +219,8 @@
   return false;
 }
 
+void QuicSession::OnForwardProgressConfirmed() {}
+
 void QuicSession::OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) {
   // Stream may be closed by the time we receive a WINDOW_UPDATE, so we can't
   // assume that it still exists.
diff --git a/net/quic/core/quic_session.h b/net/quic/core/quic_session.h
index 822fab6..33301369 100644
--- a/net/quic/core/quic_session.h
+++ b/net/quic/core/quic_session.h
@@ -117,6 +117,7 @@
   bool HasOpenDynamicStreams() const override;
   void OnPathDegrading() override;
   bool AllowSelfAddressChange() const override;
+  void OnForwardProgressConfirmed() override;
 
   // QuicStreamFrameDataProducer
   bool WriteStreamData(QuicStreamId id,
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 809fd03..f334327 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -332,6 +332,7 @@
   MOCK_METHOD0(OnAckNeedsRetransmittableFrame, void());
   MOCK_METHOD0(SendPing, void());
   MOCK_CONST_METHOD0(AllowSelfAddressChange, bool());
+  MOCK_METHOD0(OnForwardProgressConfirmed, void());
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockQuicConnectionVisitor);
diff --git a/net/quic/test_tools/simulator/quic_endpoint.h b/net/quic/test_tools/simulator/quic_endpoint.h
index bd983e4d..c064560fe 100644
--- a/net/quic/test_tools/simulator/quic_endpoint.h
+++ b/net/quic/test_tools/simulator/quic_endpoint.h
@@ -98,6 +98,7 @@
   void OnAckNeedsRetransmittableFrame() override {}
   void SendPing() override {}
   bool AllowSelfAddressChange() const override;
+  void OnForwardProgressConfirmed() override {}
   // End QuicConnectionVisitorInterface implementation.
 
   // Begin SessionNotifierInterface methods:
diff --git a/net/url_request/static_http_user_agent_settings.h b/net/url_request/static_http_user_agent_settings.h
index f6d90bdf..eda4240 100644
--- a/net/url_request/static_http_user_agent_settings.h
+++ b/net/url_request/static_http_user_agent_settings.h
@@ -14,20 +14,24 @@
 
 namespace net {
 
-// An implementation of |HttpUserAgentSettings| that always provides the
-// same constant values for the HTTP Accept-Language and User-Agent headers.
+// An implementation of |HttpUserAgentSettings| that provides configured
+// values for the HTTP Accept-Language and User-Agent headers.
 class NET_EXPORT StaticHttpUserAgentSettings : public HttpUserAgentSettings {
  public:
   StaticHttpUserAgentSettings(const std::string& accept_language,
                               const std::string& user_agent);
   ~StaticHttpUserAgentSettings() override;
 
+  void set_accept_language(const std::string& new_accept_language) {
+    accept_language_ = new_accept_language;
+  }
+
   // HttpUserAgentSettings implementation
   std::string GetAcceptLanguage() const override;
   std::string GetUserAgent() const override;
 
  private:
-  const std::string accept_language_;
+  std::string accept_language_;
   const std::string user_agent_;
 
   DISALLOW_COPY_AND_ASSIGN(StaticHttpUserAgentSettings);
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index a356f27..2f10f419 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -198,7 +198,6 @@
 URLRequestContextBuilder::URLRequestContextBuilder()
     : enable_brotli_(false),
       network_quality_estimator_(nullptr),
-      shared_http_user_agent_settings_(nullptr),
       data_enabled_(false),
 #if !BUILDFLAG(DISABLE_FILE_SUPPORT)
       file_enabled_(false),
@@ -254,18 +253,17 @@
 
 void URLRequestContextBuilder::set_accept_language(
     const std::string& accept_language) {
-  DCHECK(!shared_http_user_agent_settings_);
+  DCHECK(!http_user_agent_settings_);
   accept_language_ = accept_language;
 }
 void URLRequestContextBuilder::set_user_agent(const std::string& user_agent) {
-  DCHECK(!shared_http_user_agent_settings_);
+  DCHECK(!http_user_agent_settings_);
   user_agent_ = user_agent;
 }
-void URLRequestContextBuilder::set_shared_http_user_agent_settings(
-    HttpUserAgentSettings* shared_http_user_agent_settings) {
-  DCHECK(accept_language_.empty());
-  DCHECK(user_agent_.empty());
-  shared_http_user_agent_settings_ = shared_http_user_agent_settings;
+
+void URLRequestContextBuilder::set_http_user_agent_settings(
+    std::unique_ptr<HttpUserAgentSettings> http_user_agent_settings) {
+  http_user_agent_settings_ = std::move(http_user_agent_settings);
 }
 
 void URLRequestContextBuilder::EnableHttpCache(const HttpCacheParams& params) {
@@ -396,8 +394,8 @@
   context->set_enable_brotli(enable_brotli_);
   context->set_network_quality_estimator(network_quality_estimator_);
 
-  if (shared_http_user_agent_settings_) {
-    context->set_http_user_agent_settings(shared_http_user_agent_settings_);
+  if (http_user_agent_settings_) {
+    storage->set_http_user_agent_settings(std::move(http_user_agent_settings_));
   } else {
     storage->set_http_user_agent_settings(
         std::make_unique<StaticHttpUserAgentSettings>(accept_language_,
diff --git a/net/url_request/url_request_context_builder.h b/net/url_request/url_request_context_builder.h
index 5a09960..775476f 100644
--- a/net/url_request/url_request_context_builder.h
+++ b/net/url_request/url_request_context_builder.h
@@ -183,15 +183,13 @@
   // have the headers already set.
   void set_accept_language(const std::string& accept_language);
   void set_user_agent(const std::string& user_agent);
-  // Makes the created URLRequestContext use a shared HttpUserAgentSettings
-  // object. Not compatible with set_accept_language() / set_user_agent(). The
-  // consumer must ensure the HttpUserAgentSettings outlives the
-  // URLRequestContext returned by the builder.
+
+  // Makes the created URLRequestContext use a particular HttpUserAgentSettings
+  // object. Not compatible with set_accept_language() / set_user_agent().
   //
-  // TODO(mmenke): Take ownership of the object instead. See:
-  // https://crbug.com/743251
-  void set_shared_http_user_agent_settings(
-      HttpUserAgentSettings* shared_http_user_agent_settings);
+  // The object will be live until the URLRequestContext is destroyed.
+  void set_http_user_agent_settings(
+      std::unique_ptr<HttpUserAgentSettings> http_user_agent_settings);
 
   // Control support for data:// requests. By default it's disabled.
   void set_data_enabled(bool enable) {
@@ -364,7 +362,7 @@
 
   std::string accept_language_;
   std::string user_agent_;
-  HttpUserAgentSettings* shared_http_user_agent_settings_;
+  std::unique_ptr<HttpUserAgentSettings> http_user_agent_settings_;
 
   // Include support for data:// requests.
   bool data_enabled_;
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 3e55d72..31e5d89 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -3742,7 +3742,10 @@
 }
 
 int PDFiumEngine::GetVisiblePageIndex(FPDF_PAGE page) {
-  for (int page_index : visible_pages_) {
+  // Copy visible_pages_ since it can change as a result of loading the page in
+  // GetPage(). See https://crbug.com/822091.
+  std::vector<int> visible_pages_copy(visible_pages_);
+  for (int page_index : visible_pages_copy) {
     if (pages_[page_index]->GetPage() == page)
       return page_index;
   }
diff --git a/ppapi/BUILD.gn b/ppapi/BUILD.gn
index cf28f25..2e46f74 100644
--- a/ppapi/BUILD.gn
+++ b/ppapi/BUILD.gn
@@ -396,7 +396,7 @@
 
   deps = [
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//ppapi/proxy",
     "//ppapi/proxy:test_support",
     "//ppapi/shared_impl",
diff --git a/ppapi/proxy/BUILD.gn b/ppapi/proxy/BUILD.gn
index 5332aa63..1c767ed8 100644
--- a/ppapi/proxy/BUILD.gn
+++ b/ppapi/proxy/BUILD.gn
@@ -287,7 +287,7 @@
     "//gpu/command_buffer/common",
     "//gpu/ipc/common:command_buffer_traits",
     "//media:shared_memory_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//ppapi/c",
     "//ppapi/shared_impl",
     "//ui/gfx/geometry",
diff --git a/remoting/base/BUILD.gn b/remoting/base/BUILD.gn
index 305d1ad..19ddacd1 100644
--- a/remoting/base/BUILD.gn
+++ b/remoting/base/BUILD.gn
@@ -20,8 +20,6 @@
     "compound_buffer.h",
     "constants.cc",
     "constants.h",
-    "weighted_samples.cc",
-    "weighted_samples.h",
     "leaky_bucket.cc",
     "leaky_bucket.h",
     "name_value_map.h",
@@ -50,6 +48,8 @@
     "util.h",
     "vlog_net_log.cc",
     "vlog_net_log.h",
+    "weighted_samples.cc",
+    "weighted_samples.h",
   ]
 
   configs += [
@@ -163,7 +163,6 @@
     "buffered_socket_writer_unittest.cc",
     "capabilities_unittest.cc",
     "compound_buffer_unittest.cc",
-    "weighted_samples_unittest.cc",
     "oauth_helper_unittest.cc",
     "rate_counter_unittest.cc",
     "rsa_key_pair_unittest.cc",
@@ -173,11 +172,12 @@
     "telemetry_log_writer_unittest.cc",
     "typed_buffer_unittest.cc",
     "util_unittest.cc",
+    "weighted_samples_unittest.cc",
   ]
 
   deps = [
     ":test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//net:test_support",
     "//third_party/libyuv",
     "//third_party/webrtc/modules/desktop_capture:primitives",
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn
index 6d6ecd1..08851e9c 100644
--- a/remoting/host/BUILD.gn
+++ b/remoting/host/BUILD.gn
@@ -741,10 +741,7 @@
     }
 
     if (remoting_multi_process != 0) {
-      deps += [
-        "//mojo/edk/embedder:headers",
-        "//mojo/edk/system",
-      ]
+      deps += [ "//mojo/edk" ]
     }
   }
 
diff --git a/remoting/host/security_key/BUILD.gn b/remoting/host/security_key/BUILD.gn
index 33160c1..641103ca 100644
--- a/remoting/host/security_key/BUILD.gn
+++ b/remoting/host/security_key/BUILD.gn
@@ -37,7 +37,7 @@
 
   deps = [
     "//ipc",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//remoting/proto",
     "//third_party/webrtc/modules/desktop_capture",
   ]
diff --git a/remoting/host/win/BUILD.gn b/remoting/host/win/BUILD.gn
index c670500..875df9b5 100644
--- a/remoting/host/win/BUILD.gn
+++ b/remoting/host/win/BUILD.gn
@@ -394,7 +394,7 @@
     "//base/third_party/dynamic_annotations",
     "//build/win:default_exe_manifest",
     "//ipc",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//net",
     "//remoting/base",
     "//remoting/base:breakpad",
diff --git a/remoting/resources/remoting_strings.grd b/remoting/resources/remoting_strings.grd
index 786fe07..104e1dc 100644
--- a/remoting/resources/remoting_strings.grd
+++ b/remoting/resources/remoting_strings.grd
@@ -644,6 +644,12 @@
         <message name="IDS_REPORT_THIS" desc="Label text for a button to report a connection failure to the developers.">
           Report this
         </message>
+        <message name="IDS_IOS_PHOTO_LIBRARY_USAGE_DESCRIPTION" desc="Message shown when the app requests permission to access the user's photo library.">
+          To choose a profile picture, allow Chrome Remote Desktop to access your photos
+        </message>
+        <message name="IDS_IOS_CAMERA_USAGE_DESCRIPTION" desc="Message shown when the app requests permission to use the camera of the device.">
+          To choose a profile picture, allow Chrome Remote Desktop to access your camera
+        </message>
 
 <!-- Play Store listings text. These Android-specific strings are not marked
      with formatter_data="android_java" since they are used only for the Play
diff --git a/services/audio/BUILD.gn b/services/audio/BUILD.gn
index 4722654..206637ed 100644
--- a/services/audio/BUILD.gn
+++ b/services/audio/BUILD.gn
@@ -56,7 +56,7 @@
     ":lib",
     "//base/test:test_support",
     "//media:test_support",
-    "//mojo/edk/system:system",
+    "//mojo/edk",
     "//services/audio/public/cpp",
     "//services/audio/public/cpp:test_support",
     "//services/audio/public/mojom",
diff --git a/services/audio/output_stream_unittest.cc b/services/audio/output_stream_unittest.cc
index c4905cc..41feae2 100644
--- a/services/audio/output_stream_unittest.cc
+++ b/services/audio/output_stream_unittest.cc
@@ -12,7 +12,7 @@
 #include "media/audio/audio_io.h"
 #include "media/audio/mock_audio_manager.h"
 #include "media/audio/test_audio_thread.h"
-#include "mojo/edk/system/core.h"
+#include "mojo/edk/embedder/embedder.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "services/audio/stream_factory.h"
 #include "services/audio/test/mock_log.h"
diff --git a/services/device/BUILD.gn b/services/device/BUILD.gn
index 20301dbd..5b179a1 100644
--- a/services/device/BUILD.gn
+++ b/services/device/BUILD.gn
@@ -95,7 +95,7 @@
     "//device/base/synchronization",
     "//device/geolocation",
     "//device/geolocation/public/cpp",
-    "//mojo/edk/embedder:headers",
+    "//mojo/edk",
     "//mojo/public/cpp/bindings",
     "//net",
     "//net:test_support",
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 41fb0e7..2cefc6f 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -37,6 +37,7 @@
 #include "net/ssl/channel_id_service.h"
 #include "net/ssl/default_channel_id_store.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
+#include "net/url_request/static_http_user_agent_settings.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_builder.h"
 #include "services/network/http_server_properties_pref_delegate.h"
@@ -120,7 +121,7 @@
       socket_factory_(network_service_->net_log()) {
   url_request_context_owner_ = ApplyContextParamsToBuilder(
       builder.get(), params_.get(), network_service->quic_disabled(),
-      network_service->net_log());
+      network_service->net_log(), &user_agent_settings_);
   url_request_context_getter_ =
       url_request_context_owner_.url_request_context_getter;
   network_service_->RegisterNetworkContext(this);
@@ -259,8 +260,6 @@
         command_line->GetSwitchValueASCII(switches::kHostResolverRules));
     builder.set_host_resolver(std::move(remapped_host_resolver));
   }
-  builder.set_accept_language("en-us,en");
-  builder.set_user_agent(network_context_params->user_agent);
 
   // The cookie configuration is in this method, which is only used by the
   // network process, and not ApplyContextParamsToBuilder which is used by the
@@ -321,17 +320,30 @@
   return ApplyContextParamsToBuilder(
       &builder, network_context_params,
       network_service_ ? network_service_->quic_disabled() : false,
-      network_service_ ? network_service_->net_log() : nullptr);
+      network_service_ ? network_service_->net_log() : nullptr,
+      &user_agent_settings_);
 }
 
 URLRequestContextOwner NetworkContext::ApplyContextParamsToBuilder(
     URLRequestContextBuilderMojo* builder,
     mojom::NetworkContextParams* network_context_params,
     bool quic_disabled,
-    net::NetLog* net_log) {
+    net::NetLog* net_log,
+    net::StaticHttpUserAgentSettings** out_http_user_agent_settings) {
   if (net_log)
     builder->set_net_log(net_log);
 
+  std::string accept_language = network_context_params->accept_language
+                                    ? *network_context_params->accept_language
+                                    : "en-us,en";
+  std::unique_ptr<net::StaticHttpUserAgentSettings> user_agent_settings =
+      std::make_unique<net::StaticHttpUserAgentSettings>(
+          accept_language, network_context_params->user_agent);
+  // Borrow an alias for future use before giving the builder ownership.
+  if (out_http_user_agent_settings)
+    *out_http_user_agent_settings = user_agent_settings.get();
+  builder->set_http_user_agent_settings(std::move(user_agent_settings));
+
   builder->set_enable_brotli(network_context_params->enable_brotli);
   if (network_context_params->context_name)
     builder->set_name(*network_context_params->context_name);
@@ -490,6 +502,13 @@
                                       std::move(network_conditions));
 }
 
+void NetworkContext::SetAcceptLanguage(const std::string& new_accept_language) {
+  // This may only be called on NetworkContexts created with a constructor that
+  // calls ApplyContextParamsToBuilder.
+  DCHECK(user_agent_settings_);
+  user_agent_settings_->set_accept_language(new_accept_language);
+}
+
 void NetworkContext::CreateUDPSocket(mojom::UDPSocketRequest request,
                                      mojom::UDPSocketReceiverPtr receiver) {
   socket_factory_.CreateUDPSocket(std::move(request), std::move(receiver));
diff --git a/services/network/network_context.h b/services/network/network_context.h
index 0519c8a..ad382155 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -28,6 +28,7 @@
 
 namespace net {
 class CertVerifier;
+class StaticHttpUserAgentSettings;
 class URLRequestContext;
 }  // namespace net
 
@@ -111,6 +112,7 @@
                       ClearHttpCacheCallback callback) override;
   void SetNetworkConditions(const std::string& profile_id,
                             mojom::NetworkConditionsPtr conditions) override;
+  void SetAcceptLanguage(const std::string& new_accept_language) override;
   void CreateUDPSocket(mojom::UDPSocketRequest request,
                        mojom::UDPSocketReceiverPtr receiver) override;
   void CreateTCPServerSocket(
@@ -141,12 +143,15 @@
   void DisableQuic();
 
   // Applies the values in |network_context_params| to |builder|, and builds
-  // the URLRequestContext.
+  // the URLRequestContext. If |out_http_user_agent_settings| is non-null, it
+  // will be set to point to StaticHttpUserAgentSettings owned by the
+  // URLRequestContext.
   static URLRequestContextOwner ApplyContextParamsToBuilder(
       URLRequestContextBuilderMojo* builder,
       mojom::NetworkContextParams* network_context_params,
       bool quic_disabled,
-      net::NetLog* net_log);
+      net::NetLog* net_log,
+      net::StaticHttpUserAgentSettings** out_http_user_agent_settings);
 
  private:
   // Constructor only used in tests.
@@ -189,6 +194,9 @@
 
   int current_resource_scheduler_client_id_ = 0;
 
+  // Owned by the URLRequestContext
+  net::StaticHttpUserAgentSettings* user_agent_settings_ = nullptr;
+
   // TODO(yhirano): Consult with switches::kDisableResourceScheduler.
   constexpr static bool enable_resource_scheduler_ = true;
 
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 849a743e..28960c0 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -44,6 +44,7 @@
 #include "net/proxy_resolution/proxy_info.h"
 #include "net/proxy_resolution/proxy_resolution_service.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "net/url_request/http_user_agent_settings.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_builder.h"
 #include "net/url_request/url_request_job_factory.h"
@@ -161,6 +162,44 @@
                    .enable_quic);
 }
 
+TEST_F(NetworkContextTest, UserAgentAndLanguage) {
+  const char kUserAgent[] = "Chromium Unit Test";
+  const char kAcceptLanguage[] = "en-US,en;q=0.9,uk;q=0.8";
+  mojom::NetworkContextParamsPtr params = CreateContextParams();
+  params->user_agent = kUserAgent;
+  // Not setting accept_language, to test the default.
+  std::unique_ptr<NetworkContext> network_context =
+      CreateContextWithParams(std::move(params));
+  EXPECT_EQ(kUserAgent, network_context->GetURLRequestContext()
+                            ->http_user_agent_settings()
+                            ->GetUserAgent());
+  EXPECT_EQ("en-us,en", network_context->GetURLRequestContext()
+                            ->http_user_agent_settings()
+                            ->GetAcceptLanguage());
+
+  // Change accept-language.
+  network_context->SetAcceptLanguage(kAcceptLanguage);
+  EXPECT_EQ(kUserAgent, network_context->GetURLRequestContext()
+                            ->http_user_agent_settings()
+                            ->GetUserAgent());
+  EXPECT_EQ(kAcceptLanguage, network_context->GetURLRequestContext()
+                                 ->http_user_agent_settings()
+                                 ->GetAcceptLanguage());
+
+  // Create with custom accept-language configured.
+  params = CreateContextParams();
+  params->user_agent = kUserAgent;
+  params->accept_language = kAcceptLanguage;
+  std::unique_ptr<NetworkContext> network_context2 =
+      CreateContextWithParams(std::move(params));
+  EXPECT_EQ(kUserAgent, network_context2->GetURLRequestContext()
+                            ->http_user_agent_settings()
+                            ->GetUserAgent());
+  EXPECT_EQ(kAcceptLanguage, network_context2->GetURLRequestContext()
+                                 ->http_user_agent_settings()
+                                 ->GetAcceptLanguage());
+}
+
 TEST_F(NetworkContextTest, EnableBrotli) {
   for (bool enable_brotli : {true, false}) {
     mojom::NetworkContextParamsPtr context_params =
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
index f666cb26..01962d8 100644
--- a/services/network/public/mojom/network_service.mojom
+++ b/services/network/public/mojom/network_service.mojom
@@ -36,6 +36,10 @@
   // The user agent string.
   string user_agent;
 
+  // String to send as the Accept-Language header. This can be changed later
+  // by calling SetAcceptLanguage on the NetworkContext.
+  string? accept_language;
+
   // Whether Brotli content-encoding should be enabled for HTTPS responses.
   bool enable_brotli = true;
 
@@ -185,6 +189,9 @@
   // TODO(caseq): get rid of header, make profile_id part of ResourceRequest.
   SetNetworkConditions(string profile_id, NetworkConditions? conditions);
 
+  // Updates the Accept-Language header to be used for requests.
+  SetAcceptLanguage(string new_accept_language);
+
   // Creates a UDP socket. Caller can supply a |receiver| interface pointer
   // to listen for incoming datagrams. A null |receiver| is acceptable if caller
   // is not interested in incoming data.
diff --git a/services/network/url_request_context_builder_mojo.cc b/services/network/url_request_context_builder_mojo.cc
index 6fd9636..adfbc90 100644
--- a/services/network/url_request_context_builder_mojo.cc
+++ b/services/network/url_request_context_builder_mojo.cc
@@ -36,8 +36,9 @@
     mojom::NetworkContextParams* params,
     bool quic_disabled,
     net::NetLog* net_log) {
-  return NetworkContext::ApplyContextParamsToBuilder(this, params,
-                                                     quic_disabled, net_log);
+  return NetworkContext::ApplyContextParamsToBuilder(
+      this, params, quic_disabled, net_log,
+      nullptr /* out_static_user_agent_settings */);
 }
 
 std::unique_ptr<net::ProxyResolutionService>
diff --git a/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc b/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc
index ece4a33..79f1aec 100644
--- a/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc
+++ b/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc
@@ -46,15 +46,18 @@
   if (base::mac::IsAtLeastOS10_12()) {
     uint64_t phys_footprint_bytes =
         os_dump.platform_private_footprint->phys_footprint_bytes;
-    return base::saturated_cast<uint32_t>(phys_footprint_bytes / 1024 -
-                                          shared_resident_kb);
+    return base::saturated_cast<uint32_t>(
+        base::saturated_cast<int32_t>(phys_footprint_bytes / 1024) -
+        base::saturated_cast<int32_t>(shared_resident_kb));
   } else {
     uint64_t internal_bytes =
         os_dump.platform_private_footprint->internal_bytes;
     uint64_t compressed_bytes =
         os_dump.platform_private_footprint->compressed_bytes;
     return base::saturated_cast<uint32_t>(
-        (internal_bytes + compressed_bytes) / 1024 - shared_resident_kb);
+        base::saturated_cast<int32_t>((internal_bytes + compressed_bytes) /
+                                      1024) -
+        base::saturated_cast<int32_t>(shared_resident_kb));
   }
 #elif defined(OS_WIN)
   return os_dump.platform_private_footprint->private_bytes / 1024;
diff --git a/services/service_manager/embedder/BUILD.gn b/services/service_manager/embedder/BUILD.gn
index 67efc260..740cc36 100644
--- a/services/service_manager/embedder/BUILD.gn
+++ b/services/service_manager/embedder/BUILD.gn
@@ -66,7 +66,7 @@
 
     public_deps += [
       ":embedder_switches",
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//services/service_manager/background:lib",
       "//services/service_manager/public/cpp/standalone_service",
       "//services/service_manager/runner:init",
diff --git a/services/service_manager/public/cpp/BUILD.gn b/services/service_manager/public/cpp/BUILD.gn
index fc22798..df07080f 100644
--- a/services/service_manager/public/cpp/BUILD.gn
+++ b/services/service_manager/public/cpp/BUILD.gn
@@ -76,7 +76,7 @@
   deps = [
     "//base",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
     "//services/service_manager/background:lib",
diff --git a/services/service_manager/public/cpp/standalone_service/BUILD.gn b/services/service_manager/public/cpp/standalone_service/BUILD.gn
index 8acd6cce..707611a 100644
--- a/services/service_manager/public/cpp/standalone_service/BUILD.gn
+++ b/services/service_manager/public/cpp/standalone_service/BUILD.gn
@@ -11,7 +11,7 @@
   ]
 
   deps = [
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/system",
     "//services/service_manager/public/cpp",
     "//services/service_manager/runner:init",
diff --git a/services/service_manager/public/cpp/test/BUILD.gn b/services/service_manager/public/cpp/test/BUILD.gn
index 3473ac1..692a881c 100644
--- a/services/service_manager/public/cpp/test/BUILD.gn
+++ b/services/service_manager/public/cpp/test/BUILD.gn
@@ -18,7 +18,7 @@
   deps = [
     "//base",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//services/catalog:lib",
     "//services/service_manager/background:lib",
   ]
diff --git a/services/service_manager/runner/common/BUILD.gn b/services/service_manager/runner/common/BUILD.gn
index 98043a0..698c1ca 100644
--- a/services/service_manager/runner/common/BUILD.gn
+++ b/services/service_manager/runner/common/BUILD.gn
@@ -17,7 +17,7 @@
   ]
 
   public_deps = [
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//services/service_manager/public/mojom",
   ]
 }
diff --git a/services/service_manager/runner/host/BUILD.gn b/services/service_manager/runner/host/BUILD.gn
index 84b082b..9489078 100644
--- a/services/service_manager/runner/host/BUILD.gn
+++ b/services/service_manager/runner/host/BUILD.gn
@@ -35,7 +35,7 @@
 
   public_deps = [
     "//base",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/system",
   ]
 
@@ -61,7 +61,7 @@
       ":lib",
       "//base",
       "//base/test:test_support",
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//services/service_manager",
       "//services/service_manager/runner:init",
       "//services/service_manager/runner/common",
diff --git a/services/service_manager/standalone/BUILD.gn b/services/service_manager/standalone/BUILD.gn
index 950a21b..4a760742 100644
--- a/services/service_manager/standalone/BUILD.gn
+++ b/services/service_manager/standalone/BUILD.gn
@@ -16,7 +16,7 @@
     "//base",
     "//base/third_party/dynamic_annotations",
     "//mojo/common:common_base",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//services/catalog:lib",
     "//services/service_manager",
     "//services/service_manager/public/cpp",
diff --git a/services/service_manager/tests/BUILD.gn b/services/service_manager/tests/BUILD.gn
index 1f87477..387d695 100644
--- a/services/service_manager/tests/BUILD.gn
+++ b/services/service_manager/tests/BUILD.gn
@@ -26,7 +26,7 @@
     ":interfaces",
     "//base",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
     "//services/catalog:lib",
@@ -62,7 +62,7 @@
   deps = [
     "//base",
     "//base:base_static",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//services/service_manager/public/cpp",
     "//services/service_manager/public/mojom",
     "//services/service_manager/runner/common",
diff --git a/services/service_manager/tests/service_manager/BUILD.gn b/services/service_manager/tests/service_manager/BUILD.gn
index 8f01635e..8fc47af 100644
--- a/services/service_manager/tests/service_manager/BUILD.gn
+++ b/services/service_manager/tests/service_manager/BUILD.gn
@@ -19,7 +19,7 @@
     "//base",
     "//base/test:test_config",
     "//mojo/common:common_base",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//services/service_manager/public/cpp",
     "//services/service_manager/public/cpp:service_test_support",
     "//services/service_manager/public/mojom",
@@ -105,7 +105,7 @@
     ":interfaces",
     "//base",
     "//build/win:default_exe_manifest",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//services/service_manager/public/cpp",
     "//services/service_manager/public/cpp/standalone_service:main",
     "//services/service_manager/public/mojom",
diff --git a/services/ui/public/cpp/tests/BUILD.gn b/services/ui/public/cpp/tests/BUILD.gn
index a64453f..f58a3059 100644
--- a/services/ui/public/cpp/tests/BUILD.gn
+++ b/services/ui/public/cpp/tests/BUILD.gn
@@ -17,7 +17,7 @@
     "//base",
     "//base/test:test_support",
     "//mojo/common:common_base",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/system",
     "//services/service_manager/public/cpp",
     "//services/ui/public/cpp",
diff --git a/services/ui/ws/BUILD.gn b/services/ui/ws/BUILD.gn
index e557733..18e4cf28 100644
--- a/services/ui/ws/BUILD.gn
+++ b/services/ui/ws/BUILD.gn
@@ -44,6 +44,7 @@
     "drag_cursor_updater.h",
     "drag_source.h",
     "drag_target_connection.h",
+    "event_dispatcher.h",
     "event_location.h",
     "event_matcher.cc",
     "event_matcher.h",
diff --git a/services/ui/ws/event_dispatcher.h b/services/ui/ws/event_dispatcher.h
new file mode 100644
index 0000000..200a81cc
--- /dev/null
+++ b/services/ui/ws/event_dispatcher.h
@@ -0,0 +1,60 @@
+// Copyright 2018 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_UI_WS_EVENT_DISPATCHER_H_
+#define SERVICES_UI_WS_EVENT_DISPATCHER_H_
+
+#include <stdint.h>
+
+#include "services/ui/common/types.h"
+
+namespace ui {
+
+class Event;
+
+namespace ws {
+
+class Accelerator;
+class ServerWindow;
+
+struct EventLocation;
+
+// EventDispatcher is called from EventProcessor once it determines the target
+// for events as well as accelerators.
+class EventDispatcher {
+ public:
+  enum class AcceleratorPhase {
+    kPre,
+    kPost,
+  };
+
+  // Called when the target Window is found for |event|.
+  // |post_target_accelerator| is the accelerator to run if the target doesn't
+  // handle the event. See EventProcessor for details on event processing
+  // phases. |client_id| is the id of tree the event should be sent to. See
+  // EventLocation for details on |event_location|. |event_location| is only
+  // useful for located events.
+  virtual void DispatchInputEventToWindow(
+      ServerWindow* target,
+      ClientSpecificId client_id,
+      const EventLocation& event_location,
+      const ui::Event& event,
+      Accelerator* post_target_accelerator) = 0;
+
+  // A matching accelerator was found for the specified phase of processing.
+  // |event| is the event that the accelerator matches and |display_id|
+  // identifies the display the event came in on.
+  virtual void OnAccelerator(uint32_t accelerator,
+                             int64_t display_id,
+                             const ui::Event& event,
+                             AcceleratorPhase phase) = 0;
+
+ protected:
+  virtual ~EventDispatcher() {}
+};
+
+}  // namespace ws
+}  // namespace ui
+
+#endif  // SERVICES_UI_WS_EVENT_DISPATCHER_H_
diff --git a/services/ui/ws/event_processor.cc b/services/ui/ws/event_processor.cc
index 2092e91b8..c91535ac 100644
--- a/services/ui/ws/event_processor.cc
+++ b/services/ui/ws/event_processor.cc
@@ -11,6 +11,7 @@
 #include "services/ui/ws/accelerator.h"
 #include "services/ui/ws/drag_controller.h"
 #include "services/ui/ws/drag_source.h"
+#include "services/ui/ws/event_dispatcher.h"
 #include "services/ui/ws/event_location.h"
 #include "services/ui/ws/event_processor_delegate.h"
 #include "services/ui/ws/server_window.h"
@@ -63,8 +64,10 @@
 EventProcessor::ObservedWindow::ObservedWindow() = default;
 EventProcessor::ObservedWindow::~ObservedWindow() = default;
 
-EventProcessor::EventProcessor(EventProcessorDelegate* delegate)
+EventProcessor::EventProcessor(EventProcessorDelegate* delegate,
+                               EventDispatcher* event_dispatcher)
     : delegate_(delegate),
+      event_dispatcher_(event_dispatcher),
       capture_window_(nullptr),
       capture_window_client_id_(kInvalidClientId),
       event_targeter_(std::make_unique<EventTargeter>(this)),
@@ -309,9 +312,9 @@
       Accelerator* pre_target =
           FindAccelerator(*key_event, ui::mojom::AcceleratorPhase::PRE_TARGET);
       if (pre_target) {
-        delegate_->OnAccelerator(pre_target->id(), event_location.display_id,
-                                 event,
-                                 EventProcessorDelegate::AcceleratorPhase::PRE);
+        event_dispatcher_->OnAccelerator(
+            pre_target->id(), event_location.display_id, event,
+            EventDispatcher::AcceleratorPhase::kPre);
         return;
       }
     }
@@ -413,15 +416,15 @@
     const bool in_nonclient_area = false;
     const ClientSpecificId client_id =
         delegate_->GetEventTargetClientId(focused_window, in_nonclient_area);
-    delegate_->DispatchInputEventToWindow(focused_window, client_id,
-                                          EventLocation(display_id), event,
-                                          post_target);
+    event_dispatcher_->DispatchInputEventToWindow(focused_window, client_id,
+                                                  EventLocation(display_id),
+                                                  event, post_target);
     return;
   }
   delegate_->OnEventTargetNotFound(event, display_id);
   if (post_target)
-    delegate_->OnAccelerator(post_target->id(), display_id, event,
-                             EventProcessorDelegate::AcceleratorPhase::POST);
+    event_dispatcher_->OnAccelerator(post_target->id(), display_id, event,
+                                     EventDispatcher::AcceleratorPhase::kPost);
 }
 
 void EventProcessor::HideCursorOnMatchedKeyEvent(const ui::KeyEvent& event) {
@@ -736,8 +739,8 @@
   clone->AsLocatedEvent()->set_location(location);
   // TODO(jonross): add post-target accelerator support once accelerators
   // support pointer events.
-  delegate_->DispatchInputEventToWindow(window, client_id, event_location,
-                                        *clone, nullptr);
+  event_dispatcher_->DispatchInputEventToWindow(
+      window, client_id, event_location, *clone, nullptr);
 }
 
 void EventProcessor::CancelPointerEventsToTarget(ServerWindow* window) {
diff --git a/services/ui/ws/event_processor.h b/services/ui/ws/event_processor.h
index 3b85e27b..31df067 100644
--- a/services/ui/ws/event_processor.h
+++ b/services/ui/ws/event_processor.h
@@ -40,6 +40,7 @@
 class DragController;
 class DragSource;
 class DragTargetConnection;
+class EventDispatcher;
 class EventProcessorDelegate;
 class ServerWindow;
 class ServerWindowDrawnTracker;
@@ -67,7 +68,8 @@
     POST_ONLY,
   };
 
-  explicit EventProcessor(EventProcessorDelegate* delegate);
+  EventProcessor(EventProcessorDelegate* delegate,
+                 EventDispatcher* event_dispatcher);
   ~EventProcessor() override;
 
   ModalWindowController* modal_window_controller() {
@@ -355,6 +357,7 @@
   void OnDragCursorUpdated() override;
 
   EventProcessorDelegate* delegate_;
+  EventDispatcher* event_dispatcher_;
 
   ServerWindow* capture_window_;
   ClientSpecificId capture_window_client_id_;
diff --git a/services/ui/ws/event_processor_delegate.h b/services/ui/ws/event_processor_delegate.h
index 7f511e1..9c916bd 100644
--- a/services/ui/ws/event_processor_delegate.h
+++ b/services/ui/ws/event_processor_delegate.h
@@ -23,23 +23,12 @@
 
 namespace ws {
 
-class Accelerator;
 class ServerWindow;
 
 // Used by EventProcessor for dispatching of events, as well as to inform the
 // delegate of various state changes.
 class EventProcessorDelegate {
  public:
-  enum class AcceleratorPhase {
-    PRE,
-    POST,
-  };
-
-  virtual void OnAccelerator(uint32_t accelerator,
-                             int64_t display_id,
-                             const ui::Event& event,
-                             AcceleratorPhase phase) = 0;
-
   virtual void SetFocusedWindowFromEventProcessor(ServerWindow* window) = 0;
   virtual ServerWindow* GetFocusedWindowForEventProcessor(
       int64_t display_id) = 0;
@@ -71,13 +60,6 @@
   virtual void OnEventChangesCursorTouchVisibility(const ui::Event& event,
                                                    bool visible) = 0;
 
-  // Dispatches an event to the specific client.
-  virtual void DispatchInputEventToWindow(ServerWindow* target,
-                                          ClientSpecificId client_id,
-                                          const EventLocation& event_location,
-                                          const ui::Event& event,
-                                          Accelerator* accelerator) = 0;
-
   // Returns the id of the client to send events to. |in_nonclient_area| is
   // true if the event occurred in the non-client area of the window.
   virtual ClientSpecificId GetEventTargetClientId(const ServerWindow* window,
diff --git a/services/ui/ws/event_processor_unittest.cc b/services/ui/ws/event_processor_unittest.cc
index 5f9a3b6..12875a2 100644
--- a/services/ui/ws/event_processor_unittest.cc
+++ b/services/ui/ws/event_processor_unittest.cc
@@ -21,6 +21,7 @@
 #include "services/ui/common/switches.h"
 #include "services/ui/public/interfaces/window_tree_constants.mojom.h"
 #include "services/ui/ws/accelerator.h"
+#include "services/ui/ws/event_dispatcher.h"
 #include "services/ui/ws/event_location.h"
 #include "services/ui/ws/event_processor_delegate.h"
 #include "services/ui/ws/server_window.h"
@@ -52,7 +53,10 @@
   Accelerator* accelerator;
 };
 
-class TestEventProcessorDelegate : public EventProcessorDelegate {
+// Serves as both the EventProcessorDelegate and EventDispatcher
+// implementation. Records interesting calls for various assertions.
+class TestEventProcessorDelegate : public EventProcessorDelegate,
+                                   public EventDispatcher {
  public:
   // Delegate interface used by this class to release capture on event
   // dispatcher.
@@ -81,7 +85,7 @@
   uint32_t GetAndClearLastAccelerator() {
     uint32_t return_value = last_accelerator_;
     last_accelerator_ = 0;
-    last_accelerator_phase_ = AcceleratorPhase::POST;
+    last_accelerator_phase_ = AcceleratorPhase::kPost;
     return return_value;
   }
 
@@ -131,7 +135,19 @@
   }
 
  private:
-  // EventProcessorDelegate:
+  // EventDispatcher:
+  void DispatchInputEventToWindow(ServerWindow* target,
+                                  ClientSpecificId client_id,
+                                  const EventLocation& event_location,
+                                  const ui::Event& event,
+                                  Accelerator* accelerator) override {
+    std::unique_ptr<DispatchedEventDetails> details(new DispatchedEventDetails);
+    details->window = target;
+    details->client_id = client_id;
+    details->event = ui::Event::Clone(event);
+    details->accelerator = accelerator;
+    dispatched_event_queue_.push(std::move(details));
+  }
   void OnAccelerator(uint32_t accelerator,
                      int64_t display_id,
                      const ui::Event& event,
@@ -140,6 +156,8 @@
     last_accelerator_ = accelerator;
     last_accelerator_phase_ = phase;
   }
+
+  // EventProcessorDelegate:
   ServerWindow* GetFocusedWindowForEventProcessor(int64_t display_id) override {
     return focused_window_;
   }
@@ -161,18 +179,6 @@
   }
   void OnEventChangesCursorTouchVisibility(const ui::Event& event,
                                            bool visible) override {}
-  void DispatchInputEventToWindow(ServerWindow* target,
-                                  ClientSpecificId client_id,
-                                  const EventLocation& event_location,
-                                  const ui::Event& event,
-                                  Accelerator* accelerator) override {
-    std::unique_ptr<DispatchedEventDetails> details(new DispatchedEventDetails);
-    details->window = target;
-    details->client_id = client_id;
-    details->event = ui::Event::Clone(event);
-    details->accelerator = accelerator;
-    dispatched_event_queue_.push(std::move(details));
-  }
   ClientSpecificId GetEventTargetClientId(const ServerWindow* window,
                                           bool in_nonclient_area) override {
     return in_nonclient_area ? kNonclientAreaId : kClientAreaId;
@@ -211,7 +217,7 @@
   ServerWindow* focused_window_;
   ServerWindow* lost_capture_window_;
   uint32_t last_accelerator_;
-  AcceleratorPhase last_accelerator_phase_ = AcceleratorPhase::POST;
+  AcceleratorPhase last_accelerator_phase_ = AcceleratorPhase::kPost;
   base::queue<std::unique_ptr<DispatchedEventDetails>> dispatched_event_queue_;
   ServerWindow* root_ = nullptr;
   std::unique_ptr<ui::Event> last_event_target_not_found_;
@@ -452,7 +458,8 @@
   test_event_dispatcher_delegate_ =
       std::make_unique<TestEventProcessorDelegate>(this);
   event_dispatcher_ =
-      std::make_unique<EventProcessor>(test_event_dispatcher_delegate_.get());
+      std::make_unique<EventProcessor>(test_event_dispatcher_delegate_.get(),
+                                       test_event_dispatcher_delegate_.get());
   test_event_dispatcher_delegate_->set_root(root_window_.get());
 }
 
@@ -538,7 +545,8 @@
   test_event_dispatcher_delegate_ =
       std::make_unique<TestEventProcessorDelegate>(this);
   event_dispatcher_ =
-      std::make_unique<EventProcessor>(test_event_dispatcher_delegate_.get());
+      std::make_unique<EventProcessor>(test_event_dispatcher_delegate_.get(),
+                                       test_event_dispatcher_delegate_.get());
   test_event_dispatcher_delegate_->set_root(root_window_.get());
 
   uint32_t handle_size = 100;
@@ -603,7 +611,8 @@
 TEST_P(EventProcessorTest, AcceleratorBasic) {
   ClearSetup();
   TestEventProcessorDelegate event_dispatcher_delegate(nullptr);
-  EventProcessor dispatcher(&event_dispatcher_delegate);
+  EventProcessor dispatcher(&event_dispatcher_delegate,
+                            &event_dispatcher_delegate);
 
   uint32_t accelerator_1 = 1;
   mojom::EventMatcherPtr matcher = ui::CreateKeyMatcher(
@@ -754,7 +763,7 @@
   // DispatchInputEventToWindow().
   ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_CONTROL_DOWN);
   DispatchEvent(dispatcher, key, EventProcessor::AcceleratorMatchPhase::ANY);
-  EXPECT_EQ(EventProcessorDelegate::AcceleratorPhase::PRE,
+  EXPECT_EQ(EventDispatcher::AcceleratorPhase::kPre,
             event_dispatcher_delegate->last_accelerator_phase());
   EXPECT_EQ(pre_id, event_dispatcher_delegate->GetAndClearLastAccelerator());
   EXPECT_FALSE(event_dispatcher_delegate->has_queued_events());
diff --git a/services/ui/ws/window_manager_state.cc b/services/ui/ws/window_manager_state.cc
index 401611e..252e3af 100644
--- a/services/ui/ws/window_manager_state.cc
+++ b/services/ui/ws/window_manager_state.cc
@@ -204,7 +204,7 @@
 
 WindowManagerState::WindowManagerState(WindowTree* window_tree)
     : window_tree_(window_tree),
-      event_processor_(this),
+      event_processor_(this, this),
       cursor_state_(window_tree_->display_manager(), this) {
   frame_decoration_values_ = mojom::FrameDecorationValues::New();
   frame_decoration_values_->max_title_bar_button_width = 0u;
@@ -480,7 +480,7 @@
   if (result == mojom::EventResult::UNHANDLED &&
       details->post_target_accelerator) {
     OnAccelerator(details->post_target_accelerator->id(), details->display_id,
-                  *details->event, AcceleratorPhase::POST);
+                  *details->event, AcceleratorPhase::kPost);
   }
 
   ProcessEventTasks();
@@ -703,7 +703,7 @@
                                        int64_t display_id,
                                        const ui::Event& event,
                                        AcceleratorPhase phase) {
-  const bool needs_ack = phase == AcceleratorPhase::PRE;
+  const bool needs_ack = phase == AcceleratorPhase::kPre;
   WindowTree::AcceleratorCallback ack_callback;
   if (needs_ack) {
     DCHECK(!in_flight_event_dispatch_details_);
diff --git a/services/ui/ws/window_manager_state.h b/services/ui/ws/window_manager_state.h
index 00be863..8c7210b 100644
--- a/services/ui/ws/window_manager_state.h
+++ b/services/ui/ws/window_manager_state.h
@@ -18,6 +18,7 @@
 #include "services/ui/public/interfaces/display_manager.mojom.h"
 #include "services/ui/ws/cursor_state.h"
 #include "services/ui/ws/cursor_state_delegate.h"
+#include "services/ui/ws/event_dispatcher.h"
 #include "services/ui/ws/event_processor.h"
 #include "services/ui/ws/event_processor_delegate.h"
 #include "services/ui/ws/server_window_observer.h"
@@ -44,7 +45,8 @@
 // associated with.
 class WindowManagerState : public EventProcessorDelegate,
                            public ServerWindowObserver,
-                           public CursorStateDelegate {
+                           public CursorStateDelegate,
+                           public EventDispatcher {
  public:
   explicit WindowManagerState(WindowTree* window_tree);
   ~WindowManagerState() override;
@@ -247,10 +249,6 @@
   void AdjustEventLocation(int64_t display_id, LocatedEvent* event);
 
   // EventProcessorDelegate:
-  void OnAccelerator(uint32_t accelerator_id,
-                     int64_t display_id,
-                     const Event& event,
-                     AcceleratorPhase phase) override;
   void SetFocusedWindowFromEventProcessor(ServerWindow* window) override;
   ServerWindow* GetFocusedWindowForEventProcessor(int64_t display_id) override;
   void SetNativeCapture(ServerWindow* window) override;
@@ -264,11 +262,6 @@
                                       bool visible) override;
   void OnEventChangesCursorTouchVisibility(const ui::Event& event,
                                            bool visible) override;
-  void DispatchInputEventToWindow(ServerWindow* target,
-                                  ClientSpecificId client_id,
-                                  const EventLocation& event_location,
-                                  const Event& event,
-                                  Accelerator* accelerator) override;
   ClientSpecificId GetEventTargetClientId(const ServerWindow* window,
                                           bool in_nonclient_area) override;
   ServerWindow* GetRootWindowForDisplay(int64_t display_id) override;
@@ -281,6 +274,17 @@
   ServerWindow* GetWindowFromFrameSinkId(
       const viz::FrameSinkId& frame_sink_id) override;
 
+  // EventDispatcher:
+  void DispatchInputEventToWindow(ServerWindow* target,
+                                  ClientSpecificId client_id,
+                                  const EventLocation& event_location,
+                                  const Event& event,
+                                  Accelerator* accelerator) override;
+  void OnAccelerator(uint32_t accelerator_id,
+                     int64_t display_id,
+                     const Event& event,
+                     AcceleratorPhase phase) override;
+
   // ServerWindowObserver:
   void OnWindowEmbeddedAppDisconnected(ServerWindow* window) override;
 
diff --git a/storage/browser/BUILD.gn b/storage/browser/BUILD.gn
index 14270721..3943bac 100644
--- a/storage/browser/BUILD.gn
+++ b/storage/browser/BUILD.gn
@@ -306,7 +306,7 @@
     ":test_support",
     "//base/test:test_support",
     "//mojo/common",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//net:test_support",
     "//services/network/public/cpp",
     "//sql:test_support",
diff --git a/storage/common/BUILD.gn b/storage/common/BUILD.gn
index 1fc69195..9335c02d 100644
--- a/storage/common/BUILD.gn
+++ b/storage/common/BUILD.gn
@@ -63,7 +63,7 @@
   deps = [
     ":common",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//testing/gtest",
     "//url",
   ]
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index ce5effb6..6323a2e4 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -1809,7 +1809,7 @@
       {
         "swarming": {
           "can_use_on_swarming_builders": true,
-          "shards": 4
+          "shards": 8
         },
         "test": "net_unittests"
       },
diff --git a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
index 6f88b1e9..aa88f219 100644
--- a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
@@ -43,7 +43,6 @@
 -PreviewsStateResourceDispatcherHostBrowserTest.ShouldEnableLoFiModeReloadDisableLoFi
 
 -AsyncResourceHandlerBrowserTest/AsyncResourceHandlerBrowserTest.UploadProgress*
--DevToolsProtocolTest.ControlNavigationsMainFrame
 -GetUserMediaVideoCaptureBrowserTest.RecoverFromCrashInVideoCaptureProcess
 -IsolatedDevToolsProtocolTest.ControlNavigationsChildFrames
 -NavigationHandleImplBrowserTest.ErrorCodeOnRedirect
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 02ec9266..b4210a1 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -2520,7 +2520,7 @@
       },
       'Linux Chromium OS ASan LSan Tests (1)': {
         'swarming': {
-          'shards': 4,
+          'shards': 8,
         }
       },
       'Linux TSan Tests': {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 706b970..225927f 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3063,10 +3063,10 @@
             ],
             "experiments": [
                 {
-                    "name": "Enabled_bg_limit_8_4",
+                    "name": "Enabled_bg_limit_3_1",
                     "params": {
-                        "bg_limit": "8",
-                        "bg_sub_limit": "4"
+                        "bg_limit": "3",
+                        "bg_sub_limit": "1"
                     },
                     "enable_features": [
                         "ResourceLoadScheduler"
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/disable-blink-features=RootLayerScrolling b/third_party/WebKit/LayoutTests/FlagExpectations/disable-blink-features=RootLayerScrolling
index a2b65c9..741db51 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/disable-blink-features=RootLayerScrolling
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/disable-blink-features=RootLayerScrolling
@@ -2705,7 +2705,7 @@
 crbug.com/749738 [ Win7 Debug ] http/tests/devtools/console/console-format-es6-2.js [ Timeout ]
 
 # Sheriff failure 2017-08-07
-crbug.com/708499 [ Linux ] virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/touchpad-scroll-impl-to-main.html [ Failure Pass ]
+crbug.com/708499 [ Linux ] virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/animated-scroll/touchpad-scroll-impl-to-main.html [ Failure Pass ]
 
 # Sheriff failure 2017-08-29
 crbug.com/727252 [ Win7 ] external/wpt/media-source/mediasource-endofstream.html [ Pass Timeout ]
@@ -2890,7 +2890,7 @@
 crbug.com/757165 [ Win ] virtual/gpu/fast/canvas/canvas-filter-modified-save-restore.html [ Skip ]
 crbug.com/757165 [ Win ] virtual/gpu/fast/canvas/canvas-filter-modified.html [ Skip ]
 crbug.com/757165 [ Win ] virtual/threaded/animations/svg/animated-filter-svg-element.html [ Skip ]
-crbug.com/757165 [ Win ] virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/touchpad-scroll-impl-to-main.html [ Skip ]
+crbug.com/757165 [ Win ] virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/animated-scroll/touchpad-scroll-impl-to-main.html [ Skip ]
 crbug.com/757165 [ Win ] virtual/gpu/fast/canvas/canvas-blending-clipping.html [ Skip ]
 crbug.com/757165 [ Win ] virtual/gpu/fast/canvas/canvas-blending-color-over-color.html [ Skip ]
 crbug.com/757165 [ Win ] virtual/gpu/fast/canvas/canvas-blending-color-over-gradient.html [ Skip ]
@@ -3191,7 +3191,7 @@
 crbug.com/800078 [ Win7 ] http/tests/devtools/console/console-link-to-snippet.js [ Pass Failure ]
 
 # This test is flaking (failing, crashing) on mac_chromium_rel_ng.
-crbug.com/800840 [ Mac ] virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/touchpad-scroll-impl-to-main.html [ Skip ]
+crbug.com/800840 [ Mac ] virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/animated-scroll/touchpad-scroll-impl-to-main.html [ Skip ]
 
 # Sheriff failures 2018-01-19
 # This test is failing regularly on Win 7 (dgb), WebKit Mac10.11 (dgb),
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 4acfcbb..501461c 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -99,7 +99,7 @@
 crbug.com/591099 animations/interpolation/backdrop-filter-interpolation.html [ Timeout ]
 crbug.com/591099 animations/interpolation/line-height-interpolation.html [ Timeout ]
 crbug.com/591099 animations/interpolation/svg-stroke-dasharray-interpolation.html [ Timeout ]
-crbug.com/591099 animations/interpolation/webkit-clip-path-interpolation.html [ Timeout ]
+crbug.com/591099 animations/interpolation/webkit-clip-path-interpolation.html [ Pass Timeout ]
 crbug.com/591099 animations/interpolation/webkit-column-width-interpolation.html [ Pass ]
 crbug.com/591099 animations/rotate-transform-equivalent.html [ Failure ]
 crbug.com/591099 animations/timing/timing-model.html [ Timeout ]
@@ -131,7 +131,7 @@
 crbug.com/591099 compositing/scrollbars/nested-overlay-scrollbars.html [ Failure ]
 crbug.com/591099 compositing/squashing/add-remove-squashed-layers.html [ Failure ]
 crbug.com/591099 compositing/squashing/selection-repaint-with-gaps.html [ Failure ]
-crbug.com/591099 compositing/squashing/squash-onto-distant-relative.html [ Crash Pass ]
+crbug.com/591099 compositing/squashing/squash-onto-distant-relative.html [ Crash ]
 crbug.com/591099 compositing/squashing/vertical-writing-mode-squashed.html [ Failure ]
 crbug.com/591099 crypto/subtle/hkdf/cloneKey.html [ Timeout ]
 crbug.com/591099 crypto/subtle/hmac/cloneKey.html [ Timeout ]
@@ -283,8 +283,6 @@
 crbug.com/591099 editing/selection/mixed-editability-9.html [ Failure ]
 crbug.com/591099 editing/selection/modify_extend/extend_by_character.html [ Failure ]
 crbug.com/714962 editing/selection/modify_extend/extend_forward_line_crash.html [ Failure ]
-crbug.com/591099 editing/selection/modify_move/move-by-character-right-001.html [ Timeout ]
-crbug.com/591099 editing/selection/modify_move/move-by-character-right-002.html [ Timeout ]
 crbug.com/714962 editing/selection/modify_move/move-by-paragraph.html [ Failure ]
 crbug.com/714962 editing/selection/modify_move/move-forward-after-line-break.html [ Failure ]
 crbug.com/591099 editing/selection/modify_move/move_by_sentence_boundary.html [ Failure ]
@@ -322,6 +320,7 @@
 crbug.com/591099 editing/unsupported-content/table-type-after.html [ Failure ]
 crbug.com/591099 editing/unsupported-content/table-type-before.html [ Failure ]
 crbug.com/591099 external/wpt/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_11.html [ Pass ]
+crbug.com/591099 external/wpt/FileAPI/url/url-with-fetch.any.html [ Failure Pass ]
 crbug.com/591099 external/wpt/WebCryptoAPI/derive_bits_keys/hkdf.https.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/derive_bits_keys/test_hkdf.https.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures.worker.html [ Timeout ]
@@ -343,7 +342,7 @@
 crbug.com/591099 external/wpt/WebCryptoAPI/import_export/rsa_importKey.https.worker.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/import_export/rsa_importKey.worker.html [ Timeout ]
 crbug.com/709227 external/wpt/WebCryptoAPI/import_export/symmetric_importKey.worker.html [ Failure ]
-crbug.com/714962 external/wpt/WebCryptoAPI/import_export/test_rsa_importKey.https.html [ Timeout ]
+crbug.com/714962 external/wpt/WebCryptoAPI/import_export/test_rsa_importKey.https.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/acid/acid3/numbered-tests.html [ Crash ]
 crbug.com/591099 external/wpt/acid/acid3/test.html [ Crash ]
 crbug.com/591099 external/wpt/compat/webkit-text-fill-color-property-005.html [ Pass ]
@@ -358,7 +357,7 @@
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-nested-002.xht [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-percents-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-remove-006.xht [ Pass ]
-crbug.com/591099 external/wpt/css/CSS2/normal-flow/max-height-percentage-002.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/CSS2/normal-flow/max-height-percentage-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/max-width-applies-to-005.xht [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/root-box-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/positioning/abspos-007.xht [ Pass ]
@@ -680,7 +679,7 @@
 crbug.com/591099 external/wpt/css/css-tables/fixup-dynamic-anonymous-table-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-tables/floats/floats-wrap-bfc-006c.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-tables/height-distribution/percentage-sizing-of-table-cell-children.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-tables/table-model-fixup-2.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-tables/table-model-fixup-2.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-color-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-above-left-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-above-left-002.xht [ Failure ]
@@ -1053,6 +1052,7 @@
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-014.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-015.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/selectors4/dir-style-03a.html [ Pass ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-declaration-15.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-font-face-01.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-font-face-02.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-break-inside-001.html [ Failure ]
@@ -1199,7 +1199,8 @@
 crbug.com/591099 external/wpt/encoding/textdecoder-fatal-single-byte.html [ Timeout ]
 crbug.com/591099 external/wpt/feature-policy/payment-allowed-by-feature-policy.https.sub.html [ Pass ]
 crbug.com/591099 external/wpt/feature-policy/payment-disabled-by-feature-policy.https.sub.html [ Pass ]
-crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure ]
+crbug.com/591099 external/wpt/fetch/api/request/request-cache-default-conditional.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure Pass ]
 crbug.com/591099 external/wpt/html-media-capture/capture_audio_cancel-manual.html [ Failure ]
 crbug.com/591099 external/wpt/html-media-capture/capture_image_cancel-manual.html [ Failure ]
 crbug.com/591099 external/wpt/html-media-capture/capture_video_cancel-manual.html [ Failure ]
@@ -1798,7 +1799,7 @@
 crbug.com/591099 fast/events/wheel/mouse-wheel-scroll-latching.html [ Pass ]
 crbug.com/591099 fast/events/wheel/wheel-scroll-latching-on-scrollbar.html [ Pass ]
 crbug.com/714962 fast/events/wheel/wheelevent-basic.html [ Failure ]
-crbug.com/591099 fast/forms/calendar-picker/calendar-picker-key-operations.html [ Pass Timeout ]
+crbug.com/591099 fast/forms/calendar-picker/calendar-picker-key-operations.html [ Timeout ]
 crbug.com/714962 fast/forms/calendar-picker/calendar-picker-mouse-operations.html [ Failure ]
 crbug.com/591099 fast/forms/calendar-picker/month-picker-key-operations.html [ Timeout ]
 crbug.com/714962 fast/forms/calendar-picker/month-picker-mouse-operations.html [ Failure ]
@@ -1935,23 +1936,22 @@
 crbug.com/591099 fast/multicol/client-rects-crossing-boundaries.html [ Failure ]
 crbug.com/591099 fast/multicol/client-rects-rtl.html [ Failure ]
 crbug.com/591099 fast/multicol/client-rects.html [ Failure ]
-crbug.com/591099 fast/multicol/column-break-with-balancing.html [ Pass ]
 crbug.com/591099 fast/multicol/column-count-with-rules.html [ Failure ]
 crbug.com/591099 fast/multicol/column-rules.html [ Failure ]
 crbug.com/591099 fast/multicol/columns-shorthand-parsing.html [ Failure ]
 crbug.com/591099 fast/multicol/composited-inner-multicol.html [ Failure ]
 crbug.com/591099 fast/multicol/composited-layer.html [ Failure ]
-crbug.com/591099 fast/multicol/composited-opacity-2nd-and-3rd-column.html [ Failure ]
-crbug.com/591099 fast/multicol/composited-relpos-clipped.html [ Failure ]
-crbug.com/591099 fast/multicol/composited-relpos-in-clipped.html [ Failure ]
-crbug.com/591099 fast/multicol/composited-relpos-overlapping-will-change.html [ Failure ]
-crbug.com/591099 fast/multicol/composited-relpos-resize.html [ Failure ]
-crbug.com/591099 fast/multicol/composited-relpos.html [ Failure ]
+crbug.com/591099 fast/multicol/composited-opacity-2nd-and-3rd-column.html [ Crash Failure ]
+crbug.com/591099 fast/multicol/composited-relpos-clipped.html [ Crash Failure ]
+crbug.com/591099 fast/multicol/composited-relpos-in-clipped.html [ Failure Pass ]
+crbug.com/591099 fast/multicol/composited-relpos-overlapping-will-change.html [ Crash Failure ]
+crbug.com/591099 fast/multicol/composited-relpos-resize.html [ Crash Failure ]
+crbug.com/591099 fast/multicol/composited-relpos.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/composited-with-child-layer-in-next-column.html [ Failure ]
-crbug.com/591099 fast/multicol/composited-with-overflow-in-next-column.html [ Failure ]
+crbug.com/591099 fast/multicol/composited-with-overflow-in-next-column.html [ Crash Failure ]
 crbug.com/714962 fast/multicol/content-change-same-height.html [ Failure ]
 crbug.com/591099 fast/multicol/doubly-nested-with-top-padding-crossing-row-boundaries.html [ Failure ]
-crbug.com/591099 fast/multicol/dynamic/abspos-becomes-spanner.html [ Failure ]
+crbug.com/591099 fast/multicol/dynamic/abspos-becomes-spanner.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/dynamic/abspos-multicol-with-spanner-becomes-spanner.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/block-becomes-spanner.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/change-second-row-height.html [ Failure ]
@@ -1964,8 +1964,8 @@
 crbug.com/591099 fast/multicol/dynamic/insert-block-between-spanners.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/insert-block-into-content.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/insert-block-into-spanner.html [ Failure ]
-crbug.com/591099 fast/multicol/dynamic/insert-float-after-content-in-spanner.html [ Failure ]
-crbug.com/591099 fast/multicol/dynamic/insert-float-before-content-in-spanner.html [ Failure ]
+crbug.com/591099 fast/multicol/dynamic/insert-float-after-content-in-spanner.html [ Failure Pass ]
+crbug.com/591099 fast/multicol/dynamic/insert-float-before-content-in-spanner.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/dynamic/insert-spanner-after-content.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/insert-spanner-after-inner-multicol-crash.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/insert-spanner-after-spanner-before-content.html [ Failure ]
@@ -1981,6 +1981,7 @@
 crbug.com/591099 fast/multicol/dynamic/insert-spanner-pseudo-before-following-content.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/insert-spanner-pseudo-before.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/invalid-spanner-container-becomes-valid.html [ Failure ]
+crbug.com/591099 fast/multicol/dynamic/relayout-abspos-in-relpos-spanner.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/dynamic/relpos-becomes-static-has-abspos.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/remove-abspos-next-to-spanner.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/remove-and-insert-block-after-spanner.html [ Failure ]
@@ -2006,10 +2007,9 @@
 crbug.com/714962 fast/multicol/event-offset-complex-tree.html [ Failure ]
 crbug.com/591099 fast/multicol/event-offset-in-nested.html [ Failure ]
 crbug.com/714962 fast/multicol/event-offset.html [ Failure ]
-crbug.com/591099 fast/multicol/filter-in-second-column.html [ Pass ]
 crbug.com/591099 fast/multicol/first-line-in-float-below-next-column-top.html [ Failure ]
 crbug.com/591099 fast/multicol/first-line-in-float-with-margin.html [ Failure ]
-crbug.com/591099 fast/multicol/fixedpos-child-becomes-static.html [ Failure ]
+crbug.com/591099 fast/multicol/fixedpos-child-becomes-static.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/flexbox-starts-at-column-boundary-with-block.html [ Failure ]
 crbug.com/591099 fast/multicol/flexbox-starts-at-column-boundary.html [ Failure ]
 crbug.com/591099 fast/multicol/flexbox-with-overflow-auto-child-crash.html [ Crash ]
@@ -2033,19 +2033,20 @@
 crbug.com/591099 fast/multicol/float-with-margin-moved-by-child-line-and-unbreakable.html [ Failure ]
 crbug.com/591099 fast/multicol/float-with-margin-moved-by-child-line.html [ Failure ]
 crbug.com/591099 fast/multicol/float-with-margin-moved-unbreakable.html [ Failure ]
+crbug.com/591099 fast/multicol/flowthread-with-floats-destroyed-crash.html [ Crash Pass ]
 crbug.com/591099 fast/multicol/forced-break-after-block-with-spanner.html [ Failure ]
 crbug.com/591099 fast/multicol/forced-break-after-empty-block-after-spanner.html [ Failure ]
 crbug.com/591099 fast/multicol/forced-break-after-last-block-before-spanner.html [ Failure ]
 crbug.com/591099 fast/multicol/forced-break-in-nested-columns.html [ Failure ]
 crbug.com/591099 fast/multicol/forced-break-too-short-column.html [ Failure ]
-crbug.com/591099 fast/multicol/foreignObject.html [ Pass ]
 crbug.com/591099 fast/multicol/hit-test-above-or-below.html [ Failure ]
 crbug.com/591099 fast/multicol/hit-test-end-of-column-with-line-height.html [ Failure ]
 crbug.com/591099 fast/multicol/hit-test-end-of-column.html [ Failure ]
 crbug.com/591099 fast/multicol/hit-test-gap-between-pages-flipped.html [ Failure ]
-crbug.com/812457 fast/multicol/huge-column-count.html [ Failure ]
+crbug.com/812457 fast/multicol/huge-column-count.html [ Timeout Failure ]
 crbug.com/714962 fast/multicol/huge-column-gap-crash.html [ Failure ]
 crbug.com/591099 fast/multicol/image-inside-nested-blocks-with-border.html [ Failure ]
+crbug.com/591099 fast/multicol/infinitely-tall-content-in-outer-crash.html [ Pass Timeout ]
 crbug.com/591099 fast/multicol/inline-block-baseline.html [ Failure ]
 crbug.com/591099 fast/multicol/inline-getclientrects.html [ Failure ]
 crbug.com/591099 fast/multicol/inner-multicol-in-second-column.html [ Failure ]
@@ -2060,9 +2061,8 @@
 crbug.com/591099 fast/multicol/many-lines-overflow-in-single-row-inner.html [ Failure ]
 crbug.com/591099 fast/multicol/mixed-opacity-fixed-test.html [ Pass ]
 crbug.com/591099 fast/multicol/mixed-opacity-test.html [ Failure ]
-crbug.com/591099 fast/multicol/mixed-positioning-stacking-order.html [ Failure ]
+crbug.com/591099 fast/multicol/mixed-positioning-stacking-order.html [ Crash Failure ]
 crbug.com/714962 fast/multicol/multicol-becomes-abspos-crash.html [ Failure ]
-crbug.com/591099 fast/multicol/multicol-becomes-paged-fixed-height.html [ Pass ]
 crbug.com/591099 fast/multicol/multicol-svg.html [ Failure ]
 crbug.com/591099 fast/multicol/multicol-with-child-renderLayer-for-input.html [ Failure ]
 crbug.com/591099 fast/multicol/nested-3-multicols-fixed-height.html [ Failure ]
@@ -2100,43 +2100,36 @@
 crbug.com/714962 fast/multicol/newmulticol/balance5.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/break-before.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/breaks-2-columns-3-no-balancing.html [ Failure ]
-crbug.com/591099 fast/multicol/newmulticol/breaks-2-columns-3.html [ Pass ]
 crbug.com/591099 fast/multicol/newmulticol/breaks-3-columns-3.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/fixed-height-fill-balance-2.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/hide-box-vertical-lr.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/hide-box-vertical-rl.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/list-item.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/orphans-and-widows-balance.html [ Failure ]
-crbug.com/591099 fast/multicol/newmulticol/regular-block-becomes-multicol.html [ Pass ]
 crbug.com/591099 fast/multicol/newmulticol/table-cell.html [ Failure ]
-crbug.com/591099 fast/multicol/newmulticol/unresolvable-percent-max-height-2.html [ Pass ]
 crbug.com/591099 fast/multicol/out-of-flow/abspos-auto-left-right.html [ Pass ]
-crbug.com/591099 fast/multicol/out-of-flow/abspos-auto-position-on-line-at-boundary.html [ Failure ]
-crbug.com/591099 fast/multicol/out-of-flow/abspos-auto-position-on-line-rtl.html [ Failure ]
-crbug.com/591099 fast/multicol/out-of-flow/abspos-auto-position-on-line.html [ Failure ]
+crbug.com/591099 fast/multicol/out-of-flow/abspos-auto-position-on-line-at-boundary.html [ Crash Failure ]
+crbug.com/591099 fast/multicol/out-of-flow/abspos-auto-position-on-line-rtl.html [ Crash Failure ]
+crbug.com/591099 fast/multicol/out-of-flow/abspos-auto-position-on-line.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/out-of-flow/abspos-auto-position-small-on-line-at-boundary.html [ Failure ]
-crbug.com/591099 fast/multicol/out-of-flow/abspos-auto-position.html [ Failure ]
+crbug.com/591099 fast/multicol/out-of-flow/abspos-auto-position.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/out-of-flow/abspos-auto-top-bottom.html [ Pass ]
-crbug.com/591099 fast/multicol/out-of-flow/nested-multicol.html [ Failure ]
+crbug.com/591099 fast/multicol/out-of-flow/nested-multicol.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/out-of-flow/offset-properties.html [ Pass ]
 crbug.com/591099 fast/multicol/outlines-at-column-boundaries.html [ Failure ]
 crbug.com/591099 fast/multicol/overflow-across-columns.html [ Failure ]
 crbug.com/591099 fast/multicol/overflow-content.html [ Failure ]
 crbug.com/591099 fast/multicol/overflow-unsplittable.html [ Failure ]
 crbug.com/591099 fast/multicol/pageLogicalOffset-vertical.html [ Failure ]
-crbug.com/591099 fast/multicol/paged-becomes-multicol-auto-height.html [ Pass ]
-crbug.com/591099 fast/multicol/paged-becomes-multicol-fixed-height.html [ Pass ]
 crbug.com/591099 fast/multicol/paginate-block-replaced.html [ Failure ]
 crbug.com/591099 fast/multicol/positioned-outside-of-columns.html [ Failure ]
 crbug.com/591099 fast/multicol/positioned-split.html [ Failure ]
 crbug.com/591099 fast/multicol/positioned-with-constrained-height.html [ Failure ]
 crbug.com/591099 fast/multicol/pushed-line-affected-by-float.html [ Failure ]
-crbug.com/591099 fast/multicol/regular-block-becomes-multicol.html [ Pass ]
 crbug.com/591099 fast/multicol/relayout-and-push-float.html [ Failure ]
 crbug.com/591099 fast/multicol/renderer-positioned-assert-crash.html [ Failure ]
 crbug.com/591099 fast/multicol/rule-in-nested-with-too-tall-line.html [ Failure ]
 crbug.com/714962 fast/multicol/scale-transform-text.html [ Failure ]
-crbug.com/591099 fast/multicol/scrollable-basic.html [ Pass ]
 crbug.com/591099 fast/multicol/scrolling-overflow.html [ Failure ]
 crbug.com/591099 fast/multicol/shadow-breaking.html [ Failure ]
 crbug.com/591099 fast/multicol/single-line.html [ Failure ]
@@ -2178,7 +2171,7 @@
 crbug.com/591099 fast/multicol/span/outer-column-break-after-inner-spanner-and-float.html [ Failure ]
 crbug.com/591099 fast/multicol/span/outer-column-break-after-inner-spanner.html [ Failure ]
 crbug.com/591099 fast/multicol/span/outline.html [ Failure ]
-crbug.com/591099 fast/multicol/span/overflow-on-multicol.html [ Failure ]
+crbug.com/591099 fast/multicol/span/overflow-on-multicol.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/span/overflow-on-viewport.html [ Failure ]
 crbug.com/591099 fast/multicol/span/percent-margins.html [ Failure ]
 crbug.com/591099 fast/multicol/span/preferred-widths-with-column-content.html [ Failure ]
@@ -2197,12 +2190,13 @@
 crbug.com/591099 fast/multicol/span/span-between-text.html [ Failure ]
 crbug.com/591099 fast/multicol/span/spanner-first.html [ Failure ]
 crbug.com/591099 fast/multicol/span/spanner-img.html [ Failure ]
+crbug.com/591099 fast/multicol/span/spanner-inline-block.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/span/spanner-last.html [ Failure ]
 crbug.com/591099 fast/multicol/span/spanner-table.html [ Failure ]
 crbug.com/591099 fast/multicol/span/spanner-with-margin.html [ Failure ]
 crbug.com/591099 fast/multicol/span/spanner-with-margins-between-margins.html [ Failure ]
 crbug.com/591099 fast/multicol/span/spanner-with-relpos-child.html [ Failure ]
-crbug.com/591099 fast/multicol/span/summary-split.html [ Failure ]
+crbug.com/591099 fast/multicol/span/summary-split.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/span/trailing-margin-before-spanner.html [ Failure ]
 crbug.com/591099 fast/multicol/span/two-rows-then-spanner-then-two-rows.html [ Failure ]
 crbug.com/591099 fast/multicol/span/underflow-after-spanner.html [ Failure ]
@@ -2219,20 +2213,22 @@
 crbug.com/591099 fast/multicol/table-margin-collapse.html [ Failure ]
 crbug.com/591099 fast/multicol/tall-content-in-inner-with-fixed-height.html [ Failure ]
 crbug.com/591099 fast/multicol/tall-float2.html [ Failure ]
+crbug.com/591099 fast/multicol/text-shadow-at-column-boundaries.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/three-inner-rows.html [ Failure ]
+crbug.com/591099 fast/multicol/transform-inside-opacity.html [ Failure Pass ]
 crbug.com/714962 fast/multicol/unbreakable-content-taller-than-height-crash.html [ Failure ]
-crbug.com/591099 fast/multicol/vertical-lr/abspos-auto-position-on-line.html [ Failure ]
+crbug.com/591099 fast/multicol/vertical-lr/abspos-auto-position-on-line.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/break-properties.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/caret-range-anonymous-block-rtl.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/caret-range-anonymous-block.html [ Failure ]
-crbug.com/591099 fast/multicol/vertical-lr/caret-range-outside-columns-rtl.html [ Failure ]
+crbug.com/591099 fast/multicol/vertical-lr/caret-range-outside-columns-rtl.html [ Failure Timeout ]
 crbug.com/591099 fast/multicol/vertical-lr/caret-range-outside-columns.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/client-rect-after-spanner.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/client-rects-crossing-boundaries-nested.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/column-break-with-balancing.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/column-count-with-rules.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/column-rules.html [ Failure ]
-crbug.com/591099 fast/multicol/vertical-lr/composited-relpos-overlapping-will-change.html [ Failure ]
+crbug.com/591099 fast/multicol/vertical-lr/composited-relpos-overlapping-will-change.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/float-avoidance.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/float-big-line.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/float-break.html [ Failure ]
@@ -2246,7 +2242,7 @@
 crbug.com/591099 fast/multicol/vertical-lr/offset-top-and-left-at-boundaries.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/offset-top-and-left-nested.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/unsplittable-inline-block.html [ Failure ]
-crbug.com/591099 fast/multicol/vertical-rl/abspos-auto-position-on-line.html [ Failure ]
+crbug.com/591099 fast/multicol/vertical-rl/abspos-auto-position-on-line.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/break-properties.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/caret-range-anonymous-block-rtl.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/caret-range-anonymous-block.html [ Failure ]
@@ -2257,7 +2253,7 @@
 crbug.com/591099 fast/multicol/vertical-rl/column-break-with-balancing.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/column-count-with-rules.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/column-rules.html [ Failure ]
-crbug.com/591099 fast/multicol/vertical-rl/composited-relpos-overlapping-will-change.html [ Failure ]
+crbug.com/591099 fast/multicol/vertical-rl/composited-relpos-overlapping-will-change.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/float-avoidance.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/float-big-line.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/float-break.html [ Failure ]
@@ -2269,6 +2265,7 @@
 crbug.com/591099 fast/multicol/vertical-rl/offset-top-and-left-at-boundaries-nested.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/offset-top-and-left-at-boundaries.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/offset-top-and-left-nested.html [ Failure ]
+crbug.com/714962 fast/multicol/vertical-rl/rule-style.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/vertical-rl/unsplittable-inline-block.html [ Failure ]
 crbug.com/591099 fast/multicol/widows-and-orphans.html [ Failure ]
 crbug.com/591099 fast/multicol/widows.html [ Failure ]
@@ -2526,7 +2523,7 @@
 crbug.com/591099 fast/table/percent-height-content-in-fixed-height-border-box-sized-cell-with-collapsed-border-on-table.html [ Failure ]
 crbug.com/591099 fast/table/percent-height-content-in-fixed-height-border-box-sized-cell-with-collapsed-border.html [ Failure ]
 crbug.com/591099 fast/table/percent-height-content-in-fixed-height-content-box-sized-cell.html [ Failure ]
-crbug.com/591099 fast/table/percent-height-overflow-auto-content-in-cell.html [ Failure ]
+crbug.com/591099 fast/table/percent-height-overflow-auto-content-in-cell.html [ Failure Pass ]
 crbug.com/591099 fast/table/percent-height-overflow-scroll-content-in-cell.html [ Failure Pass ]
 crbug.com/591099 fast/table/percent-widths-stretch-vertical.html [ Failure ]
 crbug.com/714962 fast/table/split-table-section-before-anonymous-block-2.html [ Failure ]
@@ -2815,7 +2812,7 @@
 crbug.com/591099 fullscreen/full-screen-css.html [ Crash ]
 crbug.com/591099 fullscreen/full-screen-element-stack.html [ Crash ]
 crbug.com/591099 fullscreen/full-screen-iframe-not-allowed.html [ Failure ]
-crbug.com/591099 fullscreen/full-screen-remove-ancestor-after.html [ Crash Pass ]
+crbug.com/591099 fullscreen/full-screen-remove-ancestor-after.html [ Crash ]
 crbug.com/591099 fullscreen/full-screen-ruleset-crash.html [ Crash Pass ]
 crbug.com/591099 fullscreen/full-screen-twice-newapi.html [ Crash ]
 crbug.com/591099 fullscreen/full-screen-with-css-reference-filter.html [ Crash ]
@@ -2841,6 +2838,7 @@
 crbug.com/591099 html/marquee/marquee-scroll.html [ Failure ]
 crbug.com/591099 html/marquee/marquee-scrollamount.html [ Failure ]
 crbug.com/591099 http/tests/css/css-image-valued-shape.html [ Failure ]
+crbug.com/591099 http/tests/css/missing-repaint-after-slow-style-sheet.pl [ Failure Pass ]
 crbug.com/591099 http/tests/css/shape-image-file.html [ Failure ]
 crbug.com/591099 http/tests/csspaint/invalidation-background-image.html [ Timeout ]
 crbug.com/591099 http/tests/csspaint/invalidation-border-image.html [ Timeout ]
@@ -3014,7 +3012,7 @@
 crbug.com/591099 paint/invalidation/clip/outline-clip-change.html [ Failure ]
 crbug.com/591099 paint/invalidation/clip/repaint-tile-clipped.html [ Crash ]
 crbug.com/591099 paint/invalidation/clip/replaced-clipped-positioned-not-wrong-incremental-repainting.html [ Failure ]
-crbug.com/591099 paint/invalidation/compositing/column-span-under-composited-column-child.html [ Crash Pass ]
+crbug.com/591099 paint/invalidation/compositing/column-span-under-composited-column-child.html [ Crash ]
 crbug.com/714962 paint/invalidation/compositing/composited-inline-change-text-data-keep-geometry.html [ Crash ]
 crbug.com/591099 paint/invalidation/compositing/fixed-pos-with-abs-pos-child-scroll.html [ Failure ]
 crbug.com/591099 paint/invalidation/compositing/iframe-clip-removed.html [ Failure ]
@@ -3354,9 +3352,7 @@
 crbug.com/591099 payments/payment-request-in-iframe-nested-not-allowed.html [ Failure ]
 crbug.com/591099 payments/payment-request-in-iframe.html [ Failure ]
 crbug.com/591099 plugins/mouse-click-plugin-clears-selection.html [ Failure ]
-crbug.com/591099 plugins/plugin-scroll.html [ Failure ]
 crbug.com/591099 plugins/webview-plugin-nested-iframe-scroll.html [ Failure ]
-crbug.com/591099 plugins/webview-plugin-scroll.html [ Failure ]
 crbug.com/591099 printing/absolute-position-headers-and-footers.html [ Failure ]
 crbug.com/591099 printing/absolute-positioned.html [ Failure ]
 crbug.com/591099 printing/allowed-page-breaks.html [ Failure ]
@@ -3440,7 +3436,7 @@
 crbug.com/591099 svg/custom/transformed-text-pattern.html [ Failure ]
 crbug.com/591099 svg/custom/use-event-retargeting.html [ Failure ]
 crbug.com/591099 svg/custom/use-font-face-crash.svg [ Failure ]
-crbug.com/591099 svg/dom/svgangle-units.html [ Pass Timeout ]
+crbug.com/591099 svg/dom/svgangle-units.html [ Timeout ]
 crbug.com/591099 svg/filters/feTurbulence-bad-seeds.html [ Failure ]
 crbug.com/591099 svg/foreign-object-under-shadow-root-under-hidden.html [ Failure ]
 crbug.com/591099 svg/hixie/error/012.xml [ Failure ]
@@ -3450,7 +3446,7 @@
 crbug.com/591099 svg/overflow/overflow-on-outermost-svg-element-in-xhtml-defaults.xhtml [ Failure ]
 crbug.com/591099 svg/parser/whitespace-length-invalid-1.html [ Pass Timeout ]
 crbug.com/591099 svg/parser/whitespace-length-invalid-2.html [ Pass Timeout ]
-crbug.com/591099 svg/parser/whitespace-length-invalid-3.html [ Pass Timeout ]
+crbug.com/591099 svg/parser/whitespace-length-invalid-3.html [ Timeout ]
 crbug.com/591099 svg/parser/whitespace-length-invalid-4.html [ Pass Timeout ]
 crbug.com/591099 svg/parser/whitespace-number.html [ Timeout ]
 crbug.com/714962 svg/text/columns-do-not-apply.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
index 51ae3c1..9372748a 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
@@ -58,37 +58,10 @@
 crbug.com/721408 http/tests/devtools/network/network-datareceived.js [ Failure ]
 crbug.com/721408 http/tests/devtools/network/network-datasaver-warning.js [ Failure ]
 crbug.com/721408 http/tests/inspector-protocol/network-data-length.js [ Failure ]
-crbug.com/721408 http/tests/inspector-protocol/network/basic-request-interception-ignores-hash.js [ Timeout ]
-crbug.com/721408 http/tests/inspector-protocol/network/disable-interception-midway.js [ Failure ]
 crbug.com/721408 http/tests/inspector-protocol/network/interception-auth-cancel.js [ Failure ]
 crbug.com/721408 http/tests/inspector-protocol/network/interception-auth-provide-credentials.js [ Timeout ]
-crbug.com/721408 http/tests/inspector-protocol/network/navigation-interception.js [ Failure ]
-crbug.com/721408 http/tests/inspector-protocol/network/redirect-interception-blocked.js [ Timeout ]
-crbug.com/721408 http/tests/inspector-protocol/network/redirect-interception.js [ Failure ]
-crbug.com/721408 http/tests/inspector-protocol/network/redirect-interception-mocked.js [ Failure ]
-crbug.com/721408 http/tests/inspector-protocol/network/redirect-interception-modified.js [ Failure ]
-crbug.com/721408 http/tests/inspector-protocol/network/request-interception.js [ Timeout ]
-crbug.com/778510 http/tests/inspector-protocol/network/request-interception-frame-id.js [ Timeout Failure ]
-crbug.com/721408 http/tests/inspector-protocol/network/request-interception-mock302.js [ Failure ]
-crbug.com/721408 http/tests/inspector-protocol/network/request-interception-mock404.js [ Timeout ]
-crbug.com/721408 http/tests/inspector-protocol/network/request-interception-modify-get-to-post.js [ Failure ]
-crbug.com/721408 http/tests/inspector-protocol/network/request-interception-on-both-redirect-rewrite.js [ Timeout Failure ]
-crbug.com/721408 http/tests/inspector-protocol/network/request-interception-on-response-redirect.js [ Failure ]
-crbug.com/721408 http/tests/inspector-protocol/network/request-interception-on-response.js [ Failure ]
-crbug.com/721408 http/tests/inspector-protocol/network/request-interception-patterns.js [ Failure ]
-crbug.com/721408 http/tests/inspector-protocol/network/request-interception-raw-headers.js [ Failure ]
-crbug.com/721408 http/tests/inspector-protocol/network/request-interception-resource-types.js [ Failure ]
-crbug.com/721408 http/tests/inspector-protocol/network/request-response-interception-disable-between.js [ Failure Timeout ]
-crbug.com/721408 http/tests/inspector-protocol/network/response-interception-cancel-xhr-while-responding-error.js [ Failure Timeout ]
-crbug.com/721408 http/tests/inspector-protocol/network/response-interception-main-resource-cross-origin.js [ Failure Timeout ]
-crbug.com/721408 http/tests/inspector-protocol/network/response-interception-no-change-content-not-ready.js [ Failure Timeout ]
-crbug.com/721408 http/tests/inspector-protocol/network/response-interception-request-completes-network-closes.js [ Failure Timeout ]
-crbug.com/721408 http/tests/inspector-protocol/network/response-interception-with-data-url.js [ Failure Timeout ]
 crbug.com/721408 http/tests/inspector-protocol/network/xhr-interception-auth-fail.js [ Failure ]
-crbug.com/721408 http/tests/inspector-protocol/network/xhr-interception.js [ Timeout ]
-crbug.com/721408 http/tests/inspector-protocol/network/request-interception-referer.js [ Timeout ]
 crbug.com/721408 http/tests/devtools/console/console-uncaught-promise.js [ Failure ]
-crbug.com/721408 http/tests/devtools/sdk/network-interception-wildcard-pattern-matching.js [ Failure ]
 crbug.com/721408 http/tests/devtools/sources/debugger-async/async-callstack-xhrs.js [ Failure Timeout ]
 Bug(none) http/tests/media/video-buffered.html [ Timeout ]
 Bug(none) http/tests/misc/embed-image-load-outlives-gc-without-crashing.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
index c71cb71..7ce01e9 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -1061,7 +1061,7 @@
 crbug.com/692310 virtual/threaded/animations/composited-animations-rotate-zero-degrees.html [ Pass Failure Timeout ]
 
 # This test uses internal call to initiate smooth scrolling on impl-thread.
-crbug.com/667946 fast/compositor-wheel-scroll-latching/touchpad-scroll-impl-to-main.html [ Failure ]
+crbug.com/667946 fast/compositor-wheel-scroll-latching/animated-scroll/touchpad-scroll-impl-to-main.html [ Failure ]
 
 
 # virtual/threaded variants of sub-directories and tests already skipped or marked as failing above.
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 9a0d79ef..59e2e59 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -402,13 +402,13 @@
 crbug.com/714962 virtual/layout_ng/fast/inline/bpm-inline-ancestors.html [ Failure ]
 
 ### Image/text failures also on LayoutNG
-crbug.com/714962 virtual/layout_ng/fast/inline/absolute-positioned-inline-in-centred-block.html [ Crash Failure ]
+crbug.com/714962 virtual/layout_ng/fast/inline/absolute-positioned-inline-in-centred-block.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/continuation-outlines-with-layers.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/continuation-outlines.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/drawStyledEmptyInlines.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/inline-borders-with-bidi-override.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/inline-focus-ring-under-absolute-enclosing-relative-div.html [ Failure ]
-crbug.com/714962 virtual/layout_ng/fast/inline/left-right-center-inline-alignment-in-ltr-and-rtl-blocks.html [ Crash Failure ]
+crbug.com/714962 virtual/layout_ng/fast/inline/left-right-center-inline-alignment-in-ltr-and-rtl-blocks.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/nested-text-descendants.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/out-of-flow-objects-and-whitespace-after-empty-inline.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/outline-continuations.html [ Failure ]
@@ -1332,12 +1332,6 @@
 # We paint in an incorrect order when layers are present
 crbug.com/370604 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-paint-ordering-002.xhtml [ Failure ]
 
-crbug.com/582836 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-declaration-15.html [ Failure Pass ]
-crbug.com/582836 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-declaration-16.html [ Failure Pass ]
-crbug.com/582836 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-declaration-17.html [ Failure Pass ]
-crbug.com/582836 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-declaration-18.html [ Failure Pass ]
-crbug.com/582836 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-external-font-face-01.html [ Pass Failure ]
-
 crbug.com/736319 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-break-inside-001a.html [ Failure ]
 crbug.com/736319 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-001.html [ Failure ]
 crbug.com/736319 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-002.html [ Failure ]
@@ -2764,7 +2758,7 @@
 crbug.com/626703 [ Win7 Release ] external/wpt/html/semantics/tabular-data/processing-model-1/span-limits.html [ Timeout ]
 
 # Sheriff failure 2017-08-07
-crbug.com/708499 [ Linux ] virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/touchpad-scroll-impl-to-main.html [ Failure Pass ]
+crbug.com/708499 [ Linux ] virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/animated-scroll/touchpad-scroll-impl-to-main.html [ Failure Pass ]
 
 crbug.com/731018 [ Mac ] sensor/accelerometer.html [ Failure Pass Crash ]
 crbug.com/731018 [ Mac ] sensor/ambient-light-sensor.html [ Failure Pass Crash ]
@@ -2947,7 +2941,7 @@
 crbug.com/757165 [ Win ] virtual/gpu/fast/canvas/canvas-filter-modified-save-restore.html [ Skip ]
 crbug.com/757165 [ Win ] virtual/gpu/fast/canvas/canvas-filter-modified.html [ Skip ]
 crbug.com/757165 [ Win ] virtual/threaded/animations/svg/animated-filter-svg-element.html [ Skip ]
-crbug.com/757165 [ Win ] virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/touchpad-scroll-impl-to-main.html [ Skip ]
+crbug.com/757165 [ Win ] virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/animated-scroll/touchpad-scroll-impl-to-main.html [ Skip ]
 crbug.com/757165 [ Win ] virtual/gpu/fast/canvas/canvas-blending-clipping.html [ Skip ]
 crbug.com/757165 [ Win ] virtual/gpu/fast/canvas/canvas-blending-color-over-color.html [ Skip ]
 crbug.com/757165 [ Win ] virtual/gpu/fast/canvas/canvas-blending-color-over-gradient.html [ Skip ]
@@ -3247,7 +3241,7 @@
 crbug.com/799137 [ Mac ] virtual/modern-media-controls/media/controls/modern/doubletap-to-jump-backwards-at-start.html [ Pass Timeout ]
 
 # This test is flaking (failing, crashing) on mac_chromium_rel_ng.
-crbug.com/800840 [ Mac ] virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/touchpad-scroll-impl-to-main.html [ Skip ]
+crbug.com/800840 [ Mac ] virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/animated-scroll/touchpad-scroll-impl-to-main.html [ Skip ]
 
 # Sheriff failures 2018-01-23
 # Flaking on linux_chromium_rel_ng
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index 78a6e36..e5c6f9b 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -319,7 +319,13 @@
   },
   {
     "prefix": "wheelscrolllatching",
-    "base": "fast/compositor-wheel-scroll-latching",
+    "base": "fast/compositor-wheel-scroll-latching/animated-scroll",
+    "args": ["--enable-features=TouchpadAndWheelScrollLatching",
+             "--enable-threaded-compositing"]
+  },
+  {
+    "prefix": "wheelscrolllatching",
+    "base": "fast/compositor-wheel-scroll-latching/non-animated-scroll",
     "args": ["--enable-features=TouchpadAndWheelScrollLatching",
              "--enable-threaded-compositing",
              "--disable-smooth-scrolling"]
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/fake-bluetooth-chooser-test.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/fake-bluetooth-chooser-test.html
new file mode 100644
index 0000000..ce66e76
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice/chooser/fake-bluetooth-chooser-test.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="../../../external/wpt/bluetooth/resources/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+// TODO(https://crbug.com/719826): This is a temporary test to try the
+// FakeBluetoothChooser API as it is implemented. This test should be delete after
+// the feature is completed. The implementation details can be found in the design
+// document.
+// https://docs.google.com/document/d/1XFl_4ZAgO8ddM6U53A9AfUuZeWgJnlYD5wtbXqEpzeg
+const test_desc = 'Ensure that the FakeBluetoothChooser API works correctly.';
+
+bluetooth_test(() => navigator.bluetooth.test.simulateCentral({
+  state: 'powered-on'
+})
+    .then(() => navigator.bluetooth.test.getManualChooser())
+    .then(chooser => assert_true(typeof chooser !== 'undefined')),
+    test_desc);
+</script>
diff --git a/third_party/WebKit/LayoutTests/editing/selection/modify_move/move-by-character-right-001.html b/third_party/WebKit/LayoutTests/editing/selection/modify_move/move-by-character-right-001.html
deleted file mode 100644
index 0b0ad65..0000000
--- a/third_party/WebKit/LayoutTests/editing/selection/modify_move/move-by-character-right-001.html
+++ /dev/null
@@ -1,414 +0,0 @@
-<!DOCTYPE html>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../assert_selection.js"></script>
-<script>
-function testMoveRightCharacter(input_list, description) {
-  for (i = 0; i < input_list.length - 1; i++) {
-    selection_test(
-      input_list[i],
-      selection => {
-        selection.modify('move', 'right', 'character');
-      },
-      input_list[i + 1],
-      `${description} step ${i}`);
-  }
-}
-testMoveRightCharacter([
-`  <div>|abc</div>`,
-`  <div>a|bc</div>`,
-`  <div>ab|c</div>`,
-`  <div>abc|</div>`,
-], 'case 0');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", ];
-testMoveRightCharacter([
-`  <div>|${RTLs[0]}${RTLs[1]}${RTLs[2]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}|${RTLs[2]}</div>`,
-`  <div>${RTLs[0]}|${RTLs[1]}${RTLs[2]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}|</div>`,
-], 'case 1');
-
-testMoveRightCharacter([
-`  <div>|<br>abc</div>`,
-`  <div><br>|abc</div>`,
-`  <div><br>a|bc</div>`,
-`  <div><br>ab|c</div>`,
-`  <div><br>abc|</div>`,
-], 'case 2');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", ];
-testMoveRightCharacter([
-`  <div>|<br>${RTLs[0]}${RTLs[1]}${RTLs[2]}</div>`,
-`  <div><br>|${RTLs[0]}${RTLs[1]}${RTLs[2]}</div>`,
-`  <div><br>${RTLs[0]}${RTLs[1]}|${RTLs[2]}</div>`,
-`  <div><br>${RTLs[0]}|${RTLs[1]}${RTLs[2]}</div>`,
-`  <div><br>${RTLs[0]}${RTLs[1]}${RTLs[2]}|</div>`,
-], 'case 3');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", ];
-testMoveRightCharacter([
-`  <div>|abc${RTLs[0]}${RTLs[1]}${RTLs[2]}def</div>`,
-`  <div>a|bc${RTLs[0]}${RTLs[1]}${RTLs[2]}def</div>`,
-`  <div>ab|c${RTLs[0]}${RTLs[1]}${RTLs[2]}def</div>`,
-`  <div>abc|${RTLs[0]}${RTLs[1]}${RTLs[2]}def</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}|${RTLs[2]}def</div>`,
-`  <div>abc${RTLs[0]}|${RTLs[1]}${RTLs[2]}def</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}|def</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}d|ef</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}de|f</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}def|</div>`,
-], 'case 4');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", ];
-testMoveRightCharacter([
-`  <div>|${RTLs[0]}${RTLs[1]}${RTLs[2]}abc${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}|${RTLs[2]}abc${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}|${RTLs[1]}${RTLs[2]}abc${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}|abc${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}a|bc${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}ab|c${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}abc|${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}abc${RTLs[3]}${RTLs[4]}|${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}abc${RTLs[3]}|${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}abc${RTLs[3]}${RTLs[4]}${RTLs[5]}|</div>`,
-], 'case 5');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", ];
-testMoveRightCharacter([
-`  <div>|abc${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>a|bc${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>ab|c${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>abc|${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}|${RTLs[5]}</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}|${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}|${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}|${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>abc${RTLs[0]}|${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}|</div>`,
-], 'case 6');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", ];
-testMoveRightCharacter([
-`  <div>|${RTLs[0]}${RTLs[1]}${RTLs[2]}abcdef</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}|${RTLs[2]}abcdef</div>`,
-`  <div>${RTLs[0]}|${RTLs[1]}${RTLs[2]}abcdef</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}|abcdef</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}a|bcdef</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}ab|cdef</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}abc|def</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}abcd|ef</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}abcde|f</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}abcdef|</div>`,
-], 'case 7');
-
-var RTLs = ["\u0661", "\u0662", "\u0663", "\u0627", "\u0628", "\u0629", ];
-testMoveRightCharacter([
-`  <div>|${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}|${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}|${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}|${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}|${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}|</div>`,
-], 'case 8');
-
-var RTLs = ["\u0627", "\u0628", "\u0629", "\u0661", "\u0662", "\u0663", ];
-testMoveRightCharacter([
-`  <div>|${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}|${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}|${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}|${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}|${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}|</div>`,
-], 'case 9');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", ];
-testMoveRightCharacter([
-`  <div>|<span>abc</span>${RTLs[0]}${RTLs[1]}${RTLs[2]}def</div>`,
-`  <div><span>a|bc</span>${RTLs[0]}${RTLs[1]}${RTLs[2]}def</div>`,
-`  <div><span>ab|c</span>${RTLs[0]}${RTLs[1]}${RTLs[2]}def</div>`,
-`  <div><span>abc|</span>${RTLs[0]}${RTLs[1]}${RTLs[2]}def</div>`,
-`  <div><span>abc</span>${RTLs[0]}${RTLs[1]}|${RTLs[2]}def</div>`,
-`  <div><span>abc</span>${RTLs[0]}|${RTLs[1]}${RTLs[2]}def</div>`,
-`  <div><span>abc</span>${RTLs[0]}${RTLs[1]}${RTLs[2]}|def</div>`,
-`  <div><span>abc</span>${RTLs[0]}${RTLs[1]}${RTLs[2]}d|ef</div>`,
-`  <div><span>abc</span>${RTLs[0]}${RTLs[1]}${RTLs[2]}de|f</div>`,
-`  <div><span>abc</span>${RTLs[0]}${RTLs[1]}${RTLs[2]}def|</div>`,
-], 'case 10');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", ];
-testMoveRightCharacter([
-`  <div>|<span>${RTLs[0]}${RTLs[1]}${RTLs[2]}</span>abc${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div><span>${RTLs[0]}${RTLs[1]}|${RTLs[2]}</span>abc${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div><span>${RTLs[0]}|${RTLs[1]}${RTLs[2]}</span>abc${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div><span>${RTLs[0]}${RTLs[1]}${RTLs[2]}|</span>abc${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div><span>${RTLs[0]}${RTLs[1]}${RTLs[2]}</span>a|bc${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div><span>${RTLs[0]}${RTLs[1]}${RTLs[2]}</span>ab|c${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div><span>${RTLs[0]}${RTLs[1]}${RTLs[2]}</span>abc|${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div><span>${RTLs[0]}${RTLs[1]}${RTLs[2]}</span>abc${RTLs[3]}${RTLs[4]}|${RTLs[5]}</div>`,
-`  <div><span>${RTLs[0]}${RTLs[1]}${RTLs[2]}</span>abc${RTLs[3]}|${RTLs[4]}${RTLs[5]}</div>`,
-`  <div><span>${RTLs[0]}${RTLs[1]}${RTLs[2]}</span>abc${RTLs[3]}${RTLs[4]}${RTLs[5]}|</div>`,
-], 'case 11');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", ];
-testMoveRightCharacter([
-`  <div>|abc${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}def</div>`,
-`  <div>a|bc${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}def</div>`,
-`  <div>ab|c${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}def</div>`,
-`  <div>abc|${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}def</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}|${RTLs[5]}def</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}|${RTLs[4]}${RTLs[5]}def</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}|123${RTLs[3]}${RTLs[4]}${RTLs[5]}def</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}1|23${RTLs[3]}${RTLs[4]}${RTLs[5]}def</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}12|3${RTLs[3]}${RTLs[4]}${RTLs[5]}def</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}123|${RTLs[3]}${RTLs[4]}${RTLs[5]}def</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}|${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}def</div>`,
-`  <div>abc${RTLs[0]}|${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}def</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}|def</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}d|ef</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}de|f</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}def|</div>`,
-], 'case 12');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", ];
-testMoveRightCharacter([
-`  <div>|abc${RTLs[0]}${RTLs[1]}${RTLs[2]}123</div>`,
-`  <div>a|bc${RTLs[0]}${RTLs[1]}${RTLs[2]}123</div>`,
-`  <div>ab|c${RTLs[0]}${RTLs[1]}${RTLs[2]}123</div>`,
-`  <div>abc|${RTLs[0]}${RTLs[1]}${RTLs[2]}123</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}1|23</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}12|3</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}|${RTLs[2]}123</div>`,
-`  <div>abc${RTLs[0]}|${RTLs[1]}${RTLs[2]}123</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}123|</div>`,
-], 'case 13');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", ];
-testMoveRightCharacter([
-`  <div>|abc${RTLs[0]}${RTLs[1]}${RTLs[2]}123def</div>`,
-`  <div>a|bc${RTLs[0]}${RTLs[1]}${RTLs[2]}123def</div>`,
-`  <div>ab|c${RTLs[0]}${RTLs[1]}${RTLs[2]}123def</div>`,
-`  <div>abc|${RTLs[0]}${RTLs[1]}${RTLs[2]}123def</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}1|23def</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}12|3def</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}|${RTLs[2]}123def</div>`,
-`  <div>abc${RTLs[0]}|${RTLs[1]}${RTLs[2]}123def</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}123|def</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}123d|ef</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}123de|f</div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}123def|</div>`,
-], 'case 14');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", "\u05d6", "\u05d7", "\u05d8",
-"\u05d9", "\u05db", "\u05dc", ];
-testMoveRightCharacter([
-`  <div>|${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}abc${RTLs[6]}${RTLs[7]}${RTLs[8]}456${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}|${RTLs[5]}abc${RTLs[6]}${RTLs[7]}${RTLs[8]}456${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}|${RTLs[4]}${RTLs[5]}abc${RTLs[6]}${RTLs[7]}${RTLs[8]}456${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}|123${RTLs[3]}${RTLs[4]}${RTLs[5]}abc${RTLs[6]}${RTLs[7]}${RTLs[8]}456${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}1|23${RTLs[3]}${RTLs[4]}${RTLs[5]}abc${RTLs[6]}${RTLs[7]}${RTLs[8]}456${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}12|3${RTLs[3]}${RTLs[4]}${RTLs[5]}abc${RTLs[6]}${RTLs[7]}${RTLs[8]}456${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}123|${RTLs[3]}${RTLs[4]}${RTLs[5]}abc${RTLs[6]}${RTLs[7]}${RTLs[8]}456${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}|${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}abc${RTLs[6]}${RTLs[7]}${RTLs[8]}456${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}|${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}abc${RTLs[6]}${RTLs[7]}${RTLs[8]}456${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}|abc${RTLs[6]}${RTLs[7]}${RTLs[8]}456${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}a|bc${RTLs[6]}${RTLs[7]}${RTLs[8]}456${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}ab|c${RTLs[6]}${RTLs[7]}${RTLs[8]}456${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}abc|${RTLs[6]}${RTLs[7]}${RTLs[8]}456${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}abc${RTLs[6]}${RTLs[7]}${RTLs[8]}456${RTLs[9]}${RTLs[10]}|${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}abc${RTLs[6]}${RTLs[7]}${RTLs[8]}456${RTLs[9]}|${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}abc${RTLs[6]}${RTLs[7]}${RTLs[8]}|456${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}abc${RTLs[6]}${RTLs[7]}${RTLs[8]}4|56${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}abc${RTLs[6]}${RTLs[7]}${RTLs[8]}45|6${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}abc${RTLs[6]}${RTLs[7]}${RTLs[8]}456|${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}abc${RTLs[6]}${RTLs[7]}|${RTLs[8]}456${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}abc${RTLs[6]}|${RTLs[7]}${RTLs[8]}456${RTLs[9]}${RTLs[10]}${RTLs[11]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}123${RTLs[3]}${RTLs[4]}${RTLs[5]}abc${RTLs[6]}${RTLs[7]}${RTLs[8]}456${RTLs[9]}${RTLs[10]}${RTLs[11]}|</div>`,
-], 'case 15');
-
-var RTLs = ["\u05d0", "\u05d7", "\u05e8", "\u05d9", "\u05e0", "\u05e6", "\u05e7", "\u05dc", "\u05d5",
-"\u05e4", "\u05d3", "\u05d4", ];
-testMoveRightCharacter([
-`  <div style="width: 120px;">|before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">b|efore    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">be|fore    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">bef|ore    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">befo|re    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">befor|e    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before|    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before |   ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}|${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}|${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before    ${RTLs[0]}|${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}| ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} |${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}|${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}|${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}|${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}|${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}|${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}|${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}|${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}|${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}|${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}|${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}|</div>`,
-], 'case 16');
-
-var RTLs = ["\u05dc", "\u05e4", "\u05e0", "\u05d9", ];
-testMoveRightCharacter([
-`  <div style="width: 120px;">|${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encyclopedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}|${RTLs[3]}    after encyclopedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}|${RTLs[2]}${RTLs[3]}    after encyclopedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}|${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encyclopedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}|    after encyclopedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} |   after encyclopedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    a|fter encyclopedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    af|ter encyclopedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    aft|er encyclopedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    afte|r encyclopedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after| encyclopedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after |encyclopedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after e|ncyclopedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after en|cyclopedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after enc|yclopedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after ency|clopedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encyc|lopedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encycl|opedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encyclo|pedia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encyclop|edia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encyclope|dia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encycloped|ia</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encyclopedi|a</div>`,
-`  <div style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encyclopedia|</div>`,
-], 'case 17');
-
-var RTLs = ["\u05d0", "\u05d7", "\u05e8", "\u05d9", "\u05e0", "\u05e6", "\u05e7", "\u05dc", "\u05d5",
-"\u05e4", "\u05d3", "\u05d4", ];
-testMoveRightCharacter([
-`  <div contenteditable style="width: 120px;">|before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">b|efore    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">be|fore    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">bef|ore    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">befo|re    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">befor|e    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before|    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before |   ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}|${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}|${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before    ${RTLs[0]}|${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}| ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} |${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}|${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}|${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}|${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}|${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}|${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}|${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}|${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}|${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}|${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}|${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}</div>`,
-`  <div contenteditable style="width: 120px;">before    ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[0]}${RTLs[4]}${RTLs[5]}${RTLs[3]}${RTLs[6]}${RTLs[7]}${RTLs[8]}${RTLs[9]}${RTLs[10]}${RTLs[3]}${RTLs[11]}|</div>`,
-], 'case 18');
-
-var RTLs = ["\u05dc", "\u05e4", "\u05e0", "\u05d9", ];
-testMoveRightCharacter([
-`  <div contenteditable style="width: 120px;">|${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encyclopedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}|${RTLs[3]}    after encyclopedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}|${RTLs[2]}${RTLs[3]}    after encyclopedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}|${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encyclopedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}|    after encyclopedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} |   after encyclopedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    a|fter encyclopedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    af|ter encyclopedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    aft|er encyclopedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    afte|r encyclopedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after| encyclopedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after |encyclopedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after e|ncyclopedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after en|cyclopedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after enc|yclopedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after ency|clopedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encyc|lopedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encycl|opedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encyclo|pedia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encyclop|edia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encyclope|dia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encycloped|ia</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encyclopedi|a</div>`,
-`  <div contenteditable style="width: 120px;">${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}    after encyclopedia|</div>`,
-], 'case 19');
-
-var RTLs = ["\u05d9", "\u05d5", "\u05ea", "\u05e8", "\u05e6", "\u05de", ];
-testMoveRightCharacter([
-`  <div style="width: 100px;">|This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">T|his is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">Th|is is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">Thi|s is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">This| is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">This |is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">This i|s ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">This is| ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">This is |${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}|${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} |${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}| ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}|${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}|${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}|${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]}| ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} |${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}|${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}|${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}|${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]}| the boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} |the boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} t|he boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} th|e boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the| boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the |boxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the b|oxes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the bo|xes.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the box|es.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxe|s.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes|.</div>`,
-`  <div style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.|</div>`,
-], 'case 20');
-
-var RTLs = ["\u05d9", "\u05d5", "\u05ea", "\u05e8", "\u05e6", "\u05de", ];
-testMoveRightCharacter([
-`  <div contenteditable style="width: 100px;">|This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">T|his is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">Th|is is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">Thi|s is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This| is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This |is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This i|s ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is| ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is |${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}|${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} |${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}| ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}|${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}|${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}|${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]}| ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} |${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}|${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}|${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}|${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]}| the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} |the boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} t|he boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} th|e boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the| boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the |boxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the b|oxes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the bo|xes.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the box|es.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxe|s.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes|.</div>`,
-`  <div contenteditable style="width: 100px;">This is ${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]} ${RTLs[4]}${RTLs[3]} ${RTLs[5]}${RTLs[0]}${RTLs[2]}${RTLs[3]} the boxes.|</div>`,
-], 'case 21');
-</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/editing/selection/modify_move/move-by-character-right-002.html b/third_party/WebKit/LayoutTests/editing/selection/modify_move/move-by-character-right-002.html
deleted file mode 100644
index becee2b..0000000
--- a/third_party/WebKit/LayoutTests/editing/selection/modify_move/move-by-character-right-002.html
+++ /dev/null
@@ -1,420 +0,0 @@
-<!DOCTYPE html>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../assert_selection.js"></script>
-<script>
-function testMoveRightCharacter(input_list, description) {
-  for (i = 0; i < input_list.length - 1; i++) {
-    selection_test(
-      input_list[i],
-      selection => {
-        selection.modify('move', 'right', 'character');
-      },
-      input_list[i + 1],
-      `${description} step ${i}`);
-  }
-}
-
-testMoveRightCharacter([
-`  <div>|Lorem
-      <div></div>
-      ipsum</div>`,
-`  <div>L|orem
-      <div></div>
-      ipsum</div>`,
-`  <div>Lo|rem
-      <div></div>
-      ipsum</div>`,
-`  <div>Lor|em
-      <div></div>
-      ipsum</div>`,
-`  <div>Lore|m
-      <div></div>
-      ipsum</div>`,
-`  <div>Lorem|
-      <div></div>
-      ipsum</div>`,
-`  <div>Lorem
-      <div></div>
-      |ipsum</div>`,
-`  <div>Lorem
-      <div></div>
-      i|psum</div>`,
-`  <div>Lorem
-      <div></div>
-      ip|sum</div>`,
-`  <div>Lorem
-      <div></div>
-      ips|um</div>`,
-`  <div>Lorem
-      <div></div>
-      ipsu|m</div>`,
-`  <div>Lorem
-      <div></div>
-      ipsum|</div>`,
-], 'case 22');
-
-var RTLs = ["\u05e6", "\u05dc", "\u05d7", "\u05ea", "\u05de", "\u05e0", "\u05e4", ];
-testMoveRightCharacter([
-`  <div>|${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}
-      <div></div>
-      ${RTLs[4]}${RTLs[0]}${RTLs[5]}${RTLs[6]}${RTLs[3]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}|${RTLs[3]}
-      <div></div>
-      ${RTLs[4]}${RTLs[0]}${RTLs[5]}${RTLs[6]}${RTLs[3]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}|${RTLs[2]}${RTLs[3]}
-      <div></div>
-      ${RTLs[4]}${RTLs[0]}${RTLs[5]}${RTLs[6]}${RTLs[3]}</div>`,
-`  <div>${RTLs[0]}|${RTLs[1]}${RTLs[2]}${RTLs[3]}
-      <div></div>
-      ${RTLs[4]}${RTLs[0]}${RTLs[5]}${RTLs[6]}${RTLs[3]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}|
-      <div></div>
-      ${RTLs[4]}${RTLs[0]}${RTLs[5]}${RTLs[6]}${RTLs[3]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}
-      <div></div>
-      |${RTLs[4]}${RTLs[0]}${RTLs[5]}${RTLs[6]}${RTLs[3]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}
-      <div></div>
-      ${RTLs[4]}${RTLs[0]}${RTLs[5]}${RTLs[6]}|${RTLs[3]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}
-      <div></div>
-      ${RTLs[4]}${RTLs[0]}${RTLs[5]}|${RTLs[6]}${RTLs[3]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}
-      <div></div>
-      ${RTLs[4]}${RTLs[0]}|${RTLs[5]}${RTLs[6]}${RTLs[3]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}
-      <div></div>
-      ${RTLs[4]}|${RTLs[0]}${RTLs[5]}${RTLs[6]}${RTLs[3]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}
-      <div></div>
-      ${RTLs[4]}${RTLs[0]}${RTLs[5]}${RTLs[6]}${RTLs[3]}|</div>`,
-], 'case 23');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", ];
-testMoveRightCharacter([
-`  <div>|abcdef${RTLs[0]}${RTLs[1]}${RTLs[2]}<img>${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>a|bcdef${RTLs[0]}${RTLs[1]}${RTLs[2]}<img>${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>ab|cdef${RTLs[0]}${RTLs[1]}${RTLs[2]}<img>${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>abc|def${RTLs[0]}${RTLs[1]}${RTLs[2]}<img>${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>abcd|ef${RTLs[0]}${RTLs[1]}${RTLs[2]}<img>${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>abcde|f${RTLs[0]}${RTLs[1]}${RTLs[2]}<img>${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>abcdef|${RTLs[0]}${RTLs[1]}${RTLs[2]}<img>${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>abcdef${RTLs[0]}${RTLs[1]}${RTLs[2]}<img>${RTLs[3]}${RTLs[4]}|${RTLs[5]}</div>`,
-`  <div>abcdef${RTLs[0]}${RTLs[1]}${RTLs[2]}<img>${RTLs[3]}|${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>abcdef${RTLs[0]}${RTLs[1]}${RTLs[2]}<img>|${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>abcdef${RTLs[0]}${RTLs[1]}${RTLs[2]}|<img>${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>abcdef${RTLs[0]}${RTLs[1]}|${RTLs[2]}<img>${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>abcdef${RTLs[0]}|${RTLs[1]}${RTLs[2]}<img>${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>abcdef${RTLs[0]}${RTLs[1]}${RTLs[2]}<img>${RTLs[3]}${RTLs[4]}${RTLs[5]}|</div>`,
-], 'case 24');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", ];
-testMoveRightCharacter([
-`  <div>|${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}abc<img>def</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}|${RTLs[5]}abc<img>def</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}|${RTLs[4]}${RTLs[5]}abc<img>def</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}|${RTLs[3]}${RTLs[4]}${RTLs[5]}abc<img>def</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}|${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}abc<img>def</div>`,
-`  <div>${RTLs[0]}|${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}abc<img>def</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}|abc<img>def</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}a|bc<img>def</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}ab|c<img>def</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}abc|<img>def</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}abc<img>|def</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}abc<img>d|ef</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}abc<img>de|f</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}${RTLs[3]}${RTLs[4]}${RTLs[5]}abc<img>def|</div>`,
-], 'case 25');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", ];
-testMoveRightCharacter([
-`  <div>|abc<input>${RTLs[0]}${RTLs[1]}${RTLs[2]}<img><img>${RTLs[3]}${RTLs[4]}${RTLs[5]}ghi</div>`,
-`  <div>a|bc<input>${RTLs[0]}${RTLs[1]}${RTLs[2]}<img><img>${RTLs[3]}${RTLs[4]}${RTLs[5]}ghi</div>`,
-`  <div>ab|c<input>${RTLs[0]}${RTLs[1]}${RTLs[2]}<img><img>${RTLs[3]}${RTLs[4]}${RTLs[5]}ghi</div>`,
-`  <div>abc|<input>${RTLs[0]}${RTLs[1]}${RTLs[2]}<img><img>${RTLs[3]}${RTLs[4]}${RTLs[5]}ghi</div>`,
-`  <div>abc<input>|${RTLs[0]}${RTLs[1]}${RTLs[2]}<img><img>${RTLs[3]}${RTLs[4]}${RTLs[5]}ghi</div>`,
-`  <div>abc<input>${RTLs[0]}${RTLs[1]}${RTLs[2]}<img><img>${RTLs[3]}${RTLs[4]}|${RTLs[5]}ghi</div>`,
-`  <div>abc<input>${RTLs[0]}${RTLs[1]}${RTLs[2]}<img><img>${RTLs[3]}|${RTLs[4]}${RTLs[5]}ghi</div>`,
-`  <div>abc<input>${RTLs[0]}${RTLs[1]}${RTLs[2]}<img><img>|${RTLs[3]}${RTLs[4]}${RTLs[5]}ghi</div>`,
-`  <div>abc<input>${RTLs[0]}${RTLs[1]}${RTLs[2]}<img>|<img>${RTLs[3]}${RTLs[4]}${RTLs[5]}ghi</div>`,
-`  <div>abc<input>${RTLs[0]}${RTLs[1]}${RTLs[2]}|<img><img>${RTLs[3]}${RTLs[4]}${RTLs[5]}ghi</div>`,
-`  <div>abc<input>${RTLs[0]}${RTLs[1]}|${RTLs[2]}<img><img>${RTLs[3]}${RTLs[4]}${RTLs[5]}ghi</div>`,
-`  <div>abc<input>${RTLs[0]}|${RTLs[1]}${RTLs[2]}<img><img>${RTLs[3]}${RTLs[4]}${RTLs[5]}ghi</div>`,
-`  <div>abc<input>${RTLs[0]}${RTLs[1]}${RTLs[2]}<img><img>${RTLs[3]}${RTLs[4]}${RTLs[5]}|ghi</div>`,
-`  <div>abc<input>${RTLs[0]}${RTLs[1]}${RTLs[2]}<img><img>${RTLs[3]}${RTLs[4]}${RTLs[5]}g|hi</div>`,
-`  <div>abc<input>${RTLs[0]}${RTLs[1]}${RTLs[2]}<img><img>${RTLs[3]}${RTLs[4]}${RTLs[5]}gh|i</div>`,
-`  <div>abc<input>${RTLs[0]}${RTLs[1]}${RTLs[2]}<img><img>${RTLs[3]}${RTLs[4]}${RTLs[5]}ghi|</div>`,
-], 'case 26');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", ];
-testMoveRightCharacter([
-`  <div>|${RTLs[0]}${RTLs[1]}${RTLs[2]}<input>abc<img><img>def${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}|${RTLs[2]}<input>abc<img><img>def${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}|${RTLs[1]}${RTLs[2]}<input>abc<img><img>def${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}|<input>abc<img><img>def${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<input>|abc<img><img>def${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<input>a|bc<img><img>def${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<input>ab|c<img><img>def${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<input>abc|<img><img>def${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<input>abc<img>|<img>def${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<input>abc<img><img>|def${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<input>abc<img><img>d|ef${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<input>abc<img><img>de|f${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<input>abc<img><img>def|${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<input>abc<img><img>def${RTLs[3]}${RTLs[4]}|${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<input>abc<img><img>def${RTLs[3]}|${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<input>abc<img><img>def${RTLs[3]}${RTLs[4]}${RTLs[5]}|</div>`,
-], 'case 27');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", ];
-testMoveRightCharacter([
-`  <div>|abc${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>a|bc${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>ab|c${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>abc|${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>${RTLs[3]}${RTLs[4]}|${RTLs[5]}</span></div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>${RTLs[3]}|${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}|<span>${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}|${RTLs[2]}<span>${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>abc${RTLs[0]}|${RTLs[1]}${RTLs[2]}<span>${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>${RTLs[3]}${RTLs[4]}${RTLs[5]}|</span></div>`,
-], 'case 28');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", ];
-testMoveRightCharacter([
-`  <div>|${RTLs[0]}${RTLs[1]}${RTLs[2]}abc<span>def</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}|${RTLs[2]}abc<span>def</span></div>`,
-`  <div>${RTLs[0]}|${RTLs[1]}${RTLs[2]}abc<span>def</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}|abc<span>def</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}a|bc<span>def</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}ab|c<span>def</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}abc|<span>def</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}abc<span>d|ef</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}abc<span>de|f</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}abc<span>def|</span></div>`,
-], 'case 29');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", ];
-testMoveRightCharacter([
-`  <div>|ab<span>c${RTLs[0]}${RTLs[1]}${RTLs[2]}def</span></div>`,
-`  <div>a|b<span>c${RTLs[0]}${RTLs[1]}${RTLs[2]}def</span></div>`,
-`  <div>ab|<span>c${RTLs[0]}${RTLs[1]}${RTLs[2]}def</span></div>`,
-`  <div>ab<span>c|${RTLs[0]}${RTLs[1]}${RTLs[2]}def</span></div>`,
-`  <div>ab<span>c${RTLs[0]}${RTLs[1]}|${RTLs[2]}def</span></div>`,
-`  <div>ab<span>c${RTLs[0]}|${RTLs[1]}${RTLs[2]}def</span></div>`,
-`  <div>ab<span>c${RTLs[0]}${RTLs[1]}${RTLs[2]}|def</span></div>`,
-`  <div>ab<span>c${RTLs[0]}${RTLs[1]}${RTLs[2]}d|ef</span></div>`,
-`  <div>ab<span>c${RTLs[0]}${RTLs[1]}${RTLs[2]}de|f</span></div>`,
-`  <div>ab<span>c${RTLs[0]}${RTLs[1]}${RTLs[2]}def|</span></div>`,
-], 'case 30');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", ];
-testMoveRightCharacter([
-`  <div>|${RTLs[0]}${RTLs[1]}<span>${RTLs[2]}abc${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}|<span>${RTLs[2]}abc${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}|${RTLs[1]}<span>${RTLs[2]}abc${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}<span>${RTLs[2]}|abc${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}<span>${RTLs[2]}a|bc${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}<span>${RTLs[2]}ab|c${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}<span>${RTLs[2]}abc|${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}<span>${RTLs[2]}abc${RTLs[3]}${RTLs[4]}|${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}<span>${RTLs[2]}abc${RTLs[3]}|${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}<span>${RTLs[2]}abc${RTLs[3]}${RTLs[4]}${RTLs[5]}|</span></div>`,
-], 'case 31');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", ];
-testMoveRightCharacter([
-`  <div>|abc<span>${RTLs[0]}${RTLs[1]}${RTLs[2]}def</span></div>`,
-`  <div>a|bc<span>${RTLs[0]}${RTLs[1]}${RTLs[2]}def</span></div>`,
-`  <div>ab|c<span>${RTLs[0]}${RTLs[1]}${RTLs[2]}def</span></div>`,
-`  <div>abc|<span>${RTLs[0]}${RTLs[1]}${RTLs[2]}def</span></div>`,
-`  <div>abc<span>${RTLs[0]}${RTLs[1]}|${RTLs[2]}def</span></div>`,
-`  <div>abc<span>${RTLs[0]}|${RTLs[1]}${RTLs[2]}def</span></div>`,
-`  <div>abc<span>${RTLs[0]}${RTLs[1]}${RTLs[2]}|def</span></div>`,
-`  <div>abc<span>${RTLs[0]}${RTLs[1]}${RTLs[2]}d|ef</span></div>`,
-`  <div>abc<span>${RTLs[0]}${RTLs[1]}${RTLs[2]}de|f</span></div>`,
-`  <div>abc<span>${RTLs[0]}${RTLs[1]}${RTLs[2]}def|</span></div>`,
-], 'case 32');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", ];
-testMoveRightCharacter([
-`  <div>|${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>abc${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}|${RTLs[2]}<span>abc${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}|${RTLs[1]}${RTLs[2]}<span>abc${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}|<span>abc${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>a|bc${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>ab|c${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>abc|${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>abc${RTLs[3]}${RTLs[4]}|${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>abc${RTLs[3]}|${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>abc${RTLs[3]}${RTLs[4]}${RTLs[5]}|</span></div>`,
-], 'case 33');
-
-var RTLs = ["\u05d0", ];
-testMoveRightCharacter([
-`  <div>|abc${RTLs[0]}def</div>`,
-`  <div>a|bc${RTLs[0]}def</div>`,
-`  <div>ab|c${RTLs[0]}def</div>`,
-`  <div>abc|${RTLs[0]}def</div>`,
-`  <div>abc${RTLs[0]}|def</div>`,
-`  <div>abc${RTLs[0]}d|ef</div>`,
-`  <div>abc${RTLs[0]}de|f</div>`,
-`  <div>abc${RTLs[0]}def|</div>`,
-], 'case 34');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", ];
-testMoveRightCharacter([
-`  <div>|${RTLs[0]}${RTLs[1]}${RTLs[2]}a${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}|${RTLs[2]}a${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}|${RTLs[1]}${RTLs[2]}a${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}|a${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}a|${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}a${RTLs[3]}${RTLs[4]}|${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}a${RTLs[3]}|${RTLs[4]}${RTLs[5]}</div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}a${RTLs[3]}${RTLs[4]}${RTLs[5]}|</div>`,
-], 'case 35');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", ];
-testMoveRightCharacter([
-`  <div>|abc${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>def</span></div>`,
-`  <div>a|bc${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>def</span></div>`,
-`  <div>ab|c${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>def</span></div>`,
-`  <div>abc|${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>def</span></div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}|${RTLs[2]}<span>def</span></div>`,
-`  <div>abc${RTLs[0]}|${RTLs[1]}${RTLs[2]}<span>def</span></div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}|<span>def</span></div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>d|ef</span></div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>de|f</span></div>`,
-`  <div>abc${RTLs[0]}${RTLs[1]}${RTLs[2]}<span>def|</span></div>`,
-], 'case 36');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", ];
-testMoveRightCharacter([
-`  <div>|${RTLs[0]}${RTLs[1]}${RTLs[2]}abc<span>${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}|${RTLs[2]}abc<span>${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}|${RTLs[1]}${RTLs[2]}abc<span>${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}|abc<span>${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}a|bc<span>${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}ab|c<span>${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}abc|<span>${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}abc<span>${RTLs[3]}${RTLs[4]}|${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}abc<span>${RTLs[3]}|${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}abc<span>${RTLs[3]}${RTLs[4]}${RTLs[5]}|</span></div>`,
-], 'case 37');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", ];
-testMoveRightCharacter([
-`  <div>|abc${RTLs[0]}<span>${RTLs[1]}${RTLs[2]}def</span></div>`,
-`  <div>a|bc${RTLs[0]}<span>${RTLs[1]}${RTLs[2]}def</span></div>`,
-`  <div>ab|c${RTLs[0]}<span>${RTLs[1]}${RTLs[2]}def</span></div>`,
-`  <div>abc|${RTLs[0]}<span>${RTLs[1]}${RTLs[2]}def</span></div>`,
-`  <div>abc${RTLs[0]}<span>${RTLs[1]}|${RTLs[2]}def</span></div>`,
-`  <div>abc${RTLs[0]}|<span>${RTLs[1]}${RTLs[2]}def</span></div>`,
-`  <div>abc${RTLs[0]}<span>${RTLs[1]}${RTLs[2]}|def</span></div>`,
-`  <div>abc${RTLs[0]}<span>${RTLs[1]}${RTLs[2]}d|ef</span></div>`,
-`  <div>abc${RTLs[0]}<span>${RTLs[1]}${RTLs[2]}de|f</span></div>`,
-`  <div>abc${RTLs[0]}<span>${RTLs[1]}${RTLs[2]}def|</span></div>`,
-], 'case 38');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", ];
-testMoveRightCharacter([
-`  <div>|${RTLs[0]}${RTLs[1]}${RTLs[2]}a<span>bc${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}|${RTLs[2]}a<span>bc${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}|${RTLs[1]}${RTLs[2]}a<span>bc${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}|a<span>bc${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}a|<span>bc${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}a<span>b|c${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}a<span>bc|${RTLs[3]}${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}a<span>bc${RTLs[3]}${RTLs[4]}|${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}a<span>bc${RTLs[3]}|${RTLs[4]}${RTLs[5]}</span></div>`,
-`  <div>${RTLs[0]}${RTLs[1]}${RTLs[2]}a<span>bc${RTLs[3]}${RTLs[4]}${RTLs[5]}|</span></div>`,
-], 'case 39');
-
-testMoveRightCharacter([
-`  <div style="white-space: pre;">|abc
-       def</div>`,
-`  <div style="white-space: pre;">a|bc
-       def</div>`,
-`  <div style="white-space: pre;">ab|c
-       def</div>`,
-`  <div style="white-space: pre;">abc|
-       def</div>`,
-`  <div style="white-space: pre;">abc
-|       def</div>`,
-`  <div style="white-space: pre;">abc
- |      def</div>`,
-`  <div style="white-space: pre;">abc
-  |     def</div>`,
-`  <div style="white-space: pre;">abc
-   |    def</div>`,
-`  <div style="white-space: pre;">abc
-    |   def</div>`,
-`  <div style="white-space: pre;">abc
-     |  def</div>`,
-`  <div style="white-space: pre;">abc
-      | def</div>`,
-`  <div style="white-space: pre;">abc
-       |def</div>`,
-`  <div style="white-space: pre;">abc
-       d|ef</div>`,
-`  <div style="white-space: pre;">abc
-       de|f</div>`,
-`  <div style="white-space: pre;">abc
-       def|</div>`,
-], 'case 40');
-
-var RTLs = ["\u05d0", "\u05d1", "\u05d2", "\u05d3", "\u05d4", "\u05d5", ];
-testMoveRightCharacter([
-`  <div style="white-space: pre;">|${RTLs[0]}${RTLs[1]}${RTLs[2]}
-       ${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div style="white-space: pre;">${RTLs[0]}${RTLs[1]}|${RTLs[2]}
-       ${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div style="white-space: pre;">${RTLs[0]}|${RTLs[1]}${RTLs[2]}
-       ${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div style="white-space: pre;">${RTLs[0]}${RTLs[1]}${RTLs[2]}|
-       ${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div style="white-space: pre;">${RTLs[0]}${RTLs[1]}${RTLs[2]}
-|       ${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div style="white-space: pre;">${RTLs[0]}${RTLs[1]}${RTLs[2]}
- |      ${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div style="white-space: pre;">${RTLs[0]}${RTLs[1]}${RTLs[2]}
-  |     ${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div style="white-space: pre;">${RTLs[0]}${RTLs[1]}${RTLs[2]}
-   |    ${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div style="white-space: pre;">${RTLs[0]}${RTLs[1]}${RTLs[2]}
-    |   ${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div style="white-space: pre;">${RTLs[0]}${RTLs[1]}${RTLs[2]}
-     |  ${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div style="white-space: pre;">${RTLs[0]}${RTLs[1]}${RTLs[2]}
-      | ${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div style="white-space: pre;">${RTLs[0]}${RTLs[1]}${RTLs[2]}
-       |${RTLs[3]}${RTLs[4]}${RTLs[5]}</div>`,
-`  <div style="white-space: pre;">${RTLs[0]}${RTLs[1]}${RTLs[2]}
-       ${RTLs[3]}${RTLs[4]}|${RTLs[5]}</div>`,
-`  <div style="white-space: pre;">${RTLs[0]}${RTLs[1]}${RTLs[2]}
-       ${RTLs[3]}|${RTLs[4]}${RTLs[5]}</div>`,
-`  <div style="white-space: pre;">${RTLs[0]}${RTLs[1]}${RTLs[2]}
-       ${RTLs[3]}${RTLs[4]}${RTLs[5]}|</div>`,
-], 'case 41');
-
-var RTLs = ["\u05e7", "\u05e0", ];
-testMoveRightCharacter([
-`  <div>|<span dir="rtl">abc${RTLs[0]}${RTLs[0]}${RTLs[0]}123${RTLs[1]}${RTLs[1]}${RTLs[1]}def</span></div>`,
-`  <div><span dir="rtl">abc${RTLs[0]}${RTLs[0]}${RTLs[0]}123${RTLs[1]}${RTLs[1]}${RTLs[1]}d|ef</span></div>`,
-`  <div><span dir="rtl">abc${RTLs[0]}${RTLs[0]}${RTLs[0]}123${RTLs[1]}${RTLs[1]}${RTLs[1]}de|f</span></div>`,
-`  <div><span dir="rtl">abc${RTLs[0]}${RTLs[0]}${RTLs[0]}123${RTLs[1]}${RTLs[1]}|${RTLs[1]}def</span></div>`,
-`  <div><span dir="rtl">abc${RTLs[0]}${RTLs[0]}${RTLs[0]}123${RTLs[1]}|${RTLs[1]}${RTLs[1]}def</span></div>`,
-`  <div><span dir="rtl">abc${RTLs[0]}${RTLs[0]}${RTLs[0]}|123${RTLs[1]}${RTLs[1]}${RTLs[1]}def</span></div>`,
-`  <div><span dir="rtl">abc${RTLs[0]}${RTLs[0]}${RTLs[0]}1|23${RTLs[1]}${RTLs[1]}${RTLs[1]}def</span></div>`,
-`  <div><span dir="rtl">abc${RTLs[0]}${RTLs[0]}${RTLs[0]}12|3${RTLs[1]}${RTLs[1]}${RTLs[1]}def</span></div>`,
-`  <div><span dir="rtl">abc${RTLs[0]}${RTLs[0]}${RTLs[0]}123|${RTLs[1]}${RTLs[1]}${RTLs[1]}def</span></div>`,
-`  <div><span dir="rtl">abc${RTLs[0]}${RTLs[0]}|${RTLs[0]}123${RTLs[1]}${RTLs[1]}${RTLs[1]}def</span></div>`,
-`  <div><span dir="rtl">abc${RTLs[0]}|${RTLs[0]}${RTLs[0]}123${RTLs[1]}${RTLs[1]}${RTLs[1]}def</span></div>`,
-`  <div><span dir="rtl">a|bc${RTLs[0]}${RTLs[0]}${RTLs[0]}123${RTLs[1]}${RTLs[1]}${RTLs[1]}def</span></div>`,
-`  <div><span dir="rtl">ab|c${RTLs[0]}${RTLs[0]}${RTLs[0]}123${RTLs[1]}${RTLs[1]}${RTLs[1]}def</span></div>`,
-`  <div><span dir="rtl">abc${RTLs[0]}${RTLs[0]}${RTLs[0]}123${RTLs[1]}${RTLs[1]}${RTLs[1]}def|</span></div>`,
-], 'case 42');
-
-
-</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 846f5b2d..90a12ae 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -98560,12 +98560,17 @@
      {}
     ]
    ],
-   "client-hints/accept_ch.https.html.headers": [
+   "client-hints/accept_ch.http.html.headers": [
     [
      {}
     ]
    ],
-   "client-hints/echo_device_memory_header_received.py": [
+   "client-hints/accept_ch.sub.https.html.headers": [
+    [
+     {}
+    ]
+   ],
+   "client-hints/echo_client_hints_received.py": [
     [
      {}
     ]
@@ -152285,11 +152290,6 @@
      {}
     ]
    ],
-   "preload/link-header-on-subresource-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "preload/link-header-preload-delay-onload.html.headers": [
     [
      {}
@@ -152310,16 +152310,6 @@
      {}
     ]
    ],
-   "preload/onload-event-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "preload/preload-with-type-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "preload/resources/A4.ogv": [
     [
      {}
@@ -152440,11 +152430,6 @@
      {}
     ]
    ],
-   "preload/single-download-preload-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "presentation-api/OWNERS": [
     [
      {}
@@ -160045,11 +160030,6 @@
      {}
     ]
    ],
-   "user-timing/invoke_with_timing_attributes-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "user-timing/resources/webperftestharness.js": [
     [
      {}
@@ -174807,9 +174787,15 @@
      {}
     ]
    ],
-   "client-hints/accept_ch.https.html": [
+   "client-hints/accept_ch.http.html": [
     [
-     "/client-hints/accept_ch.https.html",
+     "/client-hints/accept_ch.http.html",
+     {}
+    ]
+   ],
+   "client-hints/accept_ch.sub.https.html": [
+    [
+     "/client-hints/accept_ch.sub.https.html",
      {}
     ]
    ],
@@ -204101,6 +204087,14 @@
      {}
     ]
    ],
+   "infrastructure/testdriver/click.html": [
+    [
+     "/infrastructure/testdriver/click.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
    "innerText/getter.html": [
     [
      "/innerText/getter.html",
@@ -251442,16 +251436,24 @@
    "56ef0ac9f9d3c2fcd69f16c409599402de8057f0",
    "support"
   ],
-  "client-hints/accept_ch.https.html": [
-   "b54ae9b17399e0fe4472fedbf1badd67d28e68f3",
+  "client-hints/accept_ch.http.html": [
+   "e2181077e6d378a288d4944aee8c76939aa896fe",
    "testharness"
   ],
-  "client-hints/accept_ch.https.html.headers": [
-   "bf59baf9a030d117964df414efc11ddb07e7a7fa",
+  "client-hints/accept_ch.http.html.headers": [
+   "25cd8622db940411b0e8eb39921e6086916e4f36",
    "support"
   ],
-  "client-hints/echo_device_memory_header_received.py": [
-   "defa16c455bebc2589c058d0d888326d667e317a",
+  "client-hints/accept_ch.sub.https.html": [
+   "4e3f60751fbbc8f58bbf6fb7eadd1f334c9789ad",
+   "testharness"
+  ],
+  "client-hints/accept_ch.sub.https.html.headers": [
+   "25cd8622db940411b0e8eb39921e6086916e4f36",
+   "support"
+  ],
+  "client-hints/echo_client_hints_received.py": [
+   "3d3b57376cbacbd2118fe4fe07abad5bd9ad95fd",
    "support"
   ],
   "clipboard-apis/OWNERS": [
@@ -346294,6 +346296,10 @@
    "1a291b68cdf6edcfc28a2ff22e294e8e8ebc0c42",
    "reftest"
   ],
+  "infrastructure/testdriver/click.html": [
+   "afb1a08faa639bdd1ee4387069d76803c5e38d54",
+   "testharness"
+  ],
   "innerText/OWNERS": [
    "03490d8952b9e28752778cf98c4be3e7724a8b32",
    "support"
@@ -346451,7 +346457,7 @@
    "support"
   ],
   "interfaces/hr-time.idl": [
-   "61bd84c720a00b5dfaff8a98ace54cb476a4ed18",
+   "db4f313176e4fdfb8efd78545079da42cbb0729b",
    "support"
   ],
   "interfaces/html.idl": [
@@ -356759,7 +356765,7 @@
    "testharness"
   ],
   "preload/download-resources.html": [
-   "f4894d37e5687cdadf8aa6879cf233b8af4e84da",
+   "a8af59b5a58b04bfda533a314c9822b13b5c379b",
    "testharness"
   ],
   "preload/dynamic-adding-preload-nonce.html": [
@@ -356774,12 +356780,8 @@
    "b69da90e272530d4f42bf6d9c5b3b772d1ffce48",
    "testharness"
   ],
-  "preload/link-header-on-subresource-expected.txt": [
-   "201e6d7d19583b068cd5a49a1827596e72821b3f",
-   "support"
-  ],
   "preload/link-header-on-subresource.html": [
-   "ea2f018b648d77b13b8010b4ebe63cdc5f846603",
+   "e324d7511f139f6d08c1535adfe75df579ebf747",
    "testharness"
   ],
   "preload/link-header-preload-delay-onload.html": [
@@ -356822,28 +356824,20 @@
    "9f85f429c75d8469ef4bad843a09a307a20c6f58",
    "testharness"
   ],
-  "preload/onload-event-expected.txt": [
-   "492b635e46bfa67221a89f54a73f9f7d14652cc0",
-   "support"
-  ],
   "preload/onload-event.html": [
-   "a02dd91451d598684a91575e8b09bda81c90e43f",
+   "2b8bd3c576b4d264d30dd664a5057fbfb1fa3fd5",
    "testharness"
   ],
   "preload/preload-csp.sub.html": [
-   "6b883cf98ebedfffbc66ab01db8736b3a978ba3b",
+   "a363e5f2447bbbcef709216d1b0bbfeec003d588",
    "testharness"
   ],
   "preload/preload-default-csp.sub.html": [
-   "5dc342bc568e96a53d5d8c0259a4f3c32a9a6ae5",
+   "8b22c83cb91255a74078c643d92078695bcd4cea",
    "testharness"
   ],
-  "preload/preload-with-type-expected.txt": [
-   "3357374170a78785fac96aa31a108a24f6cbed36",
-   "support"
-  ],
   "preload/preload-with-type.html": [
-   "ede6cb60bc1fff4f5b7740f66f039c88adb23f6f",
+   "5592d7d0d7495b04753d09f7e01d34358b03e22e",
    "testharness"
   ],
   "preload/reflected-as-value.html": [
@@ -356863,7 +356857,7 @@
    "support"
   ],
   "preload/resources/dummy-preloads-subresource.css.sub.headers": [
-   "74cf2e94b49905203c42c7e701bd2308997347ea",
+   "99175c5e06059af0e13bb3a7d40e5ed9e4a447fc",
    "support"
   ],
   "preload/resources/dummy.css": [
@@ -356950,12 +356944,8 @@
    "8476855931b0148754287ca5674000a1b6a9bca2",
    "testharness"
   ],
-  "preload/single-download-preload-expected.txt": [
-   "6bfb3b3398ec4ca59a8231f97429245455037851",
-   "support"
-  ],
   "preload/single-download-preload.html": [
-   "2b7af8e911957d6b49246a17ceb284b97981241e",
+   "7c11c149daba797eb7ddae3254d6166e3057e66a",
    "testharness"
   ],
   "presentation-api/OWNERS": [
@@ -372006,12 +371996,8 @@
    "b24d4d5faf5df5d67135560d5fe362cc6d72c28f",
    "testharness"
   ],
-  "user-timing/invoke_with_timing_attributes-expected.txt": [
-   "f173e3e46373df00331ab86e0c613621fac41003",
-   "support"
-  ],
   "user-timing/invoke_with_timing_attributes.html": [
-   "c946c734573a3e8598389ae854c1d9792e96440c",
+   "05283be9a7230ba0c4af09fb5dac98d828bfaf2e",
    "testharness"
   ],
   "user-timing/invoke_with_timing_attributes.worker.js": [
@@ -372035,7 +372021,7 @@
    "testharness"
   ],
   "user-timing/measure_exceptions_navigation_timing.html": [
-   "e557969014be8b0ed1870e288e7f06f4b2a149a4",
+   "ed9d9be01e740d282ec94379bfd78aca07b56325",
    "testharness"
   ],
   "user-timing/measure_navigation_timing.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/bluetooth/resources/bluetooth-helpers.js b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/resources/bluetooth-helpers.js
index 5635704..7b23742 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/bluetooth/resources/bluetooth-helpers.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/resources/bluetooth-helpers.js
@@ -42,6 +42,7 @@
     `${prefix}/mojo_layouttest_test.mojom.js`,
     `${prefix}/uuid.mojom.js`,
     `${prefix}/fake_bluetooth.mojom.js`,
+    `${prefix}/fake_bluetooth_chooser.mojom.js`,
     `${prefix}/web-bluetooth-test.js`,
   ].concat(extra))
       // Call setBluetoothFakeAdapter() to clean up any fake adapters left over
diff --git a/third_party/WebKit/LayoutTests/external/wpt/infrastructure/testdriver/click.html b/third_party/WebKit/LayoutTests/external/wpt/infrastructure/testdriver/click.html
new file mode 100644
index 0000000..37721ad
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/infrastructure/testdriver/click.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TestDriver click method</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<button type="button" id="button">Button</button>
+
+<script>
+async_test(t => {
+  let button = document.getElementById("button");
+  test_driver
+    .click(button)
+    .then(() => t.done())
+    .catch(t.unreached_func("click failed"));
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/hr-time.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/hr-time.idl
index ccbbc33..3c793c32 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/hr-time.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/hr-time.idl
@@ -1,13 +1,17 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content of this file was automatically extracted from the High Resolution Time spec.
+// See https://w3c.github.io/hr-time/
+
 typedef double DOMHighResTimeStamp;
 
 [Exposed=(Window,Worker)]
 interface Performance : EventTarget {
-    DOMHighResTimeStamp now();
+    DOMHighResTimeStamp now ();
     readonly attribute DOMHighResTimeStamp timeOrigin;
-    [Default] object              toJSON();
+    [Default] object toJSON();
 };
 
 partial interface WindowOrWorkerGlobalScope {
     [Replaceable]
-    readonly attribute Performance performance;
+    readonly    attribute Performance performance;
 };
diff --git a/third_party/WebKit/LayoutTests/external/wpt/preload/download-resources.html b/third_party/WebKit/LayoutTests/external/wpt/preload/download-resources.html
index ee8fdd0..dc2b4693 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/preload/download-resources.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/preload/download-resources.html
@@ -8,7 +8,7 @@
 <link rel=preload href="resources/dummy.js" as=script>
 <link rel=preload href="resources/dummy.css" as=style>
 <link rel=preload href="resources/square.png" as=image>
-<link rel=preload href="resources/CanvasTest.ttf" as=font crossorigin>
+<link rel=preload href="/fonts/CanvasTest.ttf" as=font crossorigin>
 <link rel=preload href="resources/white.mp4" as=video>
 <link rel=preload href="resources/sound_5.oga" as=audio>
 <link rel=preload href="resources/foo.vtt" as=track>
@@ -22,7 +22,7 @@
         verifyPreloadAndRTSupport()
         verifyNumberOfDownloads("resources/dummy.js", 1);
         verifyNumberOfDownloads("resources/dummy.css", 1);
-        verifyNumberOfDownloads("resources/CanvasTest.ttf", 1);
+        verifyNumberOfDownloads("/fonts/CanvasTest.ttf", 1);
         verifyNumberOfDownloads("resources/white.mp4", 1);
         verifyNumberOfDownloads("resources/sound_5.oga", 1);
         verifyNumberOfDownloads("resources/foo.vtt", 1);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/preload/link-header-on-subresource-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/preload/link-header-on-subresource-expected.txt
deleted file mode 100644
index cca7e5708..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/preload/link-header-on-subresource-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Makes sure that Link headers on subresources preload resources assert_equals: /preload/resources/CanvasTest.ttf?link-header-on-subresource expected 1 but got 0
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/preload/link-header-on-subresource.html b/third_party/WebKit/LayoutTests/external/wpt/preload/link-header-on-subresource.html
index 22351e3..a02bc7c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/preload/link-header-on-subresource.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/preload/link-header-on-subresource.html
@@ -10,7 +10,7 @@
 <script>
     window.addEventListener("load", t.step_func(function() {
         verifyPreloadAndRTSupport();
-        verifyNumberOfDownloads("/preload/resources/CanvasTest.ttf?link-header-on-subresource", 1);
+        verifyNumberOfDownloads("/fonts/CanvasTest.ttf?link-header-on-subresource", 1);
         t.done();
     }));
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/preload/onload-event-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/preload/onload-event-expected.txt
deleted file mode 100644
index 3ab26b17..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/preload/onload-event-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Makes sure that preloaded resources trigger the onload event assert_true: font triggered load event expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/preload/onload-event.html b/third_party/WebKit/LayoutTests/external/wpt/preload/onload-event.html
index 35ba2eb5..6af2d64a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/preload/onload-event.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/preload/onload-event.html
@@ -19,7 +19,7 @@
 <link rel=preload href="resources/dummy.js" as=script onload="scriptLoaded = true;">
 <link rel=preload href="resources/dummy.css" as=style onload="styleLoaded = true;">
 <link rel=preload href="resources/square.png" as=image onload="imageLoaded = true;">
-<link rel=preload href="resources/CanvasTest.ttf" as=font crossorigin onload="fontLoaded = true;">
+<link rel=preload href="/fonts/CanvasTest.ttf" as=font crossorigin onload="fontLoaded = true;">
 <link rel=preload href="resources/white.mp4" as=video onload="videoLoaded = true;">
 <link rel=preload href="resources/sound_5.oga" as=audio onload="audioLoaded = true;">
 <link rel=preload href="resources/foo.vtt" as=track onload="trackLoaded = true;">
diff --git a/third_party/WebKit/LayoutTests/external/wpt/preload/preload-csp.sub.html b/third_party/WebKit/LayoutTests/external/wpt/preload/preload-csp.sub.html
index 70db5f47..8e5e45b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/preload/preload-csp.sub.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/preload/preload-csp.sub.html
@@ -9,7 +9,7 @@
 <link rel=preload href="{{host}}:{{ports[http][1]}}/preload/resources/dummy.js" as=style>
 <link rel=preload href="resources/dummy.css" as=style>
 <link rel=preload href="resources/square.png" as=image>
-<link rel=preload href="resources/CanvasTest.ttf" as=font crossorigin>
+<link rel=preload href="/fonts/CanvasTest.ttf" as=font crossorigin>
 <link rel=preload href="resources/white.mp4" as=video>
 <link rel=preload href="resources/sound_5.oga" as=audio>
 <link rel=preload href="resources/foo.vtt" as=track>
@@ -23,7 +23,7 @@
         verifyNumberOfDownloads("{{host}}:{{ports[http][1]}}/preload/resources/dummy.js", 0);
         verifyNumberOfDownloads("resources/dummy.css", 0);
         verifyNumberOfDownloads("resources/square.png", 0);
-        verifyNumberOfDownloads("resources/CanvasTest.ttf", 0);
+        verifyNumberOfDownloads("/fonts/CanvasTest.ttf", 0);
         verifyNumberOfDownloads("resources/white.mp4", 0);
         verifyNumberOfDownloads("resources/sound_5.oga", 0);
         verifyNumberOfDownloads("resources/foo.vtt", 0);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/preload/preload-default-csp.sub.html b/third_party/WebKit/LayoutTests/external/wpt/preload/preload-default-csp.sub.html
index bde6b982..cb080e6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/preload/preload-default-csp.sub.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/preload/preload-default-csp.sub.html
@@ -9,7 +9,7 @@
 <link rel=preload href="{{host}}:{{ports[http][1]}}/preload/resources/dummy.js" as=style>
 <link rel=preload href="resources/dummy.css" as=style>
 <link rel=preload href="resources/square.png" as=image>
-<link rel=preload href="resources/CanvasTest.ttf" as=font crossorigin>
+<link rel=preload href="/fonts/CanvasTest.ttf" as=font crossorigin>
 <link rel=preload href="resources/white.mp4" as=video>
 <link rel=preload href="resources/sound_5.oga" as=audio>
 <link rel=preload href="resources/foo.vtt" as=track>
@@ -23,7 +23,7 @@
         verifyNumberOfDownloads("{{host}}:{{ports[http][1]}}/preload/resources/dummy.js", 0);
         verifyNumberOfDownloads("resources/dummy.css", 0);
         verifyNumberOfDownloads("resources/square.png", 0);
-        verifyNumberOfDownloads("resources/CanvasTest.ttf", 0);
+        verifyNumberOfDownloads("/fonts/CanvasTest.ttf", 0);
         verifyNumberOfDownloads("resources/white.mp4", 0);
         verifyNumberOfDownloads("resources/sound_5.oga", 0);
         verifyNumberOfDownloads("resources/foo.vtt", 0);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/preload/preload-with-type-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/preload/preload-with-type-expected.txt
deleted file mode 100644
index 6559aed..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/preload/preload-with-type-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Makes sure that preloaded resources with a type attribute trigger the onload event assert_true: font triggered load event expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/preload/preload-with-type.html b/third_party/WebKit/LayoutTests/external/wpt/preload/preload-with-type.html
index cf79e778..8578143 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/preload/preload-with-type.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/preload/preload-with-type.html
@@ -31,7 +31,7 @@
 <link rel=preload href="resources/dummy.js" as=script type="text/javascript" onload="scriptLoaded = true;">
 <link rel=preload href="resources/dummy.css" as=style type="text/css" onload="styleLoaded = true;">
 <link rel=preload href="resources/square.png" as=image type="image/png" onload="imageLoaded = true;">
-<link rel=preload href="resources/CanvasTest.ttf" as=font type="font/ttf" crossorigin onload="fontLoaded = true;">
+<link rel=preload href="/fonts/CanvasTest.ttf" as=font type="font/ttf" crossorigin onload="fontLoaded = true;">
 <script>
     document.write('<link rel=preload href="' + videoURL + '" as=video type="video/' + videoFormat + '" onload="videoLoaded = true;">');
     document.write('<link rel=preload href="' + audioURL + '" as=audio type="audio/' + audioFormat + '" onload="audioLoaded = true;">');
@@ -40,7 +40,7 @@
 <link rel=preload href="resources/dummy.js" as=script type="application/foobar" onload="gibberishLoaded++;">
 <link rel=preload href="resources/dummy.css" as=style type="text/foobar" onload="gibberishLoaded++;">
 <link rel=preload href="resources/square.png" as=image type="image/foobar" onload="gibberishLoaded++;">
-<link rel=preload href="resources/CanvasTest.ttf" as=font type="font/foobar" crossorigin onload="gibberishLoaded++;">
+<link rel=preload href="/fonts/CanvasTest.ttf" as=font type="font/foobar" crossorigin onload="gibberishLoaded++;">
 <script>
     document.write('<link rel=preload href="' + videoURL + '" as=video type="video/foobar" onload="gibberishLoaded++;">');
     document.write('<link rel=preload href="' + audioURL + '" as=audio type="audio/foobar" onload="gibberishLoaded++;">');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/preload/resources/dummy-preloads-subresource.css.sub.headers b/third_party/WebKit/LayoutTests/external/wpt/preload/resources/dummy-preloads-subresource.css.sub.headers
index 4ada08c..f6b4b49 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/preload/resources/dummy-preloads-subresource.css.sub.headers
+++ b/third_party/WebKit/LayoutTests/external/wpt/preload/resources/dummy-preloads-subresource.css.sub.headers
@@ -1,2 +1,2 @@
 Cache-Control: max-age=1000
-Link: </preload/resources/CanvasTest.ttf?link-header-on-subresource>; rel=preload;as=font;crossorigin
+Link: </fonts/CanvasTest.ttf?link-header-on-subresource>; rel=preload;as=font;crossorigin
diff --git a/third_party/WebKit/LayoutTests/external/wpt/preload/single-download-preload-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/preload/single-download-preload-expected.txt
deleted file mode 100644
index 97f91a85..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/preload/single-download-preload-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Makes sure that preloaded resources are not downloaded again when used assert_equals: resources/CanvasTest.ttf?single-download-preload expected 1 but got 0
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/preload/single-download-preload.html b/third_party/WebKit/LayoutTests/external/wpt/preload/single-download-preload.html
index 83151c2..e8f2617 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/preload/single-download-preload.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/preload/single-download-preload.html
@@ -9,7 +9,7 @@
 <link rel=preload href="resources/dummy.css?single-download-preload" as=style>
 <link rel=preload href="resources/square.png?single-download-preload" as=image>
 <link rel=preload href="resources/square.png?background&single-download-preload" as=image>
-<link rel=preload href="resources/CanvasTest.ttf?single-download-preload" as=font crossorigin>
+<link rel=preload href="/fonts/CanvasTest.ttf?single-download-preload" as=font crossorigin>
 <link rel=preload href="resources/white.mp4?single-download-preload" as=video>
 <link rel=preload href="resources/sound_5.oga?single-download-preload" as=audio>
 <link rel=preload href="resources/foo.vtt?single-download-preload" as=track>
@@ -25,7 +25,7 @@
     }
     @font-face {
       font-family:ahem;
-      src: url(resources/CanvasTest.ttf?single-download-preload);
+      src: url(/fonts/CanvasTest.ttf?single-download-preload);
     }
     span { font-family: ahem, Arial; }
 </style>
@@ -49,7 +49,7 @@
             verifyNumberOfDownloads("resources/dummy.css?single-download-preload", 1);
             verifyNumberOfDownloads("resources/square.png?single-download-preload", 1);
             verifyNumberOfDownloads("resources/square.png?background&single-download-preload", 1);
-            verifyNumberOfDownloads("resources/CanvasTest.ttf?single-download-preload", 1);
+            verifyNumberOfDownloads("/fonts/CanvasTest.ttf?single-download-preload", 1);
             verifyNumberOfDownloads("resources/dummy.xml?foobar", 0);
             verifyNumberOfDownloads("resources/foo.vtt?single-download-preload", 1);
             verifyNumberOfDownloads("resources/dummy.xml?single-download-preload", 1);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/resources/chromium/fake_bluetooth_chooser.mojom.js b/third_party/WebKit/LayoutTests/external/wpt/resources/chromium/fake_bluetooth_chooser.mojom.js
new file mode 100644
index 0000000..535a90a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/resources/chromium/fake_bluetooth_chooser.mojom.js
@@ -0,0 +1,822 @@
+// 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.
+
+'use strict';
+
+(function() {
+  var mojomId = 'content/shell/common/layout_test/fake_bluetooth_chooser.mojom';
+  if (mojo.internal.isMojomLoaded(mojomId)) {
+    console.warn('The following mojom is loaded multiple times: ' + mojomId);
+    return;
+  }
+  mojo.internal.markMojomLoaded(mojomId);
+  var bindings = mojo;
+  var associatedBindings = mojo;
+  var codec = mojo.internal;
+  var validator = mojo.internal;
+
+  var exports = mojo.internal.exposeNamespace('content.mojom');
+
+
+  var ChooserEventType = {};
+  ChooserEventType.CHOOSER_OPENED = 0;
+  ChooserEventType.SCAN_STARTED = ChooserEventType.CHOOSER_OPENED + 1;
+  ChooserEventType.DEVICE_UPDATE = ChooserEventType.SCAN_STARTED + 1;
+  ChooserEventType.ADAPTER_REMOVED = ChooserEventType.DEVICE_UPDATE + 1;
+  ChooserEventType.ADAPTER_DISABLED = ChooserEventType.ADAPTER_REMOVED + 1;
+  ChooserEventType.ADAPTER_ENABLED = ChooserEventType.ADAPTER_DISABLED + 1;
+  ChooserEventType.DISCOVERY_FAILED_TO_START = ChooserEventType.ADAPTER_ENABLED + 1;
+  ChooserEventType.DISCOVERING = ChooserEventType.DISCOVERY_FAILED_TO_START + 1;
+  ChooserEventType.DISCOVERY_IDLE = ChooserEventType.DISCOVERING + 1;
+  ChooserEventType.ADD_DEVICE = ChooserEventType.DISCOVERY_IDLE + 1;
+
+  ChooserEventType.isKnownEnumValue = function(value) {
+    switch (value) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+    case 8:
+    case 9:
+      return true;
+    }
+    return false;
+  };
+
+  ChooserEventType.validate = function(enumValue) {
+    var isExtensible = false;
+    if (isExtensible || this.isKnownEnumValue(enumValue))
+      return validator.validationError.NONE;
+
+    return validator.validationError.UNKNOWN_ENUM_VALUE;
+  };
+
+  function FakeBluetoothChooserEvent(values) {
+    this.initDefaults_();
+    this.initFields_(values);
+  }
+
+
+  FakeBluetoothChooserEvent.prototype.initDefaults_ = function() {
+    this.type = 0;
+    this.origin = null;
+    this.peripheralAddress = null;
+  };
+  FakeBluetoothChooserEvent.prototype.initFields_ = function(fields) {
+    for(var field in fields) {
+        if (this.hasOwnProperty(field))
+          this[field] = fields[field];
+    }
+  };
+
+  FakeBluetoothChooserEvent.validate = function(messageValidator, offset) {
+    var err;
+    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+    var kVersionSizes = [
+      {version: 0, numBytes: 32}
+    ];
+    err = messageValidator.validateStructVersion(offset, kVersionSizes);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+
+    // validate FakeBluetoothChooserEvent.type
+    err = messageValidator.validateEnum(offset + codec.kStructHeaderSize + 0, ChooserEventType);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+
+    // validate FakeBluetoothChooserEvent.origin
+    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 8, true)
+    if (err !== validator.validationError.NONE)
+        return err;
+
+
+    // validate FakeBluetoothChooserEvent.peripheralAddress
+    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 16, true)
+    if (err !== validator.validationError.NONE)
+        return err;
+
+    return validator.validationError.NONE;
+  };
+
+  FakeBluetoothChooserEvent.encodedSize = codec.kStructHeaderSize + 24;
+
+  FakeBluetoothChooserEvent.decode = function(decoder) {
+    var packed;
+    var val = new FakeBluetoothChooserEvent();
+    var numberOfBytes = decoder.readUint32();
+    var version = decoder.readUint32();
+    val.type = decoder.decodeStruct(codec.Int32);
+    decoder.skip(1);
+    decoder.skip(1);
+    decoder.skip(1);
+    decoder.skip(1);
+    val.origin = decoder.decodeStruct(codec.NullableString);
+    val.peripheralAddress = decoder.decodeStruct(codec.NullableString);
+    return val;
+  };
+
+  FakeBluetoothChooserEvent.encode = function(encoder, val) {
+    var packed;
+    encoder.writeUint32(FakeBluetoothChooserEvent.encodedSize);
+    encoder.writeUint32(0);
+    encoder.encodeStruct(codec.Int32, val.type);
+    encoder.skip(1);
+    encoder.skip(1);
+    encoder.skip(1);
+    encoder.skip(1);
+    encoder.encodeStruct(codec.NullableString, val.origin);
+    encoder.encodeStruct(codec.NullableString, val.peripheralAddress);
+  };
+  function FakeBluetoothChooser_WaitForEvents_Params(values) {
+    this.initDefaults_();
+    this.initFields_(values);
+  }
+
+
+  FakeBluetoothChooser_WaitForEvents_Params.prototype.initDefaults_ = function() {
+    this.numOfEvents = 0;
+  };
+  FakeBluetoothChooser_WaitForEvents_Params.prototype.initFields_ = function(fields) {
+    for(var field in fields) {
+        if (this.hasOwnProperty(field))
+          this[field] = fields[field];
+    }
+  };
+
+  FakeBluetoothChooser_WaitForEvents_Params.validate = function(messageValidator, offset) {
+    var err;
+    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+    var kVersionSizes = [
+      {version: 0, numBytes: 16}
+    ];
+    err = messageValidator.validateStructVersion(offset, kVersionSizes);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+
+    return validator.validationError.NONE;
+  };
+
+  FakeBluetoothChooser_WaitForEvents_Params.encodedSize = codec.kStructHeaderSize + 8;
+
+  FakeBluetoothChooser_WaitForEvents_Params.decode = function(decoder) {
+    var packed;
+    var val = new FakeBluetoothChooser_WaitForEvents_Params();
+    var numberOfBytes = decoder.readUint32();
+    var version = decoder.readUint32();
+    val.numOfEvents = decoder.decodeStruct(codec.Uint32);
+    decoder.skip(1);
+    decoder.skip(1);
+    decoder.skip(1);
+    decoder.skip(1);
+    return val;
+  };
+
+  FakeBluetoothChooser_WaitForEvents_Params.encode = function(encoder, val) {
+    var packed;
+    encoder.writeUint32(FakeBluetoothChooser_WaitForEvents_Params.encodedSize);
+    encoder.writeUint32(0);
+    encoder.encodeStruct(codec.Uint32, val.numOfEvents);
+    encoder.skip(1);
+    encoder.skip(1);
+    encoder.skip(1);
+    encoder.skip(1);
+  };
+  function FakeBluetoothChooser_WaitForEvents_ResponseParams(values) {
+    this.initDefaults_();
+    this.initFields_(values);
+  }
+
+
+  FakeBluetoothChooser_WaitForEvents_ResponseParams.prototype.initDefaults_ = function() {
+    this.events = null;
+  };
+  FakeBluetoothChooser_WaitForEvents_ResponseParams.prototype.initFields_ = function(fields) {
+    for(var field in fields) {
+        if (this.hasOwnProperty(field))
+          this[field] = fields[field];
+    }
+  };
+
+  FakeBluetoothChooser_WaitForEvents_ResponseParams.validate = function(messageValidator, offset) {
+    var err;
+    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+    var kVersionSizes = [
+      {version: 0, numBytes: 16}
+    ];
+    err = messageValidator.validateStructVersion(offset, kVersionSizes);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+
+    // validate FakeBluetoothChooser_WaitForEvents_ResponseParams.events
+    err = messageValidator.validateArrayPointer(offset + codec.kStructHeaderSize + 0, 8, new codec.PointerTo(FakeBluetoothChooserEvent), false, [0], 0);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+    return validator.validationError.NONE;
+  };
+
+  FakeBluetoothChooser_WaitForEvents_ResponseParams.encodedSize = codec.kStructHeaderSize + 8;
+
+  FakeBluetoothChooser_WaitForEvents_ResponseParams.decode = function(decoder) {
+    var packed;
+    var val = new FakeBluetoothChooser_WaitForEvents_ResponseParams();
+    var numberOfBytes = decoder.readUint32();
+    var version = decoder.readUint32();
+    val.events = decoder.decodeArrayPointer(new codec.PointerTo(FakeBluetoothChooserEvent));
+    return val;
+  };
+
+  FakeBluetoothChooser_WaitForEvents_ResponseParams.encode = function(encoder, val) {
+    var packed;
+    encoder.writeUint32(FakeBluetoothChooser_WaitForEvents_ResponseParams.encodedSize);
+    encoder.writeUint32(0);
+    encoder.encodeArrayPointer(new codec.PointerTo(FakeBluetoothChooserEvent), val.events);
+  };
+  function FakeBluetoothChooser_SelectPeripheral_Params(values) {
+    this.initDefaults_();
+    this.initFields_(values);
+  }
+
+
+  FakeBluetoothChooser_SelectPeripheral_Params.prototype.initDefaults_ = function() {
+    this.peripheralAddress = null;
+  };
+  FakeBluetoothChooser_SelectPeripheral_Params.prototype.initFields_ = function(fields) {
+    for(var field in fields) {
+        if (this.hasOwnProperty(field))
+          this[field] = fields[field];
+    }
+  };
+
+  FakeBluetoothChooser_SelectPeripheral_Params.validate = function(messageValidator, offset) {
+    var err;
+    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+    var kVersionSizes = [
+      {version: 0, numBytes: 16}
+    ];
+    err = messageValidator.validateStructVersion(offset, kVersionSizes);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+
+    // validate FakeBluetoothChooser_SelectPeripheral_Params.peripheralAddress
+    err = messageValidator.validateStringPointer(offset + codec.kStructHeaderSize + 0, false)
+    if (err !== validator.validationError.NONE)
+        return err;
+
+    return validator.validationError.NONE;
+  };
+
+  FakeBluetoothChooser_SelectPeripheral_Params.encodedSize = codec.kStructHeaderSize + 8;
+
+  FakeBluetoothChooser_SelectPeripheral_Params.decode = function(decoder) {
+    var packed;
+    var val = new FakeBluetoothChooser_SelectPeripheral_Params();
+    var numberOfBytes = decoder.readUint32();
+    var version = decoder.readUint32();
+    val.peripheralAddress = decoder.decodeStruct(codec.String);
+    return val;
+  };
+
+  FakeBluetoothChooser_SelectPeripheral_Params.encode = function(encoder, val) {
+    var packed;
+    encoder.writeUint32(FakeBluetoothChooser_SelectPeripheral_Params.encodedSize);
+    encoder.writeUint32(0);
+    encoder.encodeStruct(codec.String, val.peripheralAddress);
+  };
+  function FakeBluetoothChooser_SelectPeripheral_ResponseParams(values) {
+    this.initDefaults_();
+    this.initFields_(values);
+  }
+
+
+  FakeBluetoothChooser_SelectPeripheral_ResponseParams.prototype.initDefaults_ = function() {
+  };
+  FakeBluetoothChooser_SelectPeripheral_ResponseParams.prototype.initFields_ = function(fields) {
+    for(var field in fields) {
+        if (this.hasOwnProperty(field))
+          this[field] = fields[field];
+    }
+  };
+
+  FakeBluetoothChooser_SelectPeripheral_ResponseParams.validate = function(messageValidator, offset) {
+    var err;
+    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+    var kVersionSizes = [
+      {version: 0, numBytes: 8}
+    ];
+    err = messageValidator.validateStructVersion(offset, kVersionSizes);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+    return validator.validationError.NONE;
+  };
+
+  FakeBluetoothChooser_SelectPeripheral_ResponseParams.encodedSize = codec.kStructHeaderSize + 0;
+
+  FakeBluetoothChooser_SelectPeripheral_ResponseParams.decode = function(decoder) {
+    var packed;
+    var val = new FakeBluetoothChooser_SelectPeripheral_ResponseParams();
+    var numberOfBytes = decoder.readUint32();
+    var version = decoder.readUint32();
+    return val;
+  };
+
+  FakeBluetoothChooser_SelectPeripheral_ResponseParams.encode = function(encoder, val) {
+    var packed;
+    encoder.writeUint32(FakeBluetoothChooser_SelectPeripheral_ResponseParams.encodedSize);
+    encoder.writeUint32(0);
+  };
+  function FakeBluetoothChooser_Cancel_Params(values) {
+    this.initDefaults_();
+    this.initFields_(values);
+  }
+
+
+  FakeBluetoothChooser_Cancel_Params.prototype.initDefaults_ = function() {
+  };
+  FakeBluetoothChooser_Cancel_Params.prototype.initFields_ = function(fields) {
+    for(var field in fields) {
+        if (this.hasOwnProperty(field))
+          this[field] = fields[field];
+    }
+  };
+
+  FakeBluetoothChooser_Cancel_Params.validate = function(messageValidator, offset) {
+    var err;
+    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+    var kVersionSizes = [
+      {version: 0, numBytes: 8}
+    ];
+    err = messageValidator.validateStructVersion(offset, kVersionSizes);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+    return validator.validationError.NONE;
+  };
+
+  FakeBluetoothChooser_Cancel_Params.encodedSize = codec.kStructHeaderSize + 0;
+
+  FakeBluetoothChooser_Cancel_Params.decode = function(decoder) {
+    var packed;
+    var val = new FakeBluetoothChooser_Cancel_Params();
+    var numberOfBytes = decoder.readUint32();
+    var version = decoder.readUint32();
+    return val;
+  };
+
+  FakeBluetoothChooser_Cancel_Params.encode = function(encoder, val) {
+    var packed;
+    encoder.writeUint32(FakeBluetoothChooser_Cancel_Params.encodedSize);
+    encoder.writeUint32(0);
+  };
+  function FakeBluetoothChooser_Cancel_ResponseParams(values) {
+    this.initDefaults_();
+    this.initFields_(values);
+  }
+
+
+  FakeBluetoothChooser_Cancel_ResponseParams.prototype.initDefaults_ = function() {
+  };
+  FakeBluetoothChooser_Cancel_ResponseParams.prototype.initFields_ = function(fields) {
+    for(var field in fields) {
+        if (this.hasOwnProperty(field))
+          this[field] = fields[field];
+    }
+  };
+
+  FakeBluetoothChooser_Cancel_ResponseParams.validate = function(messageValidator, offset) {
+    var err;
+    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+    var kVersionSizes = [
+      {version: 0, numBytes: 8}
+    ];
+    err = messageValidator.validateStructVersion(offset, kVersionSizes);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+    return validator.validationError.NONE;
+  };
+
+  FakeBluetoothChooser_Cancel_ResponseParams.encodedSize = codec.kStructHeaderSize + 0;
+
+  FakeBluetoothChooser_Cancel_ResponseParams.decode = function(decoder) {
+    var packed;
+    var val = new FakeBluetoothChooser_Cancel_ResponseParams();
+    var numberOfBytes = decoder.readUint32();
+    var version = decoder.readUint32();
+    return val;
+  };
+
+  FakeBluetoothChooser_Cancel_ResponseParams.encode = function(encoder, val) {
+    var packed;
+    encoder.writeUint32(FakeBluetoothChooser_Cancel_ResponseParams.encodedSize);
+    encoder.writeUint32(0);
+  };
+  function FakeBluetoothChooser_Rescan_Params(values) {
+    this.initDefaults_();
+    this.initFields_(values);
+  }
+
+
+  FakeBluetoothChooser_Rescan_Params.prototype.initDefaults_ = function() {
+  };
+  FakeBluetoothChooser_Rescan_Params.prototype.initFields_ = function(fields) {
+    for(var field in fields) {
+        if (this.hasOwnProperty(field))
+          this[field] = fields[field];
+    }
+  };
+
+  FakeBluetoothChooser_Rescan_Params.validate = function(messageValidator, offset) {
+    var err;
+    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+    var kVersionSizes = [
+      {version: 0, numBytes: 8}
+    ];
+    err = messageValidator.validateStructVersion(offset, kVersionSizes);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+    return validator.validationError.NONE;
+  };
+
+  FakeBluetoothChooser_Rescan_Params.encodedSize = codec.kStructHeaderSize + 0;
+
+  FakeBluetoothChooser_Rescan_Params.decode = function(decoder) {
+    var packed;
+    var val = new FakeBluetoothChooser_Rescan_Params();
+    var numberOfBytes = decoder.readUint32();
+    var version = decoder.readUint32();
+    return val;
+  };
+
+  FakeBluetoothChooser_Rescan_Params.encode = function(encoder, val) {
+    var packed;
+    encoder.writeUint32(FakeBluetoothChooser_Rescan_Params.encodedSize);
+    encoder.writeUint32(0);
+  };
+  function FakeBluetoothChooser_Rescan_ResponseParams(values) {
+    this.initDefaults_();
+    this.initFields_(values);
+  }
+
+
+  FakeBluetoothChooser_Rescan_ResponseParams.prototype.initDefaults_ = function() {
+  };
+  FakeBluetoothChooser_Rescan_ResponseParams.prototype.initFields_ = function(fields) {
+    for(var field in fields) {
+        if (this.hasOwnProperty(field))
+          this[field] = fields[field];
+    }
+  };
+
+  FakeBluetoothChooser_Rescan_ResponseParams.validate = function(messageValidator, offset) {
+    var err;
+    err = messageValidator.validateStructHeader(offset, codec.kStructHeaderSize);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+    var kVersionSizes = [
+      {version: 0, numBytes: 8}
+    ];
+    err = messageValidator.validateStructVersion(offset, kVersionSizes);
+    if (err !== validator.validationError.NONE)
+        return err;
+
+    return validator.validationError.NONE;
+  };
+
+  FakeBluetoothChooser_Rescan_ResponseParams.encodedSize = codec.kStructHeaderSize + 0;
+
+  FakeBluetoothChooser_Rescan_ResponseParams.decode = function(decoder) {
+    var packed;
+    var val = new FakeBluetoothChooser_Rescan_ResponseParams();
+    var numberOfBytes = decoder.readUint32();
+    var version = decoder.readUint32();
+    return val;
+  };
+
+  FakeBluetoothChooser_Rescan_ResponseParams.encode = function(encoder, val) {
+    var packed;
+    encoder.writeUint32(FakeBluetoothChooser_Rescan_ResponseParams.encodedSize);
+    encoder.writeUint32(0);
+  };
+  var kFakeBluetoothChooser_WaitForEvents_Name = 457051710;
+  var kFakeBluetoothChooser_SelectPeripheral_Name = 1924310743;
+  var kFakeBluetoothChooser_Cancel_Name = 1388880682;
+  var kFakeBluetoothChooser_Rescan_Name = 2112671529;
+
+  function FakeBluetoothChooserPtr(handleOrPtrInfo) {
+    this.ptr = new bindings.InterfacePtrController(FakeBluetoothChooser,
+                                                   handleOrPtrInfo);
+  }
+
+  function FakeBluetoothChooserAssociatedPtr(associatedInterfacePtrInfo) {
+    this.ptr = new associatedBindings.AssociatedInterfacePtrController(
+        FakeBluetoothChooser, associatedInterfacePtrInfo);
+  }
+
+  FakeBluetoothChooserAssociatedPtr.prototype =
+      Object.create(FakeBluetoothChooserPtr.prototype);
+  FakeBluetoothChooserAssociatedPtr.prototype.constructor =
+      FakeBluetoothChooserAssociatedPtr;
+
+  function FakeBluetoothChooserProxy(receiver) {
+    this.receiver_ = receiver;
+  }
+  FakeBluetoothChooserPtr.prototype.waitForEvents = function() {
+    return FakeBluetoothChooserProxy.prototype.waitForEvents
+        .apply(this.ptr.getProxy(), arguments);
+  };
+
+  FakeBluetoothChooserProxy.prototype.waitForEvents = function(numOfEvents) {
+    var params = new FakeBluetoothChooser_WaitForEvents_Params();
+    params.numOfEvents = numOfEvents;
+    return new Promise(function(resolve, reject) {
+      var builder = new codec.MessageV1Builder(
+          kFakeBluetoothChooser_WaitForEvents_Name,
+          codec.align(FakeBluetoothChooser_WaitForEvents_Params.encodedSize),
+          codec.kMessageExpectsResponse, 0);
+      builder.encodeStruct(FakeBluetoothChooser_WaitForEvents_Params, params);
+      var message = builder.finish();
+      this.receiver_.acceptAndExpectResponse(message).then(function(message) {
+        var reader = new codec.MessageReader(message);
+        var responseParams =
+            reader.decodeStruct(FakeBluetoothChooser_WaitForEvents_ResponseParams);
+        resolve(responseParams);
+      }).catch(function(result) {
+        reject(Error("Connection error: " + result));
+      });
+    }.bind(this));
+  };
+  FakeBluetoothChooserPtr.prototype.selectPeripheral = function() {
+    return FakeBluetoothChooserProxy.prototype.selectPeripheral
+        .apply(this.ptr.getProxy(), arguments);
+  };
+
+  FakeBluetoothChooserProxy.prototype.selectPeripheral = function(peripheralAddress) {
+    var params = new FakeBluetoothChooser_SelectPeripheral_Params();
+    params.peripheralAddress = peripheralAddress;
+    return new Promise(function(resolve, reject) {
+      var builder = new codec.MessageV1Builder(
+          kFakeBluetoothChooser_SelectPeripheral_Name,
+          codec.align(FakeBluetoothChooser_SelectPeripheral_Params.encodedSize),
+          codec.kMessageExpectsResponse, 0);
+      builder.encodeStruct(FakeBluetoothChooser_SelectPeripheral_Params, params);
+      var message = builder.finish();
+      this.receiver_.acceptAndExpectResponse(message).then(function(message) {
+        var reader = new codec.MessageReader(message);
+        var responseParams =
+            reader.decodeStruct(FakeBluetoothChooser_SelectPeripheral_ResponseParams);
+        resolve(responseParams);
+      }).catch(function(result) {
+        reject(Error("Connection error: " + result));
+      });
+    }.bind(this));
+  };
+  FakeBluetoothChooserPtr.prototype.cancel = function() {
+    return FakeBluetoothChooserProxy.prototype.cancel
+        .apply(this.ptr.getProxy(), arguments);
+  };
+
+  FakeBluetoothChooserProxy.prototype.cancel = function() {
+    var params = new FakeBluetoothChooser_Cancel_Params();
+    return new Promise(function(resolve, reject) {
+      var builder = new codec.MessageV1Builder(
+          kFakeBluetoothChooser_Cancel_Name,
+          codec.align(FakeBluetoothChooser_Cancel_Params.encodedSize),
+          codec.kMessageExpectsResponse, 0);
+      builder.encodeStruct(FakeBluetoothChooser_Cancel_Params, params);
+      var message = builder.finish();
+      this.receiver_.acceptAndExpectResponse(message).then(function(message) {
+        var reader = new codec.MessageReader(message);
+        var responseParams =
+            reader.decodeStruct(FakeBluetoothChooser_Cancel_ResponseParams);
+        resolve(responseParams);
+      }).catch(function(result) {
+        reject(Error("Connection error: " + result));
+      });
+    }.bind(this));
+  };
+  FakeBluetoothChooserPtr.prototype.rescan = function() {
+    return FakeBluetoothChooserProxy.prototype.rescan
+        .apply(this.ptr.getProxy(), arguments);
+  };
+
+  FakeBluetoothChooserProxy.prototype.rescan = function() {
+    var params = new FakeBluetoothChooser_Rescan_Params();
+    return new Promise(function(resolve, reject) {
+      var builder = new codec.MessageV1Builder(
+          kFakeBluetoothChooser_Rescan_Name,
+          codec.align(FakeBluetoothChooser_Rescan_Params.encodedSize),
+          codec.kMessageExpectsResponse, 0);
+      builder.encodeStruct(FakeBluetoothChooser_Rescan_Params, params);
+      var message = builder.finish();
+      this.receiver_.acceptAndExpectResponse(message).then(function(message) {
+        var reader = new codec.MessageReader(message);
+        var responseParams =
+            reader.decodeStruct(FakeBluetoothChooser_Rescan_ResponseParams);
+        resolve(responseParams);
+      }).catch(function(result) {
+        reject(Error("Connection error: " + result));
+      });
+    }.bind(this));
+  };
+
+  function FakeBluetoothChooserStub(delegate) {
+    this.delegate_ = delegate;
+  }
+  FakeBluetoothChooserStub.prototype.waitForEvents = function(numOfEvents) {
+    return this.delegate_ && this.delegate_.waitForEvents && this.delegate_.waitForEvents(numOfEvents);
+  }
+  FakeBluetoothChooserStub.prototype.selectPeripheral = function(peripheralAddress) {
+    return this.delegate_ && this.delegate_.selectPeripheral && this.delegate_.selectPeripheral(peripheralAddress);
+  }
+  FakeBluetoothChooserStub.prototype.cancel = function() {
+    return this.delegate_ && this.delegate_.cancel && this.delegate_.cancel();
+  }
+  FakeBluetoothChooserStub.prototype.rescan = function() {
+    return this.delegate_ && this.delegate_.rescan && this.delegate_.rescan();
+  }
+
+  FakeBluetoothChooserStub.prototype.accept = function(message) {
+    var reader = new codec.MessageReader(message);
+    switch (reader.messageName) {
+    default:
+      return false;
+    }
+  };
+
+  FakeBluetoothChooserStub.prototype.acceptWithResponder =
+      function(message, responder) {
+    var reader = new codec.MessageReader(message);
+    switch (reader.messageName) {
+    case kFakeBluetoothChooser_WaitForEvents_Name:
+      var params = reader.decodeStruct(FakeBluetoothChooser_WaitForEvents_Params);
+      this.waitForEvents(params.numOfEvents).then(function(response) {
+        var responseParams =
+            new FakeBluetoothChooser_WaitForEvents_ResponseParams();
+        responseParams.events = response.events;
+        var builder = new codec.MessageV1Builder(
+            kFakeBluetoothChooser_WaitForEvents_Name,
+            codec.align(FakeBluetoothChooser_WaitForEvents_ResponseParams.encodedSize),
+            codec.kMessageIsResponse, reader.requestID);
+        builder.encodeStruct(FakeBluetoothChooser_WaitForEvents_ResponseParams,
+                             responseParams);
+        var message = builder.finish();
+        responder.accept(message);
+      });
+      return true;
+    case kFakeBluetoothChooser_SelectPeripheral_Name:
+      var params = reader.decodeStruct(FakeBluetoothChooser_SelectPeripheral_Params);
+      this.selectPeripheral(params.peripheralAddress).then(function(response) {
+        var responseParams =
+            new FakeBluetoothChooser_SelectPeripheral_ResponseParams();
+        var builder = new codec.MessageV1Builder(
+            kFakeBluetoothChooser_SelectPeripheral_Name,
+            codec.align(FakeBluetoothChooser_SelectPeripheral_ResponseParams.encodedSize),
+            codec.kMessageIsResponse, reader.requestID);
+        builder.encodeStruct(FakeBluetoothChooser_SelectPeripheral_ResponseParams,
+                             responseParams);
+        var message = builder.finish();
+        responder.accept(message);
+      });
+      return true;
+    case kFakeBluetoothChooser_Cancel_Name:
+      var params = reader.decodeStruct(FakeBluetoothChooser_Cancel_Params);
+      this.cancel().then(function(response) {
+        var responseParams =
+            new FakeBluetoothChooser_Cancel_ResponseParams();
+        var builder = new codec.MessageV1Builder(
+            kFakeBluetoothChooser_Cancel_Name,
+            codec.align(FakeBluetoothChooser_Cancel_ResponseParams.encodedSize),
+            codec.kMessageIsResponse, reader.requestID);
+        builder.encodeStruct(FakeBluetoothChooser_Cancel_ResponseParams,
+                             responseParams);
+        var message = builder.finish();
+        responder.accept(message);
+      });
+      return true;
+    case kFakeBluetoothChooser_Rescan_Name:
+      var params = reader.decodeStruct(FakeBluetoothChooser_Rescan_Params);
+      this.rescan().then(function(response) {
+        var responseParams =
+            new FakeBluetoothChooser_Rescan_ResponseParams();
+        var builder = new codec.MessageV1Builder(
+            kFakeBluetoothChooser_Rescan_Name,
+            codec.align(FakeBluetoothChooser_Rescan_ResponseParams.encodedSize),
+            codec.kMessageIsResponse, reader.requestID);
+        builder.encodeStruct(FakeBluetoothChooser_Rescan_ResponseParams,
+                             responseParams);
+        var message = builder.finish();
+        responder.accept(message);
+      });
+      return true;
+    default:
+      return false;
+    }
+  };
+
+  function validateFakeBluetoothChooserRequest(messageValidator) {
+    var message = messageValidator.message;
+    var paramsClass = null;
+    switch (message.getName()) {
+      case kFakeBluetoothChooser_WaitForEvents_Name:
+        if (message.expectsResponse())
+          paramsClass = FakeBluetoothChooser_WaitForEvents_Params;
+      break;
+      case kFakeBluetoothChooser_SelectPeripheral_Name:
+        if (message.expectsResponse())
+          paramsClass = FakeBluetoothChooser_SelectPeripheral_Params;
+      break;
+      case kFakeBluetoothChooser_Cancel_Name:
+        if (message.expectsResponse())
+          paramsClass = FakeBluetoothChooser_Cancel_Params;
+      break;
+      case kFakeBluetoothChooser_Rescan_Name:
+        if (message.expectsResponse())
+          paramsClass = FakeBluetoothChooser_Rescan_Params;
+      break;
+    }
+    if (paramsClass === null)
+      return validator.validationError.NONE;
+    return paramsClass.validate(messageValidator, messageValidator.message.getHeaderNumBytes());
+  }
+
+  function validateFakeBluetoothChooserResponse(messageValidator) {
+   var message = messageValidator.message;
+   var paramsClass = null;
+   switch (message.getName()) {
+      case kFakeBluetoothChooser_WaitForEvents_Name:
+        if (message.isResponse())
+          paramsClass = FakeBluetoothChooser_WaitForEvents_ResponseParams;
+        break;
+      case kFakeBluetoothChooser_SelectPeripheral_Name:
+        if (message.isResponse())
+          paramsClass = FakeBluetoothChooser_SelectPeripheral_ResponseParams;
+        break;
+      case kFakeBluetoothChooser_Cancel_Name:
+        if (message.isResponse())
+          paramsClass = FakeBluetoothChooser_Cancel_ResponseParams;
+        break;
+      case kFakeBluetoothChooser_Rescan_Name:
+        if (message.isResponse())
+          paramsClass = FakeBluetoothChooser_Rescan_ResponseParams;
+        break;
+    }
+    if (paramsClass === null)
+      return validator.validationError.NONE;
+    return paramsClass.validate(messageValidator, messageValidator.message.getHeaderNumBytes());
+  }
+
+  var FakeBluetoothChooser = {
+    name: 'content::mojom::FakeBluetoothChooser',
+    kVersion: 0,
+    ptrClass: FakeBluetoothChooserPtr,
+    proxyClass: FakeBluetoothChooserProxy,
+    stubClass: FakeBluetoothChooserStub,
+    validateRequest: validateFakeBluetoothChooserRequest,
+    validateResponse: validateFakeBluetoothChooserResponse,
+  };
+  FakeBluetoothChooserStub.prototype.validator = validateFakeBluetoothChooserRequest;
+  FakeBluetoothChooserProxy.prototype.validator = validateFakeBluetoothChooserResponse;
+  exports.ChooserEventType = ChooserEventType;
+  exports.FakeBluetoothChooserEvent = FakeBluetoothChooserEvent;
+  exports.FakeBluetoothChooser = FakeBluetoothChooser;
+  exports.FakeBluetoothChooserPtr = FakeBluetoothChooserPtr;
+  exports.FakeBluetoothChooserAssociatedPtr = FakeBluetoothChooserAssociatedPtr;
+})();
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/resources/chromium/fake_bluetooth_chooser.mojom.js.headers b/third_party/WebKit/LayoutTests/external/wpt/resources/chromium/fake_bluetooth_chooser.mojom.js.headers
new file mode 100644
index 0000000..6805c323
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/resources/chromium/fake_bluetooth_chooser.mojom.js.headers
@@ -0,0 +1 @@
+Content-Type: text/javascript; charset=utf-8
diff --git a/third_party/WebKit/LayoutTests/external/wpt/resources/chromium/web-bluetooth-test.js b/third_party/WebKit/LayoutTests/external/wpt/resources/chromium/web-bluetooth-test.js
index 42656d3..c10685f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/resources/chromium/web-bluetooth-test.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/resources/chromium/web-bluetooth-test.js
@@ -65,7 +65,7 @@
   constructor() {
     this.fake_bluetooth_ptr_ = new bluetooth.mojom.FakeBluetoothPtr();
     Mojo.bindInterface(bluetooth.mojom.FakeBluetooth.name,
-        mojo.makeRequest(this.fake_bluetooth_ptr_).handle, "process");
+        mojo.makeRequest(this.fake_bluetooth_ptr_).handle, 'process');
   }
 
   // Set it to indicate whether the platform supports BLE. For example,
@@ -102,6 +102,15 @@
     let {consumed} = await this.fake_bluetooth_ptr_.allResponsesConsumed();
     return consumed;
   }
+
+  // Returns a promise that resolves with a FakeChooser that clients can use to
+  // simulate chooser events.
+  async getManualChooser() {
+    if (typeof this.fake_chooser_ === 'undefined') {
+      this.fake_chooser_ = new FakeChooser();
+    }
+    return this.fake_chooser_;
+  }
 }
 
 // FakeCentral allows clients to simulate events that a device in the
@@ -437,6 +446,17 @@
   }
 }
 
+// FakeChooser allows clients to simulate events that a user would trigger when
+// using the Bluetooth chooser, and monitor the events that are produced.
+class FakeChooser {
+  constructor() {
+    this.fake_bluetooth_chooser_ptr_ =
+        new content.mojom.FakeBluetoothChooserPtr();
+    Mojo.bindInterface(content.mojom.FakeBluetoothChooser.name,
+        mojo.makeRequest(this.fake_bluetooth_chooser_ptr_).handle, 'process');
+  }
+}
+
 // If this line fails, it means that current environment does not support the
 // Web Bluetooth Test API.
 try {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/user-timing/invoke_with_timing_attributes.html b/third_party/WebKit/LayoutTests/external/wpt/user-timing/invoke_with_timing_attributes.html
index dc355a9a..6c06f5e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/user-timing/invoke_with_timing_attributes.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/user-timing/invoke_with_timing_attributes.html
@@ -24,8 +24,8 @@
 
 function emit_test2(attrName) {
     test(function() {
-        assert_throws("SyntaxError", function() { window.performance.measure(attrName); });
-    }, "performance.measure should throw if used with timing attribute " + attrName);
+        window.performance.measure(attrName);
+    }, "performance.measure should not throw if used with timing attribute " + attrName);
 }
 for (var i in timingAttributes) {
   emit_test2(timingAttributes[i]);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/user-timing/measure_exceptions_navigation_timing.html b/third_party/WebKit/LayoutTests/external/wpt/user-timing/measure_exceptions_navigation_timing.html
index 77c1e48e..1633221 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/user-timing/measure_exceptions_navigation_timing.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/user-timing/measure_exceptions_navigation_timing.html
@@ -59,7 +59,7 @@
                               "attribute with a value of 0, throws a InvalidAccessError exception.");
     </script>
     </head>
-    <body onload="onload_test();">
+    <body>
         <h1>Description</h1>
         <p><code>window.performance.measure()</code> method throws a InvalidAccessError
            whenever a navigation timing attribute with a value of zero is provided as the startMark or endMark.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-disconnected-input.https.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-disconnected-input.https.html
new file mode 100644
index 0000000..c58502a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-disconnected-input.https.html
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>
+      Test AudioWorkletNode's Disconnected Input Array Length
+    </title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/webaudio/resources/audit.js"></script>
+    <script src="/webaudio/resources/audit-util.js"></script>
+  </head>
+  <body>
+    <script id="layout-test-code">
+      let audit = Audit.createTaskRunner();
+
+      // Arbitrary numbers used to align the test with render quantum boundary.
+      // The sample rate is a power of two to eliminate roundoff in computing
+      // the suspend time needed for the test.
+      let sampleRate = 16384;
+      let renderLength = 8 * RENDER_QUANTUM_FRAMES;
+      let context;
+
+      let filePath = 'processors/input-length-processor.js';
+
+      let testChannelValues = [1, 2, 3];
+
+      // Creates a 3-channel buffer and play with BufferSourceNode. The source
+      // goes through a bypass AudioWorkletNode (gain value of 1).
+      audit.define(
+          {
+            label: 'test',
+            description:
+                'Input array length should be zero for disconnected input'
+          },
+          (task, should) => {
+            context = new OfflineAudioContext({
+              numberOfChannels: 1,
+              length: renderLength,
+              sampleRate: sampleRate
+            });
+
+            context.audioWorklet.addModule(filePath).then(() => {
+              let sourceNode = new ConstantSourceNode(context);
+              let workletNode =
+                  new AudioWorkletNode(context, 'input-length-processor');
+
+              workletNode.connect(context.destination);
+
+              // Connect the source now.
+              let connectFrame = RENDER_QUANTUM_FRAMES;
+
+              context.suspend(connectFrame / sampleRate)
+                  .then(() => {
+                    sourceNode.connect(workletNode);
+                  })
+                  .then(() => context.resume());
+              ;
+
+              // Then disconnect the source after a few renders
+              let disconnectFrame = 3 * RENDER_QUANTUM_FRAMES;
+              context.suspend(disconnectFrame / sampleRate)
+                  .then(() => {
+                    sourceNode.disconnect(workletNode);
+                  })
+                  .then(() => context.resume());
+
+              sourceNode.start();
+              context.startRendering()
+                  .then(resultBuffer => {
+                    let data = resultBuffer.getChannelData(0);
+
+                    should(
+                        data.slice(0, connectFrame),
+                        'Before connecting the source: Input array length')
+                        .beConstantValueOf(0);
+
+                    // Find where the output is no longer 0.
+                    let nonZeroIndex = data.findIndex(x => x > 0);
+                    should(nonZeroIndex, 'First non-zero output')
+                        .beEqualTo(connectFrame);
+
+                    should(
+                        data.slice(
+                            nonZeroIndex,
+                            nonZeroIndex + (disconnectFrame - connectFrame)),
+                        'While source is connected: Input array length')
+                        .beConstantValueOf(RENDER_QUANTUM_FRAMES);
+                    should(
+                        data.slice(disconnectFrame),
+                        'After disconnecting the source: Input array length')
+                        .beConstantValueOf(0);
+                  })
+                  .then(() => task.done());
+            });
+          });
+
+      audit.run();
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/processors/input-length-processor.js b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/processors/input-length-processor.js
new file mode 100644
index 0000000..cc0968d7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/processors/input-length-processor.js
@@ -0,0 +1,25 @@
+/**
+ * @class InputLengthProcessor
+ * @extends AudioWorkletProcessor
+ *
+ * This processor class just sets the output to the length of the
+ * input array for verifying that the input length changes when the
+ * input is disconnected.
+ */
+class InputLengthProcessor extends AudioWorkletProcessor {
+  constructor() {
+    super();
+  }
+
+  process(inputs, outputs, parameters) {
+    let input = inputs[0];
+    let output = outputs[0];
+
+    // Set output channel to the length of the input channel array.
+    output[0].fill(input[0].length);
+
+    return true;
+  }
+}
+
+registerProcessor('input-length-processor', InputLengthProcessor);
diff --git a/third_party/WebKit/LayoutTests/fast/compositor-wheel-scroll-latching/touchpad-scroll-impl-to-main.html b/third_party/WebKit/LayoutTests/fast/compositor-wheel-scroll-latching/animated-scroll/touchpad-scroll-impl-to-main.html
similarity index 77%
rename from third_party/WebKit/LayoutTests/fast/compositor-wheel-scroll-latching/touchpad-scroll-impl-to-main.html
rename to third_party/WebKit/LayoutTests/fast/compositor-wheel-scroll-latching/animated-scroll/touchpad-scroll-impl-to-main.html
index cfcf1d71..4c3c741 100644
--- a/third_party/WebKit/LayoutTests/fast/compositor-wheel-scroll-latching/touchpad-scroll-impl-to-main.html
+++ b/third_party/WebKit/LayoutTests/fast/compositor-wheel-scroll-latching/animated-scroll/touchpad-scroll-impl-to-main.html
@@ -1,6 +1,6 @@
 <!DOCTYPE HTML>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
 <style>
   body {
     margin: 0px;
@@ -29,21 +29,21 @@
 const GESTURE_SOURCE_TYPE = 2; // MOUSE_INPUT from synthetic_gesture_params.h
 
 function changeStyleToScrollOnMain() {
-  if(div.scrollTop > 150)
+  if(div.scrollTop > 100)
     div.style = "border-radius:40px; position:fixed;";
 }
-div.addEventListener("scroll", changeStyleToScrollOnMain, {passive: true});
+div.addEventListener("wheel", changeStyleToScrollOnMain, {passive: true});
 
-const MAX_RAF = 1000;
 let last_scroll_offset = div.scrollTop;
 var last_changed_count = 0;
 var raf_count = 0;
 function waitForAnimationEnd() {
   return new Promise((resolve, reject) => {
     function tick() {
-    // We requestAnimationFrame either for 1000 frames or until 20 frames with
-    // no change have been observed.
-      if (raf_count >= MAX_RAF || raf_count - last_changed_count > 20) {
+    // We requestAnimationFrame until either 70 frames with no change observed
+    // or the div is fully scrolled.
+      if (raf_count - last_changed_count > 70 ||
+          div.scrollTop == div.scrollHeight - div.clientHeight) {
         resolve();
       } else {
         if (div.scrollTop != last_scroll_offset) {
@@ -66,7 +66,7 @@
                                           (rect.top + rect.bottom) / 2,
                                           GESTURE_SOURCE_TYPE,
                                           'down',
-                                          4000);
+                                          2000);
   }).then(waitForAnimationEnd)
   .then(() => {
     assert_equals(div.scrollTop, div.scrollHeight - div.clientHeight,
diff --git a/third_party/WebKit/LayoutTests/fast/compositor-wheel-scroll-latching/subpixel-accumulation.html b/third_party/WebKit/LayoutTests/fast/compositor-wheel-scroll-latching/non-animated-scroll/subpixel-accumulation.html
similarity index 95%
rename from third_party/WebKit/LayoutTests/fast/compositor-wheel-scroll-latching/subpixel-accumulation.html
rename to third_party/WebKit/LayoutTests/fast/compositor-wheel-scroll-latching/non-animated-scroll/subpixel-accumulation.html
index dab9a254..790a9f7 100644
--- a/third_party/WebKit/LayoutTests/fast/compositor-wheel-scroll-latching/subpixel-accumulation.html
+++ b/third_party/WebKit/LayoutTests/fast/compositor-wheel-scroll-latching/non-animated-scroll/subpixel-accumulation.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
 <script>
   let t;
   if (window.internals && chrome && chrome.gpuBenchmarking) {
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/bidi-dom-tree-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/bidi-dom-tree-expected.txt
index 685da8b..e76e5be 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/bidi-dom-tree-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/bidi-dom-tree-expected.txt
@@ -1,6 +1,6 @@
 Tests that elements panel correctly displays DOM tree structure for bi-di pages.
 
-  <!DOCTYPE html>
+  <!doctype html>
 - <html>
     - <head>
           <base href="http://127.0.0.1:8000/devtools/elements/">
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/edit/delete-from-document-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/edit/delete-from-document-expected.txt
index 00dcc570..3df7d27 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/edit/delete-from-document-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/edit/delete-from-document-expected.txt
@@ -1,7 +1,7 @@
 Tests that removing child from the document is handled properly in the elements panel.
 
 Before remove doctype
-  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+  <!doctype html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 - <html>
 After remove doctype
 - <html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/elements-panel-correct-case-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/elements-panel-correct-case-expected.txt
index 6a4331ec..61915a8 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/elements-panel-correct-case-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/elements-panel-correct-case-expected.txt
@@ -1,6 +1,6 @@
 Tests that elements panel shows all types of elements in the correct case.
 
-  <!DOCTYPE html>
+  <!doctype html>
 - <html>
     - <head>
           <base href="http://127.0.0.1:8000/devtools/elements/">
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/elements-panel-structure-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/elements-panel-structure-expected.txt
index cd35df9..87d54b01 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/elements-panel-structure-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/elements-panel-structure-expected.txt
@@ -1,6 +1,6 @@
 Tests that elements panel shows DOM tree structure.
 
-  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+  <!doctype html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 - <html>
     - <head>
           <base href="http://127.0.0.1:8000/devtools/elements/">
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/user-properties-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/user-properties-expected.txt
index bf8bab3..ee02615e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/user-properties-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/user-properties-expected.txt
@@ -1,7 +1,7 @@
 Tests that DOMNode properly tracks own and descendants' user properties.
 
 attr1 set on aNode
-  <!DOCTYPE html>
+  <!doctype html>
 - <html> [subtreeMarkerCount:1]
     - <head>
           <base href="http://127.0.0.1:8000/devtools/elements/">
@@ -16,7 +16,7 @@
       </body>
   </html>
 attr2 set on child2
-  <!DOCTYPE html>
+  <!doctype html>
 - <html> [subtreeMarkerCount:2]
     - <head>
           <base href="http://127.0.0.1:8000/devtools/elements/">
@@ -31,7 +31,7 @@
       </body>
   </html>
 attr1 set on child2
-  <!DOCTYPE html>
+  <!doctype html>
 - <html> [subtreeMarkerCount:3]
     - <head>
           <base href="http://127.0.0.1:8000/devtools/elements/">
@@ -46,7 +46,7 @@
       </body>
   </html>
 attr1 modified on aNode
-  <!DOCTYPE html>
+  <!doctype html>
 - <html> [subtreeMarkerCount:3]
     - <head>
           <base href="http://127.0.0.1:8000/devtools/elements/">
@@ -61,7 +61,7 @@
       </body>
   </html>
 attr2 modified on child2
-  <!DOCTYPE html>
+  <!doctype html>
 - <html> [subtreeMarkerCount:3]
     - <head>
           <base href="http://127.0.0.1:8000/devtools/elements/">
@@ -76,7 +76,7 @@
       </body>
   </html>
 attr1 removed from aNode
-  <!DOCTYPE html>
+  <!doctype html>
 - <html> [subtreeMarkerCount:2]
     - <head>
           <base href="http://127.0.0.1:8000/devtools/elements/">
@@ -91,7 +91,7 @@
       </body>
   </html>
 aNode removed
-  <!DOCTYPE html>
+  <!doctype html>
 - <html> [subtreeMarkerCount:2]
     - <head>
           <base href="http://127.0.0.1:8000/devtools/elements/">
@@ -104,7 +104,7 @@
       </body>
   </html>
 child2 removed
-  <!DOCTYPE html>
+  <!doctype html>
 - <html> [subtreeMarkerCount:2]
     - <head>
           <base href="http://127.0.0.1:8000/devtools/elements/">
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/network/resources/resource.php b/third_party/WebKit/LayoutTests/http/tests/devtools/network/resources/resource.php
index c2b6f1ccc..4e619bf 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/network/resources/resource.php
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/network/resources/resource.php
@@ -9,6 +9,7 @@
     $chunked = $_GET["chunked"];
     $random = $_GET["random"];
     $cached = $_GET["cached"];
+    $nosniff = $_GET["nosniff"];
 
     # Wait before sending response
     if ($wait)
@@ -46,6 +47,9 @@
     else
         header("Content-Type: text/plain");
 
+    if ($nosniff)
+        header("x-content-type-options: nosniff");
+
     # Flush headers and sleep bofore sending response
     if ($send) {
         flush();
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/redirect-interception-mocked-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/redirect-interception-mocked-expected.txt
index 341cdaf..53215ba 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/redirect-interception-mocked-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/redirect-interception-mocked-expected.txt
@@ -15,7 +15,7 @@
 allowRequest ID 2
 Network.requestIntercepted ID 2 301 redirect redirect3.pl -> final.js
 mockResponse ID 2
-Network.responseReceived redirect3.pl 301 application/javascript
+Network.responseReceived redirect3.pl 200 application/javascript
 Page.frameStoppedLoading
 Hello from the mock resource
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/response-interception-cancel-xhr-while-responding-error-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/response-interception-cancel-xhr-while-responding-error-expected.txt
index f3bc44e..385c4cf8 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/response-interception-cancel-xhr-while-responding-error-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/response-interception-cancel-xhr-while-responding-error-expected.txt
@@ -1,6 +1,6 @@
 Tests to ensure error message on request cancelled while intercepting response.
 Network agent enabled
-Request Intercepted: resource.php?send=10000
+Request Intercepted: resource.php?send=10000&nosniff=1
 Aborting request
 Renderer received abort signal
 Continuing intercepted request
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/response-interception-cancel-xhr-while-responding-error.js b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/response-interception-cancel-xhr-while-responding-error.js
index 12fe9e7..b0e2b970 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/response-interception-cancel-xhr-while-responding-error.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/response-interception-cancel-xhr-while-responding-error.js
@@ -29,7 +29,7 @@
     session.evaluate(`
       window.xhr = new XMLHttpRequest();
       // This script will send headers then wait 10 seconds before sending body.
-      window.xhr.open('GET', '/devtools/network/resources/resource.php?send=10000', true);
+      window.xhr.open('GET', '/devtools/network/resources/resource.php?send=10000&nosniff=1', true);
       window.xhr.send();
     `);
   });
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/response-interception-with-data-url-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/response-interception-with-data-url-expected.txt
index d33b87f..381267c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/response-interception-with-data-url-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/response-interception-with-data-url-expected.txt
@@ -1,12 +1,9 @@
 Tests to ensure iframe can change to data url while intercepting response.
 Network agent enabled
-Request Intercepted: resource.php?send=10000&chunked=1&size=1000
+Request Intercepted: resource.php?send=10000&chunked=1&size=1000&nosniff=1
 Setting iframe to data url from renderer
 Continuing request unchanged
 
-Request Intercepted: data:,Dummy data
-Continuing request unchanged
-
 Body content received by renderer:
 Dummy data
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/response-interception-with-data-url.js b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/response-interception-with-data-url.js
index eb313d8e..52aa5af 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/response-interception-with-data-url.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/response-interception-with-data-url.js
@@ -21,7 +21,7 @@
   await session.protocol.Network.setCacheDisabled({cacheDisabled: true});
   session.protocol.Network.enable();
   testRunner.log('Network agent enabled');
-  await session.protocol.Network.setRequestInterception({patterns: [{urlPattern: "*", interceptionStage: 'HeadersReceived'}]});
+  await session.protocol.Network.setRequestInterception({patterns: [{urlPattern: "http://*", interceptionStage: 'HeadersReceived'}]});
 
   var requestId = '';
   session.protocol.Network.onRequestWillBeSent(event => {
@@ -36,7 +36,7 @@
     session.evaluate(`
       iframe = document.createElement('iframe');
       // Script wait sends headers then waits 10 seconds to send body.
-      iframe.src = '/devtools/network/resources/resource.php?send=10000&chunked=1&size=1000';
+      iframe.src = '/devtools/network/resources/resource.php?send=10000&chunked=1&size=1000&nosniff=1';
       document.body.appendChild(iframe);
     `);
   });
diff --git a/third_party/WebKit/LayoutTests/external/wpt/user-timing/invoke_with_timing_attributes-expected.txt b/third_party/WebKit/LayoutTests/platform/fuchsia/external/wpt/user-timing/invoke_with_timing_attributes-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/user-timing/invoke_with_timing_attributes-expected.txt
rename to third_party/WebKit/LayoutTests/platform/fuchsia/external/wpt/user-timing/invoke_with_timing_attributes-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/preload/download-resources-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/preload/download-resources-expected.txt
deleted file mode 100644
index 5ce86f0..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/preload/download-resources-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Makes sure that preloaded resources are downloaded assert_equals: resources/CanvasTest.ttf expected 1 but got 0
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/preload/download-resources-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/preload/download-resources-expected.txt
deleted file mode 100644
index 5ce86f0..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/preload/download-resources-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Makes sure that preloaded resources are downloaded assert_equals: resources/CanvasTest.ttf expected 1 but got 0
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/README.txt b/third_party/WebKit/LayoutTests/virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/animated-scroll/README.txt
similarity index 70%
copy from third_party/WebKit/LayoutTests/virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/README.txt
copy to third_party/WebKit/LayoutTests/virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/animated-scroll/README.txt
index 64d2beb5..9444bad 100644
--- a/third_party/WebKit/LayoutTests/virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/README.txt
+++ b/third_party/WebKit/LayoutTests/virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/animated-scroll/README.txt
@@ -1,2 +1,2 @@
-This suite runs the tests in fast/compositor-wheel-scroll-latching with
-# --enable-features=TouchpadAndWheelScrollLatching  --enable-threaded-compositing --disable-smooth-scrolling
+This suite runs the tests in fast/compositor-wheel-scroll-latching/animated-scroll with
+# --enable-features=TouchpadAndWheelScrollLatching  --enable-threaded-compositing
diff --git a/third_party/WebKit/LayoutTests/virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/README.txt b/third_party/WebKit/LayoutTests/virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/non-animated-scroll/README.txt
similarity index 85%
rename from third_party/WebKit/LayoutTests/virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/README.txt
rename to third_party/WebKit/LayoutTests/virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/non-animated-scroll/README.txt
index 64d2beb5..b15f7f7f 100644
--- a/third_party/WebKit/LayoutTests/virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/README.txt
+++ b/third_party/WebKit/LayoutTests/virtual/wheelscrolllatching/fast/compositor-wheel-scroll-latching/non-animated-scroll/README.txt
@@ -1,2 +1,2 @@
-This suite runs the tests in fast/compositor-wheel-scroll-latching with
+This suite runs the tests in fast/compositor-wheel-scroll-latching/non-animated-scroll with
 # --enable-features=TouchpadAndWheelScrollLatching  --enable-threaded-compositing --disable-smooth-scrolling
diff --git a/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_non_exclusive_adjust_size.html b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_non_exclusive_adjust_size.html
new file mode 100644
index 0000000..05a0c74
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_non_exclusive_adjust_size.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script>
+<script src="../xr/resources/xr-device-mocking.js"></script>
+<script src="../xr/resources/xr-test-utils.js"></script>
+<script src="../xr/resources/test-constants.js"></script>
+<canvas id="webgl-canvas"></canvas>
+
+<script>
+let fakeDevices = fakeXRDevices();
+let outputContext = getOutputContext();
+let outputCanvas = outputContext.canvas;
+
+// Make an unreasonably large magic window canvas.
+outputCanvas.width = 18000; // 16k ought to be a large enough max for anyone.
+outputCanvas.height = 20000;
+
+let outputCanvasRatio = outputCanvas.width / outputCanvas.height;
+
+xr_session_promise_test( (session, t) => new Promise((resolve, reject) => {
+  let webglLayer = new XRWebGLLayer(session, gl);
+  session.baseLayer = webglLayer;
+
+  t.step(() => {
+    // The layer's framebuffer should be smaller than the requested size.
+    assert_true(webglLayer.framebufferWidth < outputCanvas.width);
+    assert_true(webglLayer.framebufferHeight < outputCanvas.height);
+
+    // The layer's dimensions should keep the same ratio as the canvas.
+    let framebufferRatio = webglLayer.framebufferWidth / webglLayer.framebufferHeight;
+    assert_approx_equals(framebufferRatio, outputCanvasRatio, 0.0001);
+  });
+
+  // Resize the canvas to something more reasonable.
+  outputCanvas.width = 256;
+  outputCanvas.height = 128;
+
+  // Give the UA a chance to respond to the resize.
+  setTimeout(() => {
+    // Check to ensure the framebuffer resized to match the new canvas dimensions.
+    t.step(() => {
+      assert_equals(webglLayer.framebufferWidth, outputCanvas.width);
+      assert_equals(webglLayer.framebufferHeight, outputCanvas.height);
+    });
+
+    resolve();
+  }, 100);
+}), fakeDevices["FakeGooglePixelPhone"], [{ outputContext: outputContext }],
+"Ensure a WebGL layer's framebuffer size is adjusted appropriately when a large canvas is requested");
+
+</script>
diff --git a/third_party/WebKit/Source/core/editing/RenderedPosition.cpp b/third_party/WebKit/Source/core/editing/RenderedPosition.cpp
index 35a8a66..98cf6da 100644
--- a/third_party/WebKit/Source/core/editing/RenderedPosition.cpp
+++ b/third_party/WebKit/Source/core/editing/RenderedPosition.cpp
@@ -248,21 +248,8 @@
       PrevLeafChild()->CaretRightmostOffset());
 }
 
-// Note: If the layout object has a scrolling contents layer, the selection
-// will be relative to that.
-static GraphicsLayer* GetGraphicsLayerBacking(
-    const LayoutObject& layout_object) {
-  const LayoutBoxModelObject& paint_invalidation_container =
-      layout_object.ContainerForPaintInvalidation();
-  DCHECK(paint_invalidation_container.Layer());
-  if (paint_invalidation_container.Layer()->GetCompositingState() ==
-      kNotComposited)
-    return nullptr;
-  return paint_invalidation_container.Layer()->GraphicsLayerBacking(
-      &layout_object);
-}
-
 // Convert a local point into the coordinate system of backing coordinates.
+// Also returns the backing layer if needed.
 static FloatPoint LocalToInvalidationBackingPoint(
     const LayoutPoint& local_point,
     const LayoutObject& layout_object) {
@@ -283,20 +270,28 @@
   PaintLayer::MapPointInPaintInvalidationContainerToBacking(
       paint_invalidation_container, container_point);
 
-  if (GraphicsLayer* graphics_layer = GetGraphicsLayerBacking(layout_object))
+  // Must not use the scrolling contents layer, so pass
+  // |paintInvalidationContainer|.
+  if (GraphicsLayer* graphics_layer =
+          paint_invalidation_container.Layer()->GraphicsLayerBacking(
+              &paint_invalidation_container))
     container_point.Move(-graphics_layer->OffsetFromLayoutObject());
 
-  // Ensure the coordinates are in the scrolling contents space, if the object
-  // is a scroller.
-  if (paint_invalidation_container.UsesCompositedScrolling()) {
-    container_point.Move(paint_invalidation_container.Layer()
-                             ->GetScrollableArea()
-                             ->GetScrollOffset());
-  }
-
   return container_point;
 }
 
+static GraphicsLayer* GetGraphicsLayerBacking(
+    const LayoutObject& layout_object) {
+  const LayoutBoxModelObject& paint_invalidation_container =
+      layout_object.ContainerForPaintInvalidation();
+  DCHECK(paint_invalidation_container.Layer());
+  if (paint_invalidation_container.Layer()->GetCompositingState() ==
+      kNotComposited)
+    return nullptr;
+  return paint_invalidation_container.Layer()->GraphicsLayerBacking(
+      &paint_invalidation_container);
+}
+
 std::pair<LayoutPoint, LayoutPoint> static GetLocalSelectionStartpoints(
     const LocalCaretRect& local_caret_rect) {
   const LayoutRect rect = local_caret_rect.rect;
diff --git a/third_party/WebKit/Source/core/editing/RenderedPositionTest.cpp b/third_party/WebKit/Source/core/editing/RenderedPositionTest.cpp
index e0137935..af07c01 100644
--- a/third_party/WebKit/Source/core/editing/RenderedPositionTest.cpp
+++ b/third_party/WebKit/Source/core/editing/RenderedPositionTest.cpp
@@ -10,55 +10,37 @@
 #include "core/editing/testing/EditingTestBase.h"
 #include "core/frame/Settings.h"
 #include "core/html/forms/HTMLInputElement.h"
-#include "core/layout/LayoutBox.h"
-#include "core/paint/PaintLayerScrollableArea.h"
 #include "core/paint/compositing/CompositedSelection.h"
-#include "platform/testing/runtime_enabled_features_test_helpers.h"
 
 namespace blink {
 
-class RenderedPositionTest : public ::testing::WithParamInterface<bool>,
-                             private ScopedRootLayerScrollingForTest,
-                             public EditingTestBase {
- public:
-  RenderedPositionTest() : ScopedRootLayerScrollingForTest(GetParam()) {}
-  void SetUp() override {
-    EditingTestBase::SetUp();
-    GetPage().GetSettings().SetAcceleratedCompositingEnabled(true);
-    GetDocument().View()->SetParentVisible(true);
-    GetDocument().View()->SetSelfVisible(true);
-    LoadAhem();
-  }
+class RenderedPositionTest : public EditingTestBase {};
 
-  void FocusAndSelectAll() {
-    HTMLInputElement* target =
-        ToHTMLInputElement(GetDocument().getElementById("target"));
-    DCHECK(target);
-    target->focus();
-    Selection().SetSelection(
-        SelectionInDOMTree::Builder()
-            .SelectAllChildren(*target->InnerEditorElement())
-            .Build(),
-        SetSelectionOptions::Builder().SetShouldShowHandle(true).Build());
-    UpdateAllLifecyclePhases();
-  }
-};
+#if defined(OS_ANDROID)
+#define MAYBE_ComputeCompositedSelection DISABLED_ComputeCompositedSelection
+#else
+#define MAYBE_ComputeCompositedSelection ComputeCompositedSelection
+#endif
+TEST_F(RenderedPositionTest, MAYBE_ComputeCompositedSelection) {
+  // Enable compositing.
+  GetPage().GetSettings().SetAcceleratedCompositingEnabled(true);
+  GetDocument().View()->SetParentVisible(true);
+  GetDocument().View()->SetSelfVisible(true);
+  GetDocument().View()->UpdateAllLifecyclePhases();
 
-INSTANTIATE_TEST_CASE_P(All, RenderedPositionTest, ::testing::Bool());
-
-TEST_P(RenderedPositionTest, ComputeCompositedSelection) {
-  SetBodyContent(R"HTML(
-      <!DOCTYPE html>
-      input {
-        font: 10px/1 Ahem;
-        padding: 0;
-        border: 0;
-      }
-      <input id=target width=20 value='test test test test test tes tes test'
-      style='width: 100px; height: 20px;'>
-  )HTML");
-
-  FocusAndSelectAll();
+  SetBodyContent(
+      "<input id=target width=20 value='test test test test test tes tes test'"
+      "style='width: 100px; height: 20px;'>");
+  HTMLInputElement* target =
+      ToHTMLInputElement(GetDocument().getElementById("target"));
+  DCHECK(target);
+  target->focus();
+  Selection().SetSelection(
+      SelectionInDOMTree::Builder()
+          .SelectAllChildren(*target->InnerEditorElement())
+          .Build(),
+      SetSelectionOptions::Builder().SetShouldShowHandle(true).Build());
+  UpdateAllLifecyclePhases();
 
   const CompositedSelection& composited_selection =
       RenderedPosition::ComputeCompositedSelection(Selection());
@@ -66,115 +48,4 @@
   EXPECT_TRUE(composited_selection.end.hidden);
 }
 
-TEST_P(RenderedPositionTest, PositionInScrollableRoot) {
-  SetBodyContent(R"HTML(
-      <!DOCTYPE html>
-      <style>
-        body {
-           margin: 0;
-           height: 2000px;
-           width: 2000px;
-        }
-        input {
-          font: 10px/1 Ahem;
-          padding: 0;
-          border: 0;
-          width: 100px;
-          height: 20px;
-          position: absolute;
-          top: 900px;
-          left: 1000px;
-        }
-      </style>
-      <input id=target width=20 value='test test test test test tes tes test'>
-  )HTML");
-
-  FocusAndSelectAll();
-
-  ScrollableArea* root_scroller = GetDocument().View()->GetScrollableArea();
-  root_scroller->SetScrollOffset(ScrollOffset(800, 500), kProgrammaticScroll);
-  ASSERT_EQ(ScrollOffset(800, 500), root_scroller->GetScrollOffset());
-
-  UpdateAllLifecyclePhases();
-
-  const CompositedSelection& composited_selection =
-      RenderedPosition::ComputeCompositedSelection(Selection());
-
-  // Top-left corner should be around (1000, 905) - 10px centered in 20px
-  // height.
-  EXPECT_EQ(FloatPoint(1000, 905),
-            composited_selection.start.edge_top_in_layer);
-  EXPECT_EQ(FloatPoint(1000, 915),
-            composited_selection.start.edge_bottom_in_layer);
-  EXPECT_EQ(FloatPoint(1369, 905), composited_selection.end.edge_top_in_layer);
-  EXPECT_EQ(FloatPoint(1369, 915),
-            composited_selection.end.edge_bottom_in_layer);
-}
-
-TEST_P(RenderedPositionTest, PositionInScroller) {
-  SetBodyContent(R"HTML(
-      <!DOCTYPE html>
-      <style>
-        body {
-           margin: 0;
-           height: 2000px;
-           width: 2000px;
-        }
-        input {
-          font: 10px/1 Ahem;
-          padding: 0;
-          border: 0;
-          width: 100px;
-          height: 20px;
-          position: absolute;
-          top: 900px;
-          left: 1000px;
-        }
-
-        #scroller {
-          width: 300px;
-          height: 300px;
-          position: absolute;
-          left: 300px;
-          top: 400px;
-          overflow: scroll;
-          border: 200px;
-          will-change: transform;
-        }
-
-        #space {
-          width: 2000px;
-          height: 2000px;
-        }
-      </style>
-      <div id="scroller">
-        <div id="space"></div>
-        <input id=target width=20 value='test test test test test tes tes test'>
-      </div>
-  )HTML");
-
-  FocusAndSelectAll();
-
-  Element* e = GetDocument().getElementById("scroller");
-  PaintLayerScrollableArea* scroller =
-      ToLayoutBox(e->GetLayoutObject())->GetScrollableArea();
-  scroller->SetScrollOffset(ScrollOffset(900, 800), kProgrammaticScroll);
-  ASSERT_EQ(ScrollOffset(900, 800), scroller->GetScrollOffset());
-
-  UpdateAllLifecyclePhases();
-
-  const CompositedSelection& composited_selection =
-      RenderedPosition::ComputeCompositedSelection(Selection());
-
-  // Top-left corner should be around (1000, 905) - 10px centered in 20px
-  // height.
-  EXPECT_EQ(FloatPoint(1000, 905),
-            composited_selection.start.edge_top_in_layer);
-  EXPECT_EQ(FloatPoint(1000, 915),
-            composited_selection.start.edge_bottom_in_layer);
-  EXPECT_EQ(FloatPoint(1369, 905), composited_selection.end.edge_top_in_layer);
-  EXPECT_EQ(FloatPoint(1369, 915),
-            composited_selection.end.edge_bottom_in_layer);
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
index d232638..0aa806a 100644
--- a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
@@ -6332,7 +6332,11 @@
     blink::Node* layer_owner_node_for_start = V8Node::ToImplWithTypeCheck(
         v8::Isolate::GetCurrent(), expected_result.Get(0));
     ASSERT_TRUE(layer_owner_node_for_start);
-    EXPECT_EQ(GetExpectedLayerForSelection(layer_owner_node_for_start)
+    EXPECT_EQ(layer_owner_node_for_start->GetLayoutObject()
+                  ->EnclosingLayer()
+                  ->EnclosingLayerForPaintInvalidation()
+                  ->GetCompositedLayerMapping()
+                  ->MainGraphicsLayer()
                   ->PlatformLayer()
                   ->Id(),
               select_start->layer_id);
@@ -6347,7 +6351,11 @@
         expected_result.Get(context, 5).ToLocalChecked());
 
     ASSERT_TRUE(layer_owner_node_for_end);
-    EXPECT_EQ(GetExpectedLayerForSelection(layer_owner_node_for_end)
+    EXPECT_EQ(layer_owner_node_for_end->GetLayoutObject()
+                  ->EnclosingLayer()
+                  ->EnclosingLayerForPaintInvalidation()
+                  ->GetCompositedLayerMapping()
+                  ->MainGraphicsLayer()
                   ->PlatformLayer()
                   ->Id(),
               select_end->layer_id);
@@ -6399,18 +6407,6 @@
     RunTest(test_file);
   }
 
-  GraphicsLayer* GetExpectedLayerForSelection(blink::Node* node) const {
-    CompositedLayerMapping* clm = node->GetLayoutObject()
-                                      ->EnclosingLayer()
-                                      ->EnclosingLayerForPaintInvalidation()
-                                      ->GetCompositedLayerMapping();
-
-    // If the Node is a scroller, the selection will be relative to its
-    // scrolling contents layer.
-    return clm->ScrollingContentsLayer() ? clm->ScrollingContentsLayer()
-                                         : clm->MainGraphicsLayer();
-  }
-
   CompositedSelectionBoundsTestWebViewClient fake_selection_web_view_client_;
   CompositedSelectionBoundsTestLayerTreeView& fake_selection_layer_tree_view_;
   FrameTestHelpers::WebViewHelper web_view_helper_;
diff --git a/third_party/WebKit/Source/core/timing/PerformanceResourceTiming.cpp b/third_party/WebKit/Source/core/timing/PerformanceResourceTiming.cpp
index 1f43167e..41ff6c0 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceResourceTiming.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceResourceTiming.cpp
@@ -133,10 +133,6 @@
   // If connection_info is also unknown, return empty string.
   // (https://github.com/w3c/navigation-timing/issues/71)
   returnedProtocol = (returnedProtocol == "unknown") ? "" : returnedProtocol;
-  // If the protocol is http over quic (e.g. http/2+quic/37), convert it to the
-  // alpn id "hq". (https://github.com/w3c/navigation-timing/issues/71)
-  if (returnedProtocol.Contains("quic"))
-    returnedProtocol = "hq";
 
   return returnedProtocol;
 }
diff --git a/third_party/WebKit/Source/core/timing/PerformanceResourceTimingTest.cpp b/third_party/WebKit/Source/core/timing/PerformanceResourceTimingTest.cpp
index 54e4dac..f4c8f72 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceResourceTimingTest.cpp
+++ b/third_party/WebKit/Source/core/timing/PerformanceResourceTimingTest.cpp
@@ -32,11 +32,11 @@
   EXPECT_EQ(GetNextHopProtocol(alpn_negotiated_protocol, connection_info), "");
 }
 
-TEST_F(PerformanceResourceTimingTest, TestFallbackToHQWhenContainsQuic) {
+TEST_F(PerformanceResourceTimingTest, TestNoChangeWhenContainsQuic) {
   AtomicString connection_info = "http/1.1";
-  AtomicString alpn_negotiated_protocol = "quic/1spdy/3";
+  AtomicString alpn_negotiated_protocol = "http/2+quic/39";
   EXPECT_EQ(GetNextHopProtocol(alpn_negotiated_protocol, connection_info),
-            "hq");
+            alpn_negotiated_protocol);
 }
 
 TEST_F(PerformanceResourceTimingTest, TestNoChangeWhenOtherwise) {
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/breakpoint.png b/third_party/WebKit/Source/devtools/front_end/Images/breakpoint.png
index 1eaea29..ce145b35 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/breakpoint.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/breakpoint.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/breakpointConditional.png b/third_party/WebKit/Source/devtools/front_end/Images/breakpointConditional.png
index 8a22283..5f7c9a33 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/breakpointConditional.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/breakpointConditional.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/breakpointConditional_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/breakpointConditional_2x.png
index 851adfc..45af335 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/breakpointConditional_2x.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/breakpointConditional_2x.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/breakpoint_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/breakpoint_2x.png
index a227bac..10a35a54 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/breakpoint_2x.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/breakpoint_2x.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/checkboxCheckmark.png b/third_party/WebKit/Source/devtools/front_end/Images/checkboxCheckmark.png
index 3a80164..a054fa9f 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/checkboxCheckmark.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/checkboxCheckmark.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/checkboxCheckmark_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/checkboxCheckmark_2x.png
index 237e4199..15641b32 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/checkboxCheckmark_2x.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/checkboxCheckmark_2x.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/chevrons.png b/third_party/WebKit/Source/devtools/front_end/Images/chevrons.png
index 460aafb..aea9e1b0 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/chevrons.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/chevrons.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/chevrons_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/chevrons_2x.png
index 091217f0..024ddb96 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/chevrons_2x.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/chevrons_2x.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/errorWave.png b/third_party/WebKit/Source/devtools/front_end/Images/errorWave.png
index 32b1b68b..4ae395a 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/errorWave.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/errorWave.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/errorWave_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/errorWave_2x.png
index ffecbf8..c1633dce 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/errorWave_2x.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/errorWave_2x.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/largeIcons.png b/third_party/WebKit/Source/devtools/front_end/Images/largeIcons.png
index bec30c08..a3d5e02 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/largeIcons.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/largeIcons.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/largeIcons_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/largeIcons_2x.png
index 904ab0e9..eb4e74ff 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/largeIcons_2x.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/largeIcons_2x.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/mediumIcons.png b/third_party/WebKit/Source/devtools/front_end/Images/mediumIcons.png
index 58bbd86..187f2c37f 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/mediumIcons.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/mediumIcons.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/mediumIcons_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/mediumIcons_2x.png
index 310543573..310edf2 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/mediumIcons_2x.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/mediumIcons_2x.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/readme.md b/third_party/WebKit/Source/devtools/front_end/Images/readme.md
index 03336dc..1e0503b 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/readme.md
+++ b/third_party/WebKit/Source/devtools/front_end/Images/readme.md
@@ -1,6 +1,6 @@
 ## Adding new icons
 
-1. Use Inkscape 0.48.4. Newer versions are incompatible because of DPI issues.
+1. Use Inkscape 0.92 or newer.
 1. Choose an existing spritesheet, like `largeIcons.svg` to add the icon to
 1. Open that file with Inkscape and import the new SVG into the document
 1. Place in an open spot, and use guides to scale the icon to a good size, relative to other icons
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/securityIcons.png b/third_party/WebKit/Source/devtools/front_end/Images/securityIcons.png
index 5271256..63b3b60 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/securityIcons.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/securityIcons.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/securityIcons_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/securityIcons_2x.png
index d67c76dc..49ef2be 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/securityIcons_2x.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/securityIcons_2x.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/smallIcons.png b/third_party/WebKit/Source/devtools/front_end/Images/smallIcons.png
index baec937a..657cb133 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/smallIcons.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/smallIcons.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/smallIcons_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/smallIcons_2x.png
index 04372bb8..d505749 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/smallIcons_2x.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/smallIcons_2x.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
index 8450c4c5..6bbc7ca 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
+++ b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
@@ -4,9 +4,9 @@
     "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28",
     "checkboxCheckmark.svg": "f039bf85cee42ad5c30ca3bfdce7912a",
     "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45",
-    "smallIcons.svg": "beee6da075d6de8ef77fdf430ee798e5",
+    "smallIcons.svg": "40aefe4606ebba939725954ff9f908ef",
     "mediumIcons.svg": "5305adcb3fa224710ef2efeec01667a8",
     "breakpoint.svg": "69cd92d807259c022791112809b97799",
-    "treeoutlineTriangles.svg": "017d2f89437df0afc6b9cd5ff43735d9",
+    "treeoutlineTriangles.svg": "d6924b8ac4f6158ac1cc2fe16bd0992d",
     "chevrons.svg": "79b4b527771e30b6388ce664077b3409"
 }
\ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/smallIcons.svg b/third_party/WebKit/Source/devtools/front_end/Images/src/smallIcons.svg
index 2139a32..6b36da94 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/src/smallIcons.svg
+++ b/third_party/WebKit/Source/devtools/front_end/Images/src/smallIcons.svg
@@ -12,8 +12,11 @@
    height="110"
    id="svg4185"
    version="1.1"
-   inkscape:version="0.48.4 r9939"
-   sodipodi:docname="smallIcons.svg">
+   inkscape:version="0.92.2pre0 (973e216, 2017-07-25)"
+   sodipodi:docname="smallIcons.svg"
+   inkscape:export-filename="/Users/pfeldman/code/chromium/src/third_party/WebKit/Source/devtools/front_end/Images/smallIcons_2x.png"
+   inkscape:export-xdpi="180"
+   inkscape:export-ydpi="180">
   <metadata
      id="metadata4459">
     <rdf:RDF>
@@ -22,6 +25,7 @@
         <dc:format>image/svg+xml</dc:format>
         <dc:type
            rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
       </cc:Work>
     </rdf:RDF>
   </metadata>
@@ -78,10 +82,10 @@
      inkscape:window-height="1006"
      id="namedview4455"
      showgrid="true"
-     inkscape:zoom="3.7083823"
-     inkscape:cx="29.009401"
-     inkscape:cy="135.34201"
-     inkscape:window-x="980"
+     inkscape:zoom="7.4167646"
+     inkscape:cx="72.154899"
+     inkscape:cy="32.871453"
+     inkscape:window-x="768"
      inkscape:window-y="0"
      inkscape:window-maximized="0"
      inkscape:current-layer="svg4185">
@@ -92,8 +96,10 @@
        visible="true"
        enabled="true"
        snapvisiblegridlinesonly="true"
-       spacingx="10px"
-       spacingy="10px" />
+       spacingx="10"
+       spacingy="10"
+       originx="0"
+       originy="0" />
   </sodipodi:namedview>
   <g
      id="g4187"
@@ -620,16 +626,17 @@
        sodipodi:nodetypes="cccccccc" />
   </g>
   <g
-     transform="translate(80,80)"
+     transform="matrix(0.85714286,0,0,0.85714286,80.142857,80.142857)"
      id="g4419">
     <path
        transform="translate(-20,-98)"
-       d="m 24,106 4,-7 h -8"
+       d="m 25.083333,107.16667 4.083334,-7 H 21"
        id="path4423"
-       inkscape:connector-curvature="0" />
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccc" />
   </g>
   <g
-     transform="translate(0,100)"
+     transform="matrix(0.71428571,0,0,0.875,1.2857143,101)"
      id="g4425">
     <path
        transform="translate(-4,-98)"
@@ -686,120 +693,119 @@
   </g>
   <text
      xml:space="preserve"
-     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none"
      x="3.0508475"
      y="118.38672"
-     id="text5191"
-     sodipodi:linespacing="125%"><tspan
+     id="text5191"><tspan
        sodipodi:role="line"
        id="tspan5193"
        x="3.0508475"
-       y="118.38672">a</tspan></text>
+       y="118.38672"
+       style="font-size:8px;line-height:1.25;font-family:sans-serif">a</tspan></text>
   <text
      xml:space="preserve"
-     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none"
      x="23.050848"
      y="118.38672"
-     id="text5191-1"
-     sodipodi:linespacing="125%"><tspan
+     id="text5191-1"><tspan
        sodipodi:role="line"
        id="tspan5193-7"
        x="23.050848"
-       y="118.38672">b</tspan></text>
+       y="118.38672"
+       style="font-size:8px;line-height:1.25;font-family:sans-serif">b</tspan></text>
   <text
      xml:space="preserve"
-     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none"
      x="43.050846"
      y="118.38672"
-     id="text5191-7"
-     sodipodi:linespacing="125%"><tspan
+     id="text5191-7"><tspan
        sodipodi:role="line"
        id="tspan5193-1"
        x="43.050846"
-       y="118.38672">c</tspan></text>
+       y="118.38672"
+       style="font-size:8px;line-height:1.25;font-family:sans-serif">c</tspan></text>
   <text
      xml:space="preserve"
-     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none"
      x="63.050854"
      y="118.38672"
-     id="text5191-15"
-     sodipodi:linespacing="125%"><tspan
+     id="text5191-15"><tspan
        sodipodi:role="line"
        id="tspan5193-9"
        x="63.050854"
-       y="118.38672">d</tspan></text>
+       y="118.38672"
+       style="font-size:8px;line-height:1.25;font-family:sans-serif">d</tspan></text>
   <text
      xml:space="preserve"
-     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none"
      x="83.05085"
      y="118.38672"
-     id="text5191-77"
-     sodipodi:linespacing="125%"><tspan
+     id="text5191-77"><tspan
        sodipodi:role="line"
        id="tspan5193-6"
        x="83.05085"
-       y="118.38672">e</tspan></text>
+       y="118.38672"
+       style="font-size:8px;line-height:1.25;font-family:sans-serif">e</tspan></text>
   <text
      xml:space="preserve"
-     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none"
      x="-7.0260201"
      y="107.81779"
-     id="text5191-73"
-     sodipodi:linespacing="125%"><tspan
+     id="text5191-73"><tspan
        sodipodi:role="line"
        id="tspan5193-65"
        x="-7.0260201"
-       y="107.81779">1</tspan></text>
+       y="107.81779"
+       style="font-size:8px;line-height:1.25;font-family:sans-serif">1</tspan></text>
   <text
      xml:space="preserve"
-     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none"
      x="-6.8189888"
      y="87.880318"
-     id="text5191-6"
-     sodipodi:linespacing="125%"><tspan
+     id="text5191-6"><tspan
        sodipodi:role="line"
        id="tspan5193-3"
        x="-6.8189888"
-       y="87.880318">2</tspan></text>
+       y="87.880318"
+       style="font-size:8px;line-height:1.25;font-family:sans-serif">2</tspan></text>
   <text
      xml:space="preserve"
-     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none"
      x="-6.7564888"
      y="67.991669"
-     id="text5191-9"
-     sodipodi:linespacing="125%"><tspan
+     id="text5191-9"><tspan
        sodipodi:role="line"
        id="tspan5193-4"
        x="-6.7564888"
-       y="67.991669">3</tspan></text>
+       y="67.991669"
+       style="font-size:8px;line-height:1.25;font-family:sans-serif">3</tspan></text>
   <text
      xml:space="preserve"
-     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none"
      x="-6.9166451"
      y="47.993652"
-     id="text5191-8"
-     sodipodi:linespacing="125%"><tspan
+     id="text5191-8"><tspan
        sodipodi:role="line"
        id="tspan5193-12"
        x="-6.9166451"
-       y="47.993652">4</tspan></text>
+       y="47.993652"
+       style="font-size:8px;line-height:1.25;font-family:sans-serif">4</tspan></text>
   <text
      xml:space="preserve"
-     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none"
      x="-7.1080513"
      y="28.056175"
-     id="text5191-93"
-     sodipodi:linespacing="125%"><tspan
+     id="text5191-93"><tspan
        sodipodi:role="line"
        id="tspan5193-90"
        x="-7.1080513"
-       y="28.056175">5</tspan></text>
+       y="28.056175"
+       style="font-size:8px;line-height:1.25;font-family:sans-serif">5</tspan></text>
   <g
      transform="matrix(1.1320755,0,0,1.1320754,81.603774,102.60377)"
      style="fill:#00bcd4;stroke:#000000;stroke-width:0.30000001"
      id="g3669">
     <circle
-       d="M 5.5,3 C 5.5,4.3807119 4.3807119,5.5 3,5.5 1.6192881,5.5 0.5,4.3807119 0.5,3 0.5,1.6192881 1.6192881,0.5 3,0.5 4.3807119,0.5 5.5,1.6192881 5.5,3 z"
        sodipodi:ry="2.5"
        sodipodi:rx="2.5"
        sodipodi:cy="3"
@@ -816,15 +822,15 @@
      id="path3255" />
   <text
      xml:space="preserve"
-     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none"
      x="-6.6795936"
      y="8"
-     id="text5191-93-3"
-     sodipodi:linespacing="125%"><tspan
+     id="text5191-93-3"><tspan
        sodipodi:role="line"
        id="tspan5193-90-6"
        x="-6.6795936"
-       y="8">6</tspan></text>
+       y="8"
+       style="font-size:8px;line-height:1.25;font-family:sans-serif">6</tspan></text>
   <g
      transform="translate(13.293,-7.4383945)"
      id="g74">
@@ -854,15 +860,15 @@
   </g>
   <text
      xml:space="preserve"
-     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none"
      x="103.73887"
      y="118.48206"
-     id="text5191-77-3"
-     sodipodi:linespacing="125%"><tspan
+     id="text5191-77-3"><tspan
        sodipodi:role="line"
        id="tspan5193-6-6"
        x="103.73887"
-       y="118.48206">f</tspan></text>
+       y="118.48206"
+       style="font-size:8px;line-height:1.25;font-family:sans-serif">f</tspan></text>
   <g
      id="g4443-7"
      transform="translate(100,100)"
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
index 8450c4c5..6bbc7ca 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
+++ b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
@@ -4,9 +4,9 @@
     "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28",
     "checkboxCheckmark.svg": "f039bf85cee42ad5c30ca3bfdce7912a",
     "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45",
-    "smallIcons.svg": "beee6da075d6de8ef77fdf430ee798e5",
+    "smallIcons.svg": "40aefe4606ebba939725954ff9f908ef",
     "mediumIcons.svg": "5305adcb3fa224710ef2efeec01667a8",
     "breakpoint.svg": "69cd92d807259c022791112809b97799",
-    "treeoutlineTriangles.svg": "017d2f89437df0afc6b9cd5ff43735d9",
+    "treeoutlineTriangles.svg": "d6924b8ac4f6158ac1cc2fe16bd0992d",
     "chevrons.svg": "79b4b527771e30b6388ce664077b3409"
 }
\ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/treeoutlineTriangles.svg b/third_party/WebKit/Source/devtools/front_end/Images/src/treeoutlineTriangles.svg
index 6dcbcc5..0ad904c 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/src/treeoutlineTriangles.svg
+++ b/third_party/WebKit/Source/devtools/front_end/Images/src/treeoutlineTriangles.svg
@@ -13,8 +13,11 @@
    height="24"
    id="svg3620"
    version="1.1"
-   inkscape:version="0.48.4 r9939"
-   sodipodi:docname="treeoutlineTriangles.svg">
+   inkscape:version="0.92.2pre0 (973e216, 2017-07-25)"
+   sodipodi:docname="treeoutlineTriangles.svg"
+   inkscape:export-filename="/usr/local/google/code/chromium/src/third_party/WebKit/Source/devtools/front_end/Images/treeoutlineTriangles.png"
+   inkscape:export-xdpi="96"
+   inkscape:export-ydpi="96">
   <defs
      id="defs3622" />
   <sodipodi:namedview
@@ -25,18 +28,18 @@
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
      inkscape:zoom="11.313708"
-     inkscape:cx="11.811861"
+     inkscape:cx="-2.2860811"
      inkscape:cy="13.085725"
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
      showgrid="false"
      showguides="true"
      inkscape:guide-bbox="true"
-     inkscape:window-width="858"
-     inkscape:window-height="521"
-     inkscape:window-x="164"
-     inkscape:window-y="121"
-     inkscape:window-maximized="0" />
+     inkscape:window-width="2560"
+     inkscape:window-height="1539"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1" />
   <metadata
      id="metadata3625">
     <rdf:RDF>
@@ -55,12 +58,14 @@
      id="layer1"
      transform="translate(0,-1028.3622)">
     <path
-       d="m 8,1034.3622 -7,-4 0,8"
+       d="m 7,1034.3622 -5,-3.5 v 7"
        id="path3619"
-       inkscape:connector-curvature="0" />
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccc" />
     <path
-       d="m 20,1038.3622 4,-7 -8,0"
+       d="m 23,1037.3622 0,-6 -6,6"
        id="path3621"
-       inkscape:connector-curvature="0" />
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccc" />
   </g>
 </svg>
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/treeoutlineTriangles.png b/third_party/WebKit/Source/devtools/front_end/Images/treeoutlineTriangles.png
index 71a09d3..e21b065 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/treeoutlineTriangles.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/treeoutlineTriangles.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/treeoutlineTriangles_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/treeoutlineTriangles_2x.png
index 1d8aa0ee..d7f9fcc 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/treeoutlineTriangles_2x.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/treeoutlineTriangles_2x.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/animation/animationTimeline.css b/third_party/WebKit/Source/devtools/front_end/animation/animationTimeline.css
index 7019be3a..0ac40c35 100644
--- a/third_party/WebKit/Source/devtools/front_end/animation/animationTimeline.css
+++ b/third_party/WebKit/Source/devtools/front_end/animation/animationTimeline.css
@@ -304,7 +304,7 @@
 .animation-buffer-preview {
     height: 40px;
     margin: 4px 2px;
-    background-color: #F3F3F3;
+    background-color: var(--toolbar-bg-color);
     border-radius: 2px;
     flex: 1 1;
     padding: 4px;
diff --git a/third_party/WebKit/Source/devtools/front_end/audits2/Audits2StatusView.js b/third_party/WebKit/Source/devtools/front_end/audits2/Audits2StatusView.js
index a48c075..64e2e0d 100644
--- a/third_party/WebKit/Source/devtools/front_end/audits2/Audits2StatusView.js
+++ b/third_party/WebKit/Source/devtools/front_end/audits2/Audits2StatusView.js
@@ -211,10 +211,10 @@
 
 /** @type {!Array.<!RegExp>} */
 Audits2.Audits2StatusView.KnownBugPatterns = [
-  /Parsing problem/,
-  /Read failed/,
-  /Tracing.*already started/,
-  /Unable to load.*page/,
+  /PARSING_PROBLEM/,
+  /DOCUMENT_REQUEST/,
+  /READ_FAILED/,
+  /TRACING_ALREADY_STARTED/,
   /^You must provide a url to the runner/,
   /^You probably have multiple tabs open/,
 ];
diff --git a/third_party/WebKit/Source/devtools/front_end/changes/changesView.css b/third_party/WebKit/Source/devtools/front_end/changes/changesView.css
index 29a66c66..663af21 100644
--- a/third_party/WebKit/Source/devtools/front_end/changes/changesView.css
+++ b/third_party/WebKit/Source/devtools/front_end/changes/changesView.css
@@ -60,6 +60,6 @@
 }
 
 .changes-toolbar {
-    background-color: #f3f3f3;
+    background-color: var(--toolbar-bg-color);
     border-top: 1px solid #dadada;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/data_grid/dataGrid.css b/third_party/WebKit/Source/devtools/front_end/data_grid/dataGrid.css
index 1c9af13..2a6256fb 100644
--- a/third_party/WebKit/Source/devtools/front_end/data_grid/dataGrid.css
+++ b/third_party/WebKit/Source/devtools/front_end/data_grid/dataGrid.css
@@ -110,7 +110,7 @@
 
 .data-grid th {
     text-align: left;
-    background-color: #f3f3f3;
+    background-color: var(--toolbar-bg-color);
     border-bottom: 1px solid #aaa;
     font-weight: normal;
     vertical-align: middle;
diff --git a/third_party/WebKit/Source/devtools/front_end/devices/devicesView.css b/third_party/WebKit/Source/devtools/front_end/devices/devicesView.css
index e94b5169..6836381 100644
--- a/third_party/WebKit/Source/devtools/front_end/devices/devicesView.css
+++ b/third_party/WebKit/Source/devtools/front_end/devices/devicesView.css
@@ -69,7 +69,7 @@
 
 .devices-footer {
     border-top: 1px solid #cdcdcd;
-    background-color: #f3f3f3;
+    background-color: var(--toolbar-bg-color);
     flex: none;
     padding: 3px 10px;
     overflow: hidden;
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsBreadcrumbs.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsBreadcrumbs.js
index 6d2b609..deb7e9ae 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsBreadcrumbs.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsBreadcrumbs.js
@@ -105,7 +105,7 @@
       case Node.COMMENT_NODE:
         return '<!-->';
       case Node.DOCUMENT_TYPE_NODE:
-        return '<!DOCTYPE>';
+        return '<!doctype>';
       case Node.DOCUMENT_FRAGMENT_NODE:
         return domNode.shadowRootType() ? '#shadow-root' : domNode.nodeNameInCorrectCase();
       default:
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
index a01a52cf..570f3b12 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
@@ -258,8 +258,6 @@
    * @override
    */
   willHide() {
-    UI.context.setFlavor(Elements.ElementsPanel, null);
-
     SDK.OverlayModel.hideDOMNodeHighlight();
     for (let i = 0; i < this._treeOutlines.length; ++i) {
       const treeOutline = this._treeOutlines[i];
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
index fd7d89e..69483a6 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
@@ -1510,7 +1510,7 @@
 
       case Node.DOCUMENT_TYPE_NODE:
         const docTypeElement = titleDOM.createChild('span', 'webkit-html-doctype');
-        docTypeElement.createTextChild('<!DOCTYPE ' + node.nodeName());
+        docTypeElement.createTextChild('<!doctype ' + node.nodeName());
         if (node.publicId) {
           docTypeElement.createTextChild(' PUBLIC "' + node.publicId + '"');
           if (node.systemId)
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/breadcrumbs.css b/third_party/WebKit/Source/devtools/front_end/elements/breadcrumbs.css
index 53a516d..f2fa211 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/breadcrumbs.css
+++ b/third_party/WebKit/Source/devtools/front_end/elements/breadcrumbs.css
@@ -32,12 +32,14 @@
     display: none;
 }
 
-.crumbs .crumb.selected, .crumbs .crumb.selected:hover {
-    background-color: rgb(56, 121, 217);
-    color: white;
-    text-shadow: rgba(255, 255, 255, 0.5) 0 0 0;
+.crumb.selected, .crumb:hover {
+    background-color: var(--toolbar-hover-bg-color);
 }
 
-.crumbs .crumb:hover {
-    background-color: rgb(216, 216, 216);
+.crumb:not(.selected) .node-label-name {
+    color: var(--dom-tag-name-color);
+}
+
+.crumb:not(.selected) .node-label-class {
+    color: var(--dom-attribute-name-color);
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/classesPaneWidget.css b/third_party/WebKit/Source/devtools/front_end/elements/classesPaneWidget.css
index 66e35443..ee810fe 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/classesPaneWidget.css
+++ b/third_party/WebKit/Source/devtools/front_end/elements/classesPaneWidget.css
@@ -5,7 +5,7 @@
  */
 
 .styles-element-classes-pane {
-    background-color: #f3f3f3;
+    background-color: var(--toolbar-bg-color);
     border-bottom: 1px solid rgb(189, 189, 189);
     padding: 6px 2px 2px;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/elementStatePaneWidget.css b/third_party/WebKit/Source/devtools/front_end/elements/elementStatePaneWidget.css
index 8f782755..e018179 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/elementStatePaneWidget.css
+++ b/third_party/WebKit/Source/devtools/front_end/elements/elementStatePaneWidget.css
@@ -7,7 +7,7 @@
 .styles-element-state-pane {
     overflow: hidden;
     padding-left: 2px;
-    background-color: #f3f3f3;
+    background-color: var(--toolbar-bg-color);
     border-bottom: 1px solid rgb(189, 189, 189);
     margin-top: 0;
     padding-bottom: 2px;
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css b/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css
index 89cca88..969c115 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css
+++ b/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css
@@ -17,7 +17,8 @@
     margin-left: -2px;
     word-wrap: break-word;
     position: relative;
-    min-height: 14px;
+    min-height: 15px;
+    line-height: 15px;
 }
 
 .elements-disclosure li.parent {
@@ -63,7 +64,7 @@
 
 .elements-disclosure li.parent::before {
     -webkit-mask-position: 0 0;
-    background-color: rgb(110, 110, 110);
+    background-color: #727272;
 }
 
 .elements-disclosure li .selection {
@@ -85,7 +86,7 @@
 
 .elements-disclosure li.selected .selection {
     display: block;
-    background-color: #dadada;
+    background-color: var(--selection-inactive-bg-color);
 }
 
 .elements-disclosure ol {
@@ -129,7 +130,7 @@
 }
 
 .elements-disclosure ol li.selected:focus .selection {
-    background-color: rgb(56, 121, 217);
+    background-color: var(--selection-bg-color);
 }
 
 .elements-tree-outline ol.shadow-root-depth-4 {
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/stylesSidebarPane.css b/third_party/WebKit/Source/devtools/front_end/elements/stylesSidebarPane.css
index 929e436..3112fc0 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/stylesSidebarPane.css
+++ b/third_party/WebKit/Source/devtools/front_end/elements/stylesSidebarPane.css
@@ -21,10 +21,6 @@
     border-bottom: none;
 }
 
-.styles-pane .sidebar-separator {
-    border-top: 0 none;
-}
-
 .styles-section.read-only {
     background-color: #eee;
 }
@@ -183,15 +179,14 @@
 }
 
 .sidebar-separator {
-    background-color: #ddd;
+    background-color: var(--toolbar-bg-color);
     padding: 0 5px;
-    border-top: 1px solid #ccc;
-    border-bottom: 1px solid #ccc;
+    border-bottom: 1px solid #eee;
     color: rgb(50, 50, 50);
     white-space: nowrap;
     text-overflow: ellipsis;
     overflow: hidden;
-    line-height: 16px;
+    line-height: 22px;
 }
 
 .sidebar-separator > span.monospace {
diff --git a/third_party/WebKit/Source/devtools/front_end/help/releaseNote.css b/third_party/WebKit/Source/devtools/front_end/help/releaseNote.css
index fd9cb4b..6079e64 100644
--- a/third_party/WebKit/Source/devtools/front_end/help/releaseNote.css
+++ b/third_party/WebKit/Source/devtools/front_end/help/releaseNote.css
@@ -19,8 +19,8 @@
     padding: 0 15px;
     font-size: 16px;
     flex: none;
-    background-color:  #3367d6;
-    box-shadow: 0 2px 4px rgba(0,0,0,.28);
+    background-color: #9e9e9e;
+    box-shadow: 0 1px 1px rgba(0,0,0,.28);
     overflow: hidden;
     white-space: nowrap;
     text-overflow: ellipsis;
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 c8c4afe..81885d1 100644
--- a/third_party/WebKit/Source/devtools/front_end/main/Main.js
+++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -130,6 +130,7 @@
     Runtime.experiments.register('timelineShowAllProcesses', 'Timeline: show all processes', true);
     Runtime.experiments.register('timelineTracingJSProfile', 'Timeline: tracing based JS profiler', true);
     Runtime.experiments.register('timelineV8RuntimeCallStats', 'Timeline: V8 Runtime Call Stats on Timeline', true);
+    Runtime.experiments.register('uiExplorations', 'UI explorations', true);
 
     Runtime.experiments.cleanUpStaleExperiments();
 
@@ -143,7 +144,7 @@
     }
 
     Runtime.experiments.setDefaultExperiments(
-        ['colorContrastRatio', 'stepIntoAsync', 'timelineKeepHistory', 'oopifInlineDOM']);
+        ['colorContrastRatio', 'stepIntoAsync', 'timelineKeepHistory', 'oopifInlineDOM', 'uiExplorations']);
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/profilesPanel.css b/third_party/WebKit/Source/devtools/front_end/profiler/profilesPanel.css
index ee61997..5fa65a3 100644
--- a/third_party/WebKit/Source/devtools/front_end/profiler/profilesPanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/profiler/profilesPanel.css
@@ -65,7 +65,7 @@
 }
 
 .profiles-toolbar {
-    background-color: #f3f3f3;
+    background-color: var(--toolbar-bg-color);
     border-bottom: 1px solid #ccc;
     flex-shrink: 0;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/resourcesPanel.css b/third_party/WebKit/Source/devtools/front_end/resources/resourcesPanel.css
index 1502bcd..cf05663 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/resourcesPanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/resources/resourcesPanel.css
@@ -29,12 +29,12 @@
 
 .resources-toolbar {
     border-top: 1px solid #ccc;
-    background-color: #f3f3f3;
+    background-color: var(--toolbar-bg-color);
 }
 
 .top-resources-toolbar {
     border-bottom: 1px solid #ccc;
-    background-color: #f3f3f3;
+    background-color: var(--toolbar-bg-color);
 }
 
 li.selected .base-storage-tree-element-subtitle {
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 c0b1bae..03a8f32 100644
--- a/third_party/WebKit/Source/devtools/front_end/security/mainView.css
+++ b/third_party/WebKit/Source/devtools/front_end/security/mainView.css
@@ -7,7 +7,7 @@
     -webkit-user-select: text;
     overflow-x: hidden;
     overflow-y: auto;
-    background-color: #fafafa;
+    background-color: var(--toolbar-bg-color);
 }
 
 .security-main-view > div {
diff --git a/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js b/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js
index b82319f..2f8d2c9 100644
--- a/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js
+++ b/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js
@@ -50,7 +50,7 @@
     const tabbedPane = this._tabbedLocation.tabbedPane();
     tabbedPane.leftToolbar().appendToolbarItem(new UI.ToolbarItem(settingsLabelElement));
     tabbedPane.setShrinkableTabs(false);
-    tabbedPane.setVerticalTabLayout(true);
+    tabbedPane.makeVerticalTabLayout();
     const shortcutsView = new UI.SimpleView(Common.UIString('Shortcuts'));
     UI.shortcutsScreen.createShortcutsTabView().show(shortcutsView.element);
     this._tabbedLocation.appendView(shortcutsView);
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/sourcesPanel.css b/third_party/WebKit/Source/devtools/front_end/sources/sourcesPanel.css
index 851ee52..edd4d013 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/sourcesPanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/sources/sourcesPanel.css
@@ -31,7 +31,7 @@
     position: absolute;
     top: 0;
     width: 100%;
-    background-color: #f3f3f3;
+    background-color: var(--toolbar-bg-color);
     border-bottom: 1px solid #ccc;
     overflow: hidden;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/sourcesView.css b/third_party/WebKit/Source/devtools/front_end/sources/sourcesView.css
index 65567f8..e4095947 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/sourcesView.css
+++ b/third_party/WebKit/Source/devtools/front_end/sources/sourcesView.css
@@ -36,7 +36,7 @@
 #sources-panel-sources-view .sources-toolbar {
     display: flex;
     flex: 0 0 27px;
-    background-color: #f3f3f3;
+    background-color: var(--toolbar-bg-color);
     border-top: 1px solid #dadada;
     overflow: hidden;
     z-index: 0;
diff --git a/third_party/WebKit/Source/devtools/front_end/test_runner/TestRunner.js b/third_party/WebKit/Source/devtools/front_end/test_runner/TestRunner.js
index afc8221..3edf86f 100644
--- a/third_party/WebKit/Source/devtools/front_end/test_runner/TestRunner.js
+++ b/third_party/WebKit/Source/devtools/front_end/test_runner/TestRunner.js
@@ -515,7 +515,7 @@
 TestRunner.loadHTML = function(html) {
   if (!html.includes('<base')) {
     // <!DOCTYPE...> tag needs to be first
-    const doctypeRegex = /(<!DOCTYPE.*?>)/;
+    const doctypeRegex = /(<!DOCTYPE.*?>)/i;
     const baseTag = `<base href="${TestRunner.url()}">`;
     if (html.match(doctypeRegex))
       html = html.replace(doctypeRegex, '$1' + baseTag);
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css b/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
index e4d4659..aabfd3f 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
@@ -327,7 +327,7 @@
     flex: auto;
     overflow: auto;
     position: relative;
-    background-color: #f3f3f3;
+    background-color: var(--toolbar-bg-color);
     -webkit-user-select: text;
 }
 
@@ -439,7 +439,7 @@
 
 .timeline-flamechart-resizer {
     flex: 8px 0 0;
-    background-color: #f3f3f3;
+    background-color: var(--toolbar-bg-color);
     border: 1px #a3a3a3;
     border-style: solid none;
     display: flex;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/InspectorView.js b/third_party/WebKit/Source/devtools/front_end/ui/InspectorView.js
index 8644627f..89c6871 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/InspectorView.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/InspectorView.js
@@ -64,7 +64,7 @@
 
     this._tabbedPane = this._tabbedLocation.tabbedPane();
     this._tabbedPane.registerRequiredCSS('ui/inspectorViewTabbedPane.css');
-    this._tabbedPane.setTabSlider(true);
+    this._tabbedPane.makeTabSlider();
     this._tabbedPane.addEventListener(UI.TabbedPane.Events.TabSelected, this._tabSelected, this);
     this._tabbedPane.setAccessibleName(Common.UIString('Panels'));
 
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/TabbedPane.js b/third_party/WebKit/Source/devtools/front_end/ui/TabbedPane.js
index 85d5b04f..4d1b3c3 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/TabbedPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/TabbedPane.js
@@ -55,6 +55,8 @@
     this._tabsById = new Map();
     this._currentTabLocked = false;
     this._autoSelectFirstItemOnShow = true;
+    if (Runtime.experiments.isEnabled('uiExplorations'))
+      this.makeTabSlider();
 
     this._dropDownButton = this._createDropDownButton();
     UI.zoomManager.addEventListener(UI.ZoomManager.Events.ZoomChanged, this._zoomChanged, this);
@@ -133,11 +135,9 @@
     this._shrinkableTabs = shrinkableTabs;
   }
 
-  /**
-   * @param {boolean} verticalTabLayout
-   */
-  setVerticalTabLayout(verticalTabLayout) {
-    this._verticalTabLayout = verticalTabLayout;
+  makeVerticalTabLayout() {
+    this._verticalTabLayout = true;
+    this._setTabSlider(false);
     this.contentElement.classList.add('vertical-tab-layout');
     this.invalidateConstraints();
   }
@@ -468,13 +468,19 @@
       this.selectTab(effectiveTab.id);
   }
 
+  makeTabSlider() {
+    if (this._verticalTabLayout)
+      return;
+    this._setTabSlider(true);
+  }
+
   /**
    * @param {boolean} enable
    */
-  setTabSlider(enable) {
+  _setTabSlider(enable) {
     this._sliderEnabled = enable;
     this._tabSlider.classList.toggle('enabled', enable);
-    this._headerElement.classList.add('tabbed-pane-no-tab-borders');
+    this._headerElement.classList.toggle('tabbed-pane-no-tab-borders', enable);
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/filter.css b/third_party/WebKit/Source/devtools/front_end/ui/filter.css
index 3610a8c..d0fad0c4 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/filter.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/filter.css
@@ -29,7 +29,7 @@
  */
 
 .filter-bar {
-    background-color: #f3f3f3;
+    background-color: var(--toolbar-bg-color);
     flex: none;
     flex-wrap: wrap;
     align-items: center;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/inlineButton.css b/third_party/WebKit/Source/devtools/front_end/ui/inlineButton.css
index 53622ea9..d6d6c51 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/inlineButton.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/inlineButton.css
@@ -10,7 +10,7 @@
   position: relative;
   top: 7px;
   margin: 2px;
-  background-color: #f3f3f3;
+  background-color: var(--toolbar-bg-color);
 }
 
 :host > * {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css b/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css
index d4ca4bc..7a935d2 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css
@@ -46,6 +46,13 @@
     box-sizing: border-box;
 }
 
+:root {
+  --toolbar-bg-color: #fafafa;
+  --toolbar-hover-bg-color: #eaeaea;
+  --selection-bg-color: #3879d9;
+  --selection-inactive-bg-color: #dadada;
+}
+
 :focus {
     outline-width: 0;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/inspectorStyle.css b/third_party/WebKit/Source/devtools/front_end/ui/inspectorStyle.css
index 681f319c..d6cbdce 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/inspectorStyle.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/inspectorStyle.css
@@ -74,7 +74,7 @@
 
 .panel-sidebar {
     overflow-x: hidden;
-    background-color: #f3f3f3;
+    background-color: var(--toolbar-bg-color);
 }
 
 iframe.extension {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/inspectorSyntaxHighlight.css b/third_party/WebKit/Source/devtools/front_end/ui/inspectorSyntaxHighlight.css
index c9c1678..117ac18 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/inspectorSyntaxHighlight.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/inspectorSyntaxHighlight.css
@@ -56,6 +56,11 @@
 .cm-xml-attribute {color: rgb(153, 69, 0);}
 .cm-xml-link {color: #00e;}
 
+:root {
+    --dom-tag-name-color: rgb(136, 18, 128);
+    --dom-attribute-name-color: rgb(153, 69, 0);
+}
+
 .webkit-html-comment {
     /* Keep this in sync with view-source.css (.webkit-html-comment) */
     color: rgb(35, 110, 37);
@@ -67,7 +72,7 @@
 
 .webkit-html-tag-name, .webkit-html-close-tag-name {
     /* Keep this in sync with view-source.css (.webkit-html-tag) */
-    color: rgb(136, 18, 128);
+    color: var(--dom-tag-name-color);
 }
 
 .webkit-html-pseudo-element {
@@ -97,7 +102,7 @@
 
 .webkit-html-attribute-name {
     /* Keep this in sync with view-source.css (.webkit-html-attribute-name) */
-    color: rgb(153, 69, 0);
+    color: var(--dom-attribute-name-color);
     unicode-bidi: -webkit-isolate;
 }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/inspectorViewTabbedPane.css b/third_party/WebKit/Source/devtools/front_end/ui/inspectorViewTabbedPane.css
index 2fa4b1f..c461ce2a 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/inspectorViewTabbedPane.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/inspectorViewTabbedPane.css
@@ -13,10 +13,6 @@
     border-right: 2px solid transparent;
 }
 
-.tabbed-pane-header-tab:not(.dragging):not(:hover) {
-    background: #f3f3f3;
-}
-
 .tabbed-pane-header-tab.selected {
     border-width: 0 2px 0 2px;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/tabbedPane.css b/third_party/WebKit/Source/devtools/front_end/ui/tabbedPane.css
index d35d7b02..54307ed 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/tabbedPane.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/tabbedPane.css
@@ -79,7 +79,7 @@
     border-bottom: 1px solid #ccc;
     overflow: visible;
     width: 100%;
-    background-color: #f3f3f3;
+    background-color: var(--toolbar-bg-color);
 }
 
 .tabbed-pane-header-contents {
@@ -119,7 +119,7 @@
 .tabbed-pane-header-tab.selected:hover,
 .tabbed-pane-shadow .tabbed-pane-header-tab[data-keyboard-focus="true"]:focus {
     color: #333;
-    background-color: #e5e5e5;
+    background-color: var(--toolbar-hover-bg-color);
 }
 
 .tabbed-pane-header-tab-title {
@@ -134,11 +134,14 @@
 .tabbed-pane-header-tab.selected {
     border: 1px solid #ccc;
     border-bottom: none;
-    color: #333;
+}
+
+
+.tabbed-pane-no-tab-borders .tabbed-pane-header-tab.selected {
+    color: var(--selection-bg-color);
 }
 
 .tabbed-pane-header-tab.selected {
-    background-color: white;
     border-top-color: #ccc;
 }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/textButton.css b/third_party/WebKit/Source/devtools/front_end/ui/textButton.css
index 2d40651..001189a1 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/textButton.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/textButton.css
@@ -21,7 +21,7 @@
 :host(:not(:disabled):focus),
 :host(:not(:disabled):hover),
 :host(:not(:disabled):active) {
-    background-color: #fafafa;
+    background-color: var(--toolbar-bg-color);
     box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
     cursor: pointer;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css b/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css
index fcc1b6c..c8f3c7c 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css
@@ -119,7 +119,7 @@
 }
 
 .toolbar-toggled-gray:not(.toolbar-render-as-links) .toolbar-button:not(.toolbar-has-glyph):not(.toolbar-has-dropdown):not(.largeicon-menu):hover {
-    background-color: #f3f3f3;
+    background-color: var(--toolbar-bg-color);
 }
 
 .toolbar-glyph {
@@ -176,7 +176,7 @@
 }
 
 .toolbar-toggled-gray .toolbar-button.toolbar-state-on {
-    background-color: #f3f3f3 !important;
+    background-color: var(--toolbar-bg-color) !important;
 }
 
 .toolbar-button.toolbar-state-on.toolbar-toggle-with-red-color .toolbar-glyph,
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.css b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.css
index 8156fe6..b25f12ec 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.css
@@ -37,7 +37,7 @@
 
 .tree-outline li.selected .selection {
     display: block;
-    background-color: #ddd;
+    background-color: var(--selection-inactive-bg-color);
 }
 
 .tree-outline li.in-clipboard .highlight {
@@ -47,11 +47,12 @@
 .tree-outline li.elements-drag-over .selection {
     display: block;
     margin-top: -2px;
-    border-top: 2px solid rgb(56, 121, 217);
+    border-top: 2px solid;
+    border-top-color: var(--selection-bg-color);
 }
 
 ol.tree-outline li.selected:focus .selection {
-    background-color: rgb(56, 121, 217);
+    background-color: var(--selection-bg-color);
 }
 
 ol.tree-outline li.parent.selected:focus::before {
@@ -125,7 +126,7 @@
 
 .tree-outline li::before {
     -webkit-mask-position: 0 0;
-    background-color: rgb(110, 110, 110);
+    background-color: #727272;
 }
 
 .tree-outline li.parent.expanded::before {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/viewContainers.css b/third_party/WebKit/Source/devtools/front_end/ui/viewContainers.css
index aa3e546..41ce417 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/viewContainers.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/viewContainers.css
@@ -34,7 +34,7 @@
 .expandable-view-title {
     display: flex;
     align-items: center;
-    background-color: #f3f3f3;
+    background-color: var(--toolbar-bg-color);
     height: 22px;
     padding: 0 5px;
     border-top: 1px solid #dadada;
diff --git a/third_party/WebKit/Source/devtools/scripts/convert_svg_images_to_png.py b/third_party/WebKit/Source/devtools/scripts/convert_svg_images_to_png.py
index 9bafbbb..2f0a0a49 100755
--- a/third_party/WebKit/Source/devtools/scripts/convert_svg_images_to_png.py
+++ b/third_party/WebKit/Source/devtools/scripts/convert_svg_images_to_png.py
@@ -77,8 +77,8 @@
 for file_name in svg_file_names:
     name = re.sub(".svg$", "", file_name)
     name2x = name + "_2x"
-    processes[name] = convert_svg_to_png(name, name, 90)
-    processes[name2x] = convert_svg_to_png(name, name2x, 180)
+    processes[name] = convert_svg_to_png(name, name, 96)
+    processes[name2x] = convert_svg_to_png(name, name2x, 192)
 
 for file_name, proc in processes.items():
     (convert_out, _) = proc.communicate()
diff --git a/third_party/WebKit/Source/modules/permissions/Permissions.cpp b/third_party/WebKit/Source/modules/permissions/Permissions.cpp
index 928d6e6b..d72a12c 100644
--- a/third_party/WebKit/Source/modules/permissions/Permissions.cpp
+++ b/third_party/WebKit/Source/modules/permissions/Permissions.cpp
@@ -127,11 +127,6 @@
     return CreatePermissionDescriptor(PermissionName::ACCESSIBILITY_EVENTS);
   }
   if (name == "clipboard-read" || name == "clipboard-write") {
-    if (!RuntimeEnabledFeatures::AsyncClipboardEnabled()) {
-      exception_state.ThrowTypeError("Async Clipboard flag is not enabled.");
-      return nullptr;
-    }
-
     PermissionName permission_name = PermissionName::CLIPBOARD_READ;
     if (name == "clipboard-write")
       permission_name = PermissionName::CLIPBOARD_WRITE;
diff --git a/third_party/WebKit/Source/modules/vr/VRDisplay.idl b/third_party/WebKit/Source/modules/vr/VRDisplay.idl
index da23e37..026d6ce 100644
--- a/third_party/WebKit/Source/modules/vr/VRDisplay.idl
+++ b/third_party/WebKit/Source/modules/vr/VRDisplay.idl
@@ -25,7 +25,7 @@
 
     readonly attribute VRStageParameters stageParameters;
 
-    boolean getFrameData(VRFrameData frameData);
+    [MeasureAs=VRDisplayGetFrameData] boolean getFrameData(VRFrameData frameData);
 
     attribute double depthNear;
     attribute double depthFar;
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScope.cpp b/third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScope.cpp
index e9bf8844..8544ebc 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScope.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioWorkletGlobalScope.cpp
@@ -215,21 +215,26 @@
   // 1st arg of JS callback: inputs
   v8::Local<v8::Array> inputs = v8::Array::New(isolate, input_buses->size());
   uint32_t input_bus_index = 0;
-  for (const auto& input_bus : *input_buses) {
-    v8::Local<v8::Array> channels =
-        v8::Array::New(isolate, input_bus->NumberOfChannels());
+  for (const auto input_bus : *input_buses) {
+    // If |input_bus| is null, then the input is not connected, and
+    // the array for that input should have one channel and a length
+    // of 0.
+    unsigned number_of_channels = input_bus ? input_bus->NumberOfChannels() : 1;
+    size_t bus_length = input_bus ? input_bus->length() : 0;
+
+    v8::Local<v8::Array> channels = v8::Array::New(isolate, number_of_channels);
     bool success;
     if (!inputs
              ->CreateDataProperty(current_context, input_bus_index++, channels)
              .To(&success)) {
       return false;
     }
-    for (uint32_t channel_index = 0;
-         channel_index < input_bus->NumberOfChannels(); ++channel_index) {
+    for (uint32_t channel_index = 0; channel_index < number_of_channels;
+         ++channel_index) {
       v8::Local<v8::ArrayBuffer> array_buffer =
-          v8::ArrayBuffer::New(isolate, input_bus->length() * sizeof(float));
+          v8::ArrayBuffer::New(isolate, bus_length * sizeof(float));
       v8::Local<v8::Float32Array> float32_array =
-          v8::Float32Array::New(array_buffer, 0, input_bus->length());
+          v8::Float32Array::New(array_buffer, 0, bus_length);
       if (!channels
                ->CreateDataProperty(current_context, channel_index,
                                     float32_array)
@@ -237,8 +242,10 @@
         return false;
       }
       const v8::ArrayBuffer::Contents& contents = array_buffer->GetContents();
-      memcpy(contents.Data(), input_bus->Channel(channel_index)->Data(),
-             input_bus->length() * sizeof(float));
+      if (input_bus) {
+        memcpy(contents.Data(), input_bus->Channel(channel_index)->Data(),
+               bus_length * sizeof(float));
+      }
     }
   }
 
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioWorkletNode.cpp b/third_party/WebKit/Source/modules/webaudio/AudioWorkletNode.cpp
index 2da78f2..f08b4e8 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioWorkletNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioWorkletNode.cpp
@@ -81,12 +81,16 @@
 
   // Render and update the node state when the processor is ready with no error.
   if (processor_ && !processor_->hasErrorOccured()) {
-    Vector<AudioBus*> inputBuses;
-    Vector<AudioBus*> outputBuses;
-    for (unsigned i = 0; i < NumberOfInputs(); ++i)
-      inputBuses.push_back(Input(i).Bus());
+    Vector<AudioBus*> input_buses;
+    Vector<AudioBus*> output_buses;
+    for (unsigned i = 0; i < NumberOfInputs(); ++i) {
+      // If the input is not connected, inform the processor of that
+      // fact by setting the bus to null.
+      AudioBus* bus = Input(i).IsConnected() ? Input(i).Bus() : nullptr;
+      input_buses.push_back(bus);
+    }
     for (unsigned i = 0; i < NumberOfOutputs(); ++i)
-      outputBuses.push_back(Output(i).Bus());
+      output_buses.push_back(Output(i).Bus());
 
     for (const auto& param_name : param_value_map_.Keys()) {
       const auto param_handler = param_handler_map_.at(param_name);
@@ -103,7 +107,7 @@
 
     // Run the render code and check the state of processor. Finish the
     // processor if needed.
-    if (!processor_->Process(&inputBuses, &outputBuses, &param_value_map_) ||
+    if (!processor_->Process(&input_buses, &output_buses, &param_value_map_) ||
         processor_->hasErrorOccured()) {
       FinishProcessorOnRenderThread();
     }
diff --git a/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
index 739c96a3..3f8cc8a5 100644
--- a/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp
@@ -817,16 +817,22 @@
       }
     }
 
-    // Copy over the surviving active nodes.
-    HeapVector<Member<AudioNode>> actives;
-    CHECK_GE(active_source_nodes_.size(), remove_count);
-    actives.ReserveInitialCapacity(active_source_nodes_.size() - remove_count);
-    for (unsigned i = 0; i < removables.size(); ++i) {
-      if (!removables[i])
-        actives.push_back(active_source_nodes_[i]);
+    // Copy over the surviving active nodes after removal.
+    if (remove_count > 0) {
+      HeapVector<Member<AudioNode>> actives;
+      DCHECK_GE(active_source_nodes_.size(), remove_count);
+      size_t initial_capacity =
+          std::min(active_source_nodes_.size() - remove_count,
+                   active_source_nodes_.size());
+      actives.ReserveInitialCapacity(initial_capacity);
+      for (unsigned i = 0; i < removables.size(); ++i) {
+        if (!removables[i])
+          actives.push_back(active_source_nodes_[i]);
+      }
+      active_source_nodes_.swap(actives);
     }
-    active_source_nodes_.swap(actives);
   }
+
   has_posted_cleanup_task_ = false;
 }
 
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index 78b4a8c..b296877 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -1742,7 +1742,7 @@
 
   deps = [
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//third_party/WebKit/Source/platform/blob:test_support",
     "//third_party/WebKit/Source/platform/loader:test_support",
     "//third_party/WebKit/Source/platform/network:test_support",
@@ -1966,7 +1966,7 @@
     "//cc/blink",
     "//device/base/synchronization",
     "//mojo/common:test_common_custom_types_blink",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//mojo/public/cpp/bindings/tests:for_blink_tests",
     "//mojo/public/cpp/test_support:test_utils",
     "//mojo/public/interfaces/bindings/tests:test_interfaces_blink",
@@ -2009,7 +2009,7 @@
   deps = [
     ":platform",
     "//build/config:exe_and_shlib_deps",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//third_party/WebKit/Source/platform/wtf",
   ]
 
diff --git a/third_party/WebKit/Source/platform/graphics/VideoFrameResourceProvider.cpp b/third_party/WebKit/Source/platform/graphics/VideoFrameResourceProvider.cpp
index 146d2a2..c9717f93 100644
--- a/third_party/WebKit/Source/platform/graphics/VideoFrameResourceProvider.cpp
+++ b/third_party/WebKit/Source/platform/graphics/VideoFrameResourceProvider.cpp
@@ -35,7 +35,6 @@
 
 VideoFrameResourceProvider::~VideoFrameResourceProvider() {
   if (context_provider_) {
-    viz::ContextProvider::ScopedContextLock lock(context_provider_);
     resource_updater_ = nullptr;
     resource_provider_ = nullptr;
   }
@@ -53,7 +52,6 @@
   CHECK(media_context_provider);
   context_provider_ = media_context_provider;
 
-  viz::ContextProvider::ScopedContextLock lock(context_provider_);
   resource_provider_ = std::make_unique<cc::LayerTreeResourceProvider>(
       media_context_provider, shared_bitmap_manager_,
       gpu_memory_buffer_manager_, true, settings_.resource_settings);
@@ -89,7 +87,6 @@
       break;
   }
 
-  viz::ContextProvider::ScopedContextLock lock(context_provider_);
   resource_updater_->ObtainFrameResources(frame);
   // TODO(lethalantidote) : update with true value;
   bool contents_opaque = true;
@@ -110,20 +107,17 @@
 }
 
 void VideoFrameResourceProvider::ReleaseFrameResources() {
-  viz::ContextProvider::ScopedContextLock lock(context_provider_);
   resource_updater_->ReleaseFrameResources();
 }
 
 void VideoFrameResourceProvider::PrepareSendToParent(
     const cc::LayerTreeResourceProvider::ResourceIdArray& resource_ids,
     std::vector<viz::TransferableResource>* transferable_resources) {
-  viz::ContextProvider::ScopedContextLock lock(context_provider_);
   resource_provider_->PrepareSendToParent(resource_ids, transferable_resources);
 }
 
 void VideoFrameResourceProvider::ReceiveReturnsFromParent(
     const std::vector<viz::ReturnedResource>& transferable_resources) {
-  viz::ContextProvider::ScopedContextLock lock(context_provider_);
   resource_provider_->ReceiveReturnsFromParent(transferable_resources);
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/VideoFrameResourceProvider.h b/third_party/WebKit/Source/platform/graphics/VideoFrameResourceProvider.h
index ea876c0..233ccc2 100644
--- a/third_party/WebKit/Source/platform/graphics/VideoFrameResourceProvider.h
+++ b/third_party/WebKit/Source/platform/graphics/VideoFrameResourceProvider.h
@@ -27,6 +27,9 @@
 // Placeholder class, to be implemented in full in later CL.
 // VideoFrameResourceProvider obtains required GPU resources for the video
 // frame.
+// VideoFrameResourceProvider methods are currently called on the media thread.
+// TODO(lethalantidote): Move the usage of this class off media thread
+// https://crbug.com/753605
 class PLATFORM_EXPORT VideoFrameResourceProvider {
  public:
   explicit VideoFrameResourceProvider(WebContextProviderCallback,
diff --git a/third_party/WebKit/Source/platform/graphics/VideoFrameSubmitterTest.cpp b/third_party/WebKit/Source/platform/graphics/VideoFrameSubmitterTest.cpp
index c2274ff2..53b0a6f 100644
--- a/third_party/WebKit/Source/platform/graphics/VideoFrameSubmitterTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/VideoFrameSubmitterTest.cpp
@@ -127,7 +127,7 @@
       : now_src_(new base::SimpleTestTickClock()),
         begin_frame_source_(new viz::FakeExternalBeginFrameSource(0.f, false)),
         provider_(new StrictMock<MockVideoFrameProvider>()),
-        context_provider_(viz::TestContextProvider::CreateWorker()) {
+        context_provider_(viz::TestContextProvider::Create()) {
     context_provider_->BindToCurrentThread();
   }
 
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/XRWebGLDrawingBuffer.cpp b/third_party/WebKit/Source/platform/graphics/gpu/XRWebGLDrawingBuffer.cpp
index 1380980..3b87c25b2 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/XRWebGLDrawingBuffer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/gpu/XRWebGLDrawingBuffer.cpp
@@ -121,6 +121,8 @@
   std::unique_ptr<Extensions3DUtil> extensions_util =
       Extensions3DUtil::Create(gl);
 
+  gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_);
+
   // Check context capabilities
   int max_sample_count = 0;
   anti_aliasing_mode_ = kNone;
@@ -161,10 +163,27 @@
   return drawing_buffer_->destroyed();
 }
 
-void XRWebGLDrawingBuffer::Resize(const IntSize& new_size) {
+IntSize XRWebGLDrawingBuffer::AdjustSize(const IntSize& new_size) {
   // Ensure we always have at least a 1x1 buffer
-  IntSize adjusted_size(std::max(1, new_size.Width()),
-                        std::max(1, new_size.Height()));
+  float width = std::max(1, new_size.Width());
+  float height = std::max(1, new_size.Height());
+
+  float adjusted_scale =
+      std::min(static_cast<float>(max_texture_size_) / width,
+               static_cast<float>(max_texture_size_) / height);
+
+  // Clamp if the desired size is greater than the maximum texture size for the
+  // device. Scale both dimensions proportionally so that we avoid stretching.
+  if (adjusted_scale < 1.0f) {
+    width *= adjusted_scale;
+    height *= adjusted_scale;
+  }
+
+  return IntSize(width, height);
+}
+
+void XRWebGLDrawingBuffer::Resize(const IntSize& new_size) {
+  IntSize adjusted_size = AdjustSize(new_size);
 
   if (adjusted_size == size_)
     return;
@@ -177,6 +196,10 @@
 
   size_ = adjusted_size;
 
+  // Free all mailboxes, because they are now of the wrong size. Only the
+  // first call in this loop has any effect.
+  recycled_color_buffer_queue_.clear();
+
   gl->BindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
 
   // Provide a depth and/or stencil buffer if requested.
@@ -245,6 +268,9 @@
 
   if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
     DLOG(ERROR) << "Framebuffer incomplete";
+    framebuffer_incomplete_ = true;
+  } else {
+    framebuffer_incomplete_ = false;
   }
 
   DrawingBuffer::Client* client = drawing_buffer_->client();
@@ -341,10 +367,17 @@
                              GL_TEXTURE_2D, back_color_buffer_->texture_id, 0);
   }
 
-  if (discard_framebuffer_supported_) {
-    const GLenum kAttachments[3] = {GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT,
-                                    GL_STENCIL_ATTACHMENT};
-    gl->DiscardFramebufferEXT(GL_FRAMEBUFFER, 3, kAttachments);
+  if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+    DLOG(ERROR) << "Framebuffer incomplete";
+    framebuffer_incomplete_ = true;
+  } else {
+    framebuffer_incomplete_ = false;
+
+    if (discard_framebuffer_supported_) {
+      const GLenum kAttachments[3] = {GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT,
+                                      GL_STENCIL_ATTACHMENT};
+      gl->DiscardFramebufferEXT(GL_FRAMEBUFFER, 3, kAttachments);
+    }
   }
 
   client->DrawingBufferClientRestoreFramebufferBinding();
@@ -357,8 +390,9 @@
   scoped_refptr<ColorBuffer> buffer;
   bool success = false;
 
-  // Ensure the context isn't lost before continuing.
-  if (!ContextLost()) {
+  // Ensure the context isn't lost and the framebuffer is complete before
+  // continuing.
+  if (!ContextLost() && !framebuffer_incomplete_) {
     SwapColorBuffers();
 
     buffer = front_color_buffer_;
@@ -375,8 +409,9 @@
   if (!success) {
     // If we can't get a mailbox, return an transparent black ImageBitmap.
     // The only situation in which this could happen is when two or more calls
-    // to transferToImageBitmap are made back-to-back, or when the context gets
-    // lost.
+    // to transferToImageBitmap are made back-to-back, if the framebuffer is
+    // incomplete (likely due to a failed buffer allocation), or when the
+    // context gets lost.
     sk_sp<SkSurface> surface =
         SkSurface::MakeRasterN32Premul(size_.Width(), size_.Height());
     return StaticBitmapImage::Create(surface->makeImageSnapshot());
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/XRWebGLDrawingBuffer.h b/third_party/WebKit/Source/platform/graphics/gpu/XRWebGLDrawingBuffer.h
index 3535c6b..1e1033b 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/XRWebGLDrawingBuffer.h
+++ b/third_party/WebKit/Source/platform/graphics/gpu/XRWebGLDrawingBuffer.h
@@ -84,6 +84,8 @@
 
   bool Initialize(const IntSize&, bool use_multisampling, bool use_multiview);
 
+  IntSize AdjustSize(const IntSize&);
+
   scoped_refptr<ColorBuffer> CreateColorBuffer();
   scoped_refptr<ColorBuffer> CreateOrRecycleColorBuffer();
 
@@ -124,7 +126,9 @@
   AntialiasingMode anti_aliasing_mode_ = kNone;
 
   bool storage_texture_supported_ = false;
+  int max_texture_size_ = 0;
   int sample_count_ = 0;
+  bool framebuffer_incomplete_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
index 5bf6360..9ee1ee4 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -103,6 +103,10 @@
     [['/usr/share/doc/ttf-mscorefonts-installer/'], 'READ_ME!.gz', MS_TRUETYPE_FONTS_PACKAGE],
 
     # Other fonts: Arabic, CJK, Indic, Thai, etc.
+    [[CONTENT_SHELL_FONTS_DIR], 'Arimo-Bold.ttf', None],
+    [[CONTENT_SHELL_FONTS_DIR], 'Arimo-BoldItalic.ttf', None],
+    [[CONTENT_SHELL_FONTS_DIR], 'Arimo-Italic.ttf', None],
+    [[CONTENT_SHELL_FONTS_DIR], 'Arimo-Regular.ttf', None],
     [[CONTENT_SHELL_FONTS_DIR], 'DejaVuSans.ttf', None],
     [[CONTENT_SHELL_FONTS_DIR], 'Garuda.ttf', None],
     [[CONTENT_SHELL_FONTS_DIR], 'Lohit-Devanagari.ttf', None],
@@ -111,6 +115,10 @@
     [[CONTENT_SHELL_FONTS_DIR], 'MuktiNarrow.ttf', None],
     [[CONTENT_SHELL_FONTS_DIR], 'NotoSansKhmer-Regular.ttf', None],
     [[CONTENT_SHELL_FONTS_DIR], 'NotoSansCJKjp-Regular.otf', None],
+    [[CONTENT_SHELL_FONTS_DIR], 'Tinos-Bold.ttf', None],
+    [[CONTENT_SHELL_FONTS_DIR], 'Tinos-BoldItalic.ttf', None],
+    [[CONTENT_SHELL_FONTS_DIR], 'Tinos-Italic.ttf', None],
+    [[CONTENT_SHELL_FONTS_DIR], 'Tinos-Regular.ttf', None],
 ]
 
 
diff --git a/third_party/WebKit/public/platform/web_feature.mojom b/third_party/WebKit/public/platform/web_feature.mojom
index 97b8b6b..3420beb 100644
--- a/third_party/WebKit/public/platform/web_feature.mojom
+++ b/third_party/WebKit/public/platform/web_feature.mojom
@@ -1879,6 +1879,7 @@
   kCSSSelectorPseudoFocus = 2387,
   kCSSSelectorPseudoFocusVisible = 2388,
   kDistrustedLegacySymantecSubresource = 2389,
+  kVRDisplayGetFrameData = 2390,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/test_fonts/BUILD.gn b/third_party/test_fonts/BUILD.gn
index 8015ac5f..1008d98 100644
--- a/third_party/test_fonts/BUILD.gn
+++ b/third_party/test_fonts/BUILD.gn
@@ -5,6 +5,10 @@
 copy("test_fonts") {
   sources = [
     "LICENSE",
+    "test_fonts/Arimo-Bold.ttf",
+    "test_fonts/Arimo-BoldItalic.ttf",
+    "test_fonts/Arimo-Italic.ttf",
+    "test_fonts/Arimo-Regular.ttf",
     "test_fonts/DejaVuSans-Bold.ttf",
     "test_fonts/DejaVuSans.ttf",
     "test_fonts/Garuda.ttf",
@@ -14,6 +18,10 @@
     "test_fonts/MuktiNarrow.ttf",
     "test_fonts/NotoSansCJKjp-Regular.otf",
     "test_fonts/NotoSansKhmer-Regular.ttf",
+    "test_fonts/Tinos-Bold.ttf",
+    "test_fonts/Tinos-BoldItalic.ttf",
+    "test_fonts/Tinos-Italic.ttf",
+    "test_fonts/Tinos-Regular.ttf",
   ]
 
   outputs = [
diff --git a/third_party/test_fonts/LICENSE b/third_party/test_fonts/LICENSE
index 9a11b1e19..23256c1 100644
--- a/third_party/test_fonts/LICENSE
+++ b/third_party/test_fonts/LICENSE
@@ -735,3 +735,217 @@
 DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
 OTHER DEALINGS IN THE FONT SOFTWARE.
+
+
+--------------------------------------------------------------------------------
+The Apache License applies to the following files
+Arimo-Bold.ttf
+Arimo-BoldItalic.ttf
+Arimo-Italic.ttf
+Arimo-Regular.ttf
+Tinos-Bold.ttf
+Tinos-BoldItalic.ttf
+Tinos-Italic.ttf
+Tinos-Regular.ttf
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/third_party/test_fonts/README.chromium b/third_party/test_fonts/README.chromium
index f1cc479..2da72e9 100644
--- a/third_party/test_fonts/README.chromium
+++ b/third_party/test_fonts/README.chromium
@@ -30,12 +30,16 @@
 7.  (optional) Update FONT_FILES in
     third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py .
 
-If you need access to the chromium-fonts bucket, contact Chrome infra. For
+If you need access to the chromium-fonts bucket, contact Chrome infra.% For
 details, please refer to
 https://chromium.googlesource.com/infra/infra/+/master/doc/users/contacting_troopers.md
 
 Font Origins:
 
+Arimo-Bold.ttf             https://github.com/google/fonts/tree/master/apache/arimo
+Arimo-BoldItalic.ttf       https://github.com/google/fonts/tree/master/apache/arimo
+Arimo-Italic.ttf           https://github.com/google/fonts/tree/master/apache/arimo
+Arimo-Regular.ttf          https://github.com/google/fonts/tree/master/apache/arimo
 DejaVuSans.ttf             https://dejavu-fonts.github.io/Download.html
 Garuda.ttf                 https://linux.thai.net/projects/fonts-tlwg
 Lohit-Devanagari.ttf       https://pagure.io/lohit
@@ -44,3 +48,7 @@
 MuktiNarrow.ttf            http://www.nongnu.org/freebangfont/downloads.html#mukti
 NotoSansCJKjp-Regular.otf  https://www.google.com/get/noto/#sans-jpan
 NotoSansKhmer-Regular.ttf  https://www.google.com/get/noto/#sans-khmr
+Tinos-Bold.ttf             https://github.com/google/fonts/tree/master/apache/tinos
+Tinos-BoldItalic.ttf       https://github.com/google/fonts/tree/master/apache/tinos
+Tinos-Italic.ttf           https://github.com/google/fonts/tree/master/apache/tinos
+Tinos-Regular.ttf          https://github.com/google/fonts/tree/master/apache/tinos
diff --git a/third_party/test_fonts/test_fonts.tar.gz.sha1 b/third_party/test_fonts/test_fonts.tar.gz.sha1
index ec364f4108..9a1b2230 100644
--- a/third_party/test_fonts/test_fonts.tar.gz.sha1
+++ b/third_party/test_fonts/test_fonts.tar.gz.sha1
@@ -1 +1 @@
-9c1ff266a05e3b8523de198f62dabb9a881ab28f
\ No newline at end of file
+e494bc9cb34c0dd6629fb783acb7e8bff422a8dd
\ No newline at end of file
diff --git a/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-client-protocol.h b/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-client-protocol.h
index a1a8f23..b8b5582c 100644
--- a/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-client-protocol.h
+++ b/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-client-protocol.h
@@ -1416,10 +1416,10 @@
  * surface, e.g. fullscreen or maximized.
  */
 static inline void
-zcr_remote_surface_v1_resize(struct zcr_remote_surface_v1 *zcr_remote_surface_v1, uint32_t direction)
+zcr_remote_surface_v1_resize(struct zcr_remote_surface_v1 *zcr_remote_surface_v1)
 {
 	wl_proxy_marshal((struct wl_proxy *) zcr_remote_surface_v1,
-			 ZCR_REMOTE_SURFACE_V1_RESIZE, direction);
+			 ZCR_REMOTE_SURFACE_V1_RESIZE);
 }
 
 /**
@@ -1545,6 +1545,8 @@
  * @ingroup iface_zcr_remote_surface_v1
  *
  * Request to start an interactive, user-driven resize of the surface.
+ * "x" and "y" specifies the starting point of the pointer device
+ * that initiated the reize.
  *
  * The compositor responds to this request with a "drag_started"
  * event, followed by "bounds_changed" events, and ends the
@@ -1556,10 +1558,10 @@
  * surface, e.g. fullscreen or maximized, or no drag event is in pregress.
  */
 static inline void
-zcr_remote_surface_v1_start_resize(struct zcr_remote_surface_v1 *zcr_remote_surface_v1, uint32_t resize_direction)
+zcr_remote_surface_v1_start_resize(struct zcr_remote_surface_v1 *zcr_remote_surface_v1, uint32_t resize_direction, int32_t x, int32_t y)
 {
 	wl_proxy_marshal((struct wl_proxy *) zcr_remote_surface_v1,
-			 ZCR_REMOTE_SURFACE_V1_START_RESIZE, resize_direction);
+			 ZCR_REMOTE_SURFACE_V1_START_RESIZE, resize_direction, x, y);
 }
 
 #define ZCR_NOTIFICATION_SURFACE_V1_DESTROY 0
diff --git a/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-server-protocol.h b/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-server-protocol.h
index b486875..84a2c25 100644
--- a/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-server-protocol.h
+++ b/third_party/wayland-protocols/include/protocol/remote-shell-unstable-v1-server-protocol.h
@@ -900,12 +900,10 @@
 	 *
 	 * The compositor may ignore resize requests depending on the state
 	 * of the surface, e.g. fullscreen or maximized.
-	 * @param direction the direction of resize
 	 * @since 9
 	 */
 	void (*resize)(struct wl_client *client,
-		       struct wl_resource *resource,
-		       uint32_t direction);
+		       struct wl_resource *resource);
 	/**
 	 * expand input region for resizing
 	 *
@@ -1005,7 +1003,8 @@
 	 * start an interactive resize
 	 *
 	 * Request to start an interactive, user-driven resize of the
-	 * surface.
+	 * surface. "x" and "y" specifies the starting point of the pointer
+	 * device that initiated the reize.
 	 *
 	 * The compositor responds to this request with a "drag_started"
 	 * event, followed by "bounds_changed" events, and ends the resize
@@ -1021,7 +1020,9 @@
 	 */
 	void (*start_resize)(struct wl_client *client,
 			     struct wl_resource *resource,
-			     uint32_t resize_direction);
+			     uint32_t resize_direction,
+			     int32_t x,
+			     int32_t y);
 };
 
 #define ZCR_REMOTE_SURFACE_V1_CLOSE 0
diff --git a/third_party/wayland-protocols/protocol/remote-shell-protocol.c b/third_party/wayland-protocols/protocol/remote-shell-protocol.c
index 4af4936..eb7b56a 100644
--- a/third_party/wayland-protocols/protocol/remote-shell-protocol.c
+++ b/third_party/wayland-protocols/protocol/remote-shell-protocol.c
@@ -102,7 +102,7 @@
 	{ "move", "5", types + 0 },
 	{ "set_orientation", "6i", types + 0 },
 	{ "set_window_type", "7u", types + 0 },
-	{ "resize", "9u", types + 0 },
+	{ "resize", "9", types + 0 },
 	{ "set_resize_outset", "9i", types + 0 },
 	{ "start_move", "10ii", types + 0 },
 	{ "set_can_maximize", "10", types + 0 },
@@ -111,7 +111,7 @@
 	{ "set_max_size", "10ii", types + 0 },
 	{ "set_snapped_to_left", "11", types + 0 },
 	{ "set_snapped_to_right", "11", types + 0 },
-	{ "start_resize", "12u", types + 0 },
+	{ "start_resize", "12uii", types + 0 },
 };
 
 static const struct wl_message zcr_remote_surface_v1_events[] = {
diff --git a/third_party/wayland-protocols/unstable/remote-shell/remote-shell-unstable-v1.xml b/third_party/wayland-protocols/unstable/remote-shell/remote-shell-unstable-v1.xml
index c9da833..111d6d0 100644
--- a/third_party/wayland-protocols/unstable/remote-shell/remote-shell-unstable-v1.xml
+++ b/third_party/wayland-protocols/unstable/remote-shell/remote-shell-unstable-v1.xml
@@ -778,6 +778,8 @@
     <request name="start_resize" since="12">
       <description summary="start an interactive resize">
 	Request to start an interactive, user-driven resize of the surface.
+	"x" and "y" specifies the starting point of the pointer device
+	that initiated the reize.
 
 	The compositor responds to this request with a "drag_started"
 	event, followed by "bounds_changed" events, and ends the
@@ -789,6 +791,8 @@
 	surface, e.g. fullscreen or maximized, or no drag event is in pregress.
       </description>
       <arg name="resize_direction" type="uint" summary="the direction of resize"/>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
     </request>
 
   </interface>
diff --git a/tools/ipc_fuzzer/message_replay/BUILD.gn b/tools/ipc_fuzzer/message_replay/BUILD.gn
index 13ab40e..caa50384 100644
--- a/tools/ipc_fuzzer/message_replay/BUILD.gn
+++ b/tools/ipc_fuzzer/message_replay/BUILD.gn
@@ -5,7 +5,7 @@
 executable("ipc_fuzzer_replay") {
   configs += [ "//tools/ipc_fuzzer:ipc_fuzzer_tool_config" ]
   deps = [
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//tools/ipc_fuzzer/message_lib:ipc_message_lib",
   ]
   public_deps = [
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 7444f33..fd05a01 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -616,6 +616,7 @@
       'fuchsia_x64_cast_audio': 'release_trybot_fuchsia_cast_audio',
       'layout_test_leak_detection': 'release_trybot',
       'leak_detection_linux': 'release_trybot',
+      'linux-blink-heap-verification-try': 'release_trybot_enable_blink_heap_verification',
       'linux_arm': 'release_trybot_arm',
       'linux_chromium_archive_rel_ng': 'release_bot',
       'linux_chromium_asan_rel_ng': 'asan_lsan_release_trybot',
@@ -1609,6 +1610,10 @@
       'release_trybot', 'arm',
     ],
 
+    'release_trybot_enable_blink_heap_verification': [
+      'release_trybot', 'enable_blink_heap_verification',
+    ],
+
     'release_trybot_fuchsia': [
       'release_trybot', 'fuchsia',
     ],
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 29b988a..eaa14ae 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -17962,6 +17962,7 @@
   <int value="2387" label="CSSSelectorPseudoFocus"/>
   <int value="2388" label="CSSSelectorPseudoFocusVisible"/>
   <int value="2389" label="DistrustedLegacySymantecSubresource"/>
+  <int value="2390" label="VRDisplayGetFrameData"/>
 </enum>
 
 <enum name="FeedbackSource">
@@ -32540,6 +32541,12 @@
   </int>
 </enum>
 
+<enum name="OfflinePageTrustedState">
+  <int value="0" label="Trusted: in internal directory"/>
+  <int value="1" label="Trusted: in public directory and unmodified"/>
+  <int value="2" label="Untrusted"/>
+</enum>
+
 <enum name="OfflinePrefetchArchiveActualSizeVsExpected">
   <summary>
     Percentage ranges for the ratios of actual downloaded size of a prefetched
@@ -34145,7 +34152,7 @@
 <enum name="PasswordManagerAndroidPasswordEntryActions">
   <int value="0" label="Viewed"/>
   <int value="1" label="Deleted"/>
-  <int value="2" label="Cancelled"/>
+  <int value="2" label="Cancelled (obsolete)"/>
   <int value="3" label="ViewedAfterSearched"/>
 </enum>
 
@@ -39575,6 +39582,11 @@
   <int value="2" label="Read data error"/>
 </enum>
 
+<enum name="ServiceWorkerRendererStartWorker">
+  <int value="0" label="Received on installed service worker."/>
+  <int value="1" label="Received on uninstalled service worker."/>
+</enum>
+
 <enum name="ServiceWorkerResponseError">
   <int value="0" label="ErrorUnknown"/>
   <int value="1" label="ErrorPromiseRejected"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 4c0efb2e..3b219f8e 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -57562,6 +57562,14 @@
   </summary>
 </histogram>
 
+<histogram name="OfflinePages.TrustStateOnOpen" enum="OfflinePageTrustedState">
+  <owner>jianli@chromium.org</owner>
+  <summary>
+    The trust state of the offline page. This is recorded when an offline page
+    is being opened.
+  </summary>
+</histogram>
+
 <histogram name="OfflinePages.Wakeup.BatteryPercentage" units="%">
   <owner>petewil@chromium.org</owner>
   <owner>jianli@chromium.org</owner>
@@ -81230,6 +81238,19 @@
   </summary>
 </histogram>
 
+<histogram name="ServiceWorker.EmbeddedWorkerInstanceClient.StartWorker"
+    enum="ServiceWorkerRendererStartWorker">
+  <owner>panicker@chromium.org</owner>
+  <summary>
+    Records when StartWorker is received on the renderer. This is used to
+    surface discrepancy between StartWorker being sent on the browser side and
+    not getting received by renderer.
+    EmbeddedWorkerInstance.Start.TimeToSendStartWorker should be used as a
+    baseline. TODO(panicker): This should be removed after investigation of
+    crbug/790903, potentially in M68.
+  </summary>
+</histogram>
+
 <histogram name="ServiceWorker.EventDispatchingDelay" units="ms">
   <owner>horo@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 2d7fdb7..7b6bdca 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -1461,11 +1461,22 @@
       Measure of memory consumed by Discardable memory service.
     </summary>
   </metric>
+  <metric name="DownloadService">
+    <summary>
+      Measure of memory used by download service.
+    </summary>
+  </metric>
   <metric name="Extensions.ValueStore">
     <summary>
       Measure of memory consumed by Key Value Store databases of extensions.
     </summary>
   </metric>
+  <metric name="FontCaches">
+    <summary>
+      Measure of memory used by font platform and shape caches in renderer
+      process.
+    </summary>
+  </metric>
   <metric name="History">
     <summary>
       Approximate measure of memory consumed by History service.
@@ -1534,6 +1545,11 @@
       The number of nodes that the associated renderer owns.
     </summary>
   </metric>
+  <metric name="OmniboxSuggestions">
+    <summary>
+      Measure of memory used due to URL indexing and autocomplete suggestions.
+    </summary>
+  </metric>
   <metric name="PartitionAlloc">
     <summary>
       Measure of memory allocated by PartitionAlloc allocator.
@@ -1597,6 +1613,11 @@
       Measure of memory used due to web storage APIs in browser process.
     </summary>
   </metric>
+  <metric name="SiteStorage.BlobStorage">
+    <summary>
+      Measure of memory used by in-memory blob file API in browser process.
+    </summary>
+  </metric>
   <metric name="SiteStorage.IndexDB">
     <summary>
       Measure of memory used due to IndexedDB API in browser process.
diff --git a/tools/v8_context_snapshot/BUILD.gn b/tools/v8_context_snapshot/BUILD.gn
index 37622d67..4cb222d 100644
--- a/tools/v8_context_snapshot/BUILD.gn
+++ b/tools/v8_context_snapshot/BUILD.gn
@@ -100,7 +100,7 @@
 
     deps = [
       "//gin:gin",
-      "//mojo/edk/system:system",
+      "//mojo/edk",
       "//services/service_manager/public/cpp",
       "//third_party/WebKit/public:blink",
       "//v8",
diff --git a/ui/app_list/BUILD.gn b/ui/app_list/BUILD.gn
index a3712e5..e97e672 100644
--- a/ui/app_list/BUILD.gn
+++ b/ui/app_list/BUILD.gn
@@ -206,7 +206,7 @@
     ":test_support",
     "//base",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//skia",
     "//testing/gtest",
     "//ui/accessibility",
diff --git a/ui/app_list/views/app_list_view_unittest.cc b/ui/app_list/views/app_list_view_unittest.cc
index 2e3caf1..96020b7 100644
--- a/ui/app_list/views/app_list_view_unittest.cc
+++ b/ui/app_list/views/app_list_view_unittest.cc
@@ -1191,6 +1191,28 @@
   EXPECT_TRUE(second_suggestion_app->HasFocus());
 }
 
+// Tests that the focus is reset onto the search box and the folder exits after
+// hitting enter on folder name.
+TEST_P(AppListViewFocusTest, FocusResetAfterHittingEnterOnFolderName) {
+  Show();
+
+  // Transition to FULLSCREEN_ALL_APPS state and open the folder.
+  SetAppListState(AppListViewState::FULLSCREEN_ALL_APPS);
+  folder_item_view()->RequestFocus();
+  SimulateKeyPress(ui::VKEY_RETURN, false);
+  EXPECT_TRUE(contents_view()->GetAppsContainerView()->IsInFolderView());
+
+  // Set focus on the folder name.
+  views::View* folder_name_view =
+      app_list_folder_view()->folder_header_view()->GetFolderNameViewForTest();
+  folder_name_view->RequestFocus();
+
+  // Hit enter key.
+  SimulateKeyPress(ui::VKEY_RETURN, false);
+  search_box_view()->search_box()->RequestFocus();
+  EXPECT_FALSE(contents_view()->GetAppsContainerView()->IsInFolderView());
+}
+
 // Tests that opening the app list opens in peeking mode by default.
 TEST_F(AppListViewTest, ShowPeekingByDefault) {
   Initialize(0, false, false);
diff --git a/ui/app_list/views/folder_header_view.cc b/ui/app_list/views/folder_header_view.cc
index 9e36647..59f23555 100644
--- a/ui/app_list/views/folder_header_view.cc
+++ b/ui/app_list/views/folder_header_view.cc
@@ -217,6 +217,7 @@
   if (key_event.key_code() == ui::VKEY_RETURN &&
       key_event.type() == ui::ET_KEY_PRESSED) {
     delegate_->GiveBackFocusToSearchBox();
+    delegate_->NavigateBack(folder_item_, key_event);
     return true;
   }
   if (!CanProcessLeftRightKeyTraversal(key_event))
diff --git a/ui/arc/BUILD.gn b/ui/arc/BUILD.gn
index 40b7f36..9e78a62 100644
--- a/ui/arc/BUILD.gn
+++ b/ui/arc/BUILD.gn
@@ -69,7 +69,7 @@
     "//components/arc:arc_test_support",
     "//components/exo",
     "//components/exo:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//testing/gmock",
     "//testing/gtest",
     "//ui/aura:test_support",
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn
index 9179229e..657b7c4c 100644
--- a/ui/aura/BUILD.gn
+++ b/ui/aura/BUILD.gn
@@ -378,7 +378,7 @@
     "//base/test:test_support",
     "//components/viz/client",
     "//mojo/common",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//net",
     "//services/ui/common:task_runner_test_base",
     "//services/ui/public/cpp",
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index bf08ff78..a4ca6ad 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -904,7 +904,7 @@
     ":ui_base_unittests_bundle_data",
     "//base",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//net",
     "//net:test_support",
     "//skia",
diff --git a/ui/base/clipboard/clipboard_win.cc b/ui/base/clipboard/clipboard_win.cc
index 3757fd109..e49dd8c 100644
--- a/ui/base/clipboard/clipboard_win.cc
+++ b/ui/base/clipboard/clipboard_win.cc
@@ -208,12 +208,13 @@
 }
 
 template <typename StringType>
-void TrimTrailingNulls(StringType* result) {
-  // Text copied to the clipboard may explicitly contain trailing null
-  // characters that should be ignored, depending on the application that does
-  // the copying.
-  while (!result->empty() && result->back() == 0)
-    result->pop_back();
+void TrimAfterNull(StringType* result) {
+  // Text copied to the clipboard may explicitly contain null characters that
+  // should be ignored, depending on the application that does the copying.
+  constexpr typename StringType::value_type kNull = 0;
+  size_t pos = result->find_first_of(kNull);
+  if (pos != StringType::npos)
+    result->resize(pos);
 }
 
 }  // namespace
@@ -505,7 +506,7 @@
   result->assign(static_cast<const base::char16*>(::GlobalLock(data)),
                  ::GlobalSize(data) / sizeof(base::char16));
   ::GlobalUnlock(data);
-  TrimTrailingNulls(result);
+  TrimAfterNull(result);
 }
 
 void ClipboardWin::ReadAsciiText(ClipboardType type,
@@ -530,7 +531,7 @@
   result->assign(static_cast<const char*>(::GlobalLock(data)),
                  ::GlobalSize(data));
   ::GlobalUnlock(data);
-  TrimTrailingNulls(result);
+  TrimAfterNull(result);
 }
 
 void ClipboardWin::ReadHTML(ClipboardType type,
@@ -560,7 +561,7 @@
   std::string cf_html(static_cast<const char*>(::GlobalLock(data)),
                       ::GlobalSize(data));
   ::GlobalUnlock(data);
-  TrimTrailingNulls(&cf_html);
+  TrimAfterNull(&cf_html);
 
   size_t html_start = std::string::npos;
   size_t start_index = std::string::npos;
@@ -593,7 +594,7 @@
   DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
 
   ReadData(GetRtfFormatType(), result);
-  TrimTrailingNulls(result);
+  TrimAfterNull(result);
 }
 
 SkBitmap ClipboardWin::ReadImage(ClipboardType type) const {
@@ -716,7 +717,7 @@
   base::string16 bookmark(static_cast<const base::char16*>(::GlobalLock(data)),
                           ::GlobalSize(data) / sizeof(base::char16));
   ::GlobalUnlock(data);
-  TrimTrailingNulls(&bookmark);
+  TrimAfterNull(&bookmark);
 
   ParseBookmarkClipboardFormat(bookmark, title, url);
 }
diff --git a/ui/chromeos/BUILD.gn b/ui/chromeos/BUILD.gn
index c15c784..913671f 100644
--- a/ui/chromeos/BUILD.gn
+++ b/ui/chromeos/BUILD.gn
@@ -69,7 +69,7 @@
     ":chromeos",
     "//base/test:test_support",
     "//chromeos",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//skia",
     "//testing/gtest",
     "//ui/aura:test_support",
diff --git a/ui/compositor/BUILD.gn b/ui/compositor/BUILD.gn
index 12788fe..1e9a472 100644
--- a/ui/compositor/BUILD.gn
+++ b/ui/compositor/BUILD.gn
@@ -208,7 +208,7 @@
     "//components/viz/common",
     "//components/viz/service",
     "//components/viz/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//skia",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/ui/display/display.cc b/ui/display/display.cc
index 9a10474..9aedc85 100644
--- a/ui/display/display.cc
+++ b/ui/display/display.cc
@@ -268,7 +268,7 @@
 
 std::string Display::ToString() const {
   return base::StringPrintf(
-      "Display[%lld] bounds=%s, workarea=%s, scale=%g, %s",
+      "Display[%lld] bounds=[%s], workarea=[%s], scale=%g, %s.",
       static_cast<long long int>(id_), bounds_.ToString().c_str(),
       work_area_.ToString().c_str(), device_scale_factor_,
       IsInternal() ? "internal" : "external");
diff --git a/ui/display/display.h b/ui/display/display.h
index 49f76438..f900c7e 100644
--- a/ui/display/display.h
+++ b/ui/display/display.h
@@ -220,9 +220,7 @@
   // True if this is a monochrome display (e.g, for accessiblity). Used by media
   // query APIs.
   bool is_monochrome() const { return is_monochrome_; }
-  void set_is_monochrome(bool is_monochrome) {
-    is_monochrome_ = is_monochrome;
-  }
+  void set_is_monochrome(bool is_monochrome) { is_monochrome_ = is_monochrome; }
 
   bool operator==(const Display& rhs) const;
   bool operator!=(const Display& rhs) const { return !(*this == rhs); }
diff --git a/ui/display/manager/chromeos/display_change_observer.cc b/ui/display/manager/chromeos/display_change_observer.cc
index a594a65..68ef0da 100644
--- a/ui/display/manager/chromeos/display_change_observer.cc
+++ b/ui/display/manager/chromeos/display_change_observer.cc
@@ -25,6 +25,7 @@
 #include "ui/display/types/display_mode.h"
 #include "ui/display/types/display_snapshot.h"
 #include "ui/display/util/display_util.h"
+#include "ui/display/util/edid_parser.h"
 #include "ui/events/devices/input_device_manager.h"
 #include "ui/events/devices/touchscreen_device.h"
 #include "ui/strings/grit/ui_strings.h"
@@ -67,8 +68,10 @@
                                  display_info.device_scale_factor());
   // When display zoom option is available, we cannot change the mode for
   // internal displays.
-  if (chromeos::switches::IsDisplayZoomSettingEnabled())
+  if (chromeos::switches::IsDisplayZoomSettingEnabled()) {
+    native_mode.set_is_default(true);
     return ManagedDisplayInfo::ManagedDisplayModeList{native_mode};
+  }
   return CreateInternalManagedDisplayModeList(native_mode);
 }
 
@@ -265,21 +268,21 @@
 }
 
 ManagedDisplayInfo DisplayChangeObserver::CreateManagedDisplayInfo(
-    const DisplaySnapshot* state,
+    const DisplaySnapshot* snapshot,
     const DisplayMode* mode_info) {
   float device_scale_factor = 1.0f;
   // Sets dpi only if the screen size is not blacklisted.
-  float dpi = IsDisplaySizeBlackListed(state->physical_size())
+  float dpi = IsDisplaySizeBlackListed(snapshot->physical_size())
                   ? 0
                   : kInchInMm * mode_info->size().width() /
-                        state->physical_size().width();
+                        snapshot->physical_size().width();
 
-  if (state->type() == DISPLAY_CONNECTION_TYPE_INTERNAL) {
+  if (snapshot->type() == DISPLAY_CONNECTION_TYPE_INTERNAL) {
     if (dpi)
       device_scale_factor = FindDeviceScaleFactor(dpi);
   } else {
     ManagedDisplayMode mode;
-    if (display_manager_->GetSelectedModeForDisplayId(state->display_id(),
+    if (display_manager_->GetSelectedModeForDisplayId(snapshot->display_id(),
                                                       &mode)) {
       device_scale_factor = mode.device_scale_factor();
     } else {
@@ -288,8 +291,8 @@
       // from the value of |k2xThreshouldSizeSquaredFor4KInMm|
       const int k2xThreshouldSizeSquaredFor4KInMm =
           (40 * 40 * kInchInMm * kInchInMm) - 100;
-      gfx::Vector2d size_in_vec(state->physical_size().width(),
-                                state->physical_size().height());
+      gfx::Vector2d size_in_vec(snapshot->physical_size().width(),
+                                snapshot->physical_size().height());
       if (size_in_vec.LengthSquared() > k2xThreshouldSizeSquaredFor4KInMm &&
           mode_info->size().width() >= kMinimumWidthFor4K) {
         // Make sure that additional device scale factors table has 2x.
@@ -299,35 +302,46 @@
     }
   }
 
-  std::string name = (state->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
+  std::string name = (snapshot->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
                          ? l10n_util::GetStringUTF8(IDS_DISPLAY_NAME_INTERNAL)
-                         : state->display_name();
+                         : snapshot->display_name();
 
   if (name.empty())
     name = l10n_util::GetStringUTF8(IDS_DISPLAY_NAME_UNKNOWN);
 
-  const bool has_overscan = state->has_overscan();
-  const int64_t id = state->display_id();
+  const bool has_overscan = snapshot->has_overscan();
+  const int64_t id = snapshot->display_id();
 
   ManagedDisplayInfo new_info = ManagedDisplayInfo(id, name, has_overscan);
-  new_info.set_sys_path(state->sys_path());
+
+  if (snapshot->product_code() != DisplaySnapshot::kInvalidProductCode) {
+    uint16_t manufacturer_id = 0;
+    uint16_t product_id = 0;
+    SplitProductCodeInManufacturerIdAndProductId(snapshot->product_code(),
+                                                 &manufacturer_id, &product_id);
+    new_info.set_manufacturer_id(ManufacturerIdToString(manufacturer_id));
+    new_info.set_product_id(ProductIdToString(product_id));
+  }
+  new_info.set_year_of_manufacture(snapshot->year_of_manufacture());
+
+  new_info.set_sys_path(snapshot->sys_path());
   new_info.set_device_scale_factor(device_scale_factor);
-  const gfx::Rect display_bounds(state->origin(), mode_info->size());
+  const gfx::Rect display_bounds(snapshot->origin(), mode_info->size());
   new_info.SetBounds(display_bounds);
   new_info.set_native(true);
   new_info.set_is_aspect_preserving_scaling(
-      state->is_aspect_preserving_scaling());
+      snapshot->is_aspect_preserving_scaling());
   if (dpi)
     new_info.set_device_dpi(dpi);
-  new_info.set_color_space(state->color_space());
+  new_info.set_color_space(snapshot->color_space());
 
   ManagedDisplayInfo::ManagedDisplayModeList display_modes =
-      (state->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
-          ? GetInternalManagedDisplayModeList(new_info, *state)
-          : GetExternalManagedDisplayModeList(*state);
+      (snapshot->type() == DISPLAY_CONNECTION_TYPE_INTERNAL)
+          ? GetInternalManagedDisplayModeList(new_info, *snapshot)
+          : GetExternalManagedDisplayModeList(*snapshot);
   new_info.SetManagedDisplayModes(display_modes);
 
-  new_info.set_maximum_cursor_size(state->maximum_cursor_size());
+  new_info.set_maximum_cursor_size(snapshot->maximum_cursor_size());
   return new_info;
 }
 
diff --git a/ui/display/manager/chromeos/display_change_observer.h b/ui/display/manager/chromeos/display_change_observer.h
index 8ad853d..66cae8d 100644
--- a/ui/display/manager/chromeos/display_change_observer.h
+++ b/ui/display/manager/chromeos/display_change_observer.h
@@ -64,7 +64,7 @@
   void UpdateInternalDisplay(
       const DisplayConfigurator::DisplayStateList& display_states);
 
-  ManagedDisplayInfo CreateManagedDisplayInfo(const DisplaySnapshot* state,
+  ManagedDisplayInfo CreateManagedDisplayInfo(const DisplaySnapshot* snapshot,
                                               const DisplayMode* mode_info);
 
   // Both |display_configurator_| and |display_manager_| are not owned and must
diff --git a/ui/display/manager/fake_display_snapshot.cc b/ui/display/manager/fake_display_snapshot.cc
index 3db0e2c8..85e8fc1 100644
--- a/ui/display/manager/fake_display_snapshot.cc
+++ b/ui/display/manager/fake_display_snapshot.cc
@@ -308,6 +308,7 @@
                       current_mode,
                       native_mode,
                       product_id,
+                      2018 /*year_of_manufacture */,
                       maximum_cursor_size) {}
 
 FakeDisplaySnapshot::~FakeDisplaySnapshot() {}
diff --git a/ui/display/manager/fake_display_snapshot.h b/ui/display/manager/fake_display_snapshot.h
index d47abe134..f1ec732 100644
--- a/ui/display/manager/fake_display_snapshot.h
+++ b/ui/display/manager/fake_display_snapshot.h
@@ -85,7 +85,7 @@
     bool has_overscan_ = false;
     bool has_color_correction_matrix_ = false;
     std::string name_;
-    int64_t product_id_ = DisplaySnapshot::kInvalidProductID;
+    int64_t product_id_ = DisplaySnapshot::kInvalidProductCode;
     gfx::Size maximum_cursor_size_ = gfx::Size(64, 64);
     DisplayModeList modes_;
     const DisplayMode* current_mode_ = nullptr;
diff --git a/ui/display/manager/managed_display_info.cc b/ui/display/manager/managed_display_info.cc
index c490631..50177e42 100644
--- a/ui/display/manager/managed_display_info.cc
+++ b/ui/display/manager/managed_display_info.cc
@@ -260,6 +260,7 @@
 
 ManagedDisplayInfo::ManagedDisplayInfo()
     : id_(kInvalidDisplayId),
+      year_of_manufacture_(kInvalidYearOfManufacture),
       has_overscan_(false),
       active_rotation_source_(Display::RotationSource::UNKNOWN),
       touch_support_(Display::TouchSupport::UNKNOWN),
@@ -276,6 +277,7 @@
                                        bool has_overscan)
     : id_(id),
       name_(name),
+      year_of_manufacture_(kInvalidYearOfManufacture),
       has_overscan_(has_overscan),
       active_rotation_source_(Display::RotationSource::UNKNOWN),
       touch_support_(Display::TouchSupport::UNKNOWN),
@@ -312,6 +314,9 @@
 
 void ManagedDisplayInfo::Copy(const ManagedDisplayInfo& native_info) {
   DCHECK(id_ == native_info.id_);
+  manufacturer_id_ = native_info.manufacturer_id_;
+  product_id_ = native_info.product_id_;
+  year_of_manufacture_ = native_info.year_of_manufacture_;
   name_ = native_info.name_;
   has_overscan_ = native_info.has_overscan_;
 
diff --git a/ui/display/manager/managed_display_info.h b/ui/display/manager/managed_display_info.h
index 3f25ae1..54aa051d 100644
--- a/ui/display/manager/managed_display_info.h
+++ b/ui/display/manager/managed_display_info.h
@@ -253,6 +253,15 @@
     maximum_cursor_size_ = size;
   }
 
+  const std::string& manufacturer_id() const { return manufacturer_id_; }
+  void set_manufacturer_id(const std::string& id) { manufacturer_id_ = id; }
+
+  const std::string& product_id() const { return product_id_; }
+  void set_product_id(const std::string& id) { product_id_ = id; }
+
+  int32_t year_of_manufacture() const { return year_of_manufacture_; }
+  void set_year_of_manufacture(int32_t year) { year_of_manufacture_ = year; }
+
   // Returns a string representation of the ManagedDisplayInfo, excluding
   // display modes.
   std::string ToString() const;
@@ -264,6 +273,9 @@
  private:
   int64_t id_;
   std::string name_;
+  std::string manufacturer_id_;
+  std::string product_id_;
+  int32_t year_of_manufacture_;
   base::FilePath sys_path_;
   bool has_overscan_;
   std::map<Display::RotationSource, Display::Rotation> rotations_;
diff --git a/ui/display/mojo/display_snapshot.mojom b/ui/display/mojo/display_snapshot.mojom
index de45db2..fd6a818 100644
--- a/ui/display/mojo/display_snapshot.mojom
+++ b/ui/display/mojo/display_snapshot.mojom
@@ -28,6 +28,8 @@
   bool has_current_mode;
   uint64 native_mode_index;
   bool has_native_mode;
-  int64 product_id;
+  // |product_code| is a combination of the manufacturer id and the product id.
+  int64 product_code;
+  int32 year_of_manufacture;
   gfx.mojom.Size maximum_cursor_size;
 };
diff --git a/ui/display/mojo/display_snapshot_struct_traits.cc b/ui/display/mojo/display_snapshot_struct_traits.cc
index 85f5071..165c378e6 100644
--- a/ui/display/mojo/display_snapshot_struct_traits.cc
+++ b/ui/display/mojo/display_snapshot_struct_traits.cc
@@ -132,7 +132,7 @@
       data.is_aspect_preserving_scaling(), data.has_overscan(),
       data.has_color_correction_matrix(), color_space, display_name, file_path,
       std::move(modes), std::move(edid), current_mode, native_mode,
-      data.product_id(), maximum_cursor_size);
+      data.product_code(), data.year_of_manufacture(), maximum_cursor_size);
   return true;
 }
 
diff --git a/ui/display/mojo/display_snapshot_struct_traits.h b/ui/display/mojo/display_snapshot_struct_traits.h
index 2be5ea0..e80a273 100644
--- a/ui/display/mojo/display_snapshot_struct_traits.h
+++ b/ui/display/mojo/display_snapshot_struct_traits.h
@@ -93,9 +93,14 @@
     return snapshot->native_mode() != nullptr;
   }
 
-  static int64_t product_id(
+  static int64_t product_code(
       const std::unique_ptr<display::DisplaySnapshot>& snapshot) {
-    return snapshot->product_id();
+    return snapshot->product_code();
+  }
+
+  static int32_t year_of_manufacture(
+      const std::unique_ptr<display::DisplaySnapshot>& snapshot) {
+    return snapshot->year_of_manufacture();
   }
 
   static const gfx::Size& maximum_cursor_size(
diff --git a/ui/display/mojo/display_struct_traits_unittest.cc b/ui/display/mojo/display_struct_traits_unittest.cc
index 1dd6cf7..8d956238 100644
--- a/ui/display/mojo/display_struct_traits_unittest.cc
+++ b/ui/display/mojo/display_struct_traits_unittest.cc
@@ -83,7 +83,7 @@
             output.has_color_correction_matrix());
   EXPECT_EQ(input.display_name(), output.display_name());
   EXPECT_EQ(input.sys_path(), output.sys_path());
-  EXPECT_EQ(input.product_id(), output.product_id());
+  EXPECT_EQ(input.product_code(), output.product_code());
   EXPECT_EQ(input.modes().size(), output.modes().size());
 
   for (size_t i = 0; i < input.modes().size(); i++)
@@ -252,7 +252,8 @@
   const gfx::ColorSpace display_color_space = gfx::ColorSpace::CreateREC709();
   const std::string display_name("whatever display_name");
   const base::FilePath sys_path = base::FilePath::FromUTF8Unsafe("a/cb");
-  const int64_t product_id = 19;
+  const int64_t product_code = 19;
+  const int32_t year_of_manufacture = 1776;
 
   const DisplayMode display_mode(gfx::Size(13, 11), true, 40.0f);
 
@@ -267,7 +268,7 @@
       display_id, origin, physical_size, type, is_aspect_preserving_scaling,
       has_overscan, has_color_correction_matrix, display_color_space,
       display_name, sys_path, std::move(modes), edid, current_mode, native_mode,
-      product_id, maximum_cursor_size);
+      product_code, year_of_manufacture, maximum_cursor_size);
 
   std::unique_ptr<DisplaySnapshot> output;
   SerializeAndDeserialize<mojom::DisplaySnapshot>(input->Clone(), &output);
@@ -289,7 +290,8 @@
   const gfx::ColorSpace display_color_space = gfx::ColorSpace::CreateREC709();
   const std::string display_name("whatever display_name");
   const base::FilePath sys_path = base::FilePath::FromUTF8Unsafe("z/b");
-  const int64_t product_id = 9;
+  const int64_t product_code = 9;
+  const int32_t year_of_manufacture = 1776;
 
   const DisplayMode display_mode(gfx::Size(13, 11), true, 50.0f);
 
@@ -304,7 +306,7 @@
       display_id, origin, physical_size, type, is_aspect_preserving_scaling,
       has_overscan, has_color_correction_matrix, display_color_space,
       display_name, sys_path, std::move(modes), edid, current_mode, native_mode,
-      product_id, maximum_cursor_size);
+      product_code, year_of_manufacture, maximum_cursor_size);
 
   std::unique_ptr<DisplaySnapshot> output;
   SerializeAndDeserialize<mojom::DisplaySnapshot>(input->Clone(), &output);
@@ -326,7 +328,8 @@
   const std::string display_name("HP Z24i");
   const gfx::ColorSpace display_color_space = gfx::ColorSpace::CreateSRGB();
   const base::FilePath sys_path = base::FilePath::FromUTF8Unsafe("a/cb");
-  const int64_t product_id = 139;
+  const int64_t product_code = 139;
+  const int32_t year_of_manufacture = 2018;
 
   const DisplayMode display_mode(gfx::Size(1024, 768), false, 60.0f);
   const DisplayMode display_current_mode(gfx::Size(1440, 900), false, 59.89f);
@@ -345,7 +348,7 @@
       display_id, origin, physical_size, type, is_aspect_preserving_scaling,
       has_overscan, has_color_correction_matrix, display_color_space,
       display_name, sys_path, std::move(modes), edid, current_mode, native_mode,
-      product_id, maximum_cursor_size);
+      product_code, year_of_manufacture, maximum_cursor_size);
 
   std::unique_ptr<DisplaySnapshot> output;
   SerializeAndDeserialize<mojom::DisplaySnapshot>(input->Clone(), &output);
@@ -367,7 +370,8 @@
       gfx::ColorSpace::CreateDisplayP3D65();
   const std::string display_name("");
   const base::FilePath sys_path;
-  const int64_t product_id = 139;
+  const int64_t product_code = 139;
+  const int32_t year_of_manufacture = 2018;
 
   const DisplayMode display_mode(gfx::Size(2560, 1700), false, 95.96f);
 
@@ -382,7 +386,7 @@
       display_id, origin, physical_size, type, is_aspect_preserving_scaling,
       has_overscan, has_color_correction_matrix, display_color_space,
       display_name, sys_path, std::move(modes), edid, current_mode, native_mode,
-      product_id, maximum_cursor_size);
+      product_code, year_of_manufacture, maximum_cursor_size);
 
   std::unique_ptr<DisplaySnapshot> output;
   SerializeAndDeserialize<mojom::DisplaySnapshot>(input->Clone(), &output);
diff --git a/ui/display/types/display_constants.h b/ui/display/types/display_constants.h
index 7ef274f..75baacb 100644
--- a/ui/display/types/display_constants.h
+++ b/ui/display/types/display_constants.h
@@ -16,6 +16,9 @@
 // Display ID for a virtual display assigned to a unified desktop.
 constexpr int64_t kUnifiedDisplayId = -10;
 
+// Invalid year of manufacture of the display.
+constexpr int32_t kInvalidYearOfManufacture = -1;
+
 // Used to describe the state of a multi-display configuration.
 enum MultipleDisplayState {
   MULTIPLE_DISPLAY_STATE_INVALID,
diff --git a/ui/display/types/display_snapshot.cc b/ui/display/types/display_snapshot.cc
index fd5c6aa..b8586ff 100644
--- a/ui/display/types/display_snapshot.cc
+++ b/ui/display/types/display_snapshot.cc
@@ -74,7 +74,8 @@
                                  const std::vector<uint8_t>& edid,
                                  const DisplayMode* current_mode,
                                  const DisplayMode* native_mode,
-                                 int64_t product_id,
+                                 int64_t product_code,
+                                 int32_t year_of_manufacture,
                                  const gfx::Size& maximum_cursor_size)
     : display_id_(display_id),
       origin_(origin),
@@ -90,7 +91,8 @@
       edid_(edid),
       current_mode_(current_mode),
       native_mode_(native_mode),
-      product_id_(product_id),
+      product_code_(product_code),
+      year_of_manufacture_(year_of_manufacture),
       maximum_cursor_size_(maximum_cursor_size) {
   // We must explicitly clear out the bytes that represent the serial number.
   const size_t end =
@@ -122,20 +124,21 @@
       is_aspect_preserving_scaling_, has_overscan_,
       has_color_correction_matrix_, color_space_, display_name_, sys_path_,
       std::move(clone_modes), edid_, cloned_current_mode, cloned_native_mode,
-      product_id_, maximum_cursor_size_);
+      product_code_, year_of_manufacture_, maximum_cursor_size_);
 }
 
 std::string DisplaySnapshot::ToString() const {
   return base::StringPrintf(
       "id=%" PRId64
       " current_mode=%s native_mode=%s origin=%s"
-      " physical_size=%s, type=%s name=\"%s\" modes=(%s)",
+      " physical_size=%s, type=%s name=\"%s\" (year:%d) "
+      "modes=(%s)",
       display_id_,
       current_mode_ ? current_mode_->ToString().c_str() : "nullptr",
       native_mode_ ? native_mode_->ToString().c_str() : "nullptr",
       origin_.ToString().c_str(), physical_size_.ToString().c_str(),
       DisplayConnectionTypeString(type_).c_str(), display_name_.c_str(),
-      ModeListString(modes_).c_str());
+      year_of_manufacture_, ModeListString(modes_).c_str());
 }
 
 // static
diff --git a/ui/display/types/display_snapshot.h b/ui/display/types/display_snapshot.h
index cbb518fd9..5489277 100644
--- a/ui/display/types/display_snapshot.h
+++ b/ui/display/types/display_snapshot.h
@@ -43,7 +43,8 @@
                   const std::vector<uint8_t>& edid,
                   const DisplayMode* current_mode,
                   const DisplayMode* native_mode,
-                  int64_t product_id,
+                  int64_t product_code,
+                  int32_t year_of_manufacture,
                   const gfx::Size& maximum_cursor_size);
   virtual ~DisplaySnapshot();
 
@@ -67,7 +68,8 @@
   const DisplayMode* current_mode() const { return current_mode_; }
   void set_current_mode(const DisplayMode* mode) { current_mode_ = mode; }
   const DisplayMode* native_mode() const { return native_mode_; }
-  int64_t product_id() const { return product_id_; }
+  int64_t product_code() const { return product_code_; }
+  int32_t year_of_manufacture() const { return year_of_manufacture_; }
   const gfx::Size& maximum_cursor_size() const { return maximum_cursor_size_; }
 
   void add_mode(const DisplayMode* mode) { modes_.push_back(mode->Clone()); }
@@ -78,8 +80,8 @@
   // Returns a textual representation of this display state.
   std::string ToString() const;
 
-  // Used when no product id known.
-  static const int64_t kInvalidProductID = -1;
+  // Used when no |product_code_| known.
+  static const int64_t kInvalidProductCode = -1;
 
   // Returns the buffer format to be used for the primary plane buffer.
   static gfx::BufferFormat PrimaryFormat();
@@ -120,8 +122,10 @@
   // "Best" mode supported by the output.
   const DisplayMode* const native_mode_;
 
-  // Combination of manufacturer and product code.
-  const int64_t product_id_;
+  // Combination of manufacturer id and product id.
+  const int64_t product_code_;
+
+  const int32_t year_of_manufacture_;
 
   // Maximum supported cursor size on this display.
   const gfx::Size maximum_cursor_size_;
diff --git a/ui/display/util/edid_parser.cc b/ui/display/util/edid_parser.cc
index 8b310db..1bb9fca1 100644
--- a/ui/display/util/edid_parser.cc
+++ b/ui/display/util/edid_parser.cc
@@ -10,6 +10,7 @@
 
 #include "base/hash.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/sys_byteorder.h"
 #include "third_party/skia/include/core/SkColorSpace.h"
 #include "ui/display/util/display_util.h"
@@ -20,10 +21,10 @@
 namespace {
 
 // Returns a 32-bit identifier for this model of display, using
-// |manufacturer_id| and |product_code|.
-uint32_t GetProductID(uint16_t manufacturer_id, uint16_t product_code) {
+// |manufacturer_id| and |product_id|.
+uint32_t GetProductCode(uint16_t manufacturer_id, uint16_t product_id) {
   return ((static_cast<uint32_t>(manufacturer_id) << 16) |
-          (static_cast<uint32_t>(product_code)));
+          (static_cast<uint32_t>(product_id)));
 }
 
 }  // namespace
@@ -31,13 +32,13 @@
 bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid,
                           uint8_t output_index,
                           int64_t* display_id_out,
-                          int64_t* product_id_out) {
+                          int64_t* product_code_out) {
   uint16_t manufacturer_id = 0;
-  uint16_t product_code = 0;
+  uint16_t product_id = 0;
   std::string product_name;
 
   // ParseOutputDeviceData fails if it doesn't have product_name.
-  ParseOutputDeviceData(edid, &manufacturer_id, &product_code, &product_name,
+  ParseOutputDeviceData(edid, &manufacturer_id, &product_id, &product_name,
                         nullptr, nullptr);
 
   if (manufacturer_id == 0)
@@ -50,16 +51,16 @@
   // An ID based on display's index will be assigned later if this call fails.
   *display_id_out =
       GenerateDisplayID(manufacturer_id, product_code_hash, output_index);
-  // |product_id_out| is 64-bit signed so it can store -1 as kInvalidProductID
+  // |product_code_out| is 64-bit signed so it can store -1 as kInvalidProductID
   // and not match a valid product id which will all be in the lowest 32-bits.
-  if (product_id_out)
-    *product_id_out = GetProductID(manufacturer_id, product_code);
+  if (product_code_out)
+    *product_code_out = GetProductCode(manufacturer_id, product_id);
   return true;
 }
 
 bool ParseOutputDeviceData(const std::vector<uint8_t>& edid,
                            uint16_t* manufacturer_id,
-                           uint16_t* product_code,
+                           uint16_t* product_id,
                            std::string* human_readable_name,
                            gfx::Size* active_pixel_out,
                            gfx::Size* physical_display_size_out) {
@@ -71,8 +72,8 @@
   //     the display name.
   constexpr size_t kManufacturerOffset = 8;
   constexpr size_t kManufacturerLength = 2;
-  constexpr size_t kProductCodeOffset = 10;
-  constexpr size_t kProductCodeLength = 2;
+  constexpr size_t kProductIdOffset = 10;
+  constexpr size_t kProductIdLength = 2;
   constexpr size_t kDescriptorOffset = 54;
   constexpr size_t kNumDescriptors = 4;
   constexpr size_t kDescriptorLength = 18;
@@ -91,14 +92,13 @@
         (edid[kManufacturerOffset] << 8) + edid[kManufacturerOffset + 1];
   }
 
-  if (product_code) {
-    if (edid.size() < kProductCodeOffset + kProductCodeLength) {
-      LOG(ERROR) << "Too short EDID data: manufacturer product code";
+  if (product_id) {
+    if (edid.size() < kProductIdOffset + kProductIdLength) {
+      LOG(ERROR) << "Too short EDID data: product id";
       return false;
     }
 
-    *product_code =
-        (edid[kProductCodeOffset] << 8) + edid[kProductCodeOffset + 1];
+    *product_id = (edid[kProductIdOffset] << 8) + edid[kProductIdOffset + 1];
   }
 
   if (human_readable_name)
@@ -186,6 +186,44 @@
   return true;
 }
 
+void SplitProductCodeInManufacturerIdAndProductId(int64_t product_code,
+                                                  uint16_t* manufacturer_id,
+                                                  uint16_t* product_id) {
+  DCHECK(manufacturer_id);
+  DCHECK(product_id);
+  // Undo GetProductCode() packing.
+  *product_id = product_code & 0xFFFF;
+  *manufacturer_id = (product_code >> 16) & 0xFFFF;
+}
+
+std::string ManufacturerIdToString(uint16_t manufacturer_id) {
+  // Constants are taken from "VESA Enhanced EDID Standard" Release A, Revision
+  // 2, Sep 2006, Sec 3.4.1 "ID Manufacturer Name: 2 Bytes". Essentially these
+  // are 3 5-bit ASCII characters packed in 2 bytes, where 1 means 'A', etc.
+  constexpr uint8_t kFiveBitAsciiMask = 0x1F;
+  constexpr char kFiveBitToAsciiOffset = 'A' - 1;
+  constexpr size_t kSecondLetterOffset = 5;
+  constexpr size_t kFirstLetterOffset = 10;
+
+  char out[4] = {};
+  out[2] = (manufacturer_id & kFiveBitAsciiMask) + kFiveBitToAsciiOffset;
+  out[1] = ((manufacturer_id >> kSecondLetterOffset) & kFiveBitAsciiMask) +
+           kFiveBitToAsciiOffset;
+  out[0] = ((manufacturer_id >> kFirstLetterOffset) & kFiveBitAsciiMask) +
+           kFiveBitToAsciiOffset;
+  return out;
+}
+
+std::string ProductIdToString(uint16_t product_id) {
+  // From "VESA Enhanced EDID Standard" Release A, Revision 2, Sep 2006, Sec
+  // 3.4.2 "ID Product Code: 2 Bytes": "The ID product code field, [...]
+  // contains a 2-byte manufacturer assigned product code. [...] The 2 byte
+  // number is stored in hex with the least significant byte listed first."
+  uint8_t lower_char = (product_id >> 8) & 0xFF;
+  uint8_t upper_char = product_id & 0xFF;
+  return base::StringPrintf("%02X%02X", upper_char, lower_char);
+}
+
 bool ParseOutputOverscanFlag(const std::vector<uint8_t>& edid, bool* flag) {
   // See http://en.wikipedia.org/wiki/Extended_display_identification_data
   // for the extension format of EDID.  Also see EIA/CEA-861 spec for
@@ -254,6 +292,28 @@
   return false;
 }
 
+DISPLAY_UTIL_EXPORT bool ParseYearOfManufacture(
+    const std::vector<uint8_t>& edid,
+    int32_t* year) {
+  // Constants are taken from "VESA Enhanced EDID Standard" Release A, Revision
+  // 2, Sep 2006, Sec 3.4.4 "Week and Year of Manufacture or Model Year: 2
+  // Bytes".
+  constexpr size_t kYearOfManufactureOffset = 17;
+  constexpr uint32_t kValidValueLowerBound = 0x10;
+  constexpr int32_t kYearOffset = 1990;
+
+  if (edid.size() < kYearOfManufactureOffset + 1) {
+    LOG(ERROR) << "Too short EDID data: year of manufacture";
+    return false;
+  }
+  const uint8_t byte_data = edid[kYearOfManufactureOffset];
+  if (byte_data < kValidValueLowerBound)
+    return false;
+  DCHECK(year);
+  *year = byte_data + kYearOffset;
+  return true;
+}
+
 bool ParseChromaticityCoordinates(const std::vector<uint8_t>& edid,
                                   SkColorSpacePrimaries* primaries) {
   DCHECK(primaries);
diff --git a/ui/display/util/edid_parser.h b/ui/display/util/edid_parser.h
index 17e67de..dfc23fd 100644
--- a/ui/display/util/edid_parser.h
+++ b/ui/display/util/edid_parser.h
@@ -25,15 +25,15 @@
 namespace display {
 
 // Generates the display id and product id for the pair of |edid| and |index|,
-// and store in |display_id_out| and |product_id_out|. Returns true if the
+// and store in |display_id_out| and |product_code_out|. Returns true if the
 // display id is successfully generated, or false otherwise.
 DISPLAY_UTIL_EXPORT bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid,
                                               uint8_t index,
                                               int64_t* display_id_out,
-                                              int64_t* product_id_out);
+                                              int64_t* product_code_out);
 
 // Parses |edid| as EDID data and stores extracted data into |manufacturer_id|,
-// |product_code|, |human_readable_name|, |active_pixel_out| and
+// |product_id|, |human_readable_name|, |active_pixel_out| and
 // |physical_display_size_out|, then returns true. nullptr can be passed for
 // unwanted output parameters.  Some devices (especially internal displays) may
 // not have the field for |human_readable_name|, and it will return true in
@@ -41,15 +41,33 @@
 DISPLAY_UTIL_EXPORT bool ParseOutputDeviceData(
     const std::vector<uint8_t>& edid,
     uint16_t* manufacturer_id,
-    uint16_t* product_code,
+    uint16_t* product_id,
     std::string* human_readable_name,
     gfx::Size* active_pixel_out,
     gfx::Size* physical_display_size_out);
 
+// Splits the |product_code| (as returned by GetDisplayIdFromEDID()) into its
+// constituents |manufacturer_id| and |product_id|.
+DISPLAY_UTIL_EXPORT void SplitProductCodeInManufacturerIdAndProductId(
+    int64_t product_code,
+    uint16_t* manufacturer_id,
+    uint16_t* product_id);
+
+// Extracts the three letter Manufacturer ID out of |manufacturer_id|.
+DISPLAY_UTIL_EXPORT std::string ManufacturerIdToString(
+    uint16_t manufacturer_id);
+
+// Extracts the 2 Byte Product ID as hex out of |product_id|.
+DISPLAY_UTIL_EXPORT std::string ProductIdToString(uint16_t product_id);
+
 DISPLAY_UTIL_EXPORT bool ParseOutputOverscanFlag(
     const std::vector<uint8_t>& edid,
     bool* flag);
 
+DISPLAY_UTIL_EXPORT bool ParseYearOfManufacture(
+    const std::vector<uint8_t>& edid,
+    int32_t* year);
+
 // Extracts from |edid| the |primaries| chromaticity coordinates (CIE xy
 // coordinates for Red, Green and Blue channels and for the White Point).
 DISPLAY_UTIL_EXPORT bool ParseChromaticityCoordinates(
diff --git a/ui/display/util/edid_parser_fuzzer.cc b/ui/display/util/edid_parser_fuzzer.cc
index 7ae1b8f..d1007e5 100644
--- a/ui/display/util/edid_parser_fuzzer.cc
+++ b/ui/display/util/edid_parser_fuzzer.cc
@@ -27,11 +27,13 @@
   std::string human_readable_name;
   gfx::Size active_pixel_size, physical_display_size;
   bool overscan;
+  int32_t year_of_manufacture;
 
   display::ParseOutputDeviceData(edid, &manufacturer_id, &product_code,
                                  &human_readable_name, &active_pixel_size,
                                  &physical_display_size);
 
   display::ParseOutputOverscanFlag(edid, &overscan);
+  display::ParseYearOfManufacture(edid, &year_of_manufacture);
   return 0;
 }
diff --git a/ui/display/util/edid_parser_unittest.cc b/ui/display/util/edid_parser_unittest.cc
index 7511a13..de024ae 100644
--- a/ui/display/util/edid_parser_unittest.cc
+++ b/ui/display/util/edid_parser_unittest.cc
@@ -241,6 +241,8 @@
   EXPECT_EQ("HP ZR30w", human_readable_name);
   EXPECT_EQ("2560x1600", pixel.ToString());
   EXPECT_EQ("641x400", size.ToString());
+  EXPECT_EQ(ManufacturerIdToString(manufacturer_id), "HWP");
+  EXPECT_EQ(ProductIdToString(product_code), "286C");
 
   manufacturer_id = 0;
   product_code = 0;
@@ -255,6 +257,8 @@
   EXPECT_EQ("", human_readable_name);
   EXPECT_EQ("1280x800", pixel.ToString());
   EXPECT_EQ("261x163", size.ToString());
+  EXPECT_EQ(ManufacturerIdToString(manufacturer_id), "SEC");
+  EXPECT_EQ(ProductIdToString(product_code), "3142");
 
   // Internal display doesn't have name.
   EXPECT_TRUE(ParseOutputDeviceData(edid, nullptr, nullptr,
@@ -273,6 +277,38 @@
   EXPECT_EQ("SAMSUNG", human_readable_name);
   EXPECT_EQ("1920x1080", pixel.ToString());
   EXPECT_EQ("160x90", size.ToString());
+  EXPECT_EQ(ManufacturerIdToString(manufacturer_id), "SAM");
+  EXPECT_EQ(ProductIdToString(product_code), "08FE");
+
+  manufacturer_id = 0;
+  product_code = 0;
+  human_readable_name.clear();
+  Reset(&pixel, &size);
+  edid.assign(kSamus, kSamus + charsize(kSamus));
+  EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, &product_code,
+                                    nullptr, &pixel, &size));
+  EXPECT_EQ(0x30E4u, manufacturer_id);
+  EXPECT_EQ(0x2E04u, product_code);
+  EXPECT_EQ("", human_readable_name);
+  EXPECT_EQ("2560x1700", pixel.ToString());
+  EXPECT_EQ("272x181", size.ToString());
+  EXPECT_EQ(ManufacturerIdToString(manufacturer_id), "LGD");
+  EXPECT_EQ(ProductIdToString(product_code), "042E");
+
+  manufacturer_id = 0;
+  product_code = 0;
+  human_readable_name.clear();
+  Reset(&pixel, &size);
+  edid.assign(kEve, kEve + charsize(kEve));
+  EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, &product_code,
+                                    nullptr, &pixel, &size));
+  EXPECT_EQ(0x4D10u, manufacturer_id);
+  EXPECT_EQ(0x8A14u, product_code);
+  EXPECT_EQ("", human_readable_name);
+  EXPECT_EQ("2400x1600", pixel.ToString());
+  EXPECT_EQ("259x173", size.ToString());
+  EXPECT_EQ(ManufacturerIdToString(manufacturer_id), "SHP");
+  EXPECT_EQ(ProductIdToString(product_code), "148A");
 }
 
 TEST(EDIDParserTest, ParseBrokenEDID) {
@@ -398,6 +434,37 @@
                       kEvePrimaries);
 }
 
+TEST(EDIDParserTest, ParseYearOfManufacture) {
+  const std::vector<uint8_t> edid_normal_display(
+      kNormalDisplay, kNormalDisplay + charsize(kNormalDisplay));
+  int32_t edid_normal_display_year = 0;
+  EXPECT_TRUE(
+      ParseYearOfManufacture(edid_normal_display, &edid_normal_display_year));
+  EXPECT_EQ(2012, edid_normal_display_year);
+
+  const std::vector<uint8_t> edid_internal_display(
+      kInternalDisplay, kInternalDisplay + charsize(kInternalDisplay));
+  int32_t edid_internal_display_year = 0;
+  EXPECT_TRUE(ParseYearOfManufacture(edid_internal_display,
+                                     &edid_internal_display_year));
+  EXPECT_EQ(2011, edid_internal_display_year);
+
+  const std::vector<uint8_t> edid_hpz32x(kHPz32x, kHPz32x + charsize(kHPz32x));
+  int32_t edid_hpz32x_year = 0;
+  EXPECT_TRUE(ParseYearOfManufacture(edid_hpz32x, &edid_hpz32x_year));
+  EXPECT_EQ(2017, edid_hpz32x_year);
+
+  const std::vector<uint8_t> edid_samus(kSamus, kSamus + charsize(kSamus));
+  int32_t edid_samus_year = 0;
+  EXPECT_TRUE(ParseYearOfManufacture(edid_samus, &edid_samus_year));
+  EXPECT_EQ(2014, edid_samus_year);
+
+  const std::vector<uint8_t> edid_eve(kEve, kEve + charsize(kEve));
+  int32_t edid_eve_year = 0;
+  EXPECT_TRUE(ParseYearOfManufacture(edid_eve, &edid_eve_year));
+  EXPECT_EQ(2017, edid_eve_year);
+}
+
 TEST(EDIDParserTest, ParseGammaValue) {
   const std::vector<uint8_t> edid_normal_display(
       kNormalDisplay, kNormalDisplay + charsize(kNormalDisplay));
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc
index e9dd5025..6d779108 100644
--- a/ui/events/blink/input_handler_proxy.cc
+++ b/ui/events/blink/input_handler_proxy.cc
@@ -765,7 +765,12 @@
         return DID_HANDLE;
       case cc::InputHandler::SCROLL_IGNORED:
         return DROP_EVENT;
-      default:
+      case cc::InputHandler::SCROLL_ON_MAIN_THREAD:
+      case cc::InputHandler::SCROLL_UNKNOWN:
+        if (input_handler_->ScrollingShouldSwitchtoMainThread()) {
+          gesture_scroll_on_impl_thread_ = false;
+          client_->GenerateScrollBeginAndSendToMainThread(gesture_event);
+        }
         return DID_NOT_HANDLE;
     }
   }
diff --git a/ui/file_manager/file_manager/test/BUILD.gn b/ui/file_manager/file_manager/test/BUILD.gn
new file mode 100644
index 0000000..57025d1b4
--- /dev/null
+++ b/ui/file_manager/file_manager/test/BUILD.gn
@@ -0,0 +1,12 @@
+# 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.
+
+action("create_test_main") {
+  script = "//ui/file_manager/file_manager/test/scripts/create_test_main.py"
+  output = "$target_gen_dir/main.html"
+  args = [ "--output=" + rebase_path(output, root_build_dir) ]
+  outputs = [
+    output,
+  ]
+}
diff --git a/ui/file_manager/file_manager/test/delete.js b/ui/file_manager/file_manager/test/delete.js
new file mode 100644
index 0000000..22c36d9
--- /dev/null
+++ b/ui/file_manager/file_manager/test/delete.js
@@ -0,0 +1,72 @@
+// 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.
+
+function testDeleteMenuItemIsDisabledWhenNoItemIsSelected(done) {
+  setupAndWaitUntilReady()
+      .then(detailTable => {
+        return waitForElement('list.list');
+      })
+      .then(emptySpace => {
+        assertTrue(test.util.sync.fakeMouseRightClick(window, 'list.list'));
+        return waitForElement('#file-context-menu:not([hidden])');
+      })
+      .then(result => {
+        return waitForElement(
+            'cr-menu-item[command="#delete"][disabled="disabled"]');
+      })
+      .then(result => {
+        done();
+      })
+      .catch(err => {
+        console.error(err);
+        done(true);
+      });
+}
+
+function testDeleteOneItemFromToolbar(done) {
+  var beforeDeletion = TestEntryInfo.getExpectedRows([
+      ENTRIES.photos,
+      ENTRIES.hello,
+      ENTRIES.world,
+      ENTRIES.desktop,
+      ENTRIES.beautiful
+  ]);
+
+  var afterDeletion = TestEntryInfo.getExpectedRows([
+      ENTRIES.photos,
+      ENTRIES.hello,
+      ENTRIES.world,
+      ENTRIES.beautiful
+  ]);
+
+  setupAndWaitUntilReady()
+      .then(detailTable => {
+        return waitForFiles(beforeDeletion);
+      })
+      .then(result => {
+        return test.util.sync.selectFile(window, 'My Desktop Background.png');
+      })
+      .then(result => {
+        assertTrue(result);
+        return test.util.sync.fakeMouseClick(window, 'button#delete-button');
+      })
+      .then(result => {
+        assertTrue(result);
+        return waitForElement('.cr-dialog-container.shown');
+      })
+      .then(result => {
+        return test.util.sync.fakeMouseClick(window, 'button.cr-dialog-ok');
+      })
+      .then(result => {
+        assertTrue(result);
+        return waitForFiles(afterDeletion);
+      })
+      .then(result => {
+        done();
+      })
+      .catch(err => {
+        console.error(err);
+        done(err);
+      });
+}
diff --git a/ui/file_manager/file_manager/test/js/chrome_api_test_impl.js b/ui/file_manager/file_manager/test/js/chrome_api_test_impl.js
index 76eb54b..eada5e1 100644
--- a/ui/file_manager/file_manager/test/js/chrome_api_test_impl.js
+++ b/ui/file_manager/file_manager/test/js/chrome_api_test_impl.js
@@ -26,7 +26,6 @@
   commandLinePrivate: {
     switches_: {},
     hasSwitch: (name, callback) => {
-      console.debug('chrome.commandLinePrivate.hasSwitch called', name);
       setTimeout(callback, 0, chrome.commandLinePrivate.switches_[name]);
     },
   },
@@ -40,7 +39,6 @@
 
   echoPrivate: {
     getOfferInfo: (id, callback) => {
-      console.debug('chrome.echoPrivate.getOfferInfo called', id);
       setTimeout(() => {
         // checkSpaceAndMaybeShowWelcomeBanner_ relies on lastError being set.
         chrome.runtime.lastError = {message: 'Not found'};
@@ -52,7 +50,6 @@
 
   extension: {
     getViews: (fetchProperties) => {
-      console.debug('chrome.extension.getViews called', fetchProperties);
       // Returns Window[].
       return [window];
     },
@@ -65,11 +62,18 @@
     },
   },
 
+  i18n: {
+    getMessage: (messageName, opt_substitutions) => {
+      return messageName;
+    },
+  },
+
   metricsPrivate: {
     MetricTypeType: {
       HISTOGRAM_LINEAR: 'histogram-linear',
     },
     recordMediumCount: () => {},
+    recordPercentage: () => {},
     recordSmallCount: () => {},
     recordTime: () => {},
     recordUserAction: () => {},
@@ -97,19 +101,31 @@
     onMessageExternal: {
       addListener: () => {},
     },
+    sendMessage: (extensionId, message, options, opt_callback) => {
+      // Returns JSON.
+      if (opt_callback)
+        setTimeout(opt_callback(''), 0);
+    },
   },
 
   storage: {
+    state: {},
     local: {
       get: (keys, callback) => {
-        console.debug('chrome.storage.local.get', keys);
-        setTimeout(callback, 0, {});
+        var keys = keys instanceof Array ? keys : [keys];
+        var result = {};
+        keys.forEach(function(key) {
+          if (key in chrome.storage.state)
+            result[key] = chrome.storage.state[key];
+        });
+        setTimeout(callback, 0, result);
       },
-      set: (items, callback) => {
-        console.debug('chrome.storage.local.set', items);
-        if (callback) {
-          setTimeout(callback, 0);
+      set: (items, opt_callback) => {
+        for (var key in items) {
+          chrome.storage.state[key] = items[key];
         }
+        if (opt_callback)
+          setTimeout(opt_callback, 0);
       },
     },
     onChanged: {
@@ -117,7 +133,6 @@
     },
     sync: {
       get: (keys, callback) => {
-        console.debug('chrome.storage.sync.get', keys);
         setTimeout(callback, 0, {});
       }
     },
@@ -128,14 +143,17 @@
 // a WebView.  It calls WebView.request.onBeforeSendHeaders.
 HTMLElement.prototype.request = {
   onBeforeSendHeaders: {
-    addListener: () => {
-      console.debug(
-          'HTMLElement.request.onBeforeSendHeaders.addListener called');
-    },
+    addListener: () => {},
   },
 };
 
 // cws_widget_container.js also calls WebView.stop.
-HTMLElement.prototype.stop = () => {
-  console.debug('HTMLElement.stop called');
+HTMLElement.prototype.stop = () => {};
+
+// domAutomationController is provided in tests, but is
+// useful for debugging tests in browser.
+window.domAutomationController = window.domAutomationController || {
+  send: msg => {
+    console.debug('domAutomationController.send', msg);
+  },
 };
diff --git a/ui/file_manager/file_manager/test/js/chrome_file_manager.js b/ui/file_manager/file_manager/test/js/chrome_file_manager.js
index 11a746d..c190ed79 100644
--- a/ui/file_manager/file_manager/test/js/chrome_file_manager.js
+++ b/ui/file_manager/file_manager/test/js/chrome_file_manager.js
@@ -7,17 +7,19 @@
 // running as a regular web page, we must provide test implementations.
 
 mockVolumeManager = new MockVolumeManager();
-mockVolumeManager
-    .getCurrentProfileVolumeInfo(VolumeManagerCommon.VolumeType.DOWNLOADS)
-    .fileSystem.populate(
-        ['/New Folder/', '/a.txt', '/kittens.jpg', '/unknown.ext']);
+
+// Create drive /root/ immediately.
 mockVolumeManager
     .getCurrentProfileVolumeInfo(VolumeManagerCommon.VolumeType.DRIVE)
-    .fileSystem.populate(
-        ['/root/New Folder/', '/root/a.txt', '/root/kittens.jpg']);
+    .fileSystem.populate(['/root/']);
 
 chrome.fileManagerPrivate = {
   currentId_: 'test@example.com',
+  dispatchEvent_: function(listenerType, event) {
+    setTimeout(() => {
+      this[listenerType].listeners_.forEach(l => l.call(null, event));
+    }, 0);
+  },
   displayedId_: 'test@example.com',
   preferences_: {
     allowRedeemOffers: true,
@@ -28,6 +30,9 @@
     timezone: 'Australia/Sydney',
     use24hourClock: false,
   },
+  listeners_: {
+    'onDirectoryChanged': [],
+  },
   profiles_: [{
     displayName: 'Test User',
     isCurrentProfile: true,
@@ -40,67 +45,60 @@
     NATIVE_SOURCE: 'native_source',
   },
   addFileWatch: (entry, callback) => {
-    console.debug('c.fmp.addFileWatch called', entry);
+    // Returns success.
     setTimeout(callback, 0, true);
   },
-  enableExternalFileScheme: () => {
-    console.debug('c.fmp.enableExternalFileScheme called');
-  },
+  enableExternalFileScheme: () => {},
   executeTask: (taskId, entries, callback) => {
-    console.debug('c.fmp.executeTask called', taskId, entries);
     // Returns opened|message_sent|failed|empty.
     setTimeout(callback, 0, 'failed');
   },
   getDriveConnectionState: (callback) => {
-    console.debug('c.fmp.getDriveConnectionState called');
     setTimeout(callback, 0, mockVolumeManager.getDriveConnectionState());
   },
   getEntryProperties: (entries, names, callback) => {
-    console.debug('c.fmp.getEntryProperties called', entries, names);
     // Returns EntryProperties[].
     var results = [];
-    for (var i = 0; i < entries.length; i++) {
-      results.push({});
-    }
+    entries.forEach(entry => {
+      var props = {};
+      names.forEach(name => {
+        props[name] = entry.metadata[name];
+      });
+      results.push(props);
+    });
     setTimeout(callback, 0, results);
   },
   getFileTasks: (entries, callback) => {
-    console.debug('c.fmp.getFileTasks called', entries);
     // Returns FileTask[].
     setTimeout(callback, 0, []);
   },
   getPreferences: (callback) => {
-    console.debug('c.fmp.getPreferences called');
     setTimeout(callback, 0, chrome.fileManagerPrivate.preferences_);
   },
   getProfiles: (callback) => {
-    console.debug('c.fmp.getProfiles called');
+    // Returns profiles, currentId, displayedId
     setTimeout(
         callback, 0, chrome.fileManagerPrivate.profiles_,
         chrome.fileManagerPrivate.currentId_,
         chrome.fileManagerPrivate.displayedId_);
   },
   getProviders: (callback) => {
-    console.debug('c.fmp.getProviders called');
     // Returns Provider[].
     setTimeout(callback, 0, []);
   },
   getRecentFiles: (restriction, callback) => {
-    console.debug('c.fmp.getRecentFiles called', restriction);
     // Returns Entry[].
     setTimeout(callback, 0, []);
   },
   getSizeStats: (volumeId, callback) => {
-    console.debug('c.fmp.getSizeStats called', volumeId);
     // MountPointSizeStats { totalSize: double,  remainingSize: double }
     setTimeout(callback, 0, {totalSize: 16e9, remainingSize: 8e9});
   },
   getStrings: (callback) => {
-    console.debug('c.fmp.getStrings called');
+    // Returns map of strings.
     setTimeout(callback, 0, loadTimeData.data_);
   },
   getVolumeMetadataList: (callback) => {
-    console.debug('c.fmp.getVolumeMetadatalist called');
     var list = [];
     for (var i = 0; i < mockVolumeManager.volumeInfoList.length; i++) {
       list.push(mockVolumeManager.volumeInfoList.item(i));
@@ -108,80 +106,70 @@
     setTimeout(callback, 0, list);
   },
   grantAccess: (entryUrls, callback) => {
-    console.debug('c.fmp.grantAccess called', entryUrls);
     setTimeout(callback, 0);
   },
   isUMAEnabled: (callback) => {
-    console.debug('c.fmp.isUMAEnabled called');
     setTimeout(callback, 0, false);
   },
   onAppsUpdated: {
-    addListener: () => {
-      console.debug('c.fmp.onAppsUpdated.addListener called');
-    },
+    addListener: () => {},
   },
   onDeviceChanged: {
-    addListener: () => {
-      console.debug('c.fmp.onDeviceChanged.addListener called');
-    },
+    addListener: () => {},
   },
   onDirectoryChanged: {
-    addListener: () => {
-      console.debug('c.fmp.onDirectoryChanged.addListener called');
+    listeners_: [],
+    addListener: function(l) {
+      this.listeners_.push(l);
     },
   },
   onDriveConnectionStatusChanged: {
-    addListener: () => {
-      console.debug('c.fmp.onDriveConnectionStatusChanged.addListener called');
-    },
+    addListener: () => {},
   },
   onDriveSyncError: {
-    addListener: () => {
-      console.debug('c.fmp.onDriveSyncError.addListener called');
-    },
+    addListener: () => {},
   },
   onFileTransfersUpdated: {
-    addListener: () => {
-      console.debug('c.fmp.onFileTransfersUpdated.addListener called');
-    },
+    addListener: () => {},
   },
   onMountCompleted: {
-    addListener: () => {
-      console.debug('c.fmp.onMountCompleted.addListener called');
-    },
+    addListener: () => {},
   },
   onPreferencesChanged: {
-    addListener: () => {
-      console.debug('c.fmp.onPreferencesChanged.addListener called');
-    },
+    addListener: () => {},
   },
   removeFileWatch: (entry, callback) => {
-    console.debug('c.fmp.removeFileWatch called', entry);
     setTimeout(callback, 0, true);
   },
   requestWebStoreAccessToken: (callback) => {
-    console.debug('c.fmp.requestWebStoreAccessToken called');
     setTimeout(callback, 0, chrome.fileManagerPrivate.token_);
   },
   resolveIsolatedEntries: (entries, callback) => {
-    console.debug('c.fmp.resolveIsolatedEntries called', entries);
     setTimeout(callback, 0, entries);
   },
   searchDriveMetadata: (searchParams, callback) => {
-    console.debug('c.fmp.searchDriveMetadata called', searchParams);
     // Returns SearchResult[].
     // SearchResult { entry: Entry, highlightedBaseName: string }
     setTimeout(callback, 0, []);
   },
   validatePathNameLength: (parentEntry, name, callback) => {
-    console.debug('c.fmp.validatePathNameLength called', parentEntry, name);
     setTimeout(callback, 0, true);
   },
 };
 
+chrome.mediaGalleries = {
+  getMetadata: (mediaFile, options, callback) => {
+    // Returns metdata {mimeType: ..., ...}.
+    setTimeout(() => {
+      webkitResolveLocalFileSystemURL(mediaFile.name, entry => {
+        callback({mimeType: entry.metadata.contentMimeType});
+      }, 0);
+    });
+  },
+};
+
 chrome.fileSystem = {
   requestFileSystem: (options, callback) => {
-    console.debug('chrome.fileSystem.requestFileSystem called', options);
     var volume =
         mockVolumeManager.volumeInfoList.findByVolumeId(options.volumeId);
     setTimeout(callback, 0, volume ? volume.fileSystem : null);
@@ -195,13 +183,14 @@
  * @param {function(!DOMException)} errorCallback Error callback.
  */
 webkitResolveLocalFileSystemURL = (url, successCallback, errorCallback) => {
-  console.debug('webkitResolveLocalFileSystemURL', url);
   var match = url.match(/^filesystem:(\w+)(\/.*)/);
   if (match) {
     var volumeType = match[1];
     var path = match[2];
     var volume = mockVolumeManager.getCurrentProfileVolumeInfo(volumeType);
     if (volume) {
+      // Decode URI in file paths.
+      path = path.split('/').map(decodeURIComponent).join('/');
       var entry = volume.fileSystem.entries[path];
       if (entry) {
         setTimeout(successCallback, 0, entry);
diff --git a/ui/file_manager/file_manager/test/js/strings.js b/ui/file_manager/file_manager/test/js/strings.js
index e0a45d02..76ee406 100644
--- a/ui/file_manager/file_manager/test/js/strings.js
+++ b/ui/file_manager/file_manager/test/js/strings.js
@@ -9,12 +9,14 @@
 
 loadTimeData.data = new Proxy(
     {
+      AUDIO_FILE_TYPE: '$1 audio',
       CANCEL_LABEL: 'Cancel',
       CHROMEOS_RELEASE_BOARD: 'unknown',
       COPY_ITEMS_REMAINING: 'Copying $1 items...',
       DEFAULT_NEW_FOLDER_NAME: 'New Folder',
       DELETE_FILE_NAME: 'Deleting "$1"...',
       DOWNLOADS_DIRECTORY_LABEL: 'Downloads',
+      DATE_COLUMN_LABEL: 'Date modified',
       DRIVE_BUY_MORE_SPACE: 'Buy more storage...',
       DRIVE_DIRECTORY_LABEL: 'Google Drive',
       DRIVE_MENU_HELP: 'Help',
@@ -40,22 +42,34 @@
       EMPTY_FOLDER: 'Nothing to see here...',
       FILENAME_LABEL: 'File name',
       GALLERY_CONFIRM_DELETE_ONE: 'Are you sure you want to delete "$1"?',
+      GDOC_DOCUMENT_FILE_TYPE: 'Google document',
+      GENERIC_FILE_TYPE: '$1 file',
       GOOGLE_DRIVE_REDEEM_URL: 'http://www.google.com/intl/en/chrome/' +
           'devices/goodies.html?utm_source=filesapp&utm_medium=banner&' +
           'utm_campaign=gsg',
       IMAGE_FILE_TYPE: '$1 image',
       INSTALL_NEW_EXTENSION_LABEL: 'Install new from the webstore',
+      MANY_ENTRIES_SELECTED: '$1 items selected',
       MANY_FILES_SELECTED: '$1 files selected',
+      NAME_COLUMN_LABEL: 'Name',
+      OFFLINE_COLUMN_LABEL: 'Available offline',
       OK_LABEL: 'OK',
+      ONE_DIRECTORY_SELECTED: '1 folder selected',
       ONE_FILE_SELECTED: '1 file selected',
       OPEN_LABEL: 'Open',
+      PLAIN_TEXT_FILE_TYPE: 'Plain text',
       PREPARING_LABEL: 'Preparing',
+      SIZE_COLUMN_LABEL: 'Size',
       SPACE_AVAILABLE: '$1 available',
+      STATUS_COLUMN_LABEL: 'Status',
+      TYPE_COLUMN_LABEL: 'Type',
       UI_LOCALE: 'en_US',
       RECENT_ROOT_LABEL: 'Recent',
       SEARCH_TEXT_LABEL: 'Search',
       SIZE_BYTES: '$1 bytes',
       SIZE_GB: '$1 GB',
+      SIZE_KB: '$1 KB',
+      SIZE_PB: '$1 PB',
       SUGGEST_DIALOG_INSTALLATION_FAILED: 'Installation failed.',
       SUGGEST_DIALOG_INSTALLING_SPINNER_ALT: 'Installing',
       SUGGEST_DIALOG_LINK_TO_WEBSTORE: 'See more...',
@@ -63,6 +77,7 @@
       SUGGEST_DIALOG_TITLE: 'Select an app to open this file',
       TASK_OPEN: 'Open',
       TOGGLE_HIDDEN_FILES_COMMAND_LABEL: 'Show hidden files',
+      VIDEO_FILE_TYPE: '$1 video',
       WAITING_FOR_SPACE_INFO: 'Waiting for space info...',
       language: 'en',
       textdirection: 'ltr',
@@ -84,8 +99,6 @@
           /^SHORTCUT_/,
           /_BUTTON_LABEL$/,
           /_BUTTON_TOOLTIP$/,
-          /_COLUMN_LABEL$/,
-          /_FILE_TYPE$/,
         ];
         for (var i = 0; i < autoConvert.length; i++) {
           if (prop.match(autoConvert[i])) {
diff --git a/ui/file_manager/file_manager/test/js/test_util.js b/ui/file_manager/file_manager/test/js/test_util.js
new file mode 100644
index 0000000..c482169
--- /dev/null
+++ b/ui/file_manager/file_manager/test/js/test_util.js
@@ -0,0 +1,395 @@
+// Copyright 2018 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.
+
+'use strict';
+
+// Stores Blobs loaded from src/chrome/test/data/chromeos/file_manager.
+var DATA = {
+  'archive.zip': null,
+  'image.png': null,
+  'image2.png': null,
+  'image3.jpg': null,
+  'music.ogg': null,
+  'random.bin': null,
+  'text.txt': null,
+  'video.ogv': null,
+};
+
+// Load DATA from local filesystem.
+function loadData() {
+  return Promise.all(Object.keys(DATA).map(filename => {
+    return new Promise(resolve => {
+      var req = new XMLHttpRequest();
+      req.responseType = 'blob';
+      req.onload = () => {
+        DATA[filename] = req.response;
+        resolve();
+      };
+      req.open(
+          'GET',
+          '../../../../chrome/test/data/chromeos/file_manager/' + filename);
+      req.send();
+    });
+  }));
+}
+
+/**
+ * @enum {string}
+ * @const
+ */
+var EntryType = Object.freeze({
+  FILE: 'file',
+  DIRECTORY: 'directory'
+});
+
+/**
+ * @enum {string}
+ * @const
+ */
+var SharedOption = Object.freeze({
+  NONE: 'none',
+  SHARED: 'shared'
+});
+
+/**
+ * File system entry information for tests.
+ *
+ * @param {EntryType} type Entry type.
+ * @param {string} sourceFileName Source file name that provides file contents.
+ * @param {string} targetName Name of entry on the test file system.
+ * @param {string} mimeType Mime type.
+ * @param {SharedOption} sharedOption Shared option.
+ * @param {string} lastModifiedTime Last modified time as a text to be shown in
+ *     the last modified column.
+ * @param {string} nameText File name to be shown in the name column.
+ * @param {string} sizeText Size text to be shown in the size column.
+ * @param {string} typeText Type name to be shown in the type column.
+ * @constructor
+ */
+function TestEntryInfo(type,
+                       sourceFileName,
+                       targetPath,
+                       mimeType,
+                       sharedOption,
+                       lastModifiedTime,
+                       nameText,
+                       sizeText,
+                       typeText) {
+  this.type = type;
+  this.sourceFileName = sourceFileName || '';
+  this.targetPath = targetPath;
+  this.mimeType = mimeType || '';
+  this.sharedOption = sharedOption;
+  this.lastModifiedTime = lastModifiedTime;
+  this.nameText = nameText;
+  this.sizeText = sizeText;
+  this.typeText = typeText;
+  Object.freeze(this);
+}
+
+TestEntryInfo.getExpectedRows = function(entries) {
+  return entries.map(function(entry) { return entry.getExpectedRow(); });
+};
+
+/**
+ * Returns 4-typle name, size, type, date as shown in file list.
+ */
+TestEntryInfo.prototype.getExpectedRow = function() {
+  return [this.nameText, this.sizeText, this.typeText, this.lastModifiedTime];
+};
+
+TestEntryInfo.getMockFileSystemPopulateRows = function(entries, prefix) {
+  return entries.map(function(entry) {
+    return entry.getMockFileSystemPopulateRow(prefix);
+  });
+};
+
+/**
+ * Returns object {fullPath: ..., metadata: {...}, content: ...} as used in
+ * MockFileSystem.populate.
+ */
+TestEntryInfo.prototype.getMockFileSystemPopulateRow = function(prefix) {
+  var suffix = this.type == EntryType.DIRECTORY ? '/' : '';
+  var content = DATA[this.sourceFileName];
+  var size = content && content.size || 0;
+  return {
+    fullPath: prefix + this.nameText + suffix,
+    metadata: {
+      size: size,
+      modificationTime: new Date(Date.parse(this.lastModifiedTime)),
+      contentMimeType: this.mimeType,
+    },
+    content: content
+  };
+};
+
+/**
+ * Filesystem entries used by the test cases.
+ * @type {Object<TestEntryInfo>}
+ * @const
+ */
+var ENTRIES = {
+  hello: new TestEntryInfo(
+      EntryType.FILE, 'text.txt', 'hello.txt',
+      'text/plain', SharedOption.NONE, 'Sep 4, 1998, 12:34 PM',
+      'hello.txt', '51 bytes', 'Plain text'),
+
+  world: new TestEntryInfo(
+      EntryType.FILE, 'video.ogv', 'world.ogv',
+      'video/ogg', SharedOption.NONE, 'Jul 4, 2012, 10:35 AM',
+      'world.ogv', '59 KB', 'OGG video'),
+
+  unsupported: new TestEntryInfo(
+      EntryType.FILE, 'random.bin', 'unsupported.foo',
+      'application/x-foo', SharedOption.NONE, 'Jul 4, 2012, 10:36 AM',
+      'unsupported.foo', '8 KB', 'FOO file'),
+
+  desktop: new TestEntryInfo(
+      EntryType.FILE, 'image.png', 'My Desktop Background.png',
+      'image/png', SharedOption.NONE, 'Jan 18, 2038, 1:02 AM',
+      'My Desktop Background.png', '272 bytes', 'PNG image'),
+
+  // An image file without an extension, to confirm that file type detection
+  // using mime types works fine.
+  image2: new TestEntryInfo(
+      EntryType.FILE, 'image2.png', 'image2',
+      'image/png', SharedOption.NONE, 'Jan 18, 2038, 1:02 AM',
+      'image2', '4 KB', 'PNG image'),
+
+  image3: new TestEntryInfo(
+      EntryType.FILE, 'image3.jpg', 'image3.jpg',
+      'image/jpeg', SharedOption.NONE, 'Jan 18, 2038, 1:02 AM',
+      'image3.jpg', '3 KB', 'JPEG image'),
+
+  // An ogg file without a mime type, to confirm that file type detection using
+  // file extensions works fine.
+  beautiful: new TestEntryInfo(
+      EntryType.FILE, 'music.ogg', 'Beautiful Song.ogg',
+      null, SharedOption.NONE, 'Nov 12, 2086, 12:00 PM',
+      'Beautiful Song.ogg', '14 KB', 'OGG audio'),
+
+  photos: new TestEntryInfo(
+      EntryType.DIRECTORY, null, 'photos',
+      null, SharedOption.NONE, 'Jan 1, 1980, 11:59 PM',
+      'photos', '--', 'Folder'),
+
+  testDocument: new TestEntryInfo(
+      EntryType.FILE, null, 'Test Document',
+      'application/vnd.google-apps.document',
+      SharedOption.NONE, 'Apr 10, 2013, 4:20 PM',
+      'Test Document.gdoc', '--', 'Google document'),
+
+  testSharedDocument: new TestEntryInfo(
+      EntryType.FILE, null, 'Test Shared Document',
+      'application/vnd.google-apps.document',
+      SharedOption.SHARED, 'Mar 20, 2013, 10:40 PM',
+      'Test Shared Document.gdoc', '--', 'Google document'),
+
+  newlyAdded: new TestEntryInfo(
+      EntryType.FILE, 'music.ogg', 'newly added file.ogg',
+      'audio/ogg', SharedOption.NONE, 'Sep 4, 1998, 12:00 AM',
+      'newly added file.ogg', '14 KB', 'OGG audio'),
+
+  directoryA: new TestEntryInfo(
+      EntryType.DIRECTORY, null, 'A',
+      null, SharedOption.NONE, 'Jan 1, 2000, 1:00 AM',
+      'A', '--', 'Folder'),
+
+  directoryB: new TestEntryInfo(
+      EntryType.DIRECTORY, null, 'A/B',
+      null, SharedOption.NONE, 'Jan 1, 2000, 1:00 AM',
+      'B', '--', 'Folder'),
+
+  directoryC: new TestEntryInfo(
+      EntryType.DIRECTORY, null, 'A/B/C',
+      null, SharedOption.NONE, 'Jan 1, 2000, 1:00 AM',
+      'C', '--', 'Folder'),
+
+  directoryD: new TestEntryInfo(
+      EntryType.DIRECTORY, null, 'D',
+      null, SharedOption.NONE, 'Jan 1, 2000, 1:00 AM',
+      'D', '--', 'Folder'),
+
+  directoryE: new TestEntryInfo(
+      EntryType.DIRECTORY, null, 'D/E',
+      null, SharedOption.NONE, 'Jan 1, 2000, 1:00 AM',
+      'E', '--', 'Folder'),
+
+  directoryF: new TestEntryInfo(
+      EntryType.DIRECTORY, null, 'D/E/F',
+      null, SharedOption.NONE, 'Jan 1, 2000, 1:00 AM',
+      'F', '--', 'Folder'),
+
+  zipArchive: new TestEntryInfo(
+      EntryType.FILE, 'archive.zip', 'archive.zip',
+      'application/x-zip', SharedOption.NONE, 'Jan 1, 2014, 1:00 AM',
+      'archive.zip', '533 bytes', 'Zip archive'),
+
+  hiddenFile: new TestEntryInfo(
+    EntryType.FILE, 'text.txt', '.hiddenfile.txt',
+    'text/plain', SharedOption.NONE, 'Sep 30, 2014, 3:30 PM',
+    '.hiddenfile.txt', '51 bytes', 'Plain text')
+};
+
+/**
+ * Basic entry set for the local volume.
+ * @type {Array<TestEntryInfo>}
+ * @const
+ */
+var BASIC_LOCAL_ENTRY_SET = [
+  ENTRIES.hello,
+  ENTRIES.world,
+  ENTRIES.desktop,
+  ENTRIES.beautiful,
+  ENTRIES.photos
+];
+
+/**
+ * Basic entry set for the drive volume.
+ *
+ * TODO(hirono): Add a case for an entry cached by FileCache. For testing
+ *               Drive, create more entries with Drive specific attributes.
+ *
+ * @type {Array<TestEntryInfo>}
+ * @const
+ */
+var BASIC_DRIVE_ENTRY_SET = [
+  ENTRIES.hello,
+  ENTRIES.world,
+  ENTRIES.desktop,
+  ENTRIES.beautiful,
+  ENTRIES.photos,
+  ENTRIES.unsupported,
+  ENTRIES.testDocument,
+  ENTRIES.testSharedDocument
+];
+
+var INTERVAL_FOR_WAIT_UNTIL = 100;  // ms
+var INTERVAL_FOR_WAIT_LOGGING = 10000; // 10s
+
+/**
+ * Waits until testFunction becomes true.
+ * @param {function(): Object} testFunction A function which is tested.
+ * @return {!Promise} A promise which is fullfilled when the testFunction
+ *     becomes true.
+ */
+function waitUntil(testFunction) {
+  return new Promise(function(resolve) {
+    var tryTestFunction = function() {
+      var result = testFunction();
+      if (result) {
+        resolve(result);
+      } else {
+        setTimeout(tryTestFunction, INTERVAL_FOR_WAIT_UNTIL);
+      }
+    };
+
+    tryTestFunction();
+  });
+}
+
+/**
+ * Waits until specified element exists.
+ */
+function waitForElement(selectors) {
+  return waitUntil(() => {
+    return document.querySelector(selectors);
+  });
+}
+
+/**
+ * Adds specified TestEntryInfos to downloads and drive.
+ *
+ * @param {!Array<TestEntryInfo} downloads Entries for downloads.
+ * @param {!Array<TestEntryInfo} drive Entries for drive.
+ */
+function addEntries(downloads, drive) {
+  var fsDownloads =
+      mockVolumeManager
+          .getCurrentProfileVolumeInfo(VolumeManagerCommon.VolumeType.DOWNLOADS)
+          .fileSystem;
+  fsDownloads.populate(
+      TestEntryInfo.getMockFileSystemPopulateRows(downloads, '/'), true);
+
+  var fsDrive =
+      mockVolumeManager
+          .getCurrentProfileVolumeInfo(VolumeManagerCommon.VolumeType.DRIVE)
+          .fileSystem;
+  fsDrive.populate(
+      TestEntryInfo.getMockFileSystemPopulateRows(drive, '/root/'), true);
+
+  // Send onDirectoryChanged events.
+  chrome.fileManagerPrivate.dispatchEvent_(
+      'onDirectoryChanged', {eventType: 'changed', entry: fsDownloads.root});
+  chrome.fileManagerPrivate.dispatchEvent_(
+      'onDirectoryChanged',
+      {eventType: 'changed', entry: fsDrive.entries['/root']});
+}
+
+/**
+ * Waits for the file list turns to the given contents.
+ * @param {Array<Array<string>>} expected Expected contents of file list.
+ * @param {{orderCheck:boolean=, ignoreName:boolean=, ignoreSize:boolean=,
+ *     ignoreType:boolean=,ignoreDate:boolean=}=} opt_options
+ *     Options of the comparison. If orderCheck is true, it also compares the
+ *     order of files. If ignore[Name|Size|Type|Date] is true, it compares
+ *     the file without considering that field.
+ * @return {Promise} Promise to be fulfilled when the file list turns to the
+ *     given contents.
+ */
+function waitForFiles(expected, opt_options) {
+  var options = opt_options || {};
+  var nextLog = Date.now() + INTERVAL_FOR_WAIT_LOGGING;
+  return waitUntil(function() {
+    var files = test.util.sync.getFileList(window);
+    if (Date.now() > nextLog) {
+      console.debug('waitForFiles', expected, files);
+      nextLog = Date.now() + INTERVAL_FOR_WAIT_LOGGING;
+    }
+    if (!options.orderCheck) {
+      files.sort();
+      expected.sort();
+    }
+    if (files.length != expected.length)
+      return false;
+    for (var i = 0; i < files.length; i++) {
+      // Each row is [name, size, type, date].
+      if ((!options.ignoreName && files[i][0] != expected[i][0]) ||
+          (!options.ignoreSize && files[i][1] != expected[i][1]) ||
+          (!options.ignoreType && files[i][2] != expected[i][2]) ||
+          (!options.ignoreDate && files[i][3] != expected[i][3]))
+        return false;
+    }
+    return true;
+  });
+}
+
+/**
+ * Opens a Files app's main window and waits until it is initialized. Fills
+ * the window with initial files. Should be called for the first window only.
+ *
+ * @return {Promise} Promise to be fulfilled with the result object, which
+ *     contains the file list.
+ */
+function setupAndWaitUntilReady() {
+  return loadData()
+      .then(result => {
+        addEntries(BASIC_LOCAL_ENTRY_SET, BASIC_DRIVE_ENTRY_SET);
+        return waitForElement('#directory-tree [volume-type-icon="downloads"]');
+      })
+      .then(() => {
+        return test.util.sync.fakeMouseClick(
+            window, '#directory-tree [volume-type-icon="downloads"]');
+      })
+      .then(result => {
+        assertTrue(result);
+        return waitForFiles(
+            TestEntryInfo.getExpectedRows(BASIC_LOCAL_ENTRY_SET));
+      });
+}
+
+// Shortcut for endTests with success.
+function doneTests(opt_failed) {
+  endTests(!opt_failed);
+}
diff --git a/ui/file_manager/file_manager/test/scripts/create_test_main.py b/ui/file_manager/file_manager/test/scripts/create_test_main.py
index a20aa52..12b2cf2 100755
--- a/ui/file_manager/file_manager/test/scripts/create_test_main.py
+++ b/ui/file_manager/file_manager/test/scripts/create_test_main.py
@@ -11,11 +11,22 @@
 """
 
 
+import argparse
 import os
 import sys
 
 
 assert __name__ == '__main__'
+
+# If --output is provided, create specified empty file.
+parser = argparse.ArgumentParser()
+parser.add_argument('--output')
+args = parser.parse_args()
+if args.output:
+  with open(args.output, 'w') as output:
+    output.write('')
+
+
 root = os.path.abspath(os.path.join(sys.path[0], '../..'))
 scripts = []
 GENERATED_HTML = ('<!-- Generated by:\n  -- ui/file_manager/file_manager/'
@@ -25,14 +36,16 @@
 
 
 def read(path):
-  return open(os.path.join(root, path)).read()
+  with open(os.path.join(root, path)) as f:
+    return f.read()
 
 
 def write(path, content):
   fullpath = os.path.join(root, path)
   if not os.path.exists(os.path.dirname(fullpath)):
     os.makedirs(os.path.dirname(fullpath))
-  open(fullpath, 'w').write(content)
+  with open(fullpath, 'w') as f:
+    f.write(content)
 
 
 def insertbeforeline(f, match, lines):
@@ -118,24 +131,26 @@
     ])
 
 # Add scripts for testing.
-scripts += [
-    '<script src="js/chrome_api_test_impl.js"></script>',
-    '<script src="../../../webui/resources/js/assert.js"></script>',
-    '<script src="../../../webui/resources/js/cr.js"></script>',
-    '<script src="../../../webui/resources/js/cr/event_target.js"></script>',
-    ('<script src="../../../webui/resources/js/cr/ui/array_data_model.js">'
-     '</script>'),
-    '<script src="../../../webui/resources/js/load_time_data.js"></script>',
-    '<script src="js/strings.js"></script>',
-    '<script src="../common/js/util.js"></script>',
-    '<script src="../common/js/mock_entry.js"></script>',
-    '<script src="../common/js/volume_manager_common.js"></script>',
-    '<script src="../background/js/volume_info_impl.js"></script>',
-    '<script src="../background/js/volume_info_list_impl.js"></script>',
-    '<script src="../background/js/volume_manager_impl.js"></script>',
-    '<script src="../background/js/mock_volume_manager.js"></script>',
-    '<script src="js/chrome_file_manager.js"></script>',
-]
+scripts += ['<script src="%s"></script>' % s for s in (
+    'js/chrome_api_test_impl.js',
+    '../../../webui/resources/js/assert.js',
+    '../../../webui/resources/js/cr.js',
+    '../../../webui/resources/js/cr/event_target.js',
+    '../../../webui/resources/js/cr/ui/array_data_model.js">',
+    '../../../webui/resources/js/load_time_data.js',
+    '../../../webui/resources/js/webui_resource_test.js">',
+    'js/strings.js',
+    '../common/js/util.js',
+    '../common/js/mock_entry.js',
+    '../common/js/volume_manager_common.js',
+    '../background/js/volume_info_impl.js',
+    '../background/js/volume_info_list_impl.js',
+    '../background/js/volume_manager_impl.js',
+    '../background/js/mock_volume_manager.js',
+    'js/chrome_file_manager.js',
+    'js/test_util.js',
+    'delete.js',
+)]
 
 # Convert all includes from:
 #  * foreground/js/main_scripts.js
@@ -158,5 +173,3 @@
                         ['<script src="js/ui/banners.js"></script>'])
 
 write('test/main.html', GENERATED_HTML + '\n'.join(main_html))
-
-print 'done'
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index e0f776f..e355204 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -789,7 +789,7 @@
   if (!is_ios) {
     deps += [
       "//cc/paint",
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//mojo/public/cpp/bindings",
       "//ui/gfx/geometry/mojo:unit_test",
       "//ui/gfx/image/mojo:unit_test",
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index aceafe60..8766dce 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -430,7 +430,7 @@
 
   if (use_ozone) {
     deps += [
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//services/service_manager/public/cpp/test:test_support",
       "//ui/ozone",
     ]
diff --git a/ui/keyboard/BUILD.gn b/ui/keyboard/BUILD.gn
index ccf79d4..a5a5119 100644
--- a/ui/keyboard/BUILD.gn
+++ b/ui/keyboard/BUILD.gn
@@ -169,7 +169,7 @@
     ":test_support",
     "//base",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//testing/gtest",
     "//ui/aura:test_support",
     "//ui/base",
diff --git a/ui/message_center/BUILD.gn b/ui/message_center/BUILD.gn
index ed816055f..3511c92 100644
--- a/ui/message_center/BUILD.gn
+++ b/ui/message_center/BUILD.gn
@@ -209,7 +209,7 @@
       ":test_support",
       "//base",
       "//base/test:test_support",
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//skia",
       "//testing/gmock",
       "//testing/gtest",
@@ -236,7 +236,7 @@
     if (is_chromeos) {
       sources += [ "public/mojo/struct_traits_unittest.cc" ]
       deps += [
-        "//mojo/edk/system",
+        "//mojo/edk",
         "//ui/message_center/public/mojo:test_interfaces",
       ]
     }
diff --git a/ui/ozone/common/gpu/ozone_gpu_message_params.h b/ui/ozone/common/gpu/ozone_gpu_message_params.h
index 0c5ca17..0606510 100644
--- a/ui/ozone/common/gpu/ozone_gpu_message_params.h
+++ b/ui/ozone/common/gpu/ozone_gpu_message_params.h
@@ -53,7 +53,8 @@
   DisplayMode_Params current_mode;
   bool has_native_mode = false;
   DisplayMode_Params native_mode;
-  int64_t product_id = 0;
+  int64_t product_code = 0;
+  int32_t year_of_manufacture = display::kInvalidYearOfManufacture;
   gfx::Size maximum_cursor_size;
 };
 
diff --git a/ui/ozone/common/gpu/ozone_gpu_messages.h b/ui/ozone/common/gpu/ozone_gpu_messages.h
index 6db409c..d472f08 100644
--- a/ui/ozone/common/gpu/ozone_gpu_messages.h
+++ b/ui/ozone/common/gpu/ozone_gpu_messages.h
@@ -4,6 +4,7 @@
 
 // Multiply-included message file, hence no include guard here, but see below
 // for a much smaller-than-usual include guard section.
+// no-include-guard-because-multiply-included
 
 #include <stdint.h>
 
@@ -62,7 +63,8 @@
   IPC_STRUCT_TRAITS_MEMBER(current_mode)
   IPC_STRUCT_TRAITS_MEMBER(has_native_mode)
   IPC_STRUCT_TRAITS_MEMBER(native_mode)
-  IPC_STRUCT_TRAITS_MEMBER(product_id)
+  IPC_STRUCT_TRAITS_MEMBER(product_code)
+  IPC_STRUCT_TRAITS_MEMBER(year_of_manufacture)
   IPC_STRUCT_TRAITS_MEMBER(maximum_cursor_size)
 IPC_STRUCT_TRAITS_END()
 
diff --git a/ui/ozone/platform/drm/common/drm_util.cc b/ui/ozone/platform/drm/common/drm_util.cc
index d4c3dd5..0c17e967 100644
--- a/ui/ozone/platform/drm/common/drm_util.cc
+++ b/ui/ozone/platform/drm/common/drm_util.cc
@@ -15,6 +15,7 @@
 
 #include "base/containers/flat_map.h"
 #include "base/memory/ptr_util.h"
+#include "ui/display/types/display_constants.h"
 #include "ui/display/types/display_mode.h"
 #include "ui/display/util/edid_parser.h"
 
@@ -393,7 +394,8 @@
 
   std::vector<uint8_t> edid;
   std::string display_name;
-  int64_t product_id = display::DisplaySnapshot::kInvalidProductID;
+  int64_t product_code = display::DisplaySnapshot::kInvalidProductCode;
+  int32_t year_of_manufacture = display::kInvalidYearOfManufacture;
   bool has_overscan = false;
   gfx::ColorSpace display_color_space;
 
@@ -407,10 +409,13 @@
     edid.assign(static_cast<uint8_t*>(edid_blob->data),
                 static_cast<uint8_t*>(edid_blob->data) + edid_blob->length);
 
-    display::GetDisplayIdFromEDID(edid, display_id, &display_id, &product_id);
-
+    // TODO(mcasas): GetDisplayIdFromEDID() calls ParseOutputDeviceData(), clean
+    // up the code and add UMA for EDID errors, https://crbug.com/821393. Also
+    // handle correctly the parsing failures of the following functions.
+    display::GetDisplayIdFromEDID(edid, display_id, &display_id, &product_code);
     display::ParseOutputDeviceData(edid, nullptr, nullptr, &display_name,
                                    &active_pixel_size, nullptr);
+    display::ParseYearOfManufacture(edid, &year_of_manufacture);
     display::ParseOutputOverscanFlag(edid, &has_overscan);
 
     display_color_space = GetColorSpaceFromEdid(edid);
@@ -428,7 +433,7 @@
       display_id, origin, physical_size, type, is_aspect_preserving_scaling,
       has_overscan, has_color_correction_matrix, display_color_space,
       display_name, sys_path, std::move(modes), edid, current_mode, native_mode,
-      product_id, maximum_cursor_size);
+      product_code, year_of_manufacture, maximum_cursor_size);
 }
 
 // TODO(rjkroege): Remove in a subsequent CL once Mojo IPC is used everywhere.
@@ -464,7 +469,8 @@
     if (d->native_mode())
       p.native_mode = GetDisplayModeParams(*d->native_mode());
 
-    p.product_id = d->product_id();
+    p.product_code = d->product_code();
+    p.year_of_manufacture = d->year_of_manufacture();
     p.maximum_cursor_size = d->maximum_cursor_size();
 
     params.push_back(p);
@@ -490,7 +496,8 @@
       params.is_aspect_preserving_scaling, params.has_overscan,
       params.has_color_correction_matrix, params.color_space,
       params.display_name, params.sys_path, std::move(modes), params.edid,
-      current_mode, native_mode, params.product_id, params.maximum_cursor_size);
+      current_mode, native_mode, params.product_code,
+      params.year_of_manufacture, params.maximum_cursor_size);
 }
 
 int GetFourCCFormatFromBufferFormat(gfx::BufferFormat format) {
diff --git a/ui/ozone/platform/drm/common/drm_util_unittest.cc b/ui/ozone/platform/drm/common/drm_util_unittest.cc
index 03dae19..92227ba 100644
--- a/ui/ozone/platform/drm/common/drm_util_unittest.cc
+++ b/ui/ozone/platform/drm/common/drm_util_unittest.cc
@@ -114,7 +114,8 @@
          a.has_current_mode == b.has_current_mode &&
          a.current_mode == b.current_mode &&
          a.has_native_mode == b.has_native_mode &&
-         a.native_mode == b.native_mode && a.product_id == b.product_id &&
+         a.native_mode == b.native_mode && a.product_code == b.product_code &&
+         a.year_of_manufacture == b.year_of_manufacture &&
          a.maximum_cursor_size == b.maximum_cursor_size;
 }
 
@@ -146,7 +147,8 @@
   EXPECT_EQ(a.current_mode, b.current_mode);
   EXPECT_EQ(a.has_native_mode, b.has_native_mode);
   EXPECT_EQ(a.native_mode, b.native_mode);
-  EXPECT_EQ(a.product_id, b.product_id);
+  EXPECT_EQ(a.product_code, b.product_code);
+  EXPECT_EQ(a.year_of_manufacture, b.year_of_manufacture);
   EXPECT_EQ(a.maximum_cursor_size, b.maximum_cursor_size);
 }
 
@@ -187,7 +189,8 @@
   fp.current_mode = MakeDisplay(1.2);
   fp.has_native_mode = true;
   fp.native_mode = MakeDisplay(1.1);
-  fp.product_id = 7;
+  fp.product_code = 7;
+  fp.year_of_manufacture = 1776;
   fp.maximum_cursor_size = gfx::Size(103, 44);
 
   sp.display_id = 1002;
@@ -206,7 +209,8 @@
   sp.has_current_mode = false;
   sp.has_native_mode = true;
   sp.native_mode = MakeDisplay(500.2);
-  sp.product_id = 8;
+  sp.product_code = 8;
+  sp.year_of_manufacture = 2018;
   sp.maximum_cursor_size = gfx::Size(500, 44);
 
   ep.display_id = 2002;
@@ -225,7 +229,8 @@
   ep.has_current_mode = true;
   ep.current_mode = MakeDisplay(1000.2);
   ep.has_native_mode = false;
-  ep.product_id = 9;
+  ep.product_code = 9;
+  ep.year_of_manufacture = 2000;
   ep.maximum_cursor_size = gfx::Size(1000, 44);
 
   orig_params.push_back(fp);
diff --git a/ui/snapshot/BUILD.gn b/ui/snapshot/BUILD.gn
index f237988..840df0e7 100644
--- a/ui/snapshot/BUILD.gn
+++ b/ui/snapshot/BUILD.gn
@@ -100,7 +100,7 @@
     ":snapshot",
     "//base",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//skia",
     "//testing/gtest",
     "//ui/base",
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index c16fa85..443a433 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -803,7 +803,7 @@
     "//base/test:test_support",
     "//gpu/ipc/service",
     "//ipc:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//skia",
     "//testing/gtest",
     "//ui/base",
@@ -1118,7 +1118,7 @@
 
   deps = [
     ":views_unittests_sources",
-    "//mojo/edk/system",
+    "//mojo/edk",
   ]
 }
 
@@ -1136,7 +1136,7 @@
     ":views",
     "//base",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//skia",
     "//testing/gtest",
     "//ui/base:test_support",
@@ -1195,7 +1195,7 @@
     ":test_support",
     "//base/test:test_support",
     "//cc/base:base",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//testing/perf",
     "//ui/resources:ui_test_pak",
   ]
diff --git a/ui/views/animation/ink_drop.h b/ui/views/animation/ink_drop.h
index 3569e01..00de74c 100644
--- a/ui/views/animation/ink_drop.h
+++ b/ui/views/animation/ink_drop.h
@@ -36,6 +36,14 @@
   // Animates from the current InkDropState to |ink_drop_state|.
   virtual void AnimateToState(InkDropState ink_drop_state) = 0;
 
+  // Sets hover highlight fade animations to last for |duration_ms|
+  // milliseconds.
+  virtual void SetHoverHighlightFadeDurationMs(int duration_ms) = 0;
+
+  // Clears any set hover highlight fade durations and uses the default
+  // durations instead.
+  virtual void UseDefaultHoverHighlightFadeDuration() = 0;
+
   // Immediately snaps the InkDropState to ACTIVATED and HIDDEN specifically.
   // These are more specific implementations of the non-existent
   // SnapToState(InkDropState) function are the only ones available because they
diff --git a/ui/views/animation/ink_drop_impl.cc b/ui/views/animation/ink_drop_impl.cc
index 00ee395..cf6247ec 100644
--- a/ui/views/animation/ink_drop_impl.cc
+++ b/ui/views/animation/ink_drop_impl.cc
@@ -171,11 +171,15 @@
 }
 
 void InkDropImpl::NoAutoHighlightHiddenState::ShowOnHoverChanged() {
-  HandleHoverAndFocusChangeChanges(kHighlightFadeInOnHoverChangeDurationMs);
+  HandleHoverAndFocusChangeChanges(
+      GetInkDrop()->hover_highlight_fade_duration_ms().value_or(
+          kHighlightFadeInOnHoverChangeDurationMs));
 }
 
 void InkDropImpl::NoAutoHighlightHiddenState::OnHoverChanged() {
-  HandleHoverAndFocusChangeChanges(kHighlightFadeInOnHoverChangeDurationMs);
+  HandleHoverAndFocusChangeChanges(
+      GetInkDrop()->hover_highlight_fade_duration_ms().value_or(
+          kHighlightFadeInOnHoverChangeDurationMs));
 }
 
 void InkDropImpl::NoAutoHighlightHiddenState::ShowOnFocusChanged() {
@@ -216,11 +220,15 @@
 }
 
 void InkDropImpl::NoAutoHighlightVisibleState::ShowOnHoverChanged() {
-  HandleHoverAndFocusChangeChanges(kHighlightFadeOutOnHoverChangeDurationMs);
+  HandleHoverAndFocusChangeChanges(
+      GetInkDrop()->hover_highlight_fade_duration_ms().value_or(
+          kHighlightFadeOutOnHoverChangeDurationMs));
 }
 
 void InkDropImpl::NoAutoHighlightVisibleState::OnHoverChanged() {
-  HandleHoverAndFocusChangeChanges(kHighlightFadeOutOnHoverChangeDurationMs);
+  HandleHoverAndFocusChangeChanges(
+      GetInkDrop()->hover_highlight_fade_duration_ms().value_or(
+          kHighlightFadeOutOnHoverChangeDurationMs));
 }
 
 void InkDropImpl::NoAutoHighlightVisibleState::ShowOnFocusChanged() {
@@ -647,6 +655,14 @@
   ink_drop_ripple_->AnimateToState(ink_drop_state);
 }
 
+void InkDropImpl::SetHoverHighlightFadeDurationMs(int duration_ms) {
+  hover_highlight_fade_duration_ms_ = duration_ms;
+}
+
+void InkDropImpl::UseDefaultHoverHighlightFadeDuration() {
+  hover_highlight_fade_duration_ms_.reset();
+}
+
 void InkDropImpl::SnapToActivated() {
   DestroyHiddenTargetedAnimations();
   if (!ink_drop_ripple_)
diff --git a/ui/views/animation/ink_drop_impl.h b/ui/views/animation/ink_drop_impl.h
index 2f15875..05862e2 100644
--- a/ui/views/animation/ink_drop_impl.h
+++ b/ui/views/animation/ink_drop_impl.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/optional.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/views/animation/ink_drop.h"
@@ -66,10 +67,16 @@
   // set to SHOW_ON_RIPPLE highlight behavior.
   void SetAutoHighlightModeForPlatform();
 
+  const base::Optional<int>& hover_highlight_fade_duration_ms() const {
+    return hover_highlight_fade_duration_ms_;
+  }
+
   // InkDrop:
   void HostSizeChanged(const gfx::Size& new_size) override;
   InkDropState GetTargetInkDropState() const override;
   void AnimateToState(InkDropState ink_drop_state) override;
+  void SetHoverHighlightFadeDurationMs(int duration_ms) override;
+  void UseDefaultHoverHighlightFadeDuration() override;
   void SnapToActivated() override;
   void SnapToHidden() override;
   void SetHovered(bool is_hovered) override;
@@ -306,6 +313,9 @@
   // of the |highlight_|.
   std::unique_ptr<HighlightState> highlight_state_;
 
+  // Overrides the default hover highlight fade durations when set.
+  base::Optional<int> hover_highlight_fade_duration_ms_;
+
   // Used to ensure highlight state transitions are not triggered when exiting
   // the current state.
   bool exiting_highlight_state_;
diff --git a/ui/views/animation/ink_drop_stub.cc b/ui/views/animation/ink_drop_stub.cc
index 9a8237b..5cc5d00 100644
--- a/ui/views/animation/ink_drop_stub.cc
+++ b/ui/views/animation/ink_drop_stub.cc
@@ -18,6 +18,10 @@
 
 void InkDropStub::AnimateToState(InkDropState state) {}
 
+void InkDropStub::SetHoverHighlightFadeDurationMs(int duration_ms) {}
+
+void InkDropStub::UseDefaultHoverHighlightFadeDuration() {}
+
 void InkDropStub::SnapToActivated() {}
 
 void InkDropStub::SnapToHidden() {}
diff --git a/ui/views/animation/ink_drop_stub.h b/ui/views/animation/ink_drop_stub.h
index 86ed882..a1b441a1 100644
--- a/ui/views/animation/ink_drop_stub.h
+++ b/ui/views/animation/ink_drop_stub.h
@@ -22,6 +22,8 @@
   void HostSizeChanged(const gfx::Size& new_size) override;
   InkDropState GetTargetInkDropState() const override;
   void AnimateToState(InkDropState state) override;
+  void SetHoverHighlightFadeDurationMs(int duration_ms) override;
+  void UseDefaultHoverHighlightFadeDuration() override;
   void SnapToActivated() override;
   void SnapToHidden() override;
   void SetHovered(bool is_hovered) override;
diff --git a/ui/views/animation/test/test_ink_drop.cc b/ui/views/animation/test/test_ink_drop.cc
index 4874f1d4..13c87c2 100644
--- a/ui/views/animation/test/test_ink_drop.cc
+++ b/ui/views/animation/test/test_ink_drop.cc
@@ -20,6 +20,10 @@
   state_ = ink_drop_state;
 }
 
+void TestInkDrop::SetHoverHighlightFadeDurationMs(int duration_ms) {}
+
+void TestInkDrop::UseDefaultHoverHighlightFadeDuration() {}
+
 void TestInkDrop::SnapToActivated() {
   state_ = InkDropState::ACTIVATED;
 }
diff --git a/ui/views/animation/test/test_ink_drop.h b/ui/views/animation/test/test_ink_drop.h
index 0d2ffffe..2fdf7de2 100644
--- a/ui/views/animation/test/test_ink_drop.h
+++ b/ui/views/animation/test/test_ink_drop.h
@@ -24,6 +24,8 @@
   void HostSizeChanged(const gfx::Size& new_size) override;
   InkDropState GetTargetInkDropState() const override;
   void AnimateToState(InkDropState ink_drop_state) override;
+  void SetHoverHighlightFadeDurationMs(int duration_ms) override;
+  void UseDefaultHoverHighlightFadeDuration() override;
   void SnapToActivated() override;
   void SnapToHidden() override;
   void SetHovered(bool is_hovered) override;
diff --git a/ui/views/controls/table/table_header.cc b/ui/views/controls/table/table_header.cc
index dd72a41..8c5b20f 100644
--- a/ui/views/controls/table/table_header.cc
+++ b/ui/views/controls/table/table_header.cc
@@ -242,7 +242,7 @@
   resize_details_.reset(new ColumnResizeDetails);
   resize_details_->column_index = index;
   resize_details_->initial_x = event.root_location().x();
-  resize_details_->initial_width = table_->visible_columns()[index].width;
+  resize_details_->initial_width = table_->GetVisibleColumn(index).width;
   return true;
 }
 
@@ -253,9 +253,15 @@
   const int scale = base::i18n::IsRTL() ? -1 : 1;
   const int delta = scale *
       (event.root_location().x() - resize_details_->initial_x);
+  const TableView::VisibleColumn& column =
+      table_->GetVisibleColumn(resize_details_->column_index);
+  const int needed_for_title =
+      gfx::GetStringWidth(column.column.title, font_list_) +
+      2 * kHorizontalPadding;
   table_->SetVisibleColumnWidth(
       resize_details_->column_index,
-      std::max(kMinColumnWidth, resize_details_->initial_width + delta));
+      std::max({kMinColumnWidth, needed_for_title,
+                resize_details_->initial_width + delta}));
 }
 
 void TableHeader::ToggleSortOrder(const ui::LocatedEvent& event) {
@@ -264,7 +270,7 @@
 
   const int x = GetMirroredXInView(event.x());
   const int index = GetClosestVisibleColumnIndex(table_, x);
-  const TableView::VisibleColumn& column(table_->visible_columns()[index]);
+  const TableView::VisibleColumn& column(table_->GetVisibleColumn(index));
   if (x >= column.x && x < column.x + column.width && event.y() >= 0 &&
       event.y() < height())
     table_->ToggleSortOrder(index);
@@ -277,7 +283,7 @@
 
   const int index = GetClosestVisibleColumnIndex(table_, x);
   DCHECK_NE(-1, index);
-  const TableView::VisibleColumn& column(table_->visible_columns()[index]);
+  const TableView::VisibleColumn& column(table_->GetVisibleColumn(index));
   if (index > 0 && x >= column.x - kResizePadding &&
       x <= column.x + kResizePadding) {
     return index - 1;
diff --git a/ui/views/controls/table/table_view.cc b/ui/views/controls/table/table_view.cc
index a6c8234c..d1e4bef 100644
--- a/ui/views/controls/table/table_view.cc
+++ b/ui/views/controls/table/table_view.cc
@@ -287,6 +287,11 @@
   return false;
 }
 
+const TableView::VisibleColumn& TableView::GetVisibleColumn(int index) {
+  DCHECK(index >= 0 && index < static_cast<int>(visible_columns_.size()));
+  return visible_columns_[index];
+}
+
 void TableView::SetVisibleColumnWidth(int index, int width) {
   DCHECK(index >= 0 && index < static_cast<int>(visible_columns_.size()));
   if (visible_columns_[index].width == width)
diff --git a/ui/views/controls/table/table_view.h b/ui/views/controls/table/table_view.h
index b62e21c..eca7e3e 100644
--- a/ui/views/controls/table/table_view.h
+++ b/ui/views/controls/table/table_view.h
@@ -139,6 +139,8 @@
     return visible_columns_;
   }
 
+  const VisibleColumn& GetVisibleColumn(int index);
+
   // Sets the width of the column. |index| is in terms of |visible_columns_|.
   void SetVisibleColumnWidth(int index, int width);
 
diff --git a/ui/views/controls/table/table_view_unittest.cc b/ui/views/controls/table/table_view_unittest.cc
index e5f895e..88df9b2 100644
--- a/ui/views/controls/table/table_view_unittest.cc
+++ b/ui/views/controls/table/table_view_unittest.cc
@@ -12,6 +12,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/events/event_utils.h"
 #include "ui/events/test/event_generator.h"
+#include "ui/gfx/text_utils.h"
 #include "ui/views/controls/table/table_grouper.h"
 #include "ui/views/controls/table/table_header.h"
 #include "ui/views/controls/table/table_view_observer.h"
@@ -46,6 +47,8 @@
     table_->SetSelectionModel(new_selection);
   }
 
+  const gfx::FontList& font_list() { return table_->font_list_; }
+
  private:
   TableView* table_;
 
@@ -197,7 +200,7 @@
     // Format row |i| like this: "[value1, value2, value3]"
     result += "[";
     for (size_t j = 0; j < table->visible_columns().size(); ++j) {
-      const ui::TableColumn& column = table->visible_columns()[j].column;
+      const ui::TableColumn& column = table->GetVisibleColumn(j).column;
       if (j != 0)
         result += ", ";  // Comma between each value in the row.
 
@@ -209,6 +212,27 @@
   return result;
 }
 
+bool PressLeftMouseAt(views::View* target, const gfx::Point& point) {
+  const ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, point, point,
+                               ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+                               ui::EF_LEFT_MOUSE_BUTTON);
+  return target->OnMousePressed(pressed);
+}
+
+void ReleaseLeftMouseAt(views::View* target, const gfx::Point& point) {
+  const ui::MouseEvent release(ui::ET_MOUSE_RELEASED, point, point,
+                               ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+                               ui::EF_LEFT_MOUSE_BUTTON);
+  target->OnMouseReleased(release);
+}
+
+bool DragLeftMouseTo(views::View* target, const gfx::Point& point) {
+  const ui::MouseEvent dragged(ui::ET_MOUSE_DRAGGED, point, point,
+                               ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
+                               0);
+  return target->OnMouseDragged(dragged);
+}
+
 }  // namespace
 
 class TableViewTest : public ViewsTestBase {
@@ -324,7 +348,7 @@
   // Hide the first column.
   table_->SetColumnVisibility(0, false);
   ASSERT_EQ(1u, helper_->visible_col_count());
-  EXPECT_EQ(1, table_->visible_columns()[0].column.id);
+  EXPECT_EQ(1, table_->GetVisibleColumn(0).column.id);
   EXPECT_EQ("rows=0 4 cols=0 1", helper_->GetPaintRegion(table_->bounds()));
 
   // Hide the second column.
@@ -334,40 +358,33 @@
   // Show the second column.
   table_->SetColumnVisibility(1, true);
   ASSERT_EQ(1u, helper_->visible_col_count());
-  EXPECT_EQ(1, table_->visible_columns()[0].column.id);
+  EXPECT_EQ(1, table_->GetVisibleColumn(0).column.id);
   EXPECT_EQ("rows=0 4 cols=0 1", helper_->GetPaintRegion(table_->bounds()));
 
   // Show the first column.
   table_->SetColumnVisibility(0, true);
   ASSERT_EQ(2u, helper_->visible_col_count());
-  EXPECT_EQ(1, table_->visible_columns()[0].column.id);
-  EXPECT_EQ(0, table_->visible_columns()[1].column.id);
+  EXPECT_EQ(1, table_->GetVisibleColumn(0).column.id);
+  EXPECT_EQ(0, table_->GetVisibleColumn(1).column.id);
   EXPECT_EQ("rows=0 4 cols=0 2", helper_->GetPaintRegion(table_->bounds()));
 }
 
 // Verifies resizing a column works.
 TEST_F(TableViewTest, Resize) {
-  const int x = table_->visible_columns()[0].width;
+  const int x = table_->GetVisibleColumn(0).width;
   EXPECT_NE(0, x);
   // Drag the mouse 1 pixel to the left.
-  const ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(x, 0),
-                               gfx::Point(x, 0), ui::EventTimeForNow(),
-                               ui::EF_LEFT_MOUSE_BUTTON,
-                               ui::EF_LEFT_MOUSE_BUTTON);
-  helper_->header()->OnMousePressed(pressed);
-  const ui::MouseEvent dragged(ui::ET_MOUSE_DRAGGED, gfx::Point(x - 1, 0),
-                               gfx::Point(x - 1, 0), ui::EventTimeForNow(),
-                               ui::EF_LEFT_MOUSE_BUTTON, 0);
-  helper_->header()->OnMouseDragged(dragged);
+  PressLeftMouseAt(helper_->header(), gfx::Point(x, 0));
+  DragLeftMouseTo(helper_->header(), gfx::Point(x - 1, 0));
 
   // This should shrink the first column and pull the second column in.
-  EXPECT_EQ(x - 1, table_->visible_columns()[0].width);
-  EXPECT_EQ(x - 1, table_->visible_columns()[1].x);
+  EXPECT_EQ(x - 1, table_->GetVisibleColumn(0).width);
+  EXPECT_EQ(x - 1, table_->GetVisibleColumn(1).x);
 }
 
 // Verifies resizing a column works with a gesture.
 TEST_F(TableViewTest, ResizeViaGesture) {
-  const int x = table_->visible_columns()[0].width;
+  const int x = table_->GetVisibleColumn(0).width;
   EXPECT_NE(0, x);
   // Drag the mouse 1 pixel to the left.
   ui::GestureEvent scroll_begin(
@@ -380,8 +397,27 @@
   helper_->header()->OnGestureEvent(&scroll_update);
 
   // This should shrink the first column and pull the second column in.
-  EXPECT_EQ(x - 1, table_->visible_columns()[0].width);
-  EXPECT_EQ(x - 1, table_->visible_columns()[1].x);
+  EXPECT_EQ(x - 1, table_->GetVisibleColumn(0).width);
+  EXPECT_EQ(x - 1, table_->GetVisibleColumn(1).x);
+}
+
+// Verifies resizing a column won't reduce the column width below the width of
+// the column's title text.
+TEST_F(TableViewTest, ResizeHonorsMinimum) {
+  TableViewTestHelper helper(table_);
+  const int x = table_->GetVisibleColumn(0).width;
+  EXPECT_NE(0, x);
+
+  PressLeftMouseAt(helper_->header(), gfx::Point(x, 0));
+  DragLeftMouseTo(helper_->header(), gfx::Point(20, 0));
+
+  int title_width = gfx::GetStringWidth(
+      table_->GetVisibleColumn(0).column.title, helper.font_list());
+  EXPECT_LT(title_width, table_->GetVisibleColumn(0).width);
+
+  int old_width = table_->GetVisibleColumn(0).width;
+  DragLeftMouseTo(helper_->header(), gfx::Point(old_width + 10, 0));
+  EXPECT_EQ(old_width + 10, table_->GetVisibleColumn(0).width);
 }
 
 // Assertions for table sorting.
@@ -519,20 +555,12 @@
 TEST_F(TableViewTest, SortOnMouse) {
   EXPECT_TRUE(table_->sort_descriptors().empty());
 
-  const int x = table_->visible_columns()[0].width / 2;
+  const int x = table_->GetVisibleColumn(0).width / 2;
   EXPECT_NE(0, x);
   // Press and release the mouse.
-  const ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, gfx::Point(x, 0),
-                               gfx::Point(x, 0), ui::EventTimeForNow(),
-                               ui::EF_LEFT_MOUSE_BUTTON,
-                               ui::EF_LEFT_MOUSE_BUTTON);
   // The header must return true, else it won't normally get the release.
-  EXPECT_TRUE(helper_->header()->OnMousePressed(pressed));
-  const ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(x, 0),
-                               gfx::Point(x, 0), ui::EventTimeForNow(),
-                               ui::EF_LEFT_MOUSE_BUTTON,
-                               ui::EF_LEFT_MOUSE_BUTTON);
-  helper_->header()->OnMouseReleased(release);
+  EXPECT_TRUE(PressLeftMouseAt(helper_->header(), gfx::Point(x, 0)));
+  ReleaseLeftMouseAt(helper_->header(), gfx::Point(x, 0));
 
   ASSERT_EQ(1u, table_->sort_descriptors().size());
   EXPECT_EQ(0, table_->sort_descriptors()[0].column_id);
diff --git a/ui/views/mus/BUILD.gn b/ui/views/mus/BUILD.gn
index aa31e409..89219f7 100644
--- a/ui/views/mus/BUILD.gn
+++ b/ui/views/mus/BUILD.gn
@@ -122,7 +122,7 @@
     ":mus",
     "//base",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//services/catalog:lib",
     "//services/service_manager/background:lib",
     "//services/service_manager/public/cpp",
@@ -244,7 +244,7 @@
     ":mus",
     ":test_support",
     "//base",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//testing/gmock",
     "//testing/gtest",
     "//ui/aura",
diff --git a/ui/wm/BUILD.gn b/ui/wm/BUILD.gn
index 7b832f6..a5637d2 100644
--- a/ui/wm/BUILD.gn
+++ b/ui/wm/BUILD.gn
@@ -143,7 +143,7 @@
     ":wm",
     "//base",
     "//base/test:test_support",
-    "//mojo/edk/system",
+    "//mojo/edk",
     "//skia",
     "//testing/gtest",
     "//ui/aura:test_support",
diff --git a/url/BUILD.gn b/url/BUILD.gn
index 697a611..f2af9f9 100644
--- a/url/BUILD.gn
+++ b/url/BUILD.gn
@@ -167,7 +167,7 @@
 
   if (!is_ios) {
     deps += [
-      "//mojo/edk/system",
+      "//mojo/edk",
       "//mojo/edk/test:test_support",
       "//url/mojom:test_url_mojom_gurl",
     ]